DeepSeek Vision API: cómo analizar imágenes con Python

Para usar DeepSeek Vision API, envía una imagen y una instrucción al modelo deepseek-flash. Puedes hacerlo desde Python mediante Chat Completions y recibir texto que describa, transcriba o responda preguntas sobre el contenido visible.

El recorrido que sigue parte de una imagen guardada en tu computadora. Primero ejecutarás una solicitud completa; después podrás elegir entre base64, un enlace público o Files API, ajustar el detalle y revisar el consumo. La imagen se envía al servicio de DeepSeek: este ejemplo no ejecuta el modelo de forma local.

Qué modelo y endpoint debes usar

DatoConfiguración para este tutorial
Modelodeepseek-flash.
URL base del clientehttps://api.deepseek.com.
Endpoint HTTPPOST https://api.deepseek.com/chat/completions.
EntradaUn mensaje de usuario con partes de texto e imagen.
Salida que leerásTexto en choices[0].message.content.

La tabla oficial de modelos identifica la versión actual de Flash como DeepSeek-V4.1-Flash-1017 y marca Vision como no compatible con deepseek-v4-pro. Los identificadores antiguos deepseek-v4-flash y deepseek-v4-flash-vision-exp siguen aceptándose, pero se dirigen al Flash actual; para una integración nueva utiliza deepseek-flash.

Tabla oficial de DeepSeek: Vision compatible con deepseek-flash y no compatible con deepseek-v4-pro.

En este flujo se usa el endpoint de Chat Completions. No necesitas inventar una ruta /vision ni un modelo llamado deepseek-vision.

Cómo analizar una imagen local con Python

Prepara el entorno, la clave y la imagen

Necesitas una clave de DeepSeek Platform, saldo suficiente para la solicitud y una imagen JPEG, PNG, GIF o WebP. Para las dependencias actuales del ejemplo, utiliza Python 3.11–3.15, rango compatible con Pillow 13.

Crea una carpeta de trabajo y un entorno virtual. Si tu instalación utiliza el comando python3, úsalo en lugar de python al crear el entorno:

python -m venv .venv

En macOS o Linux:

source .venv/bin/activate
python -m pip install openai pillow
export DEEPSEEK_API_KEY="TU_CLAVE_DEEPSEEK"

En PowerShell de Windows:

.\.venv\Scripts\Activate.ps1
python -m pip install openai pillow
$env:DEEPSEEK_API_KEY="TU_CLAVE_DEEPSEEK"

Reemplaza TU_CLAVE_DEEPSEEK por tu credencial privada en la terminal. Mantén esa clave fuera del archivo Python y de los repositorios. La biblioteca openai funciona aquí como cliente compatible; la URL y la credencial corresponden a DeepSeek.

Ejemplo completo: enviar la imagen y leer la respuesta

Guarda el siguiente código como analizar_imagen_deepseek.py. Comprueba el formato real del archivo, su tamaño y sus dimensiones antes de construir la solicitud; cambiar la extensión de una imagen no cambia su contenido.

#!/usr/bin/env python3
"""Analiza una imagen local. Requiere Python 3.11+, openai y Pillow."""

import argparse
import base64
import io
import os
import sys
from pathlib import Path

from openai import APIError, APIStatusError, OpenAI
from PIL import Image

MAX_IMAGE_BYTES = 32 * 1024 * 1024
MIME_TYPES = {"JPEG": "image/jpeg", "PNG": "image/png",
              "GIF": "image/gif", "WEBP": "image/webp"}


def image_data_url(path):
    with path.open("rb") as image_file:
        raw = image_file.read(MAX_IMAGE_BYTES + 1)
    if not raw or len(raw) > MAX_IMAGE_BYTES:
        raise ValueError("La imagen debe ocupar entre 1 byte y 32 MiB.")
    with Image.open(io.BytesIO(raw)) as image:
        mime = MIME_TYPES.get(image.format)
        if mime is None:
            raise ValueError("Solo se admiten JPEG, PNG, GIF y WebP.")
        if max(image.size) > 8192:
            raise ValueError("Cada lado debe medir como máximo 8192 píxeles.")
        image.verify()
    return f"data:{mime};base64,{base64.b64encode(raw).decode('ascii')}"


