El agente devolvió un objeto JSON bien formado. El código lo aceptó y guardó un cambio. Solo después alguien notó que el identificador apuntaba a otro cliente, que la versión de la fuente estaba desactualizada o que la operación quedaba fuera de la autoridad de ese agente.
El JSON válido no es un dato confiable. Para validar la salida de un agente de IA antes de guardarla, trata el resultado como una propuesta no confiable y pásalo por cuatro fronteras: formato, significado, autoridad y efecto comprobado. Un schema resuelve la primera. Las demás dependen de tu código y de los sistemas que controlan el estado real.
Este artículo es un spoke de la guía sobre cómo probar la trayectoria de un agente de IA. Una prueba de trayectoria verifica el camino de ejecución. Aquí la pregunta es más concreta: ¿la salida final puede cruzar la frontera que guarda datos o dispara una acción?

Respuesta corta
- Valida la forma recibida, incluso cuando el proveedor ofrece structured outputs.
- Comprueba identidad, evidencia, versión y reglas de negocio contra el estado actual.
- Aplica la autorización y la aprobación en el runtime, no en el texto generado por el modelo.
- Registra una propuesta o usa una operación idempotente, y lee el destino de nuevo antes de declarar éxito.
Esto continúa la validación de argumentos y respuestas de tools en TypeScript, pero el punto de decisión cambia: la salida ya cruzó la ejecución y está a punto de convertirse en estado persistente.
¿Qué garantiza realmente una salida estructurada?
La salida estructurada garantiza una forma más predecible cuando el proveedor y el schema son compatibles. No garantiza que los valores describan correctamente el mundo, que el agente haya elegido el registro correcto ni que una escritura externa haya ocurrido.
La documentación del SDK de OpenAI para Structured Outputs, consultada el 2026-10-02, muestra cómo obtener una salida analizada con Zod. También explica que una respuesta incompleta puede no tener una salida analizada. Esto cambia el contrato: un valor ausente, un rechazo, un timeout y un objeto inválido son estados distintos de un resultado aceptado.
La guía de Microsoft Agent Framework para producir salidas estructuradas, consultada el 2026-10-02, presenta modelos tipados y mapas JSON como formatos de respuesta. La función ayuda a mover campos previsibles entre componentes. No reemplaza los controles que solo puede hacer la aplicación, como verificar que un cliente pertenece a la cuenta actual o que un cambio sigue autorizado.
Por eso, la frontera correcta no es “el modelo devolvió JSON”. Es:
salida del agente
-> formato
-> significado
-> autoridad
-> propuesta o escritura segura
-> lectura de confirmación
La guía de JSON Schema sobre propiedades requeridas y propiedades adicionales, consultada el 2026-10-02, muestra por qué required y additionalProperties representan decisiones distintas. Incluso un objeto que pasa ambas puede contener un valor desactualizado o una referencia fuera del alcance del usuario actual.
¿Cómo separar formato de significado?
El formato pregunta si el objeto tiene campos, tipos y restricciones estructurales aceptables. El significado pregunta si esos valores encajan con el estado que controla la aplicación. Mezclarlos suele producir un schema enorme, un prompt confuso o una falsa sensación de seguridad.
Considera un resultado de extracción que propone actualizar un pedido:
import { z } from "zod";
const UpdateProposal = z.object({
proposalId: z.string().min(1),
accountId: z.string().min(1),
orderId: z.string().min(1),
newStatus: z.enum(["approved", "rejected"]),
sourceVersion: z.string().min(1),
evidenceRefs: z.array(z.string().min(1)).min(1),
reason: z.string().min(1),
}).strict();
type UpdateProposal = z.infer<typeof UpdateProposal>;
El schema comprueba que orderId existe, que newStatus pertenece al conjunto permitido y que hay al menos una referencia de evidencia. No comprueba que el pedido pertenezca a la cuenta, que la versión de la fuente sea actual o que el agente pueda cambiar ese estado.
La guía de Zod sobre el manejo de errores, consultada el 2026-10-02, explica que safeParse devuelve una unión discriminada. Esa forma es útil en runtime porque el flujo puede separar result.success de result.error sin convertir cada fallo de validación en una excepción genérica.
Una comprobación de significado puede ser pequeña y determinista:
type MeaningCheck =
| { ok: true; order: { id: string; accountId: string; status: string } }
| { ok: false; code: "unknown-order" | "wrong-account" | "stale-source" };
async function checkMeaning(
proposal: UpdateProposal,
current: {
loadOrder(id: string): Promise<{ id: string; accountId: string; status: string } | null>;
currentSourceVersion(): Promise<string>;
},
): Promise<MeaningCheck> {
const order = await current.loadOrder(proposal.orderId);
if (!order) return { ok: false, code: "unknown-order" };
if (order.accountId !== proposal.accountId) {
return { ok: false, code: "wrong-account" };
}
if (await current.currentSourceVersion() !== proposal.sourceVersion) {
return { ok: false, code: "stale-source" };
}
return { ok: true, order };
}
Este código es ilustrativo. Muestra la separación entre analizar el valor y leer el estado actual, pero no conoce tu base de datos, tu política de concurrencia ni tus requisitos de aprobación. Prueba la función en la frontera real cuando una decisión pueda producir un efecto externo.
¿Dónde debe vivir la autorización?
La autorización debe ocurrir después de validar el formato y el significado, pero antes de la escritura. El agente puede proponer approved; ese campo no se convierte en permiso solo porque el modelo repita la palabra en JSON.
La guía de guardrails del OpenAI Agents SDK, consultada el 2026-10-02, separa guardrails de entrada, salida y herramientas. La distinción importa en flujos con handoffs: un guardrail de salida no es automáticamente un control alrededor de cada herramienta usada por agentes intermedios.
Una decisión de autoridad puede depender de identidad, alcance, riesgo y aprobación humana:
type AuthorityDecision =
| { kind: "allow"; approvalId?: string }
| { kind: "deny"; reason: string }
| { kind: "needs-review"; reason: string };
function authorize(
proposal: UpdateProposal,
actor: { agentId: string; accountId: string; canChangeOrders: boolean },
): AuthorityDecision {
if (actor.accountId !== proposal.accountId) {
return { kind: "deny", reason: "account scope does not match" };
}
if (!actor.canChangeOrders) {
return { kind: "needs-review", reason: "agent lacks order-write authority" };
}
return { kind: "allow" };
}
No trates este ejemplo como una política lista para usar. La aplicación debe cargar la identidad desde una fuente confiable, aplicar el alcance correcto y registrar la decisión. El modelo puede sugerir un motivo. El motivo no reemplaza la regla que permite o bloquea la operación.
Si el resultado pasa a otro agente, el receptor también debe validar el paquete. El artículo sobre diseñar un handoff de agentes de IA con contexto estructurado explica este cambio de responsabilidad. El punto aquí es que la autorización sigue siendo una decisión del runtime, aunque el valor provenga de un paso anterior.
¿Cuándo debe convertirse la salida en una propuesta?
Usa una propuesta cuando el resultado aún necesite revisión, cuando la operación sea difícil de deshacer o cuando el agente no deba escribir directamente en el destino. La propuesta debe conservar el valor validado, las referencias que lo respaldan, la versión de la regla y un identificador estable del intento.
El flujo puede modelarse así:
agent_output
-> rejected: invalid_shape
-> rejected: invalid_meaning
-> needs_review: authority_or_risk
-> staged: proposal_created
-> applied: operation_accepted
-> verified: destination_read_back
El estado staged evita que la interfaz confunda una intención con un cambio terminado. También facilita mostrarle a una persona exactamente qué cambiará. La aprobación debe apuntar a proposalId y a un hash del contenido relevante, no solo al nombre de la herramienta.
La guía de OpenAI para ejecutar agentes, consultada el 2026-10-02, documenta errores de salida final inválida y alternativas validadas que no repiten llamadas a herramientas. El patrón es útil: cuando el fallo está en la salida final, no conviertas automáticamente la recuperación en una nueva ejecución con posibles efectos duplicados.
No tengo una base de datos de producción ni un agente real detrás de este fixture. El paso de staging es una recomendación de diseño basada en las fronteras verificables anteriores. En un sistema real, el equipo debe decidir qué tipos de propuesta requieren aprobación y qué estado externo puede leerse de nuevo.
¿Cómo evitar una escritura duplicada?
Una validación correcta puede aprobar una operación que falla en transporte, termina después de un timeout o se repite en un worker. El control de reintentos debe existir en la operación de escritura, no solo en el prompt.
Usa un identificador de idempotencia derivado de la intención estable de la operación, el destino y la versión de la propuesta. El mismo intento lógico debe encontrar el mismo registro de operación. Una propuesta cuyo contenido cambió necesita un identificador nuevo, aunque apunte al mismo pedido.
El artículo sobre probar la idempotencia de una API sin efectos duplicados cubre la frontera de una operación repetible. Para los agentes, la regla es la misma: un retry del modelo no demuestra que la primera escritura no ocurrió. Antes de repetirla, consulta el registro de operaciones o el destino externo.
Los estados deben distinguir al menos:
| Estado | Significado | Siguiente paso seguro |
|---|---|---|
rejected |
El objeto o la decisión incumplió una regla | corregir la entrada o pedir revisión |
staged |
La propuesta existe, pero no se aplicó | aprobar o descartar |
applied |
El ejecutor aceptó la operación | verificar el destino |
unknown |
El proceso no sabe si el efecto ocurrió | inspeccionar el destino antes de reintentar |
verified |
Una lectura del destino confirma el resultado esperado | liberar el siguiente paso |
unknown no significa lo mismo que failed. Un timeout después de enviar la solicitud puede ocultar un efecto que ya se aplicó. La arquitectura de pipeline de Microsoft Agent Framework, consultada el 2026-10-02, describe capas de middleware y puntos de persistencia que impiden liberar o guardar una salida antes del veredicto aplicable. La implementación cambia, pero la frontera es útil.
¿Qué casos deben entrar en la prueba?
Prueba valores que parecen aceptables, no solo JSON roto. El fallo peligroso es el que pasa el parser y llega a la escritura con la referencia equivocada, una versión desactualizada o una autoridad que el agente no tiene.
Una matriz mínima incluye:
- objeto válido, cuenta correcta, evidencia actual y operación permitida;
- campo obligatorio ausente, enum inválido y propiedad inesperada;
orderIdexistente que pertenece a otra cuenta;- versión de evidencia desactualizada o referencia de evidencia ausente;
- rechazo del modelo, respuesta incompleta y timeout antes del objeto;
- fallo de transporte antes de escribir y timeout después de escribir;
- retry del mismo
proposalIdy retry con contenido cambiado; - el destino informa éxito, pero no confirma el cambio en la lectura posterior.
La prueba debe afirmar algo más que “la función devolvió un objeto”. Comprueba que no comenzó ninguna escritura cuando falló el formato, que el estado no cambió cuando se negó la autoridad y que un resultado unknown hizo consultar el destino antes de reintentar.
Esto complementa validar JSON externo antes de usarlo en TypeScript. Ese artículo explica cómo tratar los datos externos como unknown. La salida de un agente tiene el mismo problema, con riesgo adicional de evidencia, autoridad y efectos secundarios.
¿Qué no puede demostrar la validación?
La validación de schema no demuestra la verdad factual. Puede confirmar que customerId es un string, pero no que el cliente exista. Una comprobación de significado puede confirmar que el registro existe, pero no que la regla de negocio se interpretó correctamente. La autorización puede permitir una operación, pero no garantizar que la base de datos aplicó el cambio.
Tampoco uses como prueba independiente un score de confianza producido por el propio agente. Puede ayudar a enviar casos a revisión, pero no reemplaza una consulta a la fuente ni una regla determinista. Cuando la aplicación depende de evidencia, conserva la referencia y comprueba el contenido en el sistema que es dueño de los datos.
No confundas el resultado del agente con el registro de lo que ocurrió. La guía sobre el registro de auditoría de un agente de IA debe ser escrita por el runtime o el ejecutor que observa la decisión y el efecto. La salida validada es una entrada de esa decisión, no la evidencia final de ejecución.
Preguntas frecuentes
¿La salida estructurada elimina la necesidad de validar?
No. La salida estructurada reduce los fallos de formato y entrega campos que el programa puede leer. La aplicación todavía debe comprobar identidad, estado actual, evidencia, autoridad y efecto. Un objeto que pasa el schema aún puede contener el cliente equivocado o información desactualizada.
¿Debo guardar la salida sin procesar del agente?
Depende de tu política de datos y del objetivo de retención. Para operar de forma segura, conserva el resultado validado, las referencias de evidencia, las versiones, las decisiones y los IDs de correlación. Conserva la salida sin procesar solo cuando exista un propósito definido, control de acceso y una regla de retención adecuada para esos datos.
¿Puedo reintentar cuando falla el schema?
A veces. Un retry limitado puede corregir un fallo de formato antes de cualquier efecto externo. No repitas una operación solo porque la confirmación tardó demasiado. Clasifica el fallo, conserva la propuesta original e inspecciona el destino cuando la primera tentativa pueda haberse aplicado.
¿La validación puede vivir dentro del prompt?
No como único control. El prompt puede explicar el contrato al agente, pero el runtime debe validar el valor recibido, aplicar la política y bloquear la escritura cuando la regla falle. El modelo no debe ser la autoridad que decide si su propia salida es confiable.
Conclusión
Antes de guardar la salida de un agente, haz cuatro preguntas: ¿el objeto tiene la forma esperada?, ¿los valores coinciden con el estado actual?, ¿la operación está autorizada? y ¿el destino confirmó el efecto? Un schema solo resuelve la primera parte.
Empieza con un resultado discriminado para rejected, staged, applied, unknown y verified. Mantén la propuesta separada de la escritura. Usa IDs idempotentes para los retries. Lee de nuevo el sistema externo antes de declarar éxito. Esta estructura facilita probar el agente y reduce la distancia entre una respuesta convincente y un cambio confirmado.
Cómo se hizo este análisis
Samuel Fajreldines es el autor responsable de este artículo. La investigación comparó la documentación actual de OpenAI Agents SDK, OpenAI Node SDK, Microsoft Agent Framework, Zod y JSON Schema, además de discusiones públicas recientes sobre verificación de agentes. El contrato TypeScript es ilustrativo y no se ejecutó contra un proveedor, una base de datos ni un agente de producción. La asistencia de IA apoyó la organización de la investigación, la redacción, la generación de la imagen y la localización; no aportó experiencia de producción ni sustituyó la verificación de las fuentes. El autor también mantiene RemoteCode como herramienta de trabajo.
Fuentes consultadas
- OpenAI, “Structured Outputs”, consultado el 2026-10-02.
- OpenAI Agents SDK, “Guardrails”, consultado el 2026-10-02.
- OpenAI Agents SDK, “Running agents”, consultado el 2026-10-02.
- Microsoft Agent Framework, “Producing Structured Outputs with Agents”, consultado el 2026-10-02.
- Microsoft Agent Framework, “Agent pipeline architecture”, consultado el 2026-10-02.
- Zod, “Handling errors”, consultado el 2026-10-02.
- JSON Schema, “Object”, consultado el 2026-10-02.