Harness básico
Um agent harness é o sistema que permite ao modelo trabalhar com ferramentas, estado, limites e verificação. O modelo propõe decisões; o harness controla o ciclo que executa e registra o trabalho. Nesta semana você verá por que um agente útil precisa de muito mais que uma chamada de geração.
O caso é uma rotina que prepara um relatório de importação e pede aprovação antes de publicar. Ela pode falhar no meio, reiniciar e receber respostas externas. Vamos organizar estados e artefatos para recuperar o trabalho sem repetir efeitos ou confundir tentativa com conclusão.
JavaScriptAgentesAutomaçãoAo terminar esta aula
- Harness controla capacidades, estado e parada.
- Artefatos verificáveis sustentam continuidade.
- Recovery precisa reconciliar efeitos, não apenas repetir passos.
Antes de continuar: Laboratório: Spec-Driven Development
Harness e ciclo de execução
AutomaçãoO harness coordena entrada, contexto, geração, ferramentas, observações e parada. Define capacidades disponíveis, limites de passos e critérios de conclusão. Workflows fixam parte da sequência; agentes podem escolher próximos passos dentro das fronteiras. A escolha depende da tarefa. Preparar e publicar um relatório possui etapas claras e pode começar com workflow simples, usando modelo apenas onde linguagem ou decisão variável ajudam. Não aumente autonomia sem necessidade demonstrada.
↗ Effective harnesses for long-running agents↗ Building effective agents
Um ciclo útil registra estado antes e depois de cada etapa. O modelo pode sugerir publicar, mas o controlador verifica artefato, permissão e aprovação. Condições de parada incluem conclusão, falha recuperável, limite excedido e bloqueio que exige intervenção. Sem essas condições, o sistema pode insistir indefinidamente. A documentação de harnesses destaca continuidade e artefatos verificáveis para trabalho longo; adapte esses princípios ao seu caso sem assumir que um relato de engenharia garante desempenho no seu ambiente.
↗ Effective harnesses for long-running agents↗ Building effective agents
Sandbox, tools e aprovação humana
FundamentosSandbox restringe recursos conforme o ambiente, como filesystem e rede. Tool permissions limitam operações autorizadas. Human approval é uma decisão explícita em pontos relevantes, como publicação externa, e não deve ser simulada por uma mensagem do modelo dizendo “aprovado”. A aprovação precisa vir de ator autorizado e estar vinculada ao artefato e à ação. Se o conteúdo muda depois, a aprovação antiga pode deixar de ser válida.
↗ Sandbox↗ Permission profiles↗ LangGraph Interrupts↗ Configure permissions
Para o relatório, leitura e preparação local podem ser automáticas, enquanto publicar exige o gate definido pelo produto. O contexto não deve conter credenciais desnecessárias. Uma ferramenta ampla de terminal merece análise de seus efeitos, pois scripts podem acessar recursos além do aparente. As políticas variam por produto; documente o que está efetivamente bloqueado. Instruções textuais ajudam a orientar, mas o harness deve impedir execução fora do escopo mesmo quando o modelo propõe argumentos inadequados.
↗ Sandbox↗ Permission profiles↗ LangGraph Interrupts↗ Configure permissions
Estado e artifacts sustentam continuidade
FundamentosState registra o ponto atual do processo, dados necessários e decisões observadas. Artifacts são resultados concretos, como relatório, diff ou arquivo de teste. Separe os dois: um estado dizendo relatório pronto não substitui o arquivo validado. A persistência permite retomar uma execução, mas precisa de identificadores, versão de schema e política de atualização. Se o processo reinicia, o harness deve descobrir o que realmente existe, não confiar em uma narrativa de memória.
↗ LangGraph Persistence↗ Cursor Agent overview↗ Effective context engineering for AI agents↗ LangGraph Memory
Checkpoint captura um ponto de recuperação segundo a ferramenta. Pode representar estado conversacional, execução de grafo ou alterações locais; não são garantias equivalentes. Para retomar publicação, preserve hash ou versão do relatório, status de validação e intenção de publicação. Compactação do contexto mantém um resumo útil, mas referências ao artefato original permitem verificar detalhes. Como na semana de contexto, pendências devem ficar separadas de ações concluídas. Uma nota compactada que mistura as duas pode provocar repetição ou omissão de trabalho.
↗ LangGraph Persistence↗ Cursor Agent overview↗ Effective context engineering for AI agents↗ LangGraph Memory
Recovery, timeouts e retries
FundamentosRecovery reconcilia estado persistido com efeitos observados. Se a geração falhou antes de produzir relatório, pode ser refeita dentro do orçamento. Se publicar terminou com resposta perdida, o efeito pode já existir e precisa de consulta ou idempotência. Retome a distinção da semana de APIs: timeout não prova ausência de ação. O harness define quais etapas são seguras para repetir e quais exigem confirmação de estado.
↗ OpenAI Python API library↗ Rate limits↗ Making retries safe with idempotent APIs↗ LangGraph Persistence
Use orçamento total, limite de tentativas e cancelamento. SDKs podem realizar retries próprios, portanto a política deve considerar todas as camadas. Um checkpoint desatualizado não deve apagar um efeito confirmado depois dele. Antes de retomar, compare artefatos e registros de intenção. O relatório de recuperação indica o que foi repetido, reutilizado e verificado. Isso torna falhas auditáveis e evita um comportamento aparentemente resiliente que na verdade multiplica custo ou publicação.
↗ OpenAI Python API library↗ Rate limits↗ Making retries safe with idempotent APIs↗ LangGraph Persistence
Gates determinísticos e tracing
FundamentosGates verificam condições antes de avançar: schema válido, teste aprovado, artefato presente e autorização vigente. Verificações determinísticas são especialmente úteis para formato e invariantes. O modelo pode ajudar a interpretar uma falha, mas não deve redefinir um teste reprovado como sucesso. Para publicação, confira que a aprovação corresponde à versão do relatório e que o canal autorizado é o pretendido.
↗ LangSmith Observability↗ Playwright Best Practices↗ OpenAPI Specification 3.1.1↗ Effective harnesses for long-running agents
Tracing relaciona etapas da execução com identificadores, duração e estado. Ele permite entender onde o tempo foi gasto e qual ferramenta produziu um resultado. Não grave raciocínio privado nem dados sensíveis desnecessários. Preserve ações e observações relevantes. A avaliação do harness inclui falhas no meio, limites e recuperação, além do caminho feliz. Um agente que conclui a primeira execução pode ainda falhar ao retomar. O desenho é aceito quando estados, efeitos e evidências continuam coerentes nas transições difíceis.
↗ LangSmith Observability↗ Playwright Best Practices↗ OpenAPI Specification 3.1.1↗ Effective harnesses for long-running agents
Exemplo comentado e limites
FundamentosO gate rejeita aprovação de outra versão e impede repetição já confirmada. Ele não publica nem implementa persistência: verifica uma política local sobre estados fictícios. A aplicação real precisa obter a aprovação de um ator autorizado e armazenar efeitos de forma recuperável.
function podePublicar(estado) {
return estado.relatorioExiste && estado.validado &&
estado.aprovacaoVersao === estado.versao && !estado.publicado;
}
const estado = {versao:2,relatorioExiste:true,validado:true,
aprovacaoVersao:1,publicado:false};
console.log("aprovação antiga",podePublicar(estado));
estado.aprovacaoVersao=2;
console.log("aprovação vigente",podePublicar(estado));
estado.publicado=true;
console.log("repetição",podePublicar(estado));Alterar a versão do relatório invalida a associação anterior. Essa regra evita aprovar um conteúdo e publicar outro. O campo publicado só pode ser marcado a partir de evidência do efeito; uma intenção gerada não basta. Em caso de resposta perdida, use estado desconhecido e reconciliação, não um booleano arbitrário.
Exercício aplicado
Prepare um relatório, valide, aprove sua versão e publique uma vez; reinicie antes da publicação sem perder a aprovação correta.
- Tente desenhar transições e capacidades.
- Implemente gate vinculado à versão.
- Simule reinício e resultado desconhecido.
- Avalie falhas com tracing e orçamento.
Abrir resolução comentada
O programa cria arquivos reais de estado, relatório e ledger em um diretório temporário. preparar escreve um artefato versionado e invalida a validação anterior. validar vincula seu resultado à versão. aprovar exige o ator fictício autorizado e a versão atual; publicar verifica ambos os gates. Os asserts rejeitam aprovação antiga e tentativa de publicar após modificar o relatório.
O checkpoint JSON é lido por um processo Node novo e depois carregado em outro harness. A publicação simulada grava seu recibo no ledger e perde a resposta antes de confirmar no checkpoint. O estado persistido passa a desconhecido. Após retomada, reconciliar consulta o ledger pela intenção execução:versão e confirma o único efeito. Um replay devolve o recibo existente e não cria outra publicação.
chamar usa um catálogo fechado, verifica timeout global e limite de passos e grava tracing de sucesso ou falha. O teste rejeita terminal fora do catálogo, orçamento esgotado e chamada após o prazo. O relógio é injetado em unidades didáticas para testar a fronteira sem esperar. O exemplo deixa seus arquivos temporários disponíveis para inspeção; o caminho aparece na saída.
A aprovação aqui é uma simulação explícita de ator, e o ledger representa um serviço local, não publicação externa. Os arquivos não oferecem atomicidade entre processos concorrentes ou durabilidade transacional distribuída. Na integração real, substitua o ledger por consulta e idempotência documentadas do serviço, autentique o ator, use relógio apropriado e grave checkpoints com garantias do armazenamento escolhido. A recuperação e os gates locais estão implementados e exercitados, enquanto essas garantias externas permanecem declaradas.
import assert from "node:assert/strict";
import {mkdtempSync,readFileSync,writeFileSync,existsSync} from "node:fs";
import {tmpdir} from "node:os";
import {join} from "node:path";
import {spawnSync} from "node:child_process";
const pasta=mkdtempSync(join(tmpdir(),"curso-harness-"));
const estadoArquivo=join(pasta,"estado.json");
const artefatoArquivo=join(pasta,"relatorio.json");
const efeitosArquivo=join(pasta,"publicacoes.json");
writeFileSync(efeitosArquivo,"[]");
const salvar=(arquivo,objeto)=>writeFileSync(arquivo,JSON.stringify(objeto,null,2));
const ler=arquivo=>JSON.parse(readFileSync(arquivo,"utf8"));
function falhar(codigo){throw new Error(codigo);}
let inicial={execucaoId:"e1",versao:0,validadoVersao:null,aprovadoVersao:null,
status:"novo",passos:0,maxPassos:12,prazo:1000,traces:[]};
salvar(estadoArquivo,inicial);
function carregar(){
const estado=ler(estadoArquivo);
if(typeof estado.execucaoId!=="string"||!Number.isInteger(estado.passos))
falhar("CHECKPOINT_INVALIDO");
return criarHarness(estado);
}
function criarHarness(estado){
function persistir(){salvar(estadoArquivo,estado);}
function trace(etapa,status){estado.traces.push({execucaoId:estado.execucaoId,etapa,status});persistir();}
function artefatoAtual(){
if(!existsSync(artefatoArquivo)) falhar("ARTEFATO_AUSENTE");
const artefato=ler(artefatoArquivo);
if(artefato.versao!==estado.versao) falhar("ARTEFATO_DIVERGENTE");
return artefato;
}
const ferramentas={
preparar({texto}){
if(typeof texto!=="string"||!texto.trim()) falhar("TEXTO_INVALIDO");
estado.versao++;
salvar(artefatoArquivo,{versao:estado.versao,texto});
estado.validadoVersao=null;estado.status="preparado";
trace("preparar","concluido");
},
validar(){artefatoAtual();estado.validadoVersao=estado.versao;
trace("validar","concluido");},
publicar({perderResposta=false}={}){
artefatoAtual();
if(estado.validadoVersao!==estado.versao||estado.aprovadoVersao!==estado.versao)
falhar("GATE_REPROVADO");
const intencao=estado.execucaoId+":"+estado.versao;
const efeitos=ler(efeitosArquivo);
const anterior=efeitos.find(x=>x.intencao===intencao);
if(anterior){estado.status="publicado";trace("publicar","replay");return anterior;}
// Ledger local simula um serviço externo separado do checkpoint.
const recibo={intencao,versao:estado.versao,recibo:"pub-"+(efeitos.length+1)};
efeitos.push(recibo);salvar(efeitosArquivo,efeitos);
if(perderResposta){estado.status="desconhecido";trace("publicar","resposta_perdida");
falhar("RESPOSTA_PERDIDA");}
estado.status="publicado";trace("publicar","confirmado");return recibo;
},
reconciliar(){
const intencao=estado.execucaoId+":"+estado.versao;
const recibo=ler(efeitosArquivo).find(x=>x.intencao===intencao);
estado.status=recibo?"publicado":"nao_enviado";
trace("reconciliar",estado.status);return recibo??null;
}
};
return {estado,
chamar(nome,args={},agora=0){
if(!Object.hasOwn(ferramentas,nome)) falhar("TOOL_NAO_PERMITIDA");
if(agora>=estado.prazo) falhar("TIMEOUT_GLOBAL");
if(estado.passos>=estado.maxPassos) falhar("LIMITE_PASSOS");
estado.passos++;persistir();
try{return ferramentas[nome](args);}catch(erro){trace(nome,"falhou");throw erro;}
},
aprovar({ator,versao}){
if(ator!=="operador-autorizado") falhar("ATOR_INVALIDO");
if(versao!==estado.versao) falhar("APROVACAO_ANTIGA");
artefatoAtual();estado.aprovadoVersao=versao;trace("aprovar","concluido");
}
};
}
let h=carregar();
h.chamar("preparar",{texto:"Relatório inicial"});h.chamar("validar");
h.aprovar({ator:"operador-autorizado",versao:1});
h.chamar("preparar",{texto:"Relatório revisado"});
assert.throws(()=>h.chamar("publicar"),/GATE_REPROVADO/);
assert.throws(()=>h.aprovar({ator:"operador-autorizado",versao:1}),/APROVACAO_ANTIGA/);
h.chamar("validar");h.aprovar({ator:"operador-autorizado",versao:2});
// Um processo novo lê o JSON persistido, sem acesso ao objeto h.
const reinicio=spawnSync(process.execPath,["--input-type=module","-e",
"import {readFileSync} from 'node:fs';console.log(readFileSync(process.argv[1],'utf8'));",
estadoArquivo],{encoding:"utf8"});
assert.equal(reinicio.status,0);assert.equal(JSON.parse(reinicio.stdout).versao,2);
h=carregar();
assert.throws(()=>h.chamar("publicar",{perderResposta:true}),/RESPOSTA_PERDIDA/);
assert.equal(ler(estadoArquivo).status,"desconhecido");
h=carregar();assert.equal(h.chamar("reconciliar").versao,2);
h.chamar("publicar");assert.equal(ler(efeitosArquivo).length,1);
assert.equal(h.estado.status,"publicado");
assert.throws(()=>h.chamar("terminal",{comando:"qualquer"}),/TOOL_NAO_PERMITIDA/);
assert.throws(()=>h.chamar("validar",{},1000),/TIMEOUT_GLOBAL/);
const limitado=criarHarness({...h.estado,passos:12,maxPassos:12});
assert.throws(()=>limitado.chamar("validar"),/LIMITE_PASSOS/);
assert.ok(h.estado.traces.some(x=>x.status==="resposta_perdida"));
assert.ok(h.estado.traces.some(x=>x.etapa==="reconciliar"));
console.log({status:"aprovado",pasta,publicacoes:ler(efeitosArquivo).length,
checkpoint:h.estado.status,passos:h.estado.passos});Como conferir seu resultado
- Aprovação antiga é rejeitada.
- Repetição confirmada não cria efeito.
- Resultado desconhecido não é convertido automaticamente em falha sem efeito.
Aplique em um problema novo
Primeiro resolva sem consultar a resposta. Explique suas decisões e guarde a evidência. A conclusão de leitura é independente desta autoavaliação.
Confira seus pré-requisitos
- Modelar gates ligados ao artefato.
- Separar checkpoint e ledger.
v3 aprovada vira v4 antes de publicar; depois recibo é gravado e checkpoint falha. Desenhe recuperação.
Conferir raciocínio e critérios de domínio
v4 exige validação/aprovação novas vinculadas a versão/hash.
Pós-efeito sem confirmação vira desconhecido.
Retomar consulta intenção no ledger antes de repetir publicação.
Evidências para autoavaliação ou revisão por pares
- Gates: v4 exige validação/aprovação novas vinculadas a versão/hash.
- Estado: Pós-efeito sem confirmação vira desconhecido.
- Retomada: Retomar consulta intenção no ledger antes de repetir publicação.
Um erro frequente
Dois booleanos bastam para recovery.
Recuperação exige versão, intenção, estado e evidência.
Teste sua compreensão
Responda com suas palavras antes de abrir o comentário. Saber explicar uma decisão é parte do domínio.
1. Modelo dizendo aprovado conta como aprovação humana?
2. Checkpoint de toda ferramenta tem a mesma garantia?
Não.
Estado e recuperação dependem do mecanismo documentado.
3. Gate reprovado pode ser ignorado por texto convincente?
Não.
A condição determinística precisa ser satisfeita ou o contrato revisto explicitamente.
Seu progresso fica salvo neste navegador. Concluir a leitura não substitui demonstrar o domínio nos exercícios.
Referências e aprofundamento
Documentação oficial e trabalhos originais. As referências registram o escopo e as limitações para você conferir o que sustentam.
- Effective harnesses for long-running agents
Anthropic • consulta: 2026-10-06
AgentesHarness, artefatos persistentes, progresso incremental, recuperação e testes de aplicação.
Limites: Relato de engenharia; harness mínimo e gates do curso são síntese pedagógica, não implementação fornecida completa.
- Building effective agents
Anthropic • consulta: 2026-10-06
AgentesPrompt chaining, decomposição, routing, paralelização, workflows versus agentes.
Limites: Relato de engenharia do fornecedor; ganhos e escolha de padrão são hipóteses a medir, não garantia.
- Sandbox
OpenAI • consulta: 2026-10-06
OpenAISandbox de comandos, fronteiras de filesystem/rede e diferenças entre clientes.
Limites: Sandbox de processo tem limites por plataforma; conferir configuração ativa e política de aprovação.
- Permission profiles
OpenAI • consulta: 2026-10-06
OpenAIPerfis de permissões, acesso a arquivos, rede e execução de comandos.
Limites: Suporte e isolamento variam por SO/cliente; hierarquia de instruções não substitui barreira do sistema operacional.
- LangGraph Persistence
LangChain • consulta: 2026-10-06
LangGraphAgentesEstado, checkpoints, retomada e execução durável.
Limites: Reexecutar nós pode repetir efeitos; combinar persistência com idempotência e versões do estado.
- Cursor Agent overview
Cursor • consulta: 2026-10-06
AgentesExploração, edição, terminal, ferramentas de agente e checkpoints.
Limites: Checkpoints locais do Cursor não são commits Git; recursos mudam por versão/plano.
- OpenAI Python API library
OpenAI • consulta: 2026-10-06
PythonOpenAIAPIsCliente SDK, streaming, erros tipados, retries, timeout, logging e request IDs.
Limites: Defaults do SDK não substituem orçamento global de retries; pin de versão obrigatório.
- Rate limits
OpenAI • consulta: 2026-10-06
OpenAILimites por taxa, backoff e recuperação de erros temporários.
Limites: Limites por conta/modelo mudam; evitar retries ilimitados e tempestades de retry.
- Making retries safe with idempotent APIs
Amazon Web Services • consulta: 2026-10-06
APIsIdempotência, identificador de requisição, retries seguros e efeitos colaterais.
Limites: Padrão de sistemas distribuídos; suporte a chave de idempotência deve ser verificado em cada endpoint, não presumido para todo LLM.
- LangGraph Interrupts
LangChain • consulta: 2026-10-06
LangGraphAgentesPausa, human-in-the-loop, aprovação e retomada de execução.
Limites: Aprovação precisa validar ação/argumentos antes de execução; não é autorização abstrata de toda sessão.
- Configure permissions
Anthropic • consulta: 2026-10-06
FundamentosRegras allow/ask/deny, autorização de tools e comportamento de execução.
Limites: Semântica específica Claude Code; não transportar padrões para outro agente sem adaptação.
- Effective context engineering for AI agents
Anthropic • consulta: 2026-10-06
AgentesIA & MLSeleção de contexto, orçamento de attention, context rot, recuperação just-in-time, compactação, notas e handoffs.
Limites: Context rot descreve efeito empírico, sem limite universal; compactação pode perder detalhes necessários.
- LangGraph Memory
LangChain • consulta: 2026-10-06
LangGraphAgentesPersistência de memória por thread/namespace, trimming, delete e summarization.
Limites: Memória deve ter identidade/tenant; apagamento efetivo precisa incluir índices, backups e traces conforme política da aplicação.
- Playwright Best Practices
Microsoft / Playwright • consulta: 2026-10-06
FundamentosTestes E2E de comportamento visível, isolamento, locators e assertions confiáveis.
Limites: Documentação dinâmica; fixar a versão usada no laboratório e conferir compatibilidade antes de executar.
- OpenAPI Specification 3.1.1
OpenAPI Initiative • consulta: 2026-10-06
FundamentosContrato HTTP, schemas, operações, parâmetros e respostas.
Limites: Versão fixada 3.1.1; suporte das ferramentas a JSON Schema/OpenAPI deve ser verificado.
- LangSmith Observability
LangChain • consulta: 2026-10-06
AvaliaçãoTracing de execuções, visualização de chamadas e diagnóstico.
Limites: SaaS/serviço opcional; decidir redação de dados sensíveis antes de enviar traces.