def main():
    parser = argparse.ArgumentParser(description="Analiza una imagen con DeepSeek.")
    parser.add_argument("imagen", type=Path)
    parser.add_argument("--detail", choices=("low", "high"), default="high")
    args = parser.parse_args()
    api_key = os.getenv("DEEPSEEK_API_KEY", "")
    if not api_key or any(ord(c) < 33 or ord(c) > 126 for c in api_key):
        raise SystemExit("Define una DEEPSEEK_API_KEY válida en el entorno.")
    try:
        data_url = image_data_url(args.imagen)
    except ValueError as exc:
        raise SystemExit(f"Imagen no válida: {exc}") from None
    except (OSError, SyntaxError, Image.DecompressionBombError) as exc:
        raise SystemExit(f"No se pudo leer la imagen ({type(exc).__name__}).") from None

    try:
        # 90 segundos y cero reintentos son decisiones de este ejemplo.
        with OpenAI(api_key=api_key, base_url="https://api.deepseek.com",
                    timeout=90.0, max_retries=0) as client:
            response = client.chat.completions.create(
                model="deepseek-flash", stream=False, max_tokens=800,
                extra_body={"thinking": {"type": "disabled"}},
                messages=[{"role": "user", "content": [
                    {"type": "text", "text": (
                        "Responde en español. Describe lo visible y transcribe el texto "
                        "legible. Señala lo que sea incierto; no inventes detalles.")},
                    {"type": "image_url", "image_url": {
                        "url": data_url, "detail": args.detail}},
                ]}],
            )
    except APIStatusError as exc:
        raise SystemExit(f"Error de la API: HTTP {exc.status_code}.") from None
    except APIError as exc:
        raise SystemExit(f"Error de conexión o SDK ({type(exc).__name__}).") from None

    if response.usage is not None:
        for name in ("prompt_tokens", "completion_tokens", "total_tokens"):
            value = getattr(response.usage, name, None)
            if value is not None:
                print(f"{name}: {value}")
    if not response.choices:
        raise SystemExit("La API no devolvió opciones.")
    choice = response.choices[0]
    print(f"finish_reason: {choice.finish_reason}")
    if choice.finish_reason == "length":
        print("Aviso: la salida quedó truncada por el límite de tokens.", file=sys.stderr)
    elif choice.finish_reason != "stop":
        print("Aviso: la respuesta no terminó normalmente.", file=sys.stderr)
    text = choice.message.content
    if not isinstance(text, str) or not text.strip():
        raise SystemExit("La API no devolvió texto.")
    print("\n" + text)


if __name__ == "__main__":
    main()

Con el entorno activado, ejecuta el archivo e indica la ruta de tu imagen. Usa comillas si contiene espacios:

python analizar_imagen_deepseek.py "captura.png"

El ejemplo conserva los bytes de la imagen y los convierte en una URL de datos. En messages, la instrucción y la imagen son partes distintas del mismo mensaje de usuario. El campo image_url.url contiene el prefijo MIME y el contenido base64.

Ejemplo oficial en Python para enviar una imagen en base64 a DeepSeek Vision API.

Se configura una salida máxima de 800 tokens y se desactiva el modo de razonamiento para esta demostración. Son decisiones del ejemplo, no límites generales de Vision. El cliente realiza una sola solicitud y desactiva los reintentos automáticos, opción documentada en el SDK de Python.

Cómo comprobar si la respuesta está completa

El programa imprime el consumo disponible en usage, el motivo de finalización y el texto recibido. Interpreta estos resultados antes de guardar la salida en una aplicación:

  • finish_reason: stop: la generación terminó normalmente; revisa de todos modos si el contenido coincide con la imagen.
  • finish_reason: length: la salida quedó cortada por un límite de tokens. Reduce el alcance de la tarea o ajusta el presupuesto de salida y el contexto.
  • Contenido vacío u otro motivo de finalización: no lo trates como una extracción completa. El programa lo señala para que puedas revisar la solicitud.

Para evaluar tu primera prueba, elige una imagen cuyo contenido puedas comprobar: una captura de una interfaz de prueba o una etiqueta de un objeto. Contrasta unas pocas observaciones concretas, como un texto, una cantidad y la ubicación de un elemento. Una respuesta fluida no demuestra que todos esos datos sean correctos.

Base64, URL o Files API: cómo elegir la entrada

