Estado, objetivo, evidência e parada
while ao controle de produçãoEnglish summary: A reliable AI agent is not a larger prompt. It is a governed control loop over explicit state, bounded tools, fresh observations, durable checkpoints, retry policies, evidence, and stop conditions. This guide builds the smallest executable loop first, then hardens it with state machines, budgets, deadlines, cancellation, leases, idempotency, human approval, evals, tracing, safety, cost controls, ownership, and reversibility.
Published: July 2026
Reading time: 24 minutes
Keywords: #AIAgents #AgentLoops #LLMEngineering #StateMachines #Evals #Observability #TypeScript
O agente concluiu a tarefa — e o banco ficou com duas cobranças.
Nada “misterioso” aconteceu. A chamada expirou depois de o pagamento ser processado, o loop interpretou silêncio como falha e tentou de novo. O prompt podia ser excelente; o sistema de controle era ruim.
Esta é a tese do guia: um agente confiável não é um prompt que pensa por mais tempo; é uma máquina de estados que transforma objetivo e evidência em ações limitadas, sob orçamento, até uma condição explícita de parada.
Vamos construir primeiro a menor versão que torna essa tese visível. Depois vamos trocar o brinquedo por controles de produção.
Dependências: Node.js 20+ e tsx. Salve como agent-loop.ts:
npm install --save-dev tsx typescript
npx tsx agent-loop.ts
type Phase = 'running' | 'verifying' | 'succeeded' | 'failed' | 'cancelled';
type Action = 'read_spec' | 'apply_patch' | 'run_eval';
type Evidence = {
source: 'tool' | 'eval';
claim: string;
};
type State = {
phase: Phase;
step: number;
toolCalls: number;
facts: string[];
evidence: Evidence[];
completed: Action[];
idempotencyKeys: Set<string>;
deadlineAt: number;
cancelled: boolean;
};
const limits = { maxSteps: 6, maxToolCalls: 3 };
function initialState(): State {
return {
phase: 'running',
step: 0,
toolCalls: 0,
facts: [],
evidence: [],
completed: [],
idempotencyKeys: new Set(),
deadlineAt: Date.now() + 10_000,
cancelled: false,
};
}
function nextAction(state: State): Action | 'stop' {
if (!state.completed.includes('read_spec')) return 'read_spec';
if (!state.completed.includes('apply_patch')) return 'apply_patch';
if (!state.completed.includes('run_eval')) return 'run_eval';
return 'stop';
}
function execute(action: Action): { fact?: string; evidence: Evidence } {
if (action === 'read_spec') {
return {
fact: 'VIP customers receive a 15% discount',
evidence: { source: 'tool', claim: 'spec read before write' },
};
}
if (action === 'apply_patch') {
return {
evidence: { source: 'tool', claim: 'patch applied to discount.ts' },
};
}
return {
evidence: { source: 'eval', claim: 'VIP=15%; regular=0%; regression passed' },
};
}
function run(): State {
let state = initialState();
while (state.phase === 'running' || state.phase === 'verifying') {
if (state.cancelled) return { ...state, phase: 'cancelled' };
if (Date.now() >= state.deadlineAt) return { ...state, phase: 'failed' };
const action = nextAction(state);
if (action === 'stop') {
const passed = state.evidence.some(
(item) => item.source === 'eval' && item.claim.includes('regression passed'),
);
return { ...state, phase: passed ? 'succeeded' : 'failed' };
}
if (state.step >= limits.maxSteps || state.toolCalls >= limits.maxToolCalls) {
return { ...state, phase: 'failed' };
}
const key = `discount-fix:${action}:v1`;
if (state.idempotencyKeys.has(key)) return { ...state, phase: 'failed' };
const result = execute(action);
const keys = new Set(state.idempotencyKeys).add(key);
state = {
...state,
phase: action === 'run_eval' ? 'verifying' : 'running',
step: state.step + 1,
toolCalls: state.toolCalls + 1,
facts: result.fact ? [...state.facts, result.fact] : state.facts,
evidence: [...state.evidence, result.evidence],
completed: [...state.completed, action],
idempotencyKeys: keys,
};
console.log(`step=${state.step} action=${action} phase=${state.phase}`);
}
return state;
}
const finalState = run();
console.log(`final=${finalState.phase} evidence=${finalState.evidence.length}`);
Output esperado:
step=1 action=read_spec phase=running
step=2 action=apply_patch phase=running
step=3 action=run_eval phase=verifying
final=succeeded evidence=3
O exemplo não chama um LLM, não persiste estado e não produz efeito externo. Isso é deliberado. A política nextAction é o lugar que um modelo poderia ocupar; o restante existe para que a decisão do modelo não controle também os limites, a verdade e a parada.
Observe a ordem: ler, alterar, avaliar, parar. A conclusão não nasce da frase “terminei”. Ela nasce de uma transição autorizada por evidência.
Pense menos em “assistente inteligente” e mais em uma torre de controle.
A torre mantém uma visão do estado, recebe observações, autoriza movimentos e impede duas aeronaves de ocuparem o mesmo recurso. Ela trabalha com janelas de tempo, donos, procedimentos de exceção e confirmação. Uma instrução eloquente do piloto não substitui radar, clearance nem separação.
O agente tem o mesmo problema estrutural:
Em uma frase: o modelo decide dentro do loop; ele não é o loop.
Essa separação também explica quando não usar um agente. A Anthropic distingue workflows, cujos caminhos são definidos em código, de agentes, que dirigem dinamicamente o uso de tools. A mesma publicação recomenda começar pela solução mais simples e aceitar mais latência e custo apenas quando a flexibilidade trouxer ganho mensurável (fonte primária).
| Situação | Escolha | Motivo | Evidência mínima antes de promover |
|---|---|---|---|
| Uma resposta resolve a tarefa | Chamada única | Menor custo e superfície de falha | Eval do output |
| A ordem das etapas é conhecida | Workflow | Código controla sequência e exceções | Testes de cada transição |
| O próximo passo depende da observação | Agente | A política precisa escolher dinamicamente | Evals de trajetória e parada |
| Há partes realmente independentes | Orchestrator-workers | Paralelismo pode reduzir ciclo | Síntese final e conflito de escrita medidos |
| A ação é irreversível e pouco frequente | Workflow + aprovação | Autonomia não paga o risco | Auditoria e rollback ensaiado |
Não promova um workflow a agente porque o diagrama parece mais moderno. Promova quando casos reais exigirem escolha dinâmica e os evals mostrarem vantagem sobre o caminho determinístico.
Um loop de produção não deveria aceitar transições implícitas. Modele estados terminais, estados pausáveis e a razão de cada mudança.
| Estado | Pode executar tool? | Como sai | Artefato obrigatório |
|---|---|---|---|
ready | Não | objetivo válido e lease adquirido | contrato versionado |
running | Sim, dentro da policy | observação, deadline, cancelamento ou erro | span + checkpoint |
verifying | Apenas evals | gate aprovado ou falha classificada | relatório do eval |
waiting_human | Não para a ação pendente | aprovação, rejeição ou expiração | pedido de decisão |
succeeded | Não | terminal | evidência de release |
failed | Não | terminal ou novo run explícito | diagnóstico |
cancelled | Não | terminal | confirmação de cancelamento |
cancelled não é uma falha transitória. Não faça fallback, retry ou troca de provedor depois de um cancelamento. waiting_human também não é running: o processo deve persistir, liberar recursos quando possível e retomar do checkpoint correto.
Máquina de estados diz quais transições são possíveis. Invariantes dizem o que precisa continuar verdadeiro antes e depois de cada transição. Para loops que alteram software, use estes nove gates:
| Invariante | Enforcement | Evidência |
|---|---|---|
| Um incremento real de valor | rejeitar iteração sem mudança observável no objetivo | diff, artifact ou estado externo |
| Especificação antes de código | bloquear escrita enquanto a regra-alvo não estiver confirmada | spec/version no checkpoint |
| Eval definido antes | registrar assertions antes da solução candidata | eval versionado inicialmente vermelho |
| Diff cirúrgico | restringir paths, recursos e tamanho de mudança | allowlist + diff |
| Regras do codebase | carregar e validar contratos do repositório e runtime | rule set versionado |
| Quality gate verde | impedir promoção com teste, lint ou validação obrigatória falhando | relatório do gate |
| PR aberta e CI verde | não tratar mudança de software como entregue antes da integração aprovada | PR + checks, quando o fluxo usa PR |
| Aprendizado capturado | transformar erro corrigido em teste, regra ou runbook | artifact de prevenção |
| Automatizar na segunda vez | detectar toil repetido e extrair mecanismo reutilizável | tool, script, skill ou checklist |
Se um invariante falha, a iteração não “quase passou”. Ela volta a running com uma hipótese nova, vai para waiting_human quando falta autoridade ou termina em failed quando não há recuperação segura. O gate aplicável deve ser definido pelo contrato: um loop editorial pode usar revisão e pipeline de publicação onde um loop de código usa PR e CI.
Histórico de chat não é estado operacional. Ele mistura instrução, hipótese, observação, texto irrelevante e possivelmente conteúdo hostil.
Um estado útil separa pelo menos:
| Camada | Guarda | Regra de confiança |
|---|---|---|
| Objetivo | intenção, versão, critérios de sucesso | só muda por evento explícito |
| Fatos | dados confirmados e sua origem | expiram ou são revalidados |
| Hipóteses | explicações ainda não provadas | nunca autorizam side effect sozinhas |
| Plano | próxima ação e dependências | pode ser descartado após nova observação |
| Evidência | tool result, eval, aprovação, artifact hash | imutável e com proveniência |
| Governança | owner, permissões, budget, deadline, policy version | controlada fora do modelo |
| Recuperação | attempts, idempotency keys, checkpoint, lease | durável e reconciliável |
Três regras evitam boa parte da corrupção de estado:
O paper ReAct mostrou o valor de alternar raciocínio, ação e observações do ambiente (paper). Para produção, acrescente proveniência, validade temporal e política: o ambiente também pode estar errado, desatualizado ou comprometido.
“Memória” não deveria ser um bucket único.
Antes de inserir memória no contexto, pergunte: quem escreveu, quando, para qual objetivo, com qual confiança e se ainda vale. Antes de persistir, aplique minimização e redaction. O guia de human-in-the-loop do OpenAI Agents SDK documenta serialização e retomada de RunState, e alerta que contexto serializado deve ser tratado como dado persistido, inclusive quanto a segredos (documentação).
O modelo não deveria adivinhar semântica operacional. Toda tool com side effect precisa declarar:
Uma tool chamada refund é ambígua. create_refund_request com output pending_approval informa intenção, limite e próximo estado.
{
"name": "create_refund_request",
"owner": "payments-platform",
"sideEffect": "write_pending_request",
"reversible": true,
"requiresApproval": true,
"timeoutMs": 30000,
"retryOn": ["timeout_before_ack", "rate_limited"],
"neverRetryOn": ["validation_error", "permission_denied"],
"idempotencyScope": "tenant:order:intent-version",
"output": {
"requestId": "string",
"status": "pending_approval",
"evidenceRef": "string"
}
}
A descrição negativa é parte do contrato: “cria solicitação pendente; não movimenta dinheiro”. Guardrails determinísticos devem validar o contrato antes e depois da execução.
Não trate todos como maxSteps.
| Controle | Pergunta respondida | Comportamento ao disparar |
|---|---|---|
| Budget de passos | Quantas decisões ainda são permitidas? | verificar ou fazer handoff |
| Budget de tools | Quantos efeitos/observações ainda cabem? | escolher a verificação de maior valor |
| Budget de tokens | Quanto contexto e inferência podemos consumir? | compactar ou encerrar com diagnóstico |
| Budget de custo | Quanto este run pode gastar? | bloquear nova chamada antes do teto |
| Deadline | Até quando o resultado ainda tem valor? | cancelar trabalho descendente e reconciliar |
| Timeout | Quanto uma operação individual pode durar? | classificar o resultado como desconhecido, não automaticamente falho |
| Cancellation | O solicitante revogou a intenção? | parar sem fallback e propagar o sinal |
Um timeout é especialmente perigoso: ele diz que o caller não recebeu confirmação, não que o efeito não ocorreu. Antes de repetir, consulte por idempotency key ou reconcilie o estado externo.
Retry sem hipótese apenas repete o acidente. A AWS documenta timeouts, retries, backoff com jitter e a necessidade de tornar retries seguros com APIs idempotentes; a Stripe documenta idempotency keys para evitar a duplicação de operações em tentativas repetidas (AWS, AWS sobre APIs idempotentes, Stripe).
| Classe observada | Retry? | Antes da próxima tentativa | Saída se persistir |
|---|---|---|---|
| Rate limit explícito | Sim, com teto e jitter | respeitar Retry-After; consumir budget | failed ou fila posterior |
| Timeout antes de confirmação | Só se idempotente | reconciliar pelo request ID | waiting_human se efeito for incerto |
| 5xx transitório | Talvez | confirmar contrato e blast radius | circuit breaker/failed |
| Input inválido | Não | corrigir a partir do schema | failed se não houver dado |
| Permissão negada | Não | pedir autorização ou trocar escopo | waiting_human |
| Policy/guardrail | Não | registrar bloqueio | failed ou waiting_human |
| Cancelamento | Nunca | propagar cancel signal | cancelled |
Backoff controla pressão; idempotência controla duplicação; reconciliação resolve resultado desconhecido. São três mecanismos diferentes.
Quando workers podem retomar ou disputar a mesma tarefa, uma chave idempotente por tool não basta. Você também precisa saber quem tem autoridade para avançar o estado.
Uma lease deve carregar runId, ownerId, versão/fencing token, acquiredAt, expiresAt e regra de renovação. Cada escrita compara o fencing token atual. Worker com lease expirada pode terminar uma computação, mas não pode publicar o resultado.
Kubernetes usa objetos Lease para coordenação, heartbeats e leader election (documentação oficial). O padrão é útil como referência, mas a implementação do seu agente ainda precisa definir relógio, consistência, renovação, expiração e fencing.
Ownership também precisa existir no plano organizacional:
| Responsabilidade | Owner | Evidência |
|---|---|---|
| Política de decisão | Equipe de produto/agent | versão + changelog |
| Contratos de tools | Equipe dona do domínio | schema + testes de contrato |
| Permissões | Segurança/plataforma | policy-as-code + auditoria |
| Evals e thresholds | Produto + engenharia | dataset versionado + relatório |
| Operação e incidentes | On-call definido | runbook + alertas |
| Aprovação de alto risco | Papel de negócio nomeado | approval event imutável |
“O agente decidiu” não é uma linha aceitável de ownership.
Checkpoint seguro acontece depois de uma transição confirmada, não no meio de um side effect desconhecido. Persista:
Ao retomar, valide compatibilidade. Uma aprovação concedida para tool:v2 não autoriza silenciosamente tool:v3. A documentação atual do OpenAI Agents SDK descreve RunState serializável para pause/resume e recomenda versionar tarefas pendentes quando definições de agent, tools ou SDK podem mudar (fonte primária).
Pare antes da ação sensível. O pedido de aprovação deve conter:
approve, reject e modify;O OpenAI Agents SDK documenta um fluxo em que tools marcadas para aprovação interrompem o run, o estado é serializado, uma pessoa aprova ou rejeita a chamada específica e o run retoma (documentação). O princípio é mais importante que o SDK: aprovação precisa ser vinculada à intenção, aos argumentos e à versão, não a um “sim” genérico.
Ordene ações por risco:
Nem todo efeito tem rollback verdadeiro. Um email enviado não pode ser “desenviado”; um segredo exposto não volta a ser secreto. Nesses casos, reduza blast radius antes da ação e trate compensação como mitigação, não viagem no tempo.
Sintoma: o agente afirma “concluído”, mas não há eval ou mudança verificável.
Causa: texto final foi aceito como condição de parada.
Diagnóstico: trace termina em output do modelo; não existe verifying → succeeded.
Correção: só o controlador promove succeeded, com assertions sobre evidência.
Artefato preventivo: eval que falha quando sucesso não tem evidenceRef.
Sintoma: dois tickets, cobranças, posts ou patches após timeout.
Causa: retry de escrita sem chave de intenção e sem reconciliação.
Diagnóstico: duas chamadas equivalentes, request IDs diferentes, resultado inicial desconhecido.
Correção: idempotency key estável, lookup por intenção e retry apenas para classe permitida.
Artefato preventivo: teste de contrato que envia a mesma intenção duas vezes e exige um único efeito.
Sintoma: estado oscila, artifacts se sobrescrevem ou duas ações incompatíveis passam.
Causa: retomada concorrente sem lease/fencing.
Diagnóstico: spans sobrepostos para o mesmo runId, ambos com escrita aceita.
Correção: lease com expiração e fencing token validado em toda mutação.
Artefato preventivo: teste de split-brain em que o worker atrasado perde permissão de commit.
Sintoma: usuário cancela, mas uma tool termina e o agente publica mesmo assim.
Causa: cancelamento não propagado; checkpoint retomado sem revalidar intenção e deadline.
Diagnóstico: cancelledAt anterior ao side effect, sem guardrail na saída.
Correção: cancellation token descendente, verificação antes do commit e estado terminal monotônico.
Artefato preventivo: teste que cancela entre execução e commit e exige zero publicação.
As quatro falhas têm a mesma raiz: o modelo recebeu autoridade que pertencia ao controlador.
Este YAML não depende de framework. Salve como agent-loop-contract.yaml e adapte owners, limites e tools:
apiVersion: agents.example/v1
kind: AgentLoopContract
metadata:
name: discount-policy-fix
owner: checkout-platform
spec:
goal:
version: 3
statement: Fix the VIP discount rule without regressions.
successCriteria:
- spec_read_before_write
- targeted_patch_only
- deterministic_eval_passed
- release_evidence_emitted
stateMachine:
initial: ready
terminal: [succeeded, failed, cancelled]
pausable: [waiting_human]
budgets:
maxSteps: 12
maxToolCalls: 8
maxTokens: 50000
maxCostUsd: 2.00
deadlineSeconds: 300
cancellation:
propagateToTools: true
retryAfterCancel: false
verifyBeforeCommit: true
concurrency:
leaseSeconds: 30
renewEverySeconds: 10
fencingRequired: true
checkpoint:
afterEveryTransition: true
include: [phase, evidence, budgets, attempts, idempotencyKeys, approvals]
requireCompatiblePolicyVersion: true
retry:
maxAttemptsPerAction: 3
backoff: exponential_with_full_jitter
retryOn: [rate_limited, transient_5xx]
neverRetryOn: [validation_error, permission_denied, policy_block, cancelled]
tools:
allow: [read_spec, apply_patch, run_eval]
sideEffectsRequireIdempotency: true
productionWritesRequireApproval: true
safety:
sandboxByDefault: true
redactSecretsFromTrace: true
preferReversibleActions: true
observability:
traceFields: [runId, state, action, tool, attempt, latencyMs, costUsd, evidenceRef]
releaseEvidenceRequired: true
evals:
trajectory: [spec_before_patch, no_action_after_cancel, stop_after_success]
outcome: [discount_policy_passes, regression_suite_passes]
O arquivo só vira governança se runtime e CI rejeitarem violações. Configuração que ninguém aplica é documentação aspiracional.
Um eval de output pergunta “a resposta está correta?”. Um eval de agente também pergunta “como chegamos aqui?”. A Anthropic descreve tasks, trials, graders e a necessidade de avaliar sistemas multi-turn que usam tools e modificam ambientes (fonte primária).
Construa a suíte em quatro camadas:
| Camada | O que testa | Exemplo de falha |
|---|---|---|
| Outcome | estado externo desejado | desconto incorreto |
| Trajectory | ordem e escolha de ações | patch antes da spec |
| Control | budgets, cancel, lease, approval | publicação após cancelamento |
| Robustness | variação e falhas injetadas | timeout duplica efeito |
Rode múltiplos trials quando a política usa modelo, mas mantenha assertions determinísticas para invariantes. Métricas úteis incluem task success, ações proibidas, retries por classe, tempo até parada, custo por sucesso, handoffs corretos e taxa de reconciliação de resultados desconhecidos.
Não otimize apenas pass rate. Um agente que passa mais vezes porque ignora aprovação está pior.
Um trace útil permite responder:
OpenTelemetry define traces como caminhos de execução compostos por spans com timestamps, atributos, eventos, links e status (documentação). O guia do OpenAI Agents SDK expõe configuração de tracing e controle sobre a inclusão de dados sensíveis (documentação). Use ambos como referência, mas defina uma taxonomia própria para run, decision, tool, eval, approval e checkpoint.
Observabilidade não significa guardar prompt e output brutos para sempre. Redija segredos, tokenize identificadores quando possível, separe acesso operacional de acesso analítico e defina retenção.
Guardrails do modelo ajudam em decisões semânticas; não substituem controles determinísticos.
O SDK de Agents da OpenAI documenta guardrails de input, output e tool, incluindo tripwires que interrompem a execução (documentação). A regra arquitetural é simples: guardrail precisa alterar o fluxo, não apenas acrescentar um aviso ao prompt.
Tokens são só uma parte. O custo de um run inclui inferência, tools pagas, compute de sandbox, armazenamento, tracing, revisão humana, retries e incidentes.
Acompanhe pelo menos:
Compare com o baseline mais simples. Um agente só vence quando melhora resultado líquido sob as mesmas restrições de risco, não quando gera mais atividade.
| No exemplo | Em produção |
|---|---|
| Estado em memória | Event log + checkpoint versionado |
| Um processo | Lease, fencing e retomada concorrente |
| Política fixa | Modelo com output estruturado + policy determinística |
| Tools simuladas | Registry, schema, permissões, timeout e cancelamento |
Set de idempotência local | Store durável + reconciliação externa |
| Um deadline | Deadline propagado a cada dependência |
| Eval único | Suite de outcome, trajetória, controle e robustez |
console.log | Traces, métricas, logs redigidos e alertas |
| Sem side effect real | Aprovação, reversibilidade e resposta a incidente |
| Owner implícito | Donos nomeados por policy, tool, eval e operação |
O loop mínimo ensina a separação. A versão de produção precisa demonstrar, em testes e operação, que essa separação sobrevive a processo morto, rede ambígua, concorrência, custo, erro humano e mudança de versão.
run_eval falhar uma vez com rate_limited. Implemente retry com full jitter, teto de três tentativas e consumo de budget.apply_patch e retome sem aplicar o patch duas vezes.runId. Implemente lease com fencing e prove que o worker atrasado não consegue publicar.apply_patch em ação de produção que exige aprovação vinculada ao hash do diff. Altere o diff e prove que a aprovação antiga perde validade.Você aprendeu quando consegue explicar e testar não apenas o que o agente fez, mas quem autorizou, com qual estado, sob quais limites, com qual evidência e por que ele parou.
Considere o loop pronto para um piloto limitado somente quando:
Esses critérios não provam segurança absoluta. Eles provam algo mais útil: que o loop tem contratos falsificáveis e falha de maneira observável.
O menor agente é um ciclo: observar, orientar, decidir, agir, verificar e parar. O agente de produção é esse mesmo ciclo cercado por estado durável, tools estreitas, memória com proveniência, budgets, deadlines, cancelamento, leases, checkpoints, retries idempotentes, aprovação, evals, tracing, safety e owners.
Comece pelo while. Depois retire do modelo tudo que não deveria depender de linguagem: autoridade, limites, transições, contabilidade e definição de sucesso.
Autonomia útil não é liberdade para continuar. É capacidade de avançar dentro de um contrato — e parar com evidência.

AI Developer
Engenheiro apaixonado por Inteligência Artificial aplicada a produtos reais. Conecto avanços em LLMs e modelos de linguagem com resultados práticos de negócio. Também mentoro desenvolvedores e criadores em programas ao vivo, podcasts e iniciativas de comunidade focadas em tecnologia inclusiva.
Produtos gratuitos e pagos para transformar ideias em uma base que você consegue executar.
13 produtos disponíveisContinue explorando tópicos similares
Descubra como o AI Starter Kit automatiza a criação de agentes de IA para o seu projeto. Configure Claude Code, Gemini e Codex em 5 minutos com skills, hooks e MCP.
# Por Que Seus Agentes de IA Continuam Falhando (E Como Consertar) Você gastou 3 meses construindo agentes de IA. Funcionaram lindamente nas demos. Em produção, são um desastre. A
--- title: "Introdução ao LLMOps: O Ciclo de Vida de Aplicações de LLM em Produção" subtitle: "Como orquestrar modelos de fundação com gateway, roteamento, cache, guardrails e eval
Checklist de 47 pontos para encontrar bugs, riscos de segurança e problemas de performance antes do lançamento.
Templates testados em produção, usados por desenvolvedores. Economize semanas de setup no seu próximo projeto.