Harness básico
Você implementará um gate de publicação e um plano de recuperação para uma rotina longa. A tentativa inicial consiste em desenhar estados e efeitos antes de olhar o código. O objetivo é distinguir estar pronto, ter aprovação e ter publicado.
Use artefatos e canais fictícios; nenhuma publicação externa será necessária. O simulador mostra condições locais, enquanto persistência, aprovação real e integração dependem do ambiente. A entrega precisa declarar essa diferença e propor verificações para cada fronteira.
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: Leitura: Harness básico
Desenhar estados e ferramentas
FundamentosListe preparar, validar, aguardar aprovação, publicar, confirmado e desconhecido. Associe ferramentas permitidas a cada estado. Na preparação, leitura e escrita local podem bastar; publicação não deve estar disponível antes dos gates. Defina limite de passos e condição de parada. Retome contratos de ferramenta: o modelo propõe argumentos, mas o harness decide execução. Escreva também a falha esperada quando o usuário cancela. Um processo sem estado de cancelamento pode continuar gastando recursos mesmo depois de perder sua finalidade.
↗ Effective harnesses for long-running agents↗ Permission profiles
Criar artefato e aprovação vinculada
FundamentosProduza um relatório fictício com versão e identificador. Defina a validação e registre sua evidência. Execute o gate com aprovação antiga e confirme rejeição. Depois vincule aprovação à versão atual e observe aceitação. Modifique o relatório após aprovar: a publicação deve voltar a ser bloqueada. Esse caso verifica que a autorização não é uma marca genérica reaproveitada para qualquer conteúdo. Em integração real, o ator e a ação precisam ser confiáveis, não apenas campos preenchidos pelo modelo.
Simular interrupção e recovery
FundamentosSalve o estado em JSON local e reinicie o programa antes da publicação simulada. Confira existência e versão do artefato antes de retomar. Simule efeito realizado com resposta perdida e represente resultado desconhecido. A recuperação consulta o efeito em vez de criar nova intenção. Defina quais etapas podem repetir e o orçamento de tentativas. O arquivo local ensina persistência, mas não oferece transação distribuída; registre essa limitação. Compare um checkpoint anterior com estado mais recente para evitar apagar confirmação que ocorreu depois.
↗ LangGraph Persistence↗ Making retries safe with idempotent APIs
Instrumentar e avaliar gates
FundamentosCrie eventos estruturados com execuçãoId, etapa, duração e status. Não inclua segredo ou raciocínio privado. Avalie caminho nominal, aprovação antiga, artefato ausente, timeout e repetição. Para cada caso, escreva a transição esperada antes de executar. A rubrica exige efeito único, aprovação da versão correta e estado final coerente. Compare autonomia ampla com workflow delimitado: o segundo pode ser suficiente para esta rotina e mais simples de recuperar. Feche com um relatório que relacione evidência, falhas e fronteiras ainda não integradas.
↗ LangSmith Observability↗ Effective harnesses for long-running agents
Persistir e exercitar retomada
FundamentosGrave estado local com execuçãoId, versão do relatório, status, tentativas e referência do artefato. Escreva uma leitura que valide o schema antes de retomar, pois arquivos antigos podem ter formato incompatível. Faça três interrupções controladas: antes de gerar, depois de validar e após efeito simulado sem resposta. Para cada uma, descreva o trabalho reutilizado e a consulta necessária. O mini harness executa ferramentas de um catálogo permitido, não um comando arbitrário devolvido pelo modelo. Se uma proposta não existe no catálogo ou falha no schema, rejeite e registre. A rubrica inclui limite de passos e timeout global, além de efeito único. Isso transforma o gate isolado em uma rotina recuperável, preservando a separação entre política de execução e geração.
↗ LangGraph Persistence↗ Effective harnesses for long-running agents
Caso adicional para diagnóstico e decisão
FundamentosFaça uma mudança no artefato depois de validar, mas antes de receber aprovação. Se o estado ainda diz validado, o gate pode aprovar um conteúdo que nunca passou na verificação. Vincule validação à versão ou hash do relatório, assim como a aprovação. Tente esse cenário antes de consultar a solução e anote a transição esperada. Agora simule cancelamento durante espera de ferramenta: a conclusão tardia não deve retomar uma execução encerrada sem política explícita. A rubrica adicional exige identidade de execução, vínculo dos gates ao artefato e parada dentro do orçamento. Compare salvar todo o histórico com salvar estado e referências a artifacts. O primeiro simplifica inspeção inicial, mas aumenta volume e exposição; o segundo exige bons identificadores e recuperação de conteúdo. Escolha uma política que mantenha evidência suficiente sem depender de uma narrativa gerada como única fonte de verdade.
↗ Effective harnesses for long-running agents↗ Effective context engineering for AI agents
Execução, inspeção e diagnóstico
FundamentosExecute o gate em três estados e acrescente uma mudança de versão depois de aprovar. Em seguida, modele desconhecido como status próprio e escreva uma função de reconciliação fictícia. O exercício mostra por que dois booleanos não descrevem todas as falhas de um efeito externo.
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));Se relatório modificado ainda pode publicar, falta vínculo de aprovação. Se reinício repete o efeito, falta reconciliação ou intenção estável. Se o tracing não distingue tentativa e confirmação, não permite recuperar com segurança. Cada achado aponta uma mudança de contrato ou persistência.
Exercício aplicado
Entregue harness simulado com estados, artefatos, gates, aprovação e recovery.
- 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.
Harness local: relatório v1 validado/aprovado; uma edição gera v2; depois v2 é validado/aprovado e o serviço grava recibo e perde resposta. Reinicie pelo checkpoint e proponha tool shell fora do catálogo. Resolva cada estado.
Conferir raciocínio e critérios de domínio
A publicação de v2 antes dos novos gates é bloqueada porque as evidências v1 não valem para v2. Após validar/aprovar v2, a intenção execução: v2 pode produzir o recibo.
A perda da resposta deixa desconhecido. O processo novo consulta o ledger da mesma intenção, confirma publicado e o replay devolve o recibo; permanece uma publicação.
Shell fora do catálogo é TOOL_NAO_PERMITIDA. Limite de passos e timeout continuam controles independentes; o exemplo de arquivos locais não garante atomicidade distribuída.
Evidências para autoavaliação ou revisão por pares
- Gates vinculados à versão: A publicação de v2 antes dos novos gates é bloqueada porque as evidências v1 não valem para v2. Após validar/aprovar v2, a intenção execução: v2 pode produzir o recibo.
- Reconciliação após timeout: A perda da resposta deixa desconhecido. O processo novo consulta o ledger da mesma intenção, confirma publicado e o replay devolve o recibo; permanece uma publicação.
- Catálogo e limites: Shell fora do catálogo é TOOL_NAO_PERMITIDA. Limite de passos e timeout continuam controles independentes; o exemplo de arquivos locais não garante atomicidade distribuída.
Um erro frequente
Histórico autoriza qualquer tool proposta.
Histórico não amplia o catálogo de ferramentas autorizadas.
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.