MétodoCuándo resulta útilQué debes preparar
Base64 en la solicitudUna imagen local o una prueba puntual.Una URL de datos como la que construye el programa. Aumenta el tamaño del cuerpo JSON.
URL HTTP(S)Una imagen ya disponible mediante un enlace directo accesible.Una dirección que el servidor pueda descargar, sin depender de tu sesión del navegador.
Files API y file_idUna imagen que vas a referenciar en distintas solicitudes.Una carga previa y el identificador que devuelve el servicio.

Para usar un enlace con Chat Completions, conserva la parte image_url y coloca la dirección en image_url.url. Debe devolver los bytes de la imagen: una página HTML que muestra una foto, una ruta local o un enlace que exige iniciar sesión no equivalen a una URL de imagen accesible.

El enlace externo tiene un máximo de 8192 caracteres y su descarga debe completarse en 60 segundos. Ese límite de caracteres corresponde a la URL HTTP(S); el contenido base64 se controla mediante los límites de tamaño de la solicitud descritos en la guía de Vision.

Cuándo usar un archivo subido

El flujo de Files API separa la carga del archivo y la solicitud al modelo:

  1. Sube la imagen con POST https://api.deepseek.com/files, mediante multipart, con los campos file y purpose="user_data".
  2. Guarda el id devuelto por esa carga.
  3. Incluye una parte file en el contenido del mensaje cuando quieras utilizar la imagen.
Ejemplo oficial para subir una imagen a Files API y obtener su identificador en DeepSeek.

Esta es la estructura de esa parte en Chat Completions; sustituye el identificador ilustrativo por el que recibas al subir tu archivo:

{
  "type": "file",
  "file_id": "file-api-ID_DEVUELTO_POR_LA_CARGA"
}

El campo file_id va directamente en esa parte. Si eliges la alternativa de datos en línea, se utiliza file_data; ambos campos son excluyentes. No pegues el formato de otro proveedor sin comprobar el esquema de DeepSeek.

Según la referencia de carga, puedes configurar una expiración de una hora a 30 días; si la omites, el archivo se conserva sin expiración automática. Define una política de borrado o vencimiento para archivos temporales. Reutilizar el ID evita volver a cargar los bytes, pero cada análisis sigue siendo una solicitud al modelo y no garantiza un acierto de caché.

Formatos, límites y nivel de detalle

Límites que debes comprobar antes de enviar

La API admite JPEG, PNG, GIF y WebP, identificados por el contenido real del archivo. Estos son los límites relevantes publicados para entradas visuales:

ElementoLímite
Cuerpo JSON de la solicitud48 MiB.
Una imagen enviada en base64 o por URL32 MiB.
Una imagen cargada y referenciada por file_id64 MiB.
Cantidad de imágenes por solicitud600.
Tamaño total de imágenes sin file_id64 MiB.
Tamaño total incluyendo imágenes con file_idHasta 200 MiB.
Dimensión máxima por lado8192 píxeles.
Dimensión por lado con 15 o más imágenes4096 píxeles.
Límites oficiales de formatos, tamaño, cantidad y dimensiones de imágenes en DeepSeek Vision API.

Los límites se aplican juntos. Por ejemplo, un conjunto puede respetar el máximo de cada imagen y aun así exceder el cuerpo JSON al codificarse en base64. MiB significa 1024 × 1024 bytes. También debes dejar espacio para la instrucción, el historial y la salida dentro del contexto del modelo.

Qué cambia con low, high, original y auto

El campo detail controla una etapa del procesamiento de la imagen. La referencia del parámetro admite estas opciones:

ValorComportamiento documentado
lowReduce la imagen a 512 × 512.
highEquivale a original.
originalConserva la imagen original en esta etapa.
autoActualmente equivale a original.

Esto no significa que el modelo procese siempre todos los píxeles originales. DeepSeek también documenta un redimensionado automático antes de la inferencia. Elegir high no garantiza que un texto diminuto resulte legible.

Para una descripción general, compara el resultado con el modo de menor detalle:

python analizar_imagen_deepseek.py "captura.png" --detail low

Para texto pequeño, empieza con high y una imagen nítida. Si una zona ocupa pocos píxeles, prepara un recorte legible y conserva el contexto necesario para interpretarla. Dividir una página densa puede ayudar a revisar cada región, aunque aumenta la cantidad de imágenes y puede aumentar el consumo que debes presupuestar.

