Por qué los agentes de IA necesitan aún más JSON tras la Agents API: Harness, Tool Calling, JSON Schema

A 18 de septiembre de 2026: la beta pública de Agents API aloja el Codex harness. Cuando ya no escribes el bucle, casi todo lo que sigues teniendo es JSON: Schema de herramientas, arguments, tool_result, MCP, eventos de sesión. Un contrato flojo solo hace que el bucle alojado ejecute malos parámetros más rápido.

Conclusión primero: la Agents API aloja el bucle. No aloja el contrato. El 10 de septiembre de 2026, OpenAI puso el Agent Harness que impulsa Codex delante de los desarrolladores como beta pública. La planificación del modelo, la compactación de contexto, los subagents y el ciclo de vida del sandbox salieron de tu proceso y pasaron a beta.agents.sessions. Lo que sigues teniendo es casi todo JSON: el JSON Schema de cada function tool, arguments, el string de tool_result, el inputSchema de MCP y el flujo de eventos de la session. Que un harness alojado ejecute el bucle no es lo mismo que otro valide tus campos. Afloja el contrato y el bucle alojado solo ejecuta parámetros malos con más frecuencia.

Escrito a fecha de 18 de septiembre de 2026. Este sitio ya tiene por qué los agentes no pueden prescindir de JSON, por qué Tool Calling depende de JSON Schema, si JSON Schema se convierte en el contrato estándar, MCP / Skills / Tools / Subagents y qué es MCP. Este artículo solo responde por qué JSON importa más después de la Agents API, no menos.

Qué se publicó de verdad el 10 de septiembre

La frase de OpenAI es: el mismo harness e infraestructura que impulsan Codex, como agente en la nube alojado para desarrolladores. La documentación pública lo sitúa bajo el namespace beta.agents; las peticiones llevan OpenAI-Beta: agents=v1. El harness no tiene tarifa aparte. Pagas tokens del modelo, herramientas y tiempo de sandbox.

Crear una session es enviar un documento JSON: modelo, instrucciones, lista de herramientas, entorno, input. Las muestras oficiales usan gpt-6-astra. Las herramientas pueden ser MCP, functions personalizadas o retrieval integrado. El entorno puede ser none, openai_hosted, o un sandbox que tú aportas — Blaxel, Cloudflare, Daytona, E2B, Modal, Vercel y similares. Multi-agent es un flag: multi_agent.enabled más max_concurrent_subagents.

Esto no es otro endpoint de chat que dice «por favor, saca JSON». La Responses API sigue ahí. El Agents SDK sigue ahí. Lo que se lleva la Agents API es el bucle mismo: quién elige el siguiente salto, cuándo se compacta el contexto, cuándo se lanza un subagent. Los nombres de campo aún pueden moverse durante la beta. La división ya es estable: OpenAI ejecuta el harness; tú aportas el contrato de herramientas y el resultado de negocio.

Tres entradas: Responses, Agents SDK, Agents API

A septiembre de 2026, OpenAI deja tres formas de construir un agente en paralelo. Antes de mezclarlas, pregunta dónde corre el bucle:

EntradaDónde corre el bucleDónde vive el estadoQué sigues escribiendo
Responses APITu appHistory que montas / ConversationsLlamadas al modelo, retornos de herramientas, el bucle entero
Agents SDKTu procesoSessions del SDK más tu almacenamientoAprobaciones, despliegue, y aún puedes cambiar el bucle
Agents APIEl Codex harness alojado de OpenAIsession / turn / item en el servidorDefiniciones de herramientas, resultados de function, elección de entorno; no puedes cambiar el bucle

La compleción de una sola llamada sigue correspondiendo a Responses. Si necesitas ser dueño de las aprobaciones y la persistencia, usa el SDK. Si quieres trabajo de varios días, compactación, subagents y un sandbox operado para ti, usa la Agents API. Las tres siguen describiendo los parámetros de herramientas con JSON Schema. La diferencia: las dos primeras aún te dejan parchear el bucle; la tercera solo te deja parchear el contrato y el payload de retorno.

