Usa Chat Completions si tu integración ya trabaja con una lista de mensajes y cubre tus necesidades. Considera Responses API de DeepSeek cuando tu cliente requiera ese formato o necesites elementos de salida tipados, eventos de streaming detallados y funciones específicas como JSON Schema.
Ambas permiten llamar a modelos de DeepSeek. La diferencia está en el formato de los datos y en las funciones compatibles. Un punto decisivo: Responses en DeepSeek requiere que tu aplicación vuelva a enviar el historial; cambiar de endpoint no añade memoria automática a la conversación.
Esta comparación se refiere a la API oficial alojada en DeepSeek. Las pasarelas de terceros y los servidores locales pueden implementar contratos diferentes.
Qué interfaz de DeepSeek conviene usar
| Tu situación | Opción recomendada | Motivo práctico |
|---|---|---|
Tu aplicación ya usa messages y funciona correctamente. | Chat Completions. | Puedes conservar la estructura de solicitudes, respuestas y herramientas que ya tienes. |
| Tu cliente exige Responses o procesa elementos de salida por tipo. | Responses. | Permite trabajar con mensajes, llamadas a funciones y otros elementos dentro de output. |
| Necesitas una salida ajustada a JSON Schema. | Responses. | Su referencia documenta text.format con json_schema. |
| Necesitas búsqueda web integrada en el servidor. | Responses con deepseek-v4-pro. | Es la combinación documentada para la herramienta integrada web_search. |
| Solo necesitas generar texto en un proyecto nuevo. | La interfaz que tu cliente y tu aplicación manejen con menos adaptaciones. | Evalúa también el formato de las respuestas, el historial y las herramientas que utilizarás después. |
Estas recomendaciones se basan en las capacidades y restricciones que DeepSeek publica para Responses. En particular, una integración basada en Codex debe seguir la configuración específica indicada por DeepSeek; que un cliente use Responses no significa que todas sus funciones estén disponibles con cualquier proveedor.
Diferencias entre Chat Completions y Responses
Las dos interfaces usan https://api.deepseek.com como URL base del cliente. El SDK añade el endpoint correspondiente. Usa una clave de DeepSeek y comprueba el identificador del modelo en la lista oficial de modelos; las referencias actuales incluyen deepseek-flash y deepseek-v4-pro.
| Elemento | Chat Completions | Responses |
|---|---|---|
| Endpoint HTTP | POST /chat/completions | POST /responses |
| Método del SDK de Python | client.chat.completions.create() | client.responses.create() |
| Entrada | messages | input: texto o lista de elementos |
| Instrucciones del sistema | Mensaje con role: system | instructions |
| Texto mediante el SDK | choices[0].message.content | output_text |
| Límite de generación | max_tokens | max_output_tokens |
| Estado de finalización | choices[0].finish_reason | status; detalles en error o incomplete_details |
| Consumo de entrada y salida | usage.prompt_tokens y usage.completion_tokens | usage.input_tokens y usage.output_tokens |
| Continuación de una conversación | Vuelves a enviar el contexto en messages. | Vuelves a enviar el contexto en input. |
Puedes contrastar los campos en las referencias de Chat Completions y Responses. En Responses, output_text es una comodidad del SDK: si llamas por HTTP y lees el JSON directamente, procesa los elementos de output según su tipo.

Por eso, una migración requiere adaptar tanto la solicitud como la lectura del resultado. Cambiar únicamente el nombre del método deja pendientes el historial, las herramientas y el tratamiento del streaming.
Ejemplo en Python: la misma tarea con ambas interfaces
Este ejemplo resume un texto de prueba. Mantiene el mismo modelo, las mismas instrucciones y un límite de 256 tokens de salida. También desactiva el razonamiento en ambos casos para comparar la estructura del código. Las respuestas y el consumo pueden variar entre ejecuciones.