Prompts útiles para texto, gráficos y comparación

Cambia la instrucción del ejemplo según el resultado que necesites. Estos prompts delimitan la tarea y hacen más fácil detectar omisiones o interpretaciones que requieren revisión.

Extraer texto visible sin completar datos ausentes

Transcribe únicamente el texto visible de esta imagen.
Conserva los saltos de línea cuando ayuden a entenderlo.
Marca como [ilegible] los fragmentos que no puedas leer.
No completes palabras, códigos ni cantidades por contexto.
Al final, enumera los fragmentos que necesitan revisión.

Compara los códigos, fechas y cantidades con la imagen original antes de utilizarlos en otro sistema. Un carácter mal leído puede seguir formando una palabra o un número aparentemente válido.

Interpretar un gráfico sin inventar valores

Identifica el título, los ejes, las unidades y la leyenda del gráfico.
Explica la tendencia principal. Separa los valores impresos
de las estimaciones visuales. Si una cifra exacta no aparece,
indica que no puede leerse con precisión. No infieras causas
que el gráfico no muestra.

Este formato permite distinguir lo que la imagen afirma de lo que el modelo interpreta. Si necesitas una tabla exacta de datos, comprueba primero si cuentas con el archivo original que produjo el gráfico.

Comparar dos imágenes de forma ordenada

Agrega ambas imágenes como partes separadas del mismo mensaje y coloca antes de cada una una etiqueta de texto, como Imagen A e Imagen B. Después pide una comparación concreta:

Compara Imagen A e Imagen B. Enumera los cambios visibles
en textos, elementos y posiciones. Para cada cambio, indica
la zona de la imagen y lo que aparece en A y en B.
No atribuyas una causa al cambio y señala lo que sea incierto.

En capturas de interfaces, procura usar el mismo tamaño de ventana y un estado comparable. De lo contrario, un cambio de distribución puede confundirse con la desaparición de un elemento.

Si necesitas una salida JSON

La guía de JSON Output indica que debes añadir response_format={"type": "json_object"} y pedir explícitamente JSON en el mensaje. Define los campos esperados y ofrece un ejemplo de estructura; deja suficientes tokens para completarla.

Antes de deserializar, comprueba que el contenido no esté vacío y que la respuesta no se haya truncado. Después valida los tipos y los campos requeridos. Un JSON bien formado no demuestra que la transcripción o la interpretación de la imagen sean correctas.

Cuánto cuesta DeepSeek Vision API

Las imágenes se convierten en tokens de entrada, a los que se suman tu texto y la salida generada. La guía visual publica un máximo de 1024 tokens por imagen después del procesamiento; no es una tarifa fija por foto ni el total de tokens de la solicitud.

Utiliza el calculador oficial de tokens de imagen para una estimación por dimensiones y usage para comprobar el consumo que devuelve la API. Si comparas configuraciones, conserva la misma tarea y evalúa también si el resultado sigue siendo útil.

Calculadora de DeepSeek con una estimación de 968 tokens para una imagen de 1920 × 1080 píxeles.

La tarifa publicada de deepseek-flash distingue estos importes en USD por un millón de tokens:

PeriodoEntrada con cachéEntrada sin cachéSalida
Fuera de horario pico0.0030.150.60
Horario pico0.0060.301.20

El horario pico es de lunes a viernes, de 01:00 a 04:00 y de 06:00 a 10:00 UTC, excepto los feriados oficiales de China. Los demás periodos usan la tarifa fuera de pico.

Ejemplo de cálculo con tokens hipotéticos

Supón una solicitud con 1500 tokens de entrada en total, todos sin caché, y 200 tokens de salida, procesada en horario pico:

(1500 × 0.30 + 200 × 1.20) / 1000000 = 0.00069 USD

Con exactamente ese consumo y esas tarifas, 1000 solicitudes costarían 0.69 USD. Es un cálculo ilustrativo, no una medición de la imagen del tutorial. Si parte de la entrada se factura como caché, calcula esa parte con su tarifa correspondiente; no asumas el descuento solo por repetir una imagen.

Qué cambia si utilizas Responses o el formato Anthropic

DeepSeek también documenta imágenes mediante Responses y el formato compatible con Anthropic. El modelo visual sigue siendo Flash, pero cambia el cuerpo de la solicitud:

