Harness Engineering para AI Agents: conceber ciclos de controlo
Tradução automática Este artigo foi traduzido automaticamente a partir da versão original em inglês.
Atualização do artigo
Publicado originalmente em 22 de julho de 2026. Revisto e atualizado em 6 de setembro de 2026. A atualização acrescenta evidência mais recente de harness benchmarks e casos de intervenção de providers, e clarifica o que os resultados apresentados demonstram.
Um agent pode terminar o seu turno quando o trabalho ainda está incompleto. Para um coding agent, a evidência útil é o artefacto alterado e os resultados dos testes obrigatórios. Uma mensagem final a dizer «feito» não comprova nenhum dos dois.
O harness é o código de controlo em torno do reasoning loop. Fornece contexto, valida e autoriza tool calls, regista resultados e decide se a evidência é suficiente para aceitar o trabalho. O runtime mantém a execução e o estado ativos por baixo dele.
Ao rever um harness, colocaria duas perguntas: o que o impede de aceitar trabalho incompleto e que falhas justificam os controlos adicionais? Este artigo percorre acceptance checks, retries e handoffs, e mostra depois como comparar um controlo com um baseline fixo. Os exemplos da loja são fictícios; o companion lab é uma simulação determinística, não uma medição de um agent em produção.
A acceptance check mais simples é fácil de escrever para um pequeno research agent como o que esta série tem vindo a construir — um agent LangGraph que obtém dados de mercado e escreve um relatório de analista. Um hook fora do modelo valida o relatório contra um schema e verifica se contém efetivamente stock tickers; um relatório malformado mantém o run aberto. Doze linhas de código normal, e o modelo não pode declarar que o seu próprio output está bem-formado. O repositório usa uma verificação mais flexível: um evaluator com fresh context vota e, depois, uma pessoa revê o resultado. (A Parte 4 apresenta a versão determinística.)
O que esse exemplo não consegue mostrar é a parte interessante: o que acontece quando a evidência é ambígua, quando um retry pode cobrar duas vezes a alguém ou quando o trabalho sobrevive à sessão que o iniciou. Esses casos precisam de uma task com uma fronteira pass/fail mais nítida do que a de um relatório de investigação. O research agent mantém-se como exemplo de acceptance check; um pequeno repositório de loja fictício junta-se a ele nos casos de retry e handoff. A coding task consiste em baixar de $100 para $75 o limiar para um desconto automático de 10% em src/checkout.py. O repositório tem duas checks obrigatórias:
pytest tests/test_checkout.pyverifica o cálculo do desconto.pnpm playwright test tests/checkout_discount.spec.tsadiciona um artigo de $80 numa loja de testes local e verifica que a página de checkout apresenta um desconto de $8.
O exemplo é um teaching fixture, não uma aplicação real nem um benchmark. Cada tentativa começa no mesmo commit e com os mesmos dados de teste seeded. O harness só pode aceitar a alteração quando ambos os comandos passam e um acceptance record durável associa os dois resultados a um candidato committed limpo ou a um digest do snapshot completo testado, incluindo ficheiros untracked relevantes.
O diagrama acompanha a alteração do desconto, desde a proposta até à evidência. O harness fornece a task e os ficheiros, verifica os argumentos e as permissões do edit_file proposto e despacha a call aceite. Depois de o runtime aplicar a edição, o harness executa os testes de unidade e de browser acceptance indicados. Um comando que falhe regressa ao modelo como evidência para outro turno; dois comandos aprovados tornam a alteração elegível para aceitação.
O que pertence ao harness
O Codex loop walkthrough da OpenAI descreve o ciclo básico. O harness compõe um prompt, pede ao modelo a próxima ação, envia uma tool call aceite para o runtime e acrescenta o resultado. Depois pergunta novamente. Isto repete-se até o harness aceitar o resultado ou devolver o controlo ao utilizador.
As implementações podem juntar várias responsabilidades num só processo. As fronteiras de falha continuam a ser diferentes:
| Termo | Função | Exemplo de coding agent |
|---|---|---|
| Modelo | Propõe texto, uma tool call ou uma resposta final | Sugere uma edição em src/checkout.py |
| Reasoning loop | Escolhe o próximo passo a partir do contexto disponível | Inspecionar, editar, testar, voltar a inspecionar |
| Harness | Fornece contexto, valida propostas, autoriza-as, despacha calls aceites, regista resultados e verifica a conclusão | Permite edições em src/ e exige ambos os testes indicados |
| Runtime | Executa calls aceites e mantém o estado ativo fora do processo worker | Session log, sandbox, checkpoint store, trace backend |
A linha do runtime abrange quatro elementos: sessão, sandbox, checkpoint e trace. Os quatro armazenam estado ou confinam a execução. O modelo propõe a ação e o reasoning loop escolhe o próximo passo. O harness decide se uma call proposta pode ser executada e se a evidência é suficiente para terminar, razão pela qual tem um artigo próprio. A Parte 5 contabiliza o harness, juntamente com esses quatro elementos, como um dos cinco primitives que é necessário posicionar antes do deployment; este artigo volta a separá-lo.
Quando surge uma falha, diagnostique a fronteira que deve responder. Um plano fraco pode precisar de melhores instruções ou de melhor reasoning do modelo. Se edit_file apontar para um caminho fora de src/, o harness deve rejeitá-lo. Um processo sandbox que termina antes de a edição ser executada pertence ao runtime, que deve reiniciar o worker ou reportar o crash.
Onde se enquadram as partes anteriores
A linha do harness acima faz a maior parte do trabalho nessa tabela e é aí que acabam as Partes 2, 3 e 4. Cada uma decide uma coisa sobre um único turno:
| Parte anterior | O que decide neste turno | Onde atua no walkthrough da secção seguinte |
|---|---|---|
| Parte 2 — memória | Que estado anterior entra no prompt | Passo 1, o context builder |
| Parte 3 — tool use | Que ações existem e como é um resultado validado | Validação de argumentos no passo 3 e formato do resultado no passo 4 |
| Parte 4 — segurança | Se esta call específica pode ser executada agora | Passo 3, a verificação do caminho e a decisão de aprovação |
| Parte 6 — este artigo | Se a evidência resultante termina o run | Passos 5 a 7, as acceptance checks e o trace |
As Partes 3 e 4 partilham o passo 3, e essa sobreposição é precisamente o argumento para as tratar como um só programa. A mesma camada de código do harness que rejeita um argumento malformado também rejeita uma call que é permitida, mas ainda não foi aprovada. Se a validação e a autorização forem executadas em services separados, preserve os argumentos validados através dessa fronteira para que a decisão de autorização se aplique à call que será executada.
A separação continua a ser importante para debugging: uma edição no ficheiro errado é uma path rule da Parte 4, não um problema de retrieval da Parte 2. Uma secção perto do fim deste artigo transforma isso numa routing table.
O próprio estudo de caso da OpenAI sobre harness engineering descreve uma application instance bootable para cada worktree. A equipa ligou também browser automation ao ambiente do agent e expôs logs, métricas e traces.
Uma task como «nenhum span nestas quatro jornadas críticas de utilizador excede dois segundos» tornou-se testável porque o agent conseguia executar a aplicação e consultar os mesmos sinais que um engenheiro inspecionaria. O estudo de caso é específico do produto. O que é transferível é a condição subjacente ao resultado: a aplicação e os seus sinais de performance tinham de estar disponíveis dentro do ambiente do agent.
Lopopolo, autor desse estudo de caso, mantém um field guide de harness engineering. Identifica as duas alavancas que este artigo utiliza: manter o modelo e o coding agent fixos como uma black box e fazer engineering do contexto e das ferramentas à sua volta. O seu enquadramento explica também por que razão grande parte do harness acaba por ser código normal.
O quality bar, os procedimentos, o histórico de exceções e as relações de autoridade de uma organização estão fora do que um modelo geral pode conhecer. O harness expõe-nos como instruções do repositório, regras de permissões e acceptance checks. Cada run aceite pode devolver as suas lições a esses artefactos, em vez de depender da sessão seguinte para as redescobrir.
Acompanhar a alteração do desconto desde a proposta até à aceitação
Para a discount task definida acima, o modelo propõe alterar calculate_discount em src/checkout.py. Acontecem várias coisas antes de essa edição contar como progresso:
- O context builder fornece a task, as instruções do repositório, os ficheiros relevantes, os tool results anteriores e o plano atual.
- O modelo propõe uma call
edit_filecom um caminho e texto de substituição. - A tool boundary (o código do harness entre a proposta e a execução) valida os argumentos, verifica o caminho contra o scope permitido e pede aprovação se a operação o exigir.
- O runtime aplica a edição na sandbox e devolve um resultado estruturado.
- O harness executa
pytest tests/test_checkout.py, seguido depnpm playwright test tests/checkout_discount.spec.ts, e lê ambos os exit codes. O browser test verifica o desconto visível de $8 no carrinho seeded de $80. - O harness decide o que significam os resultados. Uma check falhada torna-se novo contexto para o turno seguinte do modelo, e um run aprovado torna a task candidata a conclusão.
- Um resultado aprovado só se torna completion evidence depois de o harness registar de forma durável o comando, o exit code, o snapshot testado, o grader e as versões do ambiente; um trace pode ligar-se a esse registo.
Depois do passo 2, nenhum ficheiro foi alterado. O harness pode rejeitar ../../secrets.env, exigir aprovação para um comando destrutivo ou parar um run que tenha esgotado o seu budget. Esse é o último momento barato de que dispõe. Depois de os testes serem executados, o harness lê os seus exit codes diretamente. O modelo não pode marcar a sua própria edição como aprovada.
O acceptance record deve identificar o snapshot testado, ambos os comandos e resultados, bem como as versões do grader e do ambiente; os traces podem ligar-se a esse registo. Mantenha os testes obrigatórios fora do writable scope do agent ou aprove independentemente as alterações antes de fazer a avaliação. Qualquer edição posterior de um ficheiro invalida o resultado. Estas checks implementam os princípios de stable environment e bypass-resistant grader presentes nas guidelines de avaliação da Anthropic. Uma mensagem final done sem esses registos não prova que esta alteração passou as checks obrigatórias.
Decidir onde cada regra é aplicada
O requisito de que tests/checkout_discount.spec.ts passa pertence a código determinístico, não ao prompt. O harness despacha o comando Playwright para o runtime, lê o seu exit code e recusa terminar o run enquanto ele falhar. Um prompt pode lembrar o modelo de executar o teste. Não pode impedir o modelo de declarar sucesso sem evidência.
Outras regras encaixam noutras camadas:
| Colocar a regra em | Adequado para | Exemplo |
|---|---|---|
| Prompt ou skill | Ordem de pesquisa, convenções de código e formato do plano | Ler AGENTS.md antes de editar código de checkout |
| Tool boundary | Validação de argumentos, caminhos permitidos, aprovações e acesso a ferramentas | Permitir escritas apenas em src/ |
| Código determinístico | Budgets, timeouts, retries, exit codes dos testes e requisitos de release | Manter o run aberto enquanto o teste Playwright falhar |
| Fresh-context evaluator | Revisão visual ou critérios que exigem julgamento semelhante ao humano | Comparar um diagrama gerado com uma rubric escrita |
Os tool contracts separam proposta de permissão
A discount task só precisa de edições de ficheiros e comandos de teste. Uma API que altera estado tem um modo de falha diferente, por isso mudemos os exemplos nesta secção. Suponha que o agent pode chamar create_test_order contra um order service de staging enquanto prepara dados de teste. Esta ferramenta não é uma das acceptance checks da discount task. É útil aqui porque um timeout pode esconder se o service criou uma encomenda.
A tool boundary precisa de mais do que uma descrição em linguagem natural. Precisa de um tool contract explícito. A Parte 3 defendia um do lado do modelo: ações claras, feedback compacto e erros recuperáveis. O harness precisa do mesmo contract por uma razão diferente. Tem de decidir, sem perguntar ao modelo, se uma call pode ser executada e se uma call falhada pode ser repetida. Para create_test_order, isso significa um contract com:
- argumentos validados, para que input malformado seja rejeitado antes da execução
- um resultado estruturado, como
{ "order_id": "123", "created": true }, para que as verificações posteriores não tenham de analisar texto livre - uma categoria de efeito que regista se a call apenas obtém informação ou altera um ficheiro, um registo de base de dados ou um service externo. Regista também se é seguro repetir a call. Esta etiqueta indica ao harness se um retry automático pode duplicar trabalho. O harness pode repetir
get_order_statusquando o service define essa consulta como read-only. Não deve repetir cegamentecreate_test_order, porque a primeira call pode já ter criado a encomenda - uma política de timeout e retry, para que uma resposta perdida não desencadeie uma sequência ilimitada de calls
- uma regra de permissões que indique que aprovação é necessária. A leitura do estado de uma encomenda pode ser executada automaticamente, enquanto a criação de uma encomenda pode exigir confirmação
A descrição em linguagem natural é texto apresentado ao modelo. Pode dizer: «Criar uma encomenda de teste para verificar o checkout.» Essa frase ajuda o modelo a decidir quando propor create_test_order. Não autoriza a call. Neste exemplo, o cliente Model Context Protocol (MCP) do harness valida os argumentos, aplica as suas próprias regras e verifica a confiança no server, os requisitos de aprovação e a segurança do retry antes de despachar qualquer coisa. Isto combina as regras de permissões e as verificações pre-tool discutidas na Parte 4 com uma pergunta adicional: se uma call que já falhou pode ser enviada novamente.
Um MCP server publica descrições de tools e anotações comportamentais opcionais para o cliente. Um server defeituoso ou malicioso poderia descrever uma ferramenta que altera estado como inofensiva. Um cliente que aceitasse automaticamente essa afirmação poderia executar ou repetir create_test_order sem aprovação e criar um duplicado. A especificação do MCP exige, por isso, que os clientes tratem as tool annotations como não confiáveis, salvo se o próprio server for trusted.
A especificação não prescreve uma única configuração universal de trust, pelo que precisa de uma trust policy explícita para o seu deployment; um server não pode tornar as suas próprias annotations confiáveis. Essa policy decide que metadata pode influenciar decisões de permissões ou retries e que annotations permanecem apenas advisory.
Repetir uma call que altera estado exige replay protection
A Parte 5 exige uma identidade de operação durável para side effects que podem ser duplicados num retry. O harness é que decide quando essa chave tem de suportar esse encargo. create_test_order cria a encomenda, mas a sua resposta HTTP perde-se. O harness vê um timeout e não consegue saber se o server concluiu o pedido. Repetir a call pode criar uma segunda encomenda.
Persista um operation ID da responsabilidade da aplicação antes do dispatch e associe-o aos argumentos aprovados. Reutilize-o ao recuperar a mesma encomenda pretendida, mesmo que o modelo gere um novo tool-call ID; mantenha os IDs do modelo separadamente para correlação. Reconcilie payloads alterados ou janelas de deduplicação expiradas do provider, em vez de reenviar cegamente. O contract da Stripe, por exemplo, permite eliminar chaves depois de pelo menos 24 horas.
Uma consulta de estado pode ser repetida quando o service a define como read-only. Uma call de criação precisa da chave: o cliente associa um request identifier único e o service devolve o primeiro resultado, em vez de criar outra encomenda quando vê novamente esse identifier. Sem esta proteção, o harness deve verificar se a encomenda existe ou pedir uma decisão humana antes de tentar novamente. A AWS documenta este padrão na sua orientação sobre idempotent APIs.
A aceitação precisa de evidência independente
Uma resposta create_test_order bem-sucedida apenas estabelece que a ferramenta devolveu dados. Não prova que uma coding task passou os testes. Se um browser test posterior depender da encomenda staged, o harness deve validar o schema da resposta e executar ainda esse teste antes de aceitar a alteração de código.
Alguns critérios não podem ser reduzidos a um exit code. Numa tarefa separada de visual design, um evaluator com fresh context pode comparar uma página ou diagrama renderizado com uma rubric escrita — «fresh context» significa uma segunda sessão do modelo que começa sem histórico do run e lê os artefactos produzidos, em vez do transcript. Compare esse evaluator com revisões humanas antes de permitir que o seu resultado decida se a task está concluída.
Uma migração de payment adapter precisa de um handoff
Mudemos novamente de task, mas mantenhamo-nos no repositório de loja fictício. O agent tem agora de migrar o checkout do payment adapter v1 para o v2. O trabalho abrange o checkout handler, o payment client, a configuração e os testes, pelo que pode ultrapassar uma sessão de modelo — um período contínuo de contexto do modelo, terminado por um restart ou por um fresh start deliberado, em vez de ser transportado.
Antes de a primeira sessão atingir o seu limite de contexto, modificou vários ficheiros, iniciou uma payment sandbox local e deixou tests/payment_migration.spec.ts a falhar. Esse browser acceptance test conclui um pagamento através do adapter v2 e verifica o provider ID registado. Um resumo da conversa pode orientar a sessão de modelo seguinte, mas não pode reiniciar a sandbox nem provar que ficheiros estão atualmente modificados.
A sessão seguinte tem de recuperar três coisas:
| O que tem de ser recuperado | O que inclui | Como pode falhar |
|---|---|---|
| Histórico da conversa | Mensagens, tool calls e resultados devolvidos | Detalhes antigos ocupam o lugar da task atual |
| Ambiente de trabalho | Ficheiros, payment sandbox e estado do browser test | O transcript diz que um service está a correr depois de ter terminado |
| Progresso da task | Plano, checks concluídas, aprovação pendente, próximo passo | A sessão seguinte repete trabalho concluído |
A compaction substitui mensagens antigas por um resumo mais curto para que a sessão atual possa continuar. Um progress handoff regista o que a sessão seguinte precisa: a branch atual, os ficheiros alterados, o último comando de teste e output e o próximo passo ainda não resolvido.
Um handoff file é document memory para a sessão seguinte do modelo. Um checkpoint pode já preservar o plano, os passos concluídos, os resultados e o trabalho restante. Acrescente um handoff quando esses detalhes estiverem ausentes ou forem inutilizáveis no contexto seguinte, e verifique os ficheiros e os services em execução contra o ambiente live.
Se a conversa antiga contiver pressupostos stale, o harness pode iniciar uma nova sessão de modelo com esse handoff e o workspace atual. Substituir um worker que crashou e restaurar os seus processos é um job separado de runtime recovery.
Uma pequena edição de documentação pode não precisar de nenhum destes mecanismos. A migração de pagamentos precisa de um handoff se o estado guardado não transportar progresso de task utilizável, porque a sessão seguinte do modelo tem de reconstruir tanto o workspace como o estado da task.
As experiências da Anthropic com long-running coding agents usaram histórico do git e um ficheiro de progresso entre sessões. O relatório posterior da Anthropic sobre harness design separa a compaction de um fresh-context handoff e reporta que os handoffs acrescentam orchestration, token use e wall time, sem publicar valores que atribuam esse overhead ao handoff em si.
Usar traces para distinguir três falhas
As três linhas seguintes são exemplos ilustrativos de traces, não runs medidos nem output do companion lab. Cada linha mostra uma falha diferente e, por isso, uma resposta diferente do harness.
| O que o trace regista | O que aconteceu | Resposta correta |
|---|---|---|
A call read-only get_order_status devolve 503; não há nenhuma call state-changing em curso | Uma consulta transient falhou | Repetir a consulta com limite e backoff |
create_test_order sofre timeout e, depois, uma consulta de estado encontra a encomenda 123 sob a idempotency key checkout-42 | O service criou a encomenda, mas a resposta perdeu-se | Devolver a encomenda existente; não criar outra |
A edição e o unit test passam, mas o trace não tem resultado para tests/checkout_discount.spec.ts no snapshot testado | Falta evidência de acceptance obrigatória | Manter o run aberto e despachar o browser acceptance test |
Uma falha que parece transient não torna todas as calls seguras para retry. A primeira linha é uma consulta read-only. A segunda é um pedido state-changing, pelo que a idempotency key e o estado no server determinam se é permitida outra tentativa de criação. A terceira nem sequer é uma falha de tool; o harness ainda não recolheu a evidência necessária para aceitar a alteração do desconto.
Um chat transcript regista o que o modelo viu. Não consegue provar se o order service fez commit de um pedido antes de a resposta desaparecer. Um trace só pode fornecer essa evidência se incluir o resultado relevante do server ou uma consulta de estado; um timeout apenas do lado do cliente deixa o resultado por resolver. Os operation records e acceptance records duráveis devem associar a call do cliente, a decisão de aprovação, a identidade da operação, o resultado do server ou a consulta de estado, o snapshot testado e o resultado do acceptance test. Os traces podem expor essas ligações para debugging sem se tornarem o recovery ledger. Esses campos dizem ao harness em qual dos três caminhos se encontra.
| Sintoma repetido | Pequena alteração a experimentar | O que medir |
|---|---|---|
| Consultas read-only falham de forma transient | Retry limitado com backoff | Taxa de recuperação, calls adicionais, wall time |
| Sessões retomadas repetem trabalho concluído | Progress handoff estruturado | Tool actions duplicadas após o resume |
| Faltam testes obrigatórios na conclusão | Rejeitar a conclusão até todas as checks obrigatórias passarem | Tasks aceites sem todas as checks obrigatórias |
| Defeitos visuais sobrevivem às checks determinísticas | Fresh-context evaluator com uma rubric | Defeitos encontrados, rejeições falsas, tempo de revisão |
| O agent edita fora do seu scope | Permissões de ferramentas mais restritas | Calls bloqueadas e overrides manuais |
| A memória recuperada ocupa o lugar da task atual | Limitar factos recuperados; fazer ranking antes da injeção | Tokens gastos em recall, tasks concluídas, custo por task |
Para assistência opcional, como aids de planeamento, resumos e evaluators adicionais, identifique a falha e meça se o componente compensa o seu custo. A autorização, o isolamento, os requisitos de privacidade e as acceptance checks obrigatórias continuam em vigor mesmo que as tasks normais passem sem eles. Teste essas restrições com casos adversariais e invariants explícitos; um pequeno benchmark de sucesso não pode justificar a sua remoção.
Transformar essas falhas repetidas numa regression suite versionada é um trabalho próprio. Escrevi sobre isso separadamente em AI Agent Evaluation in Production.
Medir uma alteração de cada vez
Uma ablation mede se um componente do harness provoca o efeito esperado, alterando ou removendo esse componente enquanto o resto da experiência permanece fixo. Por exemplo: o editor linting ajuda este modelo nesta task suite?
Use o protocolo seguinte:
- Congele a versão do modelo, as task instances, o ambiente, o grader e os prompts fora do componente em teste.
- Dê a ambas as variantes o mesmo token budget, time budget e dollar budget total.
- Escolha o número de trials ou a stopping rule antes de executar a comparação.
- Execute as mesmas task instances em ambas as variantes. Como os outputs do modelo variam, repita cada task várias vezes.
- Reporte a média juntamente com a dispersão ou o intervalo de confiança.
- Conte todos os trials iniciados, incluindo timeouts, policy stops, crashes do harness e falhas do evaluator.
A success rate, por si só, pode esconder um componente caro. No mínimo, acompanhe tasks quebradas aceites como concluídas, custo e wall time por task concluída, tool errors, encomendas duplicadas, minutos de revisão e overrides manuais de permissões. Escolha a métrica que representa o custo real do seu produto. Um aumento de dois pontos nas tasks concluídas é um mau trade-off se duplicar a sua fila de revisão.
Uma experiência paired de payment migration torna o progress handoff mensurável. Cada par control/treatment começa no mesmo commit do repositório e checkpoint seeded, com o mesmo modelo, task, grader e budget total. O handoff é a única variável. A métrica principal conta tool actions duplicadas depois do resume: uma action é duplicada quando a sua operação e o seu artefacto correspondem a um passo que a sessão anterior já tinha concluído.
O paper do SWE-agent fixa GPT-4 Turbo no split de 300 tasks do SWE-bench Lite e reporta 18,0% resolvidas com a sua interface completa, contra 11,0% para um agent apenas com shell, ao qual foi fornecida uma demonstração resolvida, e 7,3% para o mesmo agent sem demonstração. A diferença de 10,7 pontos destacada no paper é medida contra esse baseline de 7,3%; a Parte 3 trabalha os mesmos três números do ponto de vista do design da interface. O paper também alterou features individuais da interface:
| Alteração da interface | Resolvidas |
|---|---|
| Interface completa do SWE-agent (referência, inalterada) | 18,0% |
| Editor sem linting | 15,0% |
| Ficheiro completo em vez de um viewer de 100 linhas | 12,7% |
| Histórico completo de observação em vez dos últimos cinco | 15,0% |
Estes números pertencem àquele modelo, benchmark e limite de $4 por task. As três linhas abaixo da referência são os testes úteis de uma feature: cada uma alterou uma feature da interface enquanto o modelo e a configuração de avaliação permaneceram fixos.
A LangChain publicou uma comparação mais abrangente com modelo fixo para deepagents-cli. Reporta um aumento no Terminal-Bench 2.0 de 52,8% para 66,5% com gpt-5.2-codex fixo, enquanto a equipa alterou o system prompt, as tools e o middleware. O post agrupa várias alterações e omite um intervalo de confiança, uma comparação com budget total fixo e uma tabela de ablation por alteração. Esse resultado não consegue identificar qual das alterações ajudou. Os nomes dos modelos nesta secção são os que cada estudo fixou no momento em que foi executado; o que é transferível é o protocolo, não a lista de modelos.
Uma comparação mais recente mostra por que razão a configuração da API pertence ao baseline congelado. No seu relatório ARC-AGI-3 de 29 de julho de 2026, a OpenAI reporta que o score público de GPT-5.6 Sol subiu de 13,3% para 38,3% quando o seu harness reteve reasoning e usou compaction, em vez de descartar reasoning e truncar o histórico. A métrica é Relative Human Action Efficiency, não a fração de tasks resolvidas. Trata-se de uma comparação agrupada, reportada pelo vendor; não isola as duas configurações nem estabelece um effect size em produção. Numa atualização, registe a API, a retenção de reasoning, a política de compaction e os budgets juntamente com o model ID. Caso contrário, uma aparente regressão do modelo pode ser uma capability em falta no adapter.
Inclua a intervenção do provider na failure suite. Um misalignment_policy_violation tem de chegar a um caminho de stop-and-review mesmo depois de streamed output; não é um caso de transient retry. A Parte 4 cobre o seu scope dependente da API. Teste que o harness interrompe o dispatch e regista os efeitos já concluídos.
O relatório da Anthropic sobre aplicações long-running é um estudo de caso qualitativo e específico do produto, não um benchmark controlado. A aplicação é a RetroForge, uma ferramenta para criar jogos retro 2D; no Sprint 3, o evaluator do harness verificou 27 critérios relativos ao seu level editor. O trabalho começou com modelos Opus anteriores e, quando o Opus 4.6 foi lançado, a equipa removeu os componentes do harness um a um para perceber quais se tinham tornado redundantes com o modelo mais recente. O relatório indica que as evaluator calls passaram a ser overhead em tasks que o Opus 4.6 conseguia concluir de forma fiável sozinho, mas continuavam a ajudar perto do limite do modelo. O exemplo é uma razão para revalidar scaffolding antigo quando o modelo muda; não estima um effect size geral.
Manter o harness editável depois de justificar a sua existência
Ablation mantém o harness pequeno, mas o seu código pode sobreviver ao modelo para o qual foi afinado. Um pedido como «mascarar secrets em todos os caminhos de captura» identifica um comportamento, não um ficheiro. Num harness de produção, esse comportamento pode atravessar execution stages e estado partilhado. Antes de o poder alterar em segurança, tem de encontrar todos os locais de implementação — e o coding agent a quem delegar essa tarefa também.
Uma opção para a fase de research é um preprint de 2026 de Wang et al., o Harness Handbook, que chama a essa pesquisa behavior localization. O handbook constrói um mapa centrado no comportamento a partir da codebase do harness. A análise estática, que não precisa de model calls, extrai um program graph, e um LLM organiza depois as suas unidades em execution stages.
O maintainer ou coding agent começa com uma visão geral do sistema, abre a execution stage relevante e desce até entradas fundamentadas no source para uma função ou ficheiro. Um state register regista onde o estado partilhado é escrito e lido entre stages. Esta hierarquia mantém pequena a visão geral, preservando simultaneamente um caminho até ao source.
A freshness é uma regra separada. O mapa é um auxílio de navegação; o source live estabelece o comportamento. Cada locator tem de ser resolvido contra o repositório live. O handbook congela entradas stale em vez de adivinhar, e cada diff não vazio ressincroniza as entradas que afeta.
O diagrama comprime o modification loop: um pedido apenas sobre comportamento desce pelos níveis do handbook, cada locator candidato é verificado contra o repositório live antes de o plano ser escrito e cada diff aplicado ressincroniza o mapa.
A avaliação do Handbook compara braços matched em 30 pedidos por repositório. Não estabelece budgets totais iguais, trials estocásticos repetidos nem estimativas de incerteza, e as comparações reportadas excluem outputs em falta e erros do planner. Ilustra, por isso, apenas parte do protocolo acima. Abrange dois harnesses open source: Terminus-2 (seis ficheiros Python) e o monorepo do Codex (2.267 ficheiros Rust). Em cada um, um planner read-only alimentado por DeepSeek-V4-Pro explorou diretamente o repositório ou fez routing através do handbook. Os pedidos, o repositório, as permissões das tools e o decoding eram idênticos em ambos os braços. Três judges (GPT-5.5, Opus 4.8, DeepSeek-V4-Pro) atribuíram uma pontuação a cada edit plan em localization, scope control e reasoning — note-se que um dos judges é o mesmo modelo que produziu os planos. Uma vitória significa que o quality score de um braço, entre 0 e 100, excedeu o do outro em pelo menos três pontos; caso contrário, a comparação judge–request foi um empate. A taxa reportada é o número de vitórias dividido pelo número de comparações judge–request válidas:
| Harness | Win rate do baseline | Win rate com handbook | Tokens do planner |
|---|---|---|---|
| Terminus-2 (6 ficheiros) | 26,7% | 45,6% | −8,6% |
| Codex monorepo (2.267 ficheiros) | 28,3% | 38,3% | −12,7% |
O planner com assistência do handbook ganhou mais vezes e utilizou menos tokens do planner nos dois repositórios. As condições permanecem associadas a esse resultado: três LLM judges avaliaram edit plans produzidos por um único planner model em dois harnesses. O estudo avaliou planos, não diffs executados nem taxas de defeitos em produção.
Experimentar o método no companion lab
O projeto harness-demo no commit 517353f3 é um pequeno exercício determinístico com 12 tasks sintéticas genéricas que abrangem alterações de código como fix-parser-edge-case, split-large-module e wire-browser-test. Não implementa o repositório de loja fictício.
Cada task fixture declara uma dificuldade e quatro condições booleanas: uma tool flaky, progresso perdido, uma lacuna de implementação não detetada e conclusão ambígua. O simulador deriva uma quinta condição para tasks difíceis que também precisam de um progress file: sem context_reset, a compaction preserva pressupostos stale. Um grader determinístico marca uma task como passed apenas quando a configuração selecionada trata todas as condições aplicáveis. Não é executado qualquer modelo ou service externo.
Os comandos respondem a perguntas diferentes:
make checkexecuta Ruff e sete unit tests, incluindo o validator que rejeita qualquer par de ablation que altere mais do que um componente.make runimprime uma teaching matrix cumulativa e, depois, cinco comparações válidas leave-one-component-out.make failuresidentifica a condição não tratada para cada task falhada. O harness completo deve terminar comall synthetic tasks pass.
make check
make run
make failures
A secção causal de make run é assim:
component control treatment delta
retry_policy 8/12 12/12 +4
progress_handoff 7/12 12/12 +5
evaluator 8/12 12/12 +4
fail_closed_acceptance 7/12 12/12 +5
context_reset 10/12 12/12 +2
Em cada linha, o control é a configuração completa com um componente removido; o treatment restaura apenas esse componente. A matriz cumulativa anterior é útil para orientação, mas algumas das suas linhas adjacentes acrescentam vários componentes de uma só vez e, por isso, não conseguem identificar uma causa.
O lab valida cada par declarado antes de o executar. Os seus regression tests incluem também um par intencionalmente inválido que altera simultaneamente a retry policy e o evaluator; o validator rejeita-o.
O lab compara os cinco component fields ao validar um par. Este runnable excerpt mostra a mesma guard num par válido de progress handoff:
from dataclasses import dataclass, fields
@dataclass(frozen=True)
class Config:
progress_handoff: bool = False
evaluator: bool = False
retry_policy: bool = False
fail_closed_acceptance: bool = False
context_reset: bool = False
def changed_components(control: Config, treatment: Config) -> tuple[str, ...]:
return tuple(
field.name
for field in fields(control)
if getattr(control, field.name) != getattr(treatment, field.name)
)
control = Config(progress_handoff=False, evaluator=True, retry_policy=True)
treatment = Config(progress_handoff=True, evaluator=True, retry_policy=True)
assert changed_components(control, treatment) == ("progress_handoff",)
Que camada abrir quando um run corre mal
A série avançou do reasoning loop para fora. Comece pela primeira falha que observar e investigue o componente responsável por esse trabalho. Um run pode envolver mais do que um componente:
| O que o run fez | Onde está a correção | Parte |
|---|---|---|
| Escolheu o próximo passo errado apesar de ter a informação certa à frente | Reasoning loop ou modelo | 1 |
| Repetiu trabalho ou perdeu uma decisão tomada uma hora antes | Context assembly e handoffs | 2 |
| Não conseguiu expressar a ação necessária ou interpretou mal um resultado devolvido | Tool contract | 3 |
| Fez algo que nunca deveria ter conseguido fazer | Permission rules | 4 |
| Perdeu tudo quando um worker morreu a meio de uma call | Session, checkpoint, sandbox | 5 |
| Declarou sucesso num trabalho que não estava concluído | Acceptance checks e traces | 6 |
Quatro linhas apontam para código do harness, enquanto a linha 5 aponta para o runtime. As instruções podem influenciar o comportamento, mas não substituem uma verificação de permissões, um checkpoint durável ou um acceptance test.
Começar com um loop e uma acceptance check
Eu começaria um harness de coding agent com um modelo capaz, instruções do repositório, algumas tools restritas, uma sandbox e um acceptance test explícito. Registaria as tool calls, os resultados, os custos e esse teste final num único trace, para que as primeiras falhas úteis fossem visíveis sem ter de as reconstruir a partir de logs de terminal e chat transcripts. Este é um baseline proposto, não evidência de um sistema deployed.
A partir daí, acrescente apenas aquilo que um trace justificar. Registe quem mantém cada componente, quantos tokens ou segundos acrescenta e que regression test justificaria removê-lo depois de uma atualização do modelo.
Seis meses mais tarde, alguém que veja progress_handoff=True deve conseguir encontrar os traces falhados que justificaram a sua existência e os regression cases que ainda o mantêm. Os traces explicam por que razão o componente existe; um mapa atual do comportamento explica onde intervir.
Se chegou aqui através de uma pesquisa, os cinco artigos anteriores construíram um sistema em torno de um reasoning loop:
- O loop escolhe o próximo passo.
- A memória fornece contexto e um checkpoint store Postgres real preserva-o.
- Os tool contracts definem ações e os formatos de resultado que as verificações posteriores podem ler.
- A segurança acrescenta o deny hook e o stop-hook validator. Ambos continuam a ser sketches no exemplo, mas assinalam os pontos de controlo.
- O runtime mantém o processo ativo entre sessões e falhas.
A série acrescentou também uma superfície MCP opcional e um evaluator node que verifica o draft report antes de este chegar a uma pessoa. Encaminhar o worker através de um proxy que guarda credentials continua a ser uma extensão proposta. Estes são componentes normais de código em torno de uma model call. O router é código do harness pela mesma razão: escolhe o padrão de reasoning antes de o reasoning loop começar.
Para o próximo componente opcional de assistência, mantenha juntos o trace falhado, a regra de aceitação e a comparação com esse componente desativado. Deixe-o de fora se não conseguir identificar o seu benefício. As restrições obrigatórias de segurança e aceitação não dependem dessa comparação.
Referências
- OpenAI, Unrolling the Codex agent loop.
- OpenAI, Harness engineering: leveraging Codex in an agent-first world.
- Lopopolo, Harness engineering: anthology, field guide, and agent context bundle.
- Anthropic Engineering, Effective harnesses for long-running agents.
- Anthropic Engineering, Harness design for long-running application development.
- LangChain, Improving Deep Agents with harness engineering.
- Yang et al., SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering.
- Wang et al., Harness Handbook: Making Evolving Agent Harnesses Readable, Navigable, and Editable, arXiv:2607.13285, 2026.
- AWS, Making retries safe with idempotent APIs.
- Model Context Protocol, Tools specification.
- Market Analyst Agent Repository
The Market Analyst Agent code is on GitHub.