Prepara el cliente y la clave
Necesitas Python 3.10 o superior, de acuerdo con los requisitos actuales del SDK oficial de OpenAI para Python, y una clave de tu cuenta en la plataforma oficial de DeepSeek. Dentro de tu entorno de Python, instala o actualiza el cliente:
python -m pip install --upgrade openai
Define la variable DEEPSEEK_API_KEY en la misma terminal donde ejecutarás el archivo. En macOS o Linux:
export DEEPSEEK_API_KEY="TU_CLAVE_DEEPSEEK"
En Windows PowerShell:
$env:DEEPSEEK_API_KEY="TU_CLAVE_DEEPSEEK"
Sustituye el valor de ejemplo por tu clave. El archivo Python la leerá desde el entorno; no la incluyas en el código ni en un repositorio. El nombre de la biblioteca openai identifica al cliente utilizado, mientras que base_url determina el servicio al que se envían las solicitudes.
Guarda y ejecuta el ejemplo
Guarda este código como comparar_deepseek.py. Cada ejecución selecciona una interfaz y envía una solicitud:
"""Envía una sola solicitud de resumen a DeepSeek con la interfaz elegida."""
import argparse
import os
import sys
from openai import APIError, APIStatusError, OpenAI
MODEL = "deepseek-flash"
INSTRUCTIONS = "Responde en español latinoamericano neutro y no añadas datos."
PROMPT = (
"Resume en una frase: El equipo revisó 20 solicitudes. Aprobó 15 y dejó "
"5 pendientes por falta de información."
)
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("api", choices=("chat", "responses"))
args = parser.parse_args()
api_key = os.environ.get("DEEPSEEK_API_KEY", "").strip()
if not api_key:
print("Falta la variable DEEPSEEK_API_KEY.", file=sys.stderr)
return 2
try:
with OpenAI(
api_key=api_key,
base_url="https://api.deepseek.com",
timeout=60.0, # Elección para esta demostración.
max_retries=0, # Una solicitud, sin reintentos automáticos.
) as client:
if args.api == "chat":
result = client.chat.completions.create(
model=MODEL,
messages=[
{"role": "system", "content": INSTRUCTIONS},
{"role": "user", "content": PROMPT},
],
max_tokens=256,
extra_body={"thinking": {"type": "disabled"}},
)
choice = result.choices[0] if result.choices else None
text = choice.message.content if choice else None
completed = choice is not None and choice.finish_reason == "stop"
finish_state = choice.finish_reason if choice else "sin_resultado"
usage_fields = ("prompt_tokens", "completion_tokens")
else:
result = client.responses.create(
model=MODEL,
instructions=INSTRUCTIONS,
input=PROMPT,
max_output_tokens=256,
reasoning={"effort": "none"},
)
text = result.output_text
completed = result.status == "completed"
finish_state = result.status
usage_fields = ("input_tokens", "output_tokens")
except APIStatusError as error:
print(f"Error HTTP: {error.status_code}.", file=sys.stderr)
return 1
except APIError as error:
print(f"Error del SDK: {type(error).__name__}.", file=sys.stderr)
return 1
print(f"Finalización: {finish_state}")
if not completed or not isinstance(text, str) or not text.strip():
print("Respuesta incompleta o sin texto utilizable.", file=sys.stderr)
return 1
print(text.strip())
usage = getattr(result, "usage", None)
for label, field in zip(("entrada", "salida"), usage_fields):
value = getattr(usage, field, None)
if value is not None:
print(f"Tokens de {label}: {value}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
Ejecuta la ruta que quieras comprobar:
python comparar_deepseek.py chat
python comparar_deepseek.py responses
Si ejecutas los dos comandos, realizarás dos solicitudes independientes. El programa muestra la finalización, el resumen y los contadores de tokens disponibles. Comprueba que el resumen conserve los datos del texto original; una respuesta completada también necesita revisión de contenido.
El límite de 256 tokens, el timeout de 60 segundos y la ausencia de reintentos automáticos son decisiones de esta demostración. Ajusta esas políticas a tu aplicación. El timeout del cliente no representa una garantía sobre la duración total de la operación.
DeepSeek documenta el razonamiento activado por defecto. En este ejemplo, Chat Completions lo desactiva mediante thinking.type, mientras Responses usa reasoning.effort="none". Si lo activas, revisa los controles y las reglas del modo de razonamiento de cada interfaz.
Cómo conservar el historial de conversación
En Chat Completions, tu aplicación incorpora los mensajes anteriores a messages. La guía oficial de conversaciones de varios turnos explica este funcionamiento sin estado. Responses sigue el mismo principio: el contexto necesario debe viajar en la nueva solicitud.
Para continuar el ejemplo anterior, una pregunta como “¿Cuántas solicitudes quedaron pendientes?” necesita el texto que contenía los datos. En una conversación solo de texto, sin herramientas y con razonamiento desactivado, el flujo es:
- Conserva el mensaje inicial del usuario y la respuesta del asistente.
- Añade la nueva pregunta al historial.
- Envía esa secuencia en
messagesoinput, según la interfaz. - Incluye de nuevo las instrucciones de sistema que deban seguir vigentes.
En Responses de DeepSeek, previous_response_id y conversation no recuperan el turno anterior. store tampoco habilita esa persistencia. Esta limitación está descrita en su referencia de Responses.

Cuando agregues herramientas, conserva también las llamadas y sus resultados, emparejados con sus identificadores. Guardar únicamente output_text puede perder información necesaria para continuar el proceso. En Chat Completions, si envías tools con el modo de razonamiento, la guía de thinking exige devolver el reasoning_content de los turnos anteriores; eliminarlo puede provocar HTTP 400.
Que la API sea sin estado y devuelva store: false describe la continuidad de la conversación. Por sí solo, ese comportamiento no demuestra una política de retención cero para todos los datos.
Streaming: cómo leer el texto y confirmar que terminó
Con stream=True, la aplicación recibe contenido a medida que se genera. La diferencia práctica está en el lector que procesa esos fragmentos y reconoce la finalización.
| Qué revisar | Chat Completions | Responses |
|---|---|---|
| Fragmentos de texto | choices[].delta.content | Eventos response.output_text.delta; texto en event.delta |
| Finalización | finish_reason en el último fragmento; cierre SSE con [DONE] | response.completed, response.incomplete o response.failed |
| Consumo | usage en el último fragmento de DeepSeek | usage en el objeto de respuesta del evento final |
| Lectura defensiva | Comprueba que exista una opción y que el fragmento contenga texto. | Comprueba el tipo de evento antes de leer sus campos. |
DeepSeek documenta un detalle relevante para Chat Completions: el último fragmento transporta el consumo junto con una opción cuyo finish_reason ya está definido. No emite un fragmento adicional dedicado únicamente a usage con choices vacío. Revisa este contrato en la referencia de streaming de Chat Completions.
Responses utiliza los eventos finales documentados para Responses y no envía data: [DONE]. Además, stream_options no está soportado en esa interfaz; trasladarlo desde Chat Completions no configura el consumo del streaming.

En tu aplicación, distingue el texto provisional del resultado terminado. Marca la operación como completada solo cuando recibas la señal correspondiente. Si llega response.incomplete, consulta incomplete_details; si llega response.failed, revisa error. Si la conexión se interrumpe sin señal final, conserva ese estado como interrupción. La ausencia de usage no demuestra consumo cero.
En un flujo con herramientas, incluso una respuesta marcada como completada puede contener una llamada que tu aplicación deba ejecutar. Comprueba el tipo de salida que necesita tu siguiente paso.
Herramientas, JSON Schema e imágenes: diferencias que cambian la elección
Llamadas a funciones y resultados
Las dos interfaces admiten llamadas a funciones. Tu aplicación recibe los argumentos, los valida, ejecuta la función autorizada y devuelve el resultado. El modelo no ejecuta por sí mismo el código de esa función, como explica la guía oficial de Tool Calls.
| Paso | Chat Completions | Responses |
|---|---|---|
| Declarar la función | name y parameters dentro de function. | name y parameters directamente en el objeto de herramienta. |
| Recibir la llamada | message.tool_calls. | Elemento de tipo function_call en output. |
| Devolver el resultado | Mensaje role: tool con tool_call_id. | Elemento function_call_output con call_id. |
Al migrar, conserva la relación entre cada llamada y su resultado. En Responses, utiliza call_id para esa relación; no lo sustituyas por el id de otro elemento. Si pueden llegar varias llamadas, procesa y vincula cada resultado de forma independiente.
Algunos agentes insertan en el historial llamadas a herramientas que no fueron generadas por el modelo, junto con sus resultados. La guía de Tool Calls documenta este mecanismo para Responses, pero no para Chat Completions. Si tu orquestador necesita crear esas llamadas, comprueba esta capacidad antes de elegir la interfaz.
JSON válido y salida con JSON Schema
Chat Completions documenta response_format={"type":"json_object"}. En este modo debes pedir JSON en las instrucciones, proporcionar un formato claro y dejar un presupuesto suficiente de salida. La guía de JSON Output también advierte que puede aparecer contenido formado solo por espacios.
Responses documenta text.format con json_schema. Para extraer los datos del texto de prueba, define este diccionario de Python antes de main():
FORMATO_TEXTO = {
"format": {
"type": "json_schema",
"name": "resumen_solicitudes",
"schema": {
"type": "object",
"properties": {
"revisadas": {
"type": "integer"
},
"aprobadas": {
"type": "integer"
},
"pendientes": {
"type": "integer"
}
},
"required": [
"revisadas",
"aprobadas",
"pendientes"
],
"additionalProperties": False
}
}
}
Añade text=FORMATO_TEXTO a la llamada de Responses. En PROMPT, cambia “Resume en una frase” por “Extrae revisadas, aprobadas y pendientes de este texto”, conservando los datos de prueba. El diccionario configura el formato; la instrucción define la tarea. La referencia de Responses exige name y schema para json_schema.
Antes de utilizar los datos, comprueba el estado de finalización y que el texto tenga contenido. Después analiza el JSON y valida los tipos, los campos y las reglas de tu aplicación. En este caso, verifica además que los totales correspondan al texto de entrada. json.loads() comprueba que el texto se pueda interpretar como JSON; la validación del esquema y del contenido requiere comprobaciones adicionales.
La salida JSON del mensaje y los esquemas de argumentos de una función son mecanismos distintos. El modo strict de Tool Calls tiene sus propias condiciones; no lo confundas con el formato de salida de Responses.
Búsqueda web y herramientas integradas
En Responses, web_search está documentada para deepseek-v4-pro y se ignora con deepseek-flash. Entre las herramientas custom, solo se admite apply_patch. Otros tipos integrados, como file_search, code_interpreter, computer_use y mcp, se ignoran según la tabla de compatibilidad de herramientas.

Si tu aplicación usa Chat Completions, puedes implementar una función de búsqueda y devolver sus resultados al modelo. La disponibilidad de la búsqueda integrada en Responses debe distinguirse de los endpoints independientes Search & Fetch. Elige el mecanismo que encaje con el control y los datos que necesita tu aplicación.
Imágenes: revisa el modelo además del endpoint
DeepSeek documenta entrada de imágenes con deepseek-flash en ambas interfaces. Chat Completions usa bloques de imagen dentro de los mensajes; Responses utiliza contenido input_image. Sigue la guía oficial de visión para preparar el contenido y comprobar sus límites.
Una imagen subida y referenciada mediante file_id no implica compatibilidad general con documentos PDF ni con cualquier tipo de archivo. Antes de migrar una entrada multimodal, verifica por separado el modelo, el formato del contenido y el tipo de archivo admitido.
Parámetros que debes revisar antes de migrar
DeepSeek advierte que los parámetros no soportados de Responses pueden ignorarse sin producir un error. Por ello, HTTP 200 no confirma que cada opción enviada haya tenido efecto. Contrasta la solicitud con la matriz oficial de compatibilidad.
| Opción o comportamiento | Qué debes comprobar |
|---|---|
| Persistencia y segundo plano | previous_response_id, conversation, store y background no habilitan esas funciones. |
| Recorte automático | truncation no está soportado. Gestiona el tamaño del contexto en tu aplicación. |
| Control de llamadas a herramientas | parallel_tool_calls y max_tool_calls se ignoran. Aplica los límites necesarios en tu orquestador. |
| Estilo y resúmenes de razonamiento | text.verbosity no tiene efecto; reasoning.summary no genera un resumen. |
Revisa también la jerarquía de instrucciones: DeepSeek trata el rol developer de Responses como user. Para instrucciones de sistema, utiliza instructions o un mensaje de sistema admitido. Una traducción mecánica de roles puede cambiar cómo se interpreta tu solicitud.
Esta tolerancia no se aplica a todos los errores. Un valor inválido en un campo soportado o una estructura mal formada puede producir un rechazo explícito. Valida el comportamiento que necesita tu aplicación, además de la respuesta HTTP.
Costos y rendimiento: qué comparar realmente
La tarifa oficial de DeepSeek distingue modelos y categorías de tokens, además de las condiciones de caché y horario aplicables. El nombre del endpoint, por sí solo, no demuestra que una integración vaya a ser más barata, rápida o precisa.
Para comparar tu caso de uso, mantén constantes el modelo, las instrucciones, la tarea, el modo de razonamiento y el límite de salida. Registra el consumo real y el resultado de cada solicitud. Si usas herramientas de búsqueda u otras operaciones adicionales, revisa también su consumo y las condiciones correspondientes.
Al cambiar de interfaz, actualiza el registro de métricas con los nombres de campos de usage que aparecen en la tabla inicial. Un contador ausente debe registrarse como dato no disponible, no como cero.
La caché de contexto reutiliza prefijos compatibles bajo sus reglas de funcionamiento. Eso no sustituye el envío del historial: la solicitud sigue teniendo que contener el contexto que el modelo necesita.
Checklist para migrar de Chat Completions a Responses
Antes de cambiar una integración, comprueba estos puntos con casos representativos de tu aplicación:
- Configuración: usa la clave de DeepSeek, la URL base correcta y un modelo compatible.
- Solicitud: transforma
messageseninputy coloca las instrucciones de sistema donde corresponda. - Generación: adapta el límite de salida y configura explícitamente el razonamiento.
- Lectura: procesa
outputsegún su tipo y comprueba el estado final antes de aceptar el resultado. - Continuidad: conserva el historial necesario y las relaciones entre llamadas a herramientas y resultados.
- Streaming: maneja finalización correcta, respuesta incompleta, fallo e interrupción de la conexión.
- Métricas: comprueba los campos de consumo y los efectos reales de las opciones que necesitas.
Cómo reconocer los fallos de migración más comunes
| Síntoma | Qué revisar primero |
|---|---|
| El segundo turno pierde los datos anteriores. | Inspecciona el input enviado. Debe incluir el historial necesario, sin depender de previous_response_id. |
| Llega texto, pero la interfaz queda esperando. | Comprueba que el lector de Responses reconoce sus eventos finales y no espera [DONE]. |
| La respuesta llega, pero tu código no encuentra el texto. | Revisa si sigues leyendo choices después de migrar a Responses, o si la salida contiene una llamada a herramienta. |
| Una opción parece no hacer nada. | Consulta si figura como ignorada o sin efecto en la tabla oficial de compatibilidad. |
| Aparece HTTP 400 o 422 después del cambio. | Revisa los nombres, valores y estructuras de los campos enviados, el contexto y los identificadores de herramientas. |
Los errores de autenticación, saldo y límites requieren otro diagnóstico: DeepSeek documenta 401 para autenticación, 402 para saldo insuficiente y 429 para límites de solicitudes o concurrencia. Consulta su referencia de códigos de error cuando el problema sea del servicio o de la cuenta.
Verificación documental: 10 de noviembre de 2026. Los ejemplos se revisaron con las referencias oficiales indicadas. El archivo Python se comprobó localmente a nivel de sintaxis; no se ejecutaron solicitudes autenticadas ni pruebas comparativas de rendimiento.