ProtocoloEndpoint HTTP completoParte de imagen
Chat Completionshttps://api.deepseek.com/chat/completionstype: "image_url", con el enlace dentro de image_url.url.
Responseshttps://api.deepseek.com/responsestype: "input_image", con image_url como cadena o con file_id.
Anthropic Messageshttps://api.deepseek.com/anthropic/v1/messagestype: "image", con un objeto source.

En Responses, image_url y file_id son excluyentes, y detail se ignora cuando envías un file_id. En Anthropic, una fuente base64 lleva media_type y los datos codificados sin el prefijo de URL de datos. Las referencias a archivos requieren el encabezado anthropic-beta: files-api-2025-04-14.

Si una integración ya utiliza uno de estos protocolos, conserva su estructura. Cambiar únicamente el endpoint mientras mantienes los campos de otro formato suele dejar una solicitud incompatible.

Errores frecuentes al analizar imágenes

Cuando una llamada falla, separa la preparación de la imagen, el formato del mensaje y el acceso al servicio. La referencia de errores de DeepSeek permite interpretar los códigos generales:

Error o síntomaQué revisarQué hacer
El modelo no procesa la imagenIdentificador del modelo y formato de entrada.Utiliza deepseek-flash y las partes de contenido del protocolo elegido.
Imagen inválida o petición rechazada por tamañoFormato real, bytes, dimensiones y tamaño final del JSON.Corrige o reduce la imagen; no basta con renombrar su extensión.
400 o 422Campos, tipos y parámetros enviados.Compara la estructura con la referencia del endpoint.
No puede descargarse una URLAcceso público, respuesta del enlace y vencimiento.Usa un enlace directo vigente o envía el archivo mediante otra vía.
No puede utilizarse un file_idArchivo eliminado, vencido o perteneciente a otra cuenta.Comprueba el archivo disponible y usa el ID correcto.
401Credencial utilizada por el proceso.Revisa la clave de DeepSeek y la variable de entorno.
402Saldo disponible.Revisa la cuenta y el crédito antes de reintentar.
429, 500 o 503Límites, error o sobrecarga del servicio.Reduce la carga y utiliza reintentos limitados con espera.
Texto vacío o respuesta cortadaContenido recibido, finish_reason y presupuesto de tokens.No guardes la salida como completa; corrige la tarea o la configuración.

El timeout del ejemplo está configurado en 90 segundos en el SDK; no representa una garantía de duración máxima total. Si tu aplicación pierde la conexión, eso tampoco demuestra por sí solo que el servidor no haya procesado la solicitud. Decide los reintentos de forma explícita para evitar repeticiones innecesarias.

Diferencias entre Vision, DeepSeek-OCR, VL2 y Janus

Antes de cambiar de integración, identifica qué producto resuelve tu necesidad. Estos nombres corresponden a rutas de trabajo distintas:

Proyecto o funciónCuándo considerarlo
Vision en la API de DeepSeekPara enviar imágenes al servicio alojado y obtener respuestas de texto mediante Flash.
DeepSeek-OCRPara evaluar el proyecto especializado en OCR y sus flujos de inferencia, incluido el procesamiento de PDF documentado en su repositorio.
DeepSeek-VL2Para trabajar con modelos de comprensión visual descargables y configurar tu propia inferencia.
JanusPara explorar los modelos que documentan comprensión multimodal y generación de imágenes.

La función Vision de este tutorial recibe imágenes y devuelve respuestas sobre ellas; las capacidades de generación de Janus no convierten Chat Completions en un endpoint de creación de imágenes.

Tampoco debes tratar un PDF o un video como si fuera un JPEG. El contrato de entrada visual descrito aquí admite imágenes. Para analizar páginas de un documento o momentos de un video con este flujo, prepara primero las páginas o fotogramas relevantes como imágenes compatibles y controla su orden, cantidad y tamaño.

Empieza con una tarea que puedas verificar visualmente, registra su consumo real y amplía el flujo cuando el resultado sea suficiente para tu aplicación. Esa comprobación te permitirá elegir el detalle y la forma de envío con una referencia concreta.

Verificación documental: 10 de noviembre de 2026. El ejemplo se revisó en sintaxis y en validación local de imágenes; no se ejecutó una solicitud autenticada contra la API de DeepSeek.