Guia completo de harness engineering: como construir agentes de IA no estilo Claude Code
Apenas um bom prompt não domina um LLM. Aprenda a tecer ferramentas, contexto e loops de controle em um harness, com código executável e a arquitetura do Claude Code como guia.
A era do “joga um prompt no ChatGPT e pronto” acabou. Desde 2025, o centro de gravidade da engenharia de IA vem se deslocando rapidamente para o harness engineering. É uma das palavras-chave que mais aparecem nos posts internos da Anthropic e nas pesquisas de agentes da OpenAI.
Ainda assim, pergunte a alguém “o que é um harness?” e poucos responderão com clareza. Neste artigo, destrincho o harness engineering usando código que funciona e a própria arquitetura do Claude Code como estudo de caso. Ao final, você terá o necessário para montar seu próprio agente do zero.
Um harness é o “andaime” em torno da IA
“Harness” significa originalmente arreio de cavalo ou cinto de segurança. No mundo do software, pense no “test harness”: a estrutura externa que permite que algo realmente rode.
No contexto de IA, harness é a camada envoltória em torno do LLM. Concretamente, ele reúne tudo de que o modelo precisa para resolver tarefas do mundo real:
- Ferramentas: ler arquivos, executar comandos, chamar APIs etc.
- Gestão de contexto: o que lembrar, o que esquecer, o que comprimir
- Loop de controle: quando chamar, quando parar, quando tentar de novo
- Permissões e salvaguardas: impedir que operações destrutivas rodem sozinhas
- Memória: conhecimento que persiste entre sessões
O prompt é apenas uma das entradas desse harness. Com um harness fraco, até o prompt mais engenhoso esbarra em um teto de desempenho. Por isso se ouve cada vez mais: “só prompt engineering não basta.”
Por que o harness importa: pense em loops OODA
Sozinho, o LLM só sabe “gerar o próximo token”. Para resolver tarefas reais, é preciso girar um loop OODA (Observe → Orient → Decide → Act), emprestado da estratégia militar.
| Fase | Conteúdo | Responsável |
|---|---|---|
| Observe (observar) | Ler o ambiente (arquivos, consultas a BD) | Harness |
| Orient (orientar) | Organizar a informação e entregá-la ao LLM | Harness |
| Decide (decidir) | Escolher o próximo movimento | LLM |
| Act (agir) | Executar (comandos, chamadas de API) | Harness |
Como se vê, três das quatro fases pertencem ao harness. O LLM só brilha no Decide. A qualidade do andaime em volta define a qualidade do agente inteiro.
Três níveis de harness, por exemplos
Vamos resolver a mesma tarefa “gerar um post de blog” em três níveis crescentes de harness.
Nível 1: chamada crua à API (quase sem harness)
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const res = await client.messages.create({
model: "claude-opus-4-6",
max_tokens: 4096,
messages: [{ role: "user", content: "Escreva um post de blog" }],
});
console.log(res.content[0].text);
Resultado: texto genérico e vazio. Tema e estrutura mudam a cada execução.
Nível 2: dar ferramentas (harness intermediário)
const tools = [
{
name: "read_existing_posts",
description: "Retorna a lista de posts existentes com seus títulos",
input_schema: { type: "object", properties: {} },
},
{
name: "write_post",
description: "Grava um arquivo MDX",
input_schema: {
type: "object",
properties: {
slug: { type: "string" },
frontmatter: { type: "object" },
body: { type: "string" },
},
required: ["slug", "frontmatter", "body"],
},
},
];
async function runAgent(userGoal: string) {
let messages = [{ role: "user", content: userGoal }];
while (true) {
const res = await client.messages.create({
model: "claude-opus-4-6",
max_tokens: 4096,
tools,
messages,
});
if (res.stop_reason === "end_turn") break;
// O harness executa a chamada da ferramenta
const toolUse = res.content.find((c) => c.type === "tool_use");
const result = await executeTool(toolUse.name, toolUse.input);
messages.push({ role: "assistant", content: res.content });
messages.push({
role: "user",
content: [{ type: "tool_result", tool_use_id: toolUse.id, content: result }],
});
}
}
Resultado: um tema não duplicado é escolhido e um MDX no formato correto é produzido. Apenas adicionar ferramentas já muda a qualidade radicalmente.
Nível 3: um harness completo no patamar do Claude Code
- Loop autônomo (aprovação do usuário, retries em erros)
- Compressão de contexto (resumir conversas longas para economizar tokens)
- Delegação para subagentes (traduzir em contexto isolado)
- Prompt caching (não reenviar o prefixo estático)
- Hooks (lint automático antes de commit)
Montar tudo isso à mão é um projeto sério. Por isso estudar o Claude Code como implementação de referência compensa.
Desmontando o harness do Claude Code
O Claude Code é o harness de agente mais polido da Anthropic. Ele se decompõe em cinco camadas.
Camada 1: design de ferramentas
Já vêm Read, Edit, Write, Bash, Glob, Grep, Agent etc. Note a granularidade:
Grepnão é ogrepcomum, mas um wrapper de ripgrep — preciso e rápidoEditnão reescreve o arquivo inteiro, mas substitui um trecho específico — diff mínimoAgentgera um subagente e isola seu contexto
A qualidade das ferramentas se traduz diretamente na qualidade do agente. “Se funciona, tá bom” não serve. Projete ferramentas pensando em idempotência, mensagens de erro claras e responsabilidade única.
Camada 2: contexto em camadas
~/.claude/CLAUDE.md ← regras globais
./CLAUDE.md ← regras do projeto (carregamento automático)
~/.claude/memory/ ← memória de longo prazo (entre sessões)
├── user_profile.md
├── feedback_xxx.md
└── project_xxx.md
histórico da conversa ← trocas recentes
tarefas/plano ← progresso da sessão atual
Cada camada tem vida útil e papel diferentes. Escrever no lugar errado faz a informação sumir depressa ou, pior, deixa dados velhos convivendo. “Só para esta sessão” vai em tarefas; “uso recorrente” vai em memória.
Camada 3: delegação a subagentes
Com a ferramenta Agent, você inicia outro agente em contexto próprio.
# O principal só dá instruções; o trabalho pesado vai para o subagente
Agent(
subagent_type: "general-purpose",
prompt: "Traduza blog/harness.mdx para inglês + 8 idiomas,
salve cada versão em blog-{lang}/ e então reporte"
)
Assim, o contexto principal não fica sujo com logs barulhentos. Logs longos de build, traduções intermediárias, dumps de busca — sempre que você só quer o produto final, pode terceirizar.
Camada 4: hooks (processamento determinístico)
Pelo .claude/settings.json é possível encaixar comandos de shell antes e depois das chamadas de ferramenta.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "npx tsc --noEmit" }
]
}
]
}
}
Após cada edição, a checagem de tipos roda automaticamente. Tudo aquilo que “deveria ser resolvido de forma determinística em vez de pedir ao LLM toda hora” vira hook.
Camada 5: modos de permissão
{
"permissions": {
"allow": ["Read", "Grep", "Glob"],
"deny": ["Bash(rm -rf*)", "Bash(git push --force*)"],
"ask": ["Write", "Edit", "Bash"]
}
}
Negue comandos destrutivos de forma explícita e exija aprovação para escritas. Acidentes acontecem quando algo roda sem supervisão, então esta camada decide a segurança operacional.
Cinco armadilhas clássicas
1. Ferramentas demais Com 30 ferramentas, o modelo se perde na escolha e a precisão cai. Regra prática: 5-15. Capacidades extras vão para subagentes.
2. Não aproveitar prompt caching
Sem cache_control na API do Claude, você reenvia o longo system prompt inteiro a cada turno — e paga por isso. Fique atento ao TTL de 5 minutos e coloque a parte estática em cache.
messages: [{
role: "system",
content: [
{ type: "text", text: longStaticInstructions,
cache_control: { type: "ephemeral" } }, // ← esta linha
{ type: "text", text: dynamicContext },
],
}]
3. Mensagens de erro ilegíveis para o LLM
Se uma ferramenta só devolve Error: undefined, o modelo não consegue se autocorrigir. Diga o que falhou e como consertar.
throw new Error(
`Arquivo '${path}' não existe. ` +
`Arquivos atualmente em scripts/: ${list.join(", ")}`
);
4. Pular a aprovação humana Aprovar automaticamente ações destrutivas (excluir, force push, update em BD) garante um desastre em algum momento. Padrão: pergunta para escrita, nega para remoção.
5. Não arrumar a memória
Informação velha empurra o agente a premissas erradas. Memória também pede podas periódicas (no Claude Code, /compact ou edição manual).
Rode seu mini harness
Para fechar, um harness mínimo em Node.js + TypeScript.
// mini-harness.ts
import Anthropic from "@anthropic-ai/sdk";
import { readFileSync, writeFileSync } from "fs";
const client = new Anthropic();
const tools = [
{ name: "read_file",
description: "Lê um arquivo de texto",
input_schema: { type: "object", properties: { path: { type: "string" } }, required: ["path"] } },
{ name: "write_file",
description: "Grava um arquivo de texto",
input_schema: { type: "object", properties: { path: { type: "string" }, content: { type: "string" } }, required: ["path", "content"] } },
];
const executors = {
read_file: ({ path }) => readFileSync(path, "utf-8"),
write_file: ({ path, content }) => { writeFileSync(path, content); return `written ${path}`; },
};
async function loop(goal: string, maxSteps = 10) {
const messages: any[] = [{ role: "user", content: goal }];
for (let i = 0; i < maxSteps; i++) {
const res = await client.messages.create({
model: "claude-opus-4-6", max_tokens: 4096, tools, messages,
});
messages.push({ role: "assistant", content: res.content });
if (res.stop_reason === "end_turn") return res.content;
const toolUse = res.content.find((c: any) => c.type === "tool_use") as any;
if (!toolUse) return res.content;
const result = executors[toolUse.name](toolUse.input);
messages.push({
role: "user",
content: [{ type: "tool_result", tool_use_id: toolUse.id, content: String(result) }],
});
}
}
await loop("Leia README.md e salve um resumo de 3 linhas em TL;DR.md");
Isso já basta para ter um mini-agente capaz de ler um arquivo existente e gravar um novo. Acrescente uma ferramenta Grep, outra Bash e outra Agent, e você tem um Claude Code em miniatura.
Conclusão: do redator de prompts ao arquiteto de harness
| Visão anterior | Visão atual |
|---|---|
| Bom prompt = bom resultado | Bom harness = bom resultado |
| Escolher um modelo | Projetar modelo + ferramentas + contexto + permissões |
| Perguntas pontuais | Operação contínua em loop |
O Claude Code é o melhor material didático para absorver essa virada de perspectiva. Não se limite a usá-lo: desmonte a engrenagem e leve as ideias para o seu próprio agente. É a postura exigida dos engenheiros de IA a partir de 2026.
Comece copiando o mini harness acima e rodando-o. Em dez minutos, você terá dado o primeiro passo rumo ao seu próprio agente.
Artigos relacionados
- 10 padrões de subagentes no Claude Code
- Boas práticas de CLAUDE.md
- Técnicas de otimização de tokens no Claude Code
- Guia de permissões do Claude Code
Referências
Leve seu fluxo no Claude Code a outro nível
50 modelos de prompt testados em campo, prontos para colar direto no Claude Code.
PDF gratuito: Cheatsheet do Claude Code em 5 minutos
Basta informar seu e-mail e enviamos na hora o cheatsheet em uma página A4.
Cuidamos dos seus dados pessoais e nunca enviamos spam.
Sobre o autor
Masa
Engenheiro apaixonado por Claude Code. Mantém o claudecode-lab.com, uma mídia tech em 10 idiomas com mais de 2.000 páginas.
Artigos relacionados
Guia Completo de Segurança do Claude Code: Chaves API, Permissões e Proteção da Produção
Um guia prático de segurança para usar o Claude Code com segurança. Do gerenciamento de chaves API às configurações de permissões, automação baseada em Hooks e proteção do ambiente de produção — com exemplos de código funcionais.
7 Casos de Falha de Segurança no Claude Code | Incidentes Reais e Prevenção
Sete incidentes de segurança reais com Claude Code: vazamentos de .env, exclusão de BD em produção, explosão de fatura e mais — com análise de causa raiz e código de prevenção.
Guia Completo de Permissões do Claude Code | settings.json, Hooks e Allowlist Explicados
Guia completo das configurações de permissão do Claude Code. Aprenda a usar allow/deny/ask, automação com Hooks, settings.json por ambiente e padrões práticos — com código funcional.