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
| Dato | Configuración para este tutorial |
|---|---|
| Modelo | deepseek-flash. |
| URL base del cliente | https://api.deepseek.com. |
| Endpoint HTTP | POST https://api.deepseek.com/chat/completions. |
| Entrada | Un mensaje de usuario con partes de texto e imagen. |
| Salida que leerás | Texto 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.

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.

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étodo | Cuándo resulta útil | Qué debes preparar |
|---|---|---|
| Base64 en la solicitud | Una 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_id | Una 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:
- Sube la imagen con
POST https://api.deepseek.com/files, mediante multipart, con los camposfileypurpose="user_data". - Guarda el
iddevuelto por esa carga. - Incluye una parte
fileen el contenido del mensaje cuando quieras utilizar la imagen.

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:
| Elemento | Límite |
|---|---|
| Cuerpo JSON de la solicitud | 48 MiB. |
| Una imagen enviada en base64 o por URL | 32 MiB. |
Una imagen cargada y referenciada por file_id | 64 MiB. |
| Cantidad de imágenes por solicitud | 600. |
Tamaño total de imágenes sin file_id | 64 MiB. |
Tamaño total incluyendo imágenes con file_id | Hasta 200 MiB. |
| Dimensión máxima por lado | 8192 píxeles. |
| Dimensión por lado con 15 o más imágenes | 4096 píxeles. |

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:
| Valor | Comportamiento documentado |
|---|---|
low | Reduce la imagen a 512 × 512. |
high | Equivale a original. |
original | Conserva la imagen original en esta etapa. |
auto | Actualmente 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.

La tarifa publicada de deepseek-flash distingue estos importes en USD por un millón de tokens:
| Periodo | Entrada con caché | Entrada sin caché | Salida |
|---|---|---|---|
| Fuera de horario pico | 0.003 | 0.15 | 0.60 |
| Horario pico | 0.006 | 0.30 | 1.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:
| Protocolo | Endpoint HTTP completo | Parte de imagen |
|---|---|---|
| Chat Completions | https://api.deepseek.com/chat/completions | type: "image_url", con el enlace dentro de image_url.url. |
| Responses | https://api.deepseek.com/responses | type: "input_image", con image_url como cadena o con file_id. |
| Anthropic Messages | https://api.deepseek.com/anthropic/v1/messages | type: "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íntoma | Qué revisar | Qué hacer |
|---|---|---|
| El modelo no procesa la imagen | Identificador 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ño | Formato real, bytes, dimensiones y tamaño final del JSON. | Corrige o reduce la imagen; no basta con renombrar su extensión. |
400 o 422 | Campos, tipos y parámetros enviados. | Compara la estructura con la referencia del endpoint. |
| No puede descargarse una URL | Acceso 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_id | Archivo eliminado, vencido o perteneciente a otra cuenta. | Comprueba el archivo disponible y usa el ID correcto. |
401 | Credencial utilizada por el proceso. | Revisa la clave de DeepSeek y la variable de entorno. |
402 | Saldo disponible. | Revisa la cuenta y el crédito antes de reintentar. |
429, 500 o 503 | Límites, error o sobrecarga del servicio. | Reduce la carga y utiliza reintentos limitados con espera. |
| Texto vacío o respuesta cortada | Contenido 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ón | Cuándo considerarlo |
|---|---|
| Vision en la API de DeepSeek | Para enviar imágenes al servicio alojado y obtener respuestas de texto mediante Flash. |
| DeepSeek-OCR | Para evaluar el proyecto especializado en OCR y sus flujos de inferencia, incluido el procesamiento de PDF documentado en su repositorio. |
| DeepSeek-VL2 | Para trabajar con modelos de comprensión visual descargables y configurar tu propia inferencia. |
| Janus | Para 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.