Qué es un Agent Harness — y qué no firmará

Un harness es el runtime entre el modelo y los efectos secundarios: leer eventos, elegir herramientas, devolver resultados, compactar contexto, mantener vivo un trabajo largo. El harness de Codex es open source. La Agents API es OpenAI operando esa misma lógica y versionándola con los modelos. La nota de lanzamiento destaca compactación automática, Tool search, Programmatic Tool Calling y subagents en paralelo.

No firmará ninguna de estas cosas:

  • si un customer_id debe existir, o debe ser un UUID;
  • si tu función puede aceptar claves de más;
  • si el inputSchema de un MCP server es estricto o laxo;
  • si el output que devuelves es un objeto, un string o un párrafo de chat.

Eso sigue siendo JSON Schema más una comprobación que ejecutas tú. Un harness alojado sube cuánto tiempo puede correr un bucle y cuánto puede paralelizar. No sube si los parámetros de este salto son legales. Tratar ambas cosas como lo mismo es la primera confusión que este artículo separa.

Por qué un bucle alojado implica más saltos JSON

Cuando escribes el bucle, el JSON malo suele morir de tu lado: el parse falla, los campos no coinciden, paras. Una vez el bucle está alojado, el fallo se aplaza, se copia y se envía por más canales:

SaltoPayloadQuién lo produceQuién debe validar
Crear sessionJSON de agent / tools / environmentTu appTú, antes de enviar
Definición de functionJSON Schema (parameters)Tu appTú: estrecha required / additionalProperties
El modelo emite una llamadaobjeto argumentsHarness alojado + modeloTú: valida otra vez antes de ejecutar
Devolver un resultadostring tool_result.outputTu appTú: stringify un valor legal
MCPJSON-RPC + inputSchemaServer / harnessEl server y tu lista de permitidos
Flujo de eventoseventos JSON agent.session.*El servicio alojadoTú: ramifica por type; no lo parsees como prosa de chat

Suma Tool search cargando definiciones bajo demanda, Programmatic Tool Calling encadenando llamadas en código, y subagents cada uno con su propio contexto — una tarea de usuario ahora hace más idas y vueltas JSON que un solo salto de Function Calling. Alojar oculta esos saltos. Oculto no es lo mismo que opcional de validar. Para un mapa salto a salto, ver de Tool Calling a MCP.

Tool Calling: las function tools siguen siendo JSON Schema

Las function tools de la Agents API reutilizan la forma de la Responses API. Lo que pones en agent.tools no es un párrafo. Es un nombre, una descripción y un JSON Schema:

{
  "type": "function",
  "name": "get_customer",
  "description": "Look up a customer by ID.",
  "parameters": {
    "type": "object",
    "properties": { "customer_id": { "type": "string" } },
    "required": ["customer_id"],
    "additionalProperties": false
  }
}

La muestra oficial rellena required y pone additionalProperties a false. No es un hábito de formato. Si el agente puede añadir una clave de más, esa clave puede convertirse en una ruta, un fragmento SQL o un delete. El schema es el contrato que ve el modelo al decodificar, y el contrato que deberías volver a ejecutar antes de ejecutar. Para modo estricto, ajv y un pipeline de segunda pasada, ver por qué Tool Calling depende de JSON Schema.

La descripción sigue ayudando al modelo a elegir una herramienta. No sustituye tipos, enums ni campos required. Cuanto más listo es el harness, más ganas tiene de elegir una herramienta «más o menos» de una lista larga. Más o menos es lo que el schema está para rechazar.

requires_action y tool_result: el camino de vuelta también es JSON

Cuando el modelo necesita tu función, la session se pausa en agent.session.requires_action. El trabajo pendiente vive en required_actions. Un ítem function_call en el history no basta por sí solo. Una llamada pendiente típica se ve así:

{
  "type": "function_call",
  "turn_id": "turn_123",
  "call_id": "call_123",
  "name": "get_customer",
  "arguments": { "customer_id": "123" }
}

