OpenAI Responses API: function calling fiable, estado y trabajos en segundo plano
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.
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`.
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.
Checklist
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.
<div style="margin:28px 0;border:1px solid #dbe3ef;border-radius:12px;overflow:hidden;background:#0f172a;"> <div style="padding:10px 14px;background:#111827;color:#cbd5e1;font:13px Consolas,monospace;">responses_tools.py</div> <pre style="margin:0;padding:18px;overflow:auto;color:#e5e7eb;font:13px/1.55 Consolas,monospace;"><code>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)</code></pre> </div>
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.
Suscribirme gratisCuando 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.
Puntos a revisar
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.
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
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
También te puede interesar
OpenAI Agents SDK: MCP, guardrails y tracingEvaluación RAG en producciónOpenTelemetry GenAI para observar agentesPrompt injection en agentes de IAMCP en producción: seguridad, permisos y supply chainRecibe 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.
Suscribirme gratis