O agente devolveu um objeto JSON bem formado. O código aceitou o resultado e gravou uma alteração. Só depois alguém percebeu que o identificador apontava para outro cliente, a versão da fonte estava antiga ou a operação não fazia parte da autoridade daquele agente.
JSON válido não é dado confiável. Para validar a saída de um agente de IA antes de salvar, trate o resultado como uma proposta não confiável e passe por quatro fronteiras: formato, significado, autoridade e efeito confirmado. Um schema resolve a primeira. As outras dependem do seu código e dos sistemas que controlam o estado real.
Este artigo é um spoke do guia sobre como testar a trajetória de um agente de IA. A trajetória verifica o caminho da execução. Aqui, a pergunta é mais estreita: a saída final pode atravessar a fronteira que grava ou dispara uma ação?

Resposta curta
- Valide a forma recebida, mesmo quando o provedor oferece structured outputs.
- Confira identidade, evidência, versão e regras de negócio contra o estado atual.
- Faça autorização e aprovação no runtime, não no texto que o modelo gerou.
- Grave uma proposta ou uma operação idempotente e leia o destino de volta antes de declarar sucesso.
Isso continua a validação de argumentos e respostas de tool em TypeScript, mas muda o ponto de decisão: aqui a saída já atravessou a execução e está prestes a virar estado persistente.
O que a saída estruturada realmente garante?
A saída estruturada garante, quando o provedor e o schema são compatíveis, que o programa recebe uma forma mais previsível. Ela não garante que os valores descrevem o mundo corretamente, que o agente escolheu o registro certo ou que uma escrita externa aconteceu.
A documentação do OpenAI Node SDK sobre Structured Outputs, consultada em 2026-10-02, mostra como obter uma saída analisada com Zod. A documentação também deixa claro que uma resposta incompleta pode não ter saída analisada. Esse detalhe muda o contrato: ausência de valor, recusa, timeout e objeto inválido são estados diferentes de um resultado aceito.
O Microsoft Agent Framework sobre structured outputs, consultado em 2026-10-02, apresenta modelos tipados e mapas JSON como formatos de resposta. O recurso ajuda a transportar campos previsíveis entre componentes. Não substitui as verificações que só a aplicação consegue fazer, como consultar se um cliente pertence à conta atual ou se uma mudança ainda está autorizada.
Portanto, a fronteira correta não é “o modelo retornou JSON”. É esta:
saída do agente
-> formato
-> significado
-> autoridade
-> proposta ou escrita segura
-> leitura de confirmação
O JSON Schema sobre propriedades obrigatórias e extras, consultado em 2026-10-02, mostra por que required e additionalProperties representam decisões diferentes. Mesmo um objeto que passa por essas regras ainda pode conter um valor antigo ou uma referência que não pertence ao usuário atual.
Como separar formato de significado?
Formato responde se o objeto tem campos, tipos e valores estruturais aceitáveis. Significado responde se esses valores fazem sentido para o estado que a aplicação controla. Misturar os dois costuma produzir um schema enorme, um prompt confuso ou uma falsa sensação de segurança.
Considere uma saída de classificação que propõe atualizar um 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>;
O schema verifica que existe um orderId, que newStatus pertence ao conjunto permitido e que há pelo menos uma referência de evidência. Ele não verifica se o pedido pertence à conta, se a versão da fonte continua atual ou se o agente pode alterar aquele status.
O Zod explica que safeParse devolve uma união discriminada, consultado em 2026-10-02. Esse formato é útil no runtime porque o fluxo consegue separar result.success de result.error sem transformar toda falha de validação em uma exceção genérica.
Uma checagem de significado pode ser pequena e determinística:
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 };
}
Esse código é ilustrativo. Ele mostra a divisão entre o parse e a consulta ao estado atual, mas não conhece o seu banco, sua política de concorrência ou seus requisitos de aprovação. A função deve ser testada na fronteira real quando uma decisão puder produzir um efeito externo.
Onde deve ficar a autorização?
A autorização precisa ficar depois da validação do formato e do significado, mas antes da escrita. O agente pode propor approved; ele não deve conseguir transformar esse campo em permissão apenas repetindo a palavra no JSON.
O guia de guardrails do OpenAI Agents SDK, consultado em 2026-10-02, separa guardrails de entrada, saída e ferramenta. Essa separação é importante em fluxos com handoffs: um guardrail de saída não é automaticamente uma checagem de cada ferramenta usada por agentes intermediários.
Uma decisão de autoridade pode depender de identidade, escopo, risco e aprovação 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" };
}
Não trate esse exemplo como uma política pronta. A aplicação precisa buscar a identidade em uma fonte confiável, aplicar o escopo correto e registrar a decisão. O modelo pode sugerir uma justificativa. A justificativa não substitui a regra que permite ou bloqueia a operação.
Se o resultado for entregue a outro agente, o pacote também precisa ser validado pelo receptor. O artigo sobre handoff entre agentes com contexto estruturado trata dessa mudança de responsabilidade. Aqui, o ponto é que a autorização continua sendo uma decisão do runtime, mesmo quando o valor veio de uma etapa anterior.
Quando a saída deve virar uma proposta?
Use uma proposta quando a saída ainda precisa de revisão, quando a operação é difícil de desfazer ou quando o agente não deveria escrever diretamente no destino. A proposta deve guardar o valor validado, as referências que sustentam a decisão, a versão da regra e um identificador estável para a tentativa.
O fluxo pode ser modelado assim:
agent_output
-> rejected: invalid_shape
-> rejected: invalid_meaning
-> needs_review: authority_or_risk
-> staged: proposal_created
-> applied: operation_accepted
-> verified: destination_read_back
O estado staged evita que a interface confunda uma intenção com uma mudança realizada. Também facilita mostrar a uma pessoa exatamente o que será alterado. Uma aprovação deve apontar para o proposalId e para um hash do conteúdo relevante, não apenas para o nome da ferramenta.
O guia de execução de agentes do OpenAI, consultado em 2026-10-02, documenta o erro de saída final inválida e o uso de um fallback validado sem repetir chamadas de ferramenta. O padrão é útil: quando a falha está na saída final, não transforme automaticamente a recuperação em uma nova execução com possíveis efeitos duplicados.
Não tenho um banco de produção ou um agente real por trás desta fixture. A escolha por uma etapa de staging é uma recomendação de desenho baseada nas fronteiras verificáveis acima. Em um sistema real, o time precisa decidir quais tipos de proposta exigem aprovação e qual estado externo pode ser lido de volta.
Como evitar uma escrita duplicada?
Uma validação bem feita pode aprovar uma operação que falha no transporte, termina depois do timeout ou é repetida por um worker. O controle de repetição precisa existir na operação de escrita, não apenas no prompt.
Use um identificador idempotente derivado da intenção estável da operação, do destino e da versão da proposta. A mesma tentativa lógica deve encontrar o mesmo registro de operação. Uma proposta que mudou de conteúdo deve ganhar outro identificador, mesmo que use o mesmo pedido.
O artigo sobre testar a idempotência de uma API sem duplicar efeitos cobre a fronteira de uma operação repetível. Para agentes, a regra é a mesma: um retry do modelo não prova que o primeiro write não aconteceu. Antes de repetir, consulte o registro da operação ou o destino externo.
Os estados precisam distinguir pelo menos:
| Estado | O que significa | Próximo passo seguro |
|---|---|---|
rejected |
O objeto ou a decisão não passou por uma regra | corrigir a entrada ou pedir revisão |
staged |
A proposta existe, mas não foi aplicada | aprovar ou descartar |
applied |
O executor aceitou a operação | verificar o destino |
unknown |
O processo não sabe se o efeito ocorreu | consultar o destino antes de repetir |
verified |
A leitura do destino confirma o resultado esperado | liberar a etapa seguinte |
unknown não é sinônimo de failed. Um timeout depois do envio pode esconder um efeito já aplicado. O Microsoft Agent Framework sobre sua arquitetura de pipeline, consultado em 2026-10-02, descreve camadas de middleware e gates de persistência que impedem liberar ou armazenar uma saída antes do veredito aplicável. A implementação varia, mas a fronteira continua sendo útil.
Quais casos devem entrar no teste?
Teste valores que parecem aceitáveis, não somente JSON quebrado. A falha perigosa é a que passa pelo parser e chega perto da escrita com uma referência errada, uma versão antiga ou uma permissão que o agente não possui.
Uma matriz mínima inclui:
- objeto válido, conta correta, evidência atual e operação permitida;
- campo obrigatório ausente, enum inválido e propriedade extra inesperada;
orderIdexistente, mas pertencente a outra conta;- evidência com versão antiga ou referência inexistente;
- saída recusada pelo modelo, resposta incompleta e timeout antes do objeto;
- falha de transporte antes do write e timeout depois do write;
- retry da mesma
proposalIde retry com conteúdo alterado; - destino que responde sucesso, mas não confirma a mudança na leitura posterior.
O teste deve afirmar mais que “a função retornou um objeto”. Confira se a escrita não começou quando o formato falhou, se o estado não mudou quando a autoridade foi negada e se o retry consultou o destino em um resultado unknown.
Esse recorte complementa validar JSON externo antes de usar em TypeScript. O post anterior ensina a tratar dados externos como unknown. A saída de um agente tem o mesmo problema, mas acrescenta evidência, autoridade e risco de efeito.
O que a validação não consegue provar?
Validação de schema não prova verdade factual. Ela pode confirmar que customerId é uma string, mas não que o cliente existe. Uma checagem de significado pode confirmar que o registro existe, mas não que a regra de negócio foi interpretada corretamente. Uma autorização pode permitir uma operação, mas não garantir que o banco aplicou a mudança.
Também não use um score de confiança produzido pelo próprio agente como prova independente. Ele pode ser útil para encaminhar casos à revisão, mas não substitui uma consulta à fonte ou uma regra determinística. Quando a aplicação depende de evidência, guarde a referência e confira o conteúdo no sistema que é dono daquele dado.
Não confunda o resultado do agente com o log que registra o que aconteceu. O log de auditoria de um agente de IA deve ser escrito pelo runtime ou pelo executor que observa a decisão e o efeito. A saída validada é uma entrada da decisão, não a prova final da execução.
Perguntas frequentes
Structured output elimina a necessidade de validação?
Não. Structured output reduz falhas de forma e oferece campos que o programa pode ler. A aplicação ainda precisa verificar identidade, estado atual, evidência, autoridade e efeito. Um objeto que passa pelo schema pode conter o cliente errado ou uma informação antiga.
Devo salvar a saída bruta do agente?
Depende da política de dados e do motivo de retenção. Para operar com segurança, guarde o resultado validado, referências de evidência, versões, decisões e IDs de correlação. Preserve a saída bruta somente quando houver uma finalidade definida, controle de acesso e uma regra de retenção compatível.
Posso tentar de novo quando o schema falhar?
Às vezes. Um retry limitado pode corrigir uma falha de formato antes de qualquer efeito externo. Não repita uma operação apenas porque a confirmação demorou. Classifique a falha, preserve a proposta original e consulte o destino quando houver possibilidade de que a primeira tentativa tenha sido aplicada.
A validação pode ficar dentro do prompt?
Não como único controle. O prompt pode explicar o contrato ao agente, mas o runtime deve validar o valor recebido, aplicar a política e bloquear a escrita quando a regra falhar. O modelo não deve ser a autoridade que decide se a própria saída é confiável.
Conclusão
Antes de salvar a saída de um agente, faça quatro perguntas: o objeto tem a forma esperada, os valores descrevem o estado atual, a operação está autorizada e o destino confirmou o efeito? Um schema resolve apenas a primeira parte.
Comece com um resultado discriminado para rejected, staged, applied, unknown e verified. Mantenha a proposta separada da escrita. Use IDs idempotentes para retries. Leia o sistema externo de volta antes de declarar sucesso. Essa estrutura deixa o agente mais fácil de testar e reduz a distância entre uma resposta convincente e uma mudança realmente confirmada.
Como esta análise foi feita
Samuel Fajreldines é o autor responsável por este artigo. A pesquisa comparou a documentação atual do OpenAI Agents SDK, OpenAI Node SDK, Microsoft Agent Framework, Zod e JSON Schema, além de discussões públicas recentes sobre verificação de agentes. O contrato TypeScript é ilustrativo e não foi executado contra um provedor, banco ou agente de produção. A assistência de IA apoiou a organização da pesquisa, a redação, a geração da imagem e a localização; não forneceu experiência de produção nem substituiu a verificação das fontes. O autor também mantém o RemoteCode como ferramenta de trabalho.
Fontes consultadas
- OpenAI, “Structured Outputs”, consultado em 2026-10-02.
- OpenAI Agents SDK, “Guardrails”, consultado em 2026-10-02.
- OpenAI Agents SDK, “Running agents”, consultado em 2026-10-02.
- Microsoft Agent Framework, “Producing Structured Outputs with Agents”, consultado em 2026-10-02.
- Microsoft Agent Framework, “Agent pipeline architecture”, consultado em 2026-10-02.
- Zod, “Handling errors”, consultado em 2026-10-02.
- JSON Schema, “Object”, consultado em 2026-10-02.