La documentación presenta arguments como objeto. No lo envuelvas en una respuesta de chat y lo extraigas con JSON.parse — ese es el canal equivocado, cubierto en por qué JSON.parse falla. Valida el objeto contra el mismo schema, ejecuta la función y luego envía agent.session.input.tool_result al endpoint de eventos de la session con el turn_id y el call_id originales.

Si va bien, success: true y output como string o un array de contenido soportado. Los objetos pasan primero por JSON.stringify. Si falla, success: false y un error que el modelo pueda leer. No envíes stacks, secretos ni una fila entera de la base de datos. Si el proceso muere después de que la función corrió pero antes de que el resultado llegara a OpenAI, identifica el efecto secundario por session / turn / call y mantén la idempotencia: al reiniciar, lee las acciones pendientes antes de volver a ejecutarla.

Los handlers de function siempre corren en tu aplicación, aunque la session tenga sandbox. El harness no ejecutará get_customer por ti. Si estás offline, el salto se queda bloqueado. Ese es uno de los pocos puntos síncronos de un bucle alojado que sigue perteneciendo por completo a ti — y el salto donde el JSON tiene que estar bien.

Tool search y Programmatic Tool Calling

Una lista grande de herramientas quema tokens y rompe la caché si cada schema está en el contexto. La Agents API carga las functions de inmediato por defecto. Las raras pueden poner defer_loading: true, con {"type": "tool_search"} en agent.tools. El modelo encuentra la definición y luego la llama. Eso añade un salto donde «la definición también es JSON»: el schema que devuelve la búsqueda tiene que coincidir con la función que de verdad implementaste. No anuncies un contrato ancho y ejecutes uno estrecho.

Programmatic Tool Calling deja que los modelos soportados escriban un programa corto que ejecuta herramientas elegibles en paralelo o en cadena, y luego solo trae al contexto los resultados filtrados. Eso recorta el coste de llenar la ventana en cada salto. Sube el requisito de que el JSON intermedio sea legal. Si los tipos derivan en medio, los filtros y fusiones posteriores fallan dentro de un harness que no ves. El SDK ya tiene un arreglo que codifica errores estructurados como JSON. Ese camino come schema, no prosa.

MCP y subagents: más schemas, más JSON

Añade un MCP server a agent.tools y el harness descubre herramientas, las llama y devuelve resultados. A diferencia de las functions, esas llamadas no pasan por tu aplicación. HTTP conecta desde OpenAI por defecto; también puedes conectar desde el entorno, o lanzar stdio dentro del sandbox. Lo que sigues controlando es allowed_tools, si un init fallido falla el turn (required: true), y lo estricto que es el inputSchema del propio server.

Los mensajes MCP siguen siendo JSON-RPC. Un schema laxo significa que el harness alojado disparará más peticiones que nunca ves. Eso no es «el protocolo te hizo seguro». Es «el bucle se alejó». Para las capas del protocolo, ver qué es MCP; para el límite con Skills y Subagents, ver la pila de agentes de 2026.

Cada subagent guarda su propio contexto; el padre fusiona. El trabajo en paralelo recorta latencia y también abre muchos objetos arguments. Si la fusión sigue siendo un texto largo sin schema, solo aplazaste «parsea el chat» al último salto. Las conclusiones que entran en un programa deberían seguir usando Structured Output o un schema de resultado que definas tú — no otro raspado de prosa. Ver qué es Structured Output.

Cuatro cosas que sigues validando en local

Tras alojar el harness, la lista no se acorta. Se estrecha:

  1. Schemas de herramientas. Rellena required, pon additionalProperties: false, estrecha los enums. No te apoyes en la descripción para parar efectos secundarios.
  2. Arguments antes de ejecutar. Aunque el vendor ya haya aplicado el schema, ejecuta el mismo documento otra vez en tu proceso. Tipos mal, campos que faltan, claves de más se paran aquí.
  3. El output que devuelves. Haz JSON legal, luego stringify. Los errores salen como success: false. No le pases al modelo una excepción interna en crudo.
  4. Mantén eventos y chat en canales separados. Ramifica por event.type. No trates un stream SSE entero como un valor JSON. Las respuestas estructuradas al usuario van por Structured Output, no por JSON.parse sobre una frase del assistant.

