Responses API no convierte una función en fiable por sí sola. Esta guía muestra el bucle correcto de tool calls, validación, estado y trabajos largos para que un agente no confunda una respuesta convincente con una acción segura.
OpenAI Responses API es la interfaz unificada para generar respuestas, usar herramientas y conservar estado entre turnos. Un tool call no es una orden que el servidor deba obedecer: es una propuesta del modelo que tu backend debe autorizar, validar, ejecutar de forma idempotente y devolver al modelo como function_call_output.
TL;DR
La keyword principal es
OpenAI Responses API. La intención es técnica: un developer que ya puede hacer una llamada básica necesita montar un flujo fiable con function calling, JSON estructurado, streaming, estado conversacional y trabajos que no caben en una petición HTTP corta.Mi postura: empieza con Responses API antes de introducir una capa de agentes. Es un contrato explícito que te obliga a entender input, output, tools y estado. Un SDK de agentes puede ahorrar orquestación después; no debería ocultar permisos, validación ni efectos externos.
Qué es Responses API y qué no resuelve
Responses API crea un objeto
responsea partir de un modelo, una entrada y, opcionalmente, herramientas. La salida no tiene por qué ser texto: puede contener mensajes, llamadas de función, resultados de herramientas alojadas, elementos de razonamiento y eventos de streaming. Leer solooutput_textes correcto para un chat simple, pero insuficiente para un flujo que actúa sobre sistemas reales.La API puede encadenar contexto con
previous_response_ido con Conversations. Eso evita reenviar un historial manual enorme, pero no sustituye tu modelo de negocio: tú decides qué conversación pertenece a qué usuario, cuánto vive, qué datos se permiten y cuándo hay que resumir o borrar estado.
Tampoco decide si una llamada es segura. El modelo puede proponer create_invoice, send_email o deploy. Tu aplicación sigue siendo el control de autoridad: autentica al usuario, limita el recurso, valida argumentos, exige aprobación cuando corresponde y registra el efecto final.
El modelo propone pasos; el backend conserva la autoridad. Estado, validación, colas y auditoría son piezas distintas del texto generado.
El bucle correcto de function calling
Function calling tiene cuatro etapas: declaras una tool con un schema; el modelo emite uno o más elementos
function_call; tu servidor valida y ejecuta solo los que autoriza; devuelves unfunction_call_outputcon elcall_idoriginal y pides la siguiente respuesta. Si falta el último paso, el modelo no ve el resultado real de la acción y tenderá a completar la conversación con una suposición.No ejecutes argumentos directamente con
json.loadsy una llamada a tu SDK interno. El schema reduce salidas mal formadas, pero no prueba que el usuario tenga acceso aproject_id, que una fecha exista ni que la acción sea razonable. Valida tipos, rangos, pertenencia al tenant y política de negocio fuera del modelo.Para una operación con efecto, asocia una clave idempotente a la intención de negocio, no al texto del modelo. Un retry HTTP, una reconexión de streaming o una segunda respuesta no debe enviar dos emails o crear dos facturas. Guarda
call_id, usuario, recurso, hash del payload y resultado de la ejecución.
Código: tool estrecha y resultado verificable en Python
Este ejemplo ilustra el bucle. La tool es deliberadamente de lectura y el resultado vuelve como datos, no como instrucciones. En producción, get_release debería imponer autorización y recuperar solo los campos permitidos para el usuario autenticado.
responses_tools.py
import json
from openai import OpenAI
client = OpenAI()
TOOLS = [{
"type": "function",
"name": "get_release",
"description": "Returns approved release metadata for one repository.",
"parameters": {
"type": "object",
"properties": {"repo": {"type": "string", "minLength": 1}},
"required": ["repo"],
"additionalProperties": False,
},
"strict": True,
}]
def get_release_for_user(user_id: str, repo: str) -> dict:
assert repo in allowed_repos_for(user_id) # authz, not a model prompt
return read_release_metadata(repo)
response = client.responses.create(
model="gpt-5",
input="¿Cuál es el último release de api-gateway?",
tools=TOOLS,
)
tool_outputs = []
for item in response.output:
if item.type == "function_call" and item.name == "get_release":
args = json.loads(item.arguments)
result = get_release_for_user(current_user.id, args["repo"])
tool_outputs.append({
"type": "function_call_output",
"call_id": item.call_id,
"output": json.dumps(result),
})
final = client.responses.create(
model="gpt-5",
previous_response_id=response.id,
input=tool_outputs,
)
print(final.output_text)
El detalle importante no es el nombre de la función: es que allowed_repos_for vive en tu backend. Si el modelo propone otro repo, la autorización falla antes de tocar la fuente de datos. Devuelve un error de dominio breve y deja que el modelo explique el límite al usuario, en vez de darle una excepción cruda o inventar una respuesta.
Structured Outputs: contrato de interfaz, no control de seguridad
¿Te está sirviendo? Hay una dosis cada semana
Te resumo herramientas de IA para devs, agentes, MCP, seguridad y workflows en un email de 5 minutos. En español y sin ruido.
Cuando necesitas una salida que otro sistema consuma, usa Structured Outputs con JSON Schema estricto. En Responses API el formato se configura dentro de text.format; para tools, define strict: true y limita propiedades. Eso hace que el contrato sea más predecible que pedir «devuelve JSON válido» en un prompt.
Lo que conviene comprobar
Un schema debe representar una decisión pequeña y verificable. Para triage, por ejemplo: categoría de una allowlist, confianza acotada, evidencia citada y needs_human_review. Evita un objeto genérico tipo action: string que luego se convierte en una puerta trasera de comandos para cualquier integración.
Trata cualquier campo generado como entrada no confiable al cruzar una frontera. strict evita muchas formas inválidas; no sustituye escape HTML, validación de URLs, autorización, control de concurrencia, límites de tamaño ni saneamiento para SQL o shell. Un JSON impecable puede describir una acción equivocada.
Estado: previous_response_id frente a Conversations
previous_response_id es útil para enlazar el siguiente turno al anterior con una relación explícita. Es cómodo en una conversación corta o en un workflow donde tu base de datos guarda el último response ID por sesión. Las instrucciones de una llamada anterior no se arrastran automáticamente si pasas instrucciones nuevas: verifica ese comportamiento antes de asumir que una política quedó vigente.
Conversations es una entidad de estado reutilizable para añadir y recuperar ítems entre respuestas. Encaja cuando necesitas una conversación estable que pueda sobrevivir a distintos dispositivos o workers. Aun así, no conviertas la Conversation en tu única fuente de verdad: conserva en tu base la identidad del usuario, el tenant, el estado de aprobación y referencias de auditoría.
Mi regla: guarda solo IDs y contexto mínimo de producto; vuelve a resolver permisos, herramientas permitidas y policy en cada petición. El estado puede recordar la conversación, pero no debe heredar autoridad. Un usuario que pierde acceso a un proyecto no debería mantenerlo porque una conversación vieja lo mencionaba.
Streaming y background mode son flujos distintos
Streaming usa eventos server-sent para pintar progreso o texto parcial con baja latencia. Es una decisión de experiencia de usuario; no conviertas cada delta en un registro de negocio ni ejecutes una tool al primer fragmento. Espera al elemento de function call completo y conserva una ruta clara de cancelación del cliente.
Background mode sirve para respuestas largas que deben continuar aunque la petición web se corte. Creas la respuesta con
background=true, persistes su ID y consultas su estado o recibes el evento webhook correspondiente. El frontend no debería mantener una conexión abierta durante minutos solo para fingir que un job asíncrono es streaming.La consecuencia operativa importa: background mode conserva datos para poder hacer polling y no es compatible con Zero Data Retention. Revisa data controls, retención y la región de datos de tu organización antes de activarlo en flujos con información sensible. Para una tarea larga sin datos que deban salir, una cola propia y una llamada normal puede ser una alternativa más controlable.
Herramientas alojadas, MCP y límites de datos
Responses API puede combinar funciones de tu aplicación con herramientas alojadas, como web search, file search, code interpreter o image generation, según modelo y disponibilidad. Cada una introduce otra frontera: cuota, tiempo, datos enviados y resultados que pueden estar equivocados o contener instrucciones externas.
Los servidores MCP remotos son servicios de terceros. No les pases un token o documento solo porque una tool description sea atractiva. Delimita por servidor la URL, identidad, scopes, datos que puede recibir, rate limits y la aprobación para efectos externos. MCP conecta capacidades; no valida automáticamente su confianza.
Usa allowed_tools o un conjunto de tools por tarea cuando sea posible. Un agente de triage no necesita la misma superficie que uno de release. Reducir opciones también mejora la calidad: al modelo le cuesta menos elegir una tool cuando no le ofreces quince acciones parecidas con permisos distintos.
Arquitectura mínima que llevaría a producción
Entrada autenticada → policy de tenant → creación de response → parser de output → validador de schema y negocio → executor idempotente → auditoría → function_call_output → respuesta final. Si hay una acción sensible, añade una transición explícita de propuesta a aprobación: el modelo prepara payload y evidencia; una persona o regla independiente habilita la mutación.
Mantén los executors fuera del prompt. Una tool debería ser una función estrecha, con nombre que explique el efecto, parámetros mínimos y un resultado redactado. update_customer es demasiado grande; propose_customer_address_change y apply_approved_address_change dejan una frontera revisable.
Mide más que éxito HTTP: porcentaje de tool calls válidas, denegadas por policy, reintentos idempotentes, aprobaciones, errores por tipo, latencia p50/p95, coste por workflow y tareas resueltas sin escalado. Una respuesta fluida puede ocultar que el modelo llama tres veces a una API o que el 20% de acciones queda bloqueado al final.
Checklist antes de habilitar una tool con efecto
La tool expresa una única capacidad y no acepta campos libres que acaben en SQL, shell o URLs arbitrarias.
El backend autentica al usuario y comprueba autorización por tenant, recurso y operación; el modelo no decide permisos.
Los argumentos pasan JSON Schema y validación de negocio antes de llegar a un executor.
Las mutaciones tienen una clave idempotente y un registro de resultado por operación de negocio.
Las acciones externas o irreversibles muestran destino, payload, evidencia y riesgo antes de la aprobación.
Las tools disponibles se reducen por tarea y se revisan al cambiar de modelo, prompt o integración.
El estado conversacional no concede permisos persistentes y tiene una política de retención explícita.
Streaming, background jobs y webhooks tienen timeouts, cancelación, reintentos y observabilidad propios.
Hay evals con entradas ambiguas, argumentos inválidos, recursos de otro tenant y prompt injection indirecta.
Conclusión
Responses API es una buena base cuando quieres control fino: te enseña exactamente cuándo el modelo habló, cuándo pidió una tool y cuándo tu sistema produjo un resultado verificable. Esa claridad vale más que una demo de agente que parece autónoma hasta que intenta escribir en producción.
Empieza por una tool de lectura, un schema pequeño y una traza completa. Añade estado cuando haya una razón de producto, y background mode cuando el trabajo de verdad sea largo. La autonomía útil no consiste en dar más funciones al modelo: consiste en hacer que cada capacidad tenga una frontera, una evidencia y una forma segura de fallar.
Preguntas frecuentes
¿Qué es OpenAI Responses API?
Es la API unificada de OpenAI para crear respuestas con input multimodal, herramientas, streaming y estado conversacional. La salida puede incluir texto y elementos de tool calling, no solo una cadena.
¿Responses API sustituye a OpenAI Agents SDK?
No necesariamente. Responses API ofrece el contrato de bajo nivel; Agents SDK puede ayudar a orquestar agentes. Si necesitas permisos y efectos controlados, debes implementar validación y autorización en cualquiera de las dos capas.
¿Function calling ejecuta mi función automáticamente?
No. El modelo devuelve una propuesta de llamada; tu aplicación interpreta el output, valida argumentos y permisos, ejecuta si procede y devuelve un function_call_output.
¿Para qué sirve previous_response_id?
Enlaza una respuesta nueva con el contexto de la respuesta anterior. Es útil para turnos cortos, pero no sustituye una política de identidad, autorización o retención de datos.
¿Cuándo uso background mode?
Cuando una respuesta puede durar más que la petición HTTP normal y quieres consultar su estado o recibir un webhook. Revisa antes su efecto en retención de datos y compatibilidad con Zero Data Retention.
¿Structured Outputs hace segura una acción?
No. Hace más predecible el formato. Todavía debes validar negocio, scopes, tenant, recursos, límites, idempotencia y aprobación humana cuando exista efecto externo.
Cómo llevar una tool de Responses API de demo a producción
- Elegir una capacidad de lectura. Empieza por una consulta reversible con un recurso claro, como recuperar metadata de un release aprobado.
-
Diseñar el schema. Declara campos mínimos, tipos, allowlists y
additionalProperties: false; activa modo estricto cuando sea compatible. - Separar autorización. Resuelve usuario, tenant, scopes y recurso en el backend antes de llamar a la fuente de datos.
- Crear el primer response. Envía el input y solo las tools necesarias para esa tarea; registra el response ID y la versión de policy.
- Interpretar function calls. Procesa únicamente elementos completos de tipo function call; no ejecutes texto libre ni deltas de streaming.
- Validar y ejecutar. Comprueba schema y reglas de negocio, aplica rate limits e idempotencia y captura un resultado redactado.
- Devolver function_call_output. Usa el call ID original y datos estructurados para que el siguiente response pueda explicar el resultado real.
- Añadir aprobación. Separa propuesta y mutación cuando la acción escriba, envíe, despliegue o transfiera información.
- Preparar fallos. Define errores de autorización, validación, proveedor y timeout; cada uno debe tener una recuperación distinta.
- Medir y evaluar. Prueba tenants cruzados, argumentos hostiles y retries; mide tools inválidas, bloqueos, coste, latencia y resolución.
Fuentes y referencias
- OpenAI API: Responses
- OpenAI API: function calling
- OpenAI API: Structured Outputs
- OpenAI API: conversation state
- OpenAI API: background mode
- OpenAI API: streaming
- OpenAI API: built-in tools
- OpenAI API: data controls
También te puede interesar
- OpenAI Agents SDK: MCP, guardrails y tracing
- Evaluación RAG en producción
- OpenTelemetry GenAI para observar agentes
- Prompt injection en agentes de IA
- MCP en producción: seguridad, permisos y supply chain
Recibe una lectura semanal de herramientas IA para devs
Cada semana te resumo herramientas de IA para devs, agentes, MCP, seguridad y workflows en un email de 5 minutos. En español y sin ruido.

Top comments (0)