Tips & Tricks

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.

FaseConteúdoResponsável
Observe (observar)Ler o ambiente (arquivos, consultas a BD)Harness
Orient (orientar)Organizar a informação e entregá-la ao LLMHarness
Decide (decidir)Escolher o próximo movimentoLLM
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:

  • Grep não é o grep comum, mas um wrapper de ripgrep — preciso e rápido
  • Edit não reescreve o arquivo inteiro, mas substitui um trecho específico — diff mínimo
  • Agent gera 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 anteriorVisão atual
Bom prompt = bom resultadoBom harness = bom resultado
Escolher um modeloProjetar modelo + ferramentas + contexto + permissões
Perguntas pontuaisOperaçã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

Referências

#claude-code #agent-sdk #harness #prompt-engineering #llm #anthropic

Leve seu fluxo no Claude Code a outro nível

50 modelos de prompt testados em campo, prontos para colar direto no Claude Code.

Grátis

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.

Masa

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.