En el lado de seguridad: un string dentro de arguments puede ser una inyección, no «el tipo coincidió, así que ejecútalo». Ver JSON malicioso y prompt injection. Si JSON Schema se convierte en el contrato entre vendors es el artículo del contrato estándar — la Agents API no debilita esa tesis. Empuja la tesis a la única capa que aún puedes cambiar.

Inspecciona el contrato con herramientas JSON locales

Antes de entregar trabajo a una session alojada, mira tres textos en el navegador: el schema de la herramienta, un objeto arguments de muestra y el output que piensas devolver.

  • Validador JSON — ¿es legal la gramática? Si tienes un schema, comprueba campos, required y claves de más juntos.
  • Formateador JSON — expande un tool_result de una línea y mira si serializaste una fila entera de la base de datos.
  • JSON Diff — compara los arguments que envió el modelo con el objeto mínimo que permite el schema.

Nada sale del navegador. Es el sitio correcto para poner juntos un payload fallido de required_actions, un documento parameters y un resultado ya stringify. Estabiliza el contrato y luego deja que el harness alojado corra días.

FAQ

¿La Agents API significa que puedo dejar de escribir JSON Schema?

Lo contrario. Una vez el bucle está alojado, el schema es el contrato principal que sigues teniendo. Los parameters de function, el inputSchema de MCP y el output que devuelves siguen siendo JSON.

¿Cómo elijo entre Agents API, Agents SDK y Responses?

Las llamadas de un solo disparo van a Responses. Si necesitas ser dueño del bucle, las aprobaciones y el almacenamiento, usa el SDK. Si quieres trabajos largos, compactación, subagents y un sandbox operado por OpenAI, usa la Agents API. Las tres siguen pidiendo JSON Schema para los parámetros de herramientas.

Arguments ya es un objeto. ¿Sigo llamando a JSON.parse?

No vuelvas a parsear el chat de alrededor. Trata arguments como objeto, como hace la documentación, y valídalo con el mismo JSON Schema. Raspar arguments de la prosa es el canal equivocado.

¿Por qué hay que hacer stringify de tool_result?

La documentación quiere output como string o un array de contenido soportado. Haz JSON legal, luego stringify, para no mezclar una segunda codificación con «parece un objeto, en realidad es un string».

¿Las herramientas MCP pasan por mi aplicación?

Por defecto, no. El harness habla con el server. Lo que restringes es el inputSchema del propio server, allowed_tools, y cualquier aprobación de acciones irreversibles dentro de ese server.

¿Cambiarán los nombres de campo durante la beta?

Puede. Este artículo sigue la documentación pública a fecha de 18 de septiembre de 2026. La división no cambiará: el harness ejecuta el bucle; tú aportas el contrato JSON. Si un campo se renombra, el deber de validar sigue de tu lado.

Resumen

La Agents API recorta el trabajo de «cómo llevar un agente hasta el final». Sube el peso de «cada salto JSON tiene que estar bien». Lo que salió el 10 de septiembre es el Codex harness: sessions, compactación, tool search, llamadas programáticas, subagents, sandboxes. No comprobará cómo debe verse un customer_id, y no convertirá tu tool_result en un string legal por ti.

Cablear un agente a un programa en 2026 sigue el mismo orden: herramientas en JSON Schema, respuestas finales en Structured Output, la prosa del chat no es una API. Lo que cambió es que, una vez el bucle está alojado, el único sitio donde aún puedes parchear es el contrato. Comprueba primero el schema, los arguments y el payload de retorno en un validador local, y luego entrega el trabajo a una session alojada. Los modelos cambiarán. El harness tomará versiones nuevas. Tu contrato de campos no debería aflojarse con ellos.