~/beer-and-code
▪ próximo evento AI Engineering Lab 4ª Edição — Harness Engineering para Agentes Inteligentes · 14—15 Nov · 14 e 15 de novembro, das 09h às 13h — ao vivo via Google Meet garantir vaga ›
~ / tutoriais / harness-self-improving-gate-anti-regressao $
Tutoriais

Harness self-improving: como deixar o agente reescrever as próprias regras sem quebrar o que funciona

LS Lucas Souza · · 12 min de leitura
Harness self-improving: como deixar o agente reescrever as próprias regras sem quebrar o que funciona

Um harness self-improving é um harness de agente que lê as próprias falhas, propõe mudanças nas próprias regras, prompts e ferramentas, e só mantém o que comprovadamente melhorou. Os pesos do modelo não mudam. O que evolui é o código e o texto em volta dele.

Parece o sonho de todo mundo que já passou um domingo lendo trace de agente.

Só que tem um número que deveria estar colado no monitor de quem vai construir isso.

Num paper de setembro de 2026, o portão de validação de um harness desses rejeitou 383 mudanças propostas pelo próprio agente. 211 delas, 55%, consertavam a falha que as motivou e quebravam um caso que antes funcionava. Mais da metade das "melhorias" barradas eram troca de bug.

Neste tutorial você vai montar, em PHP, o loop completo de um harness self-improving com a peça que faz ele ser engenharia e não roleta: o gate anti-regressão. Regras versionadas em arquivo, mineração de falhas, proposta de correção mínima, validação com casos protegidos, promoção com autoridade provisória e poda do que parou de ajudar.

TL;DR

  • O que é: um loop em que o agente edita o próprio harness (regras, prompt, política) a partir das falhas, com um portão que barra qualquer mudança que regrida um caso que funcionava.
  • Stack/Modelos: PHP 8.3 + Laravel + Claude Messages API (qualquer modelo com saída estruturada serve), git para versionar as regras.
  • Custo/Acesso: chave paga de API. Cada proposta exige rodar a suíte de validação, então o custo do loop é dominado pelos reruns, não pela proposta.
  • Link útil: Self-Healing Harness for Runtime Oversight of Agent Self-Modification.

O contexto: por que harness self-improving virou tendência (e por que o gate é o que importa)

Até o ano passado, melhorar um agente era manual. Você lia o trace, achava no olho que faltava uma regra, editava o prompt, rodava de novo e torcia.

Em 2026 isso virou loop automático, e a pesquisa convergiu num mesmo desenho. Os principais exemplos:

  • Self-Harness, do Shanghai AI Lab, faz três etapas: minera fraquezas nos traces que falharam, propõe edições mínimas ligadas a um mecanismo de falha e só promove a edição se ela melhora sem degradação mensurável em tarefas reservadas. Uma das regras que o agente aprendeu foi um "loop breaker" depois de 50 chamadas de ferramenta. O ganho relativo reportado no Terminal-Bench-2.0 foi de 33% a 60%.
  • Meta-Harness coloca um agente propositor lendo, via sistema de arquivos, o código, as notas e os traces de todos os candidatos anteriores. Em classificação de texto online, superou o estado da arte em 7,7 pontos usando 4x menos tokens de contexto.
  • RRSI, do Google Research, adicionou o que faltava: um podador que remove mudanças "too small, too expensive, or no longer useful". O harness final saiu com 30% menos tokens de política.
  • Self-Healing Harness é o do número dos 55%. Nele, a regra proposta ganha autoridade provisória e só persiste entre episódios se melhora a falha que a disparou "without regression beyond a fixed margin on protected cases". Resultado: a versão com o harness bateu a versão sem ele em 16 de 16 pares no AppWorld, Terminal-Bench e τ²-Bench.

Repare no que todos têm em comum. Ninguém confia na autoavaliação do agente. Toda mudança passa por uma verificação externa antes de virar parte do harness.

Esse é o ponto que separa harness que evolui de harness que apodrece, e é o tipo de peça que vamos montar e quebrar de propósito, ao vivo, no AI Engineering Lab 4ª Edição, dias 14 e 15 de novembro, das 9h às 13h: o agente propõe a regra, o gate decide na frente de todo mundo.

Pré-requisitos

  • [ ] Um agente que já roda em loop de tool calling. Se ainda não tem, veja como construir seu primeiro harness em Laravel.
  • [ ] Uma suíte de casos com verificação determinística: teste que passa ou falha, estado final conferível, saída comparável. Sem isso, não há gate.
  • [ ] Traces salvos por execução (tool calls, erros, resposta final).
  • [ ] O diretório de regras do harness dentro de um repositório git.

Se você já montou o agent improvement loop, este post é a evolução dele. Lá a trava aceitava a mudança quando o score agregado subia. Aqui você vai ver por que isso não basta.

▪ Clã Beer and Code

Tutorial te mostra o caminho — no Clã você constrói junto. Aula ao vivo toda semana, projetos reais de Engenharia de IA, ao lado de quem já está em produção.

Entrar no Clã

Mão na massa: o loop do harness self-improving com gate anti-regressão

O loop tem seis passos:

rodar suíte → minerar falhas → propor 1 regra mínima → validar (gate) → provisória → promover ou descartar
                                                                         ↑
                                                         poda periódica remove regra inútil

Passo 1: harness como arquivos versionados

A primeira decisão é a mais importante: o agente nunca edita o código do harness diretamente. Ele edita um diretório de regras em texto, que o harness carrega no system prompt. Isso limita o raio de dano e deixa tudo auditável por diff, a mesma ideia que o Harness2 do Google e o Dreaming da Anthropic seguem.

harness/
├── base-prompt.md          # escrito por humano, o agente não toca
├── rules/
│   ├── active/             # regras promovidas
│   │   └── 0007-nao-repetir-comando-identico.md
│   └── provisional/        # regras em período de teste
└── suites/
    ├── protected.json      # casos que passam hoje e NÃO podem regredir
    └── holdout.json        # casos que o proposer nunca vê

O carregador é trivial, e isso é proposital:

class HarnessLoader
{
    public function systemPrompt(bool $includeProvisional = true): string
    {
        $parts = [file_get_contents(base_path('harness/base-prompt.md'))];

        $dirs = ['harness/rules/active'];
        if ($includeProvisional) {
            $dirs[] = 'harness/rules/provisional';
        }

        foreach ($dirs as $dir) {
            foreach (glob(base_path("$dir/*.md")) as $file) {
                $parts[] = file_get_contents($file);
            }
        }

        return implode("\n\n---\n\n", $parts);
    }
}

Passo 2: minerar falhas dos traces

Rode a suíte, colete os casos que falharam e agrupe por mecanismo de falha, não por caso. Dez casos que falharam porque o agente repetiu o mesmo comando são uma falha só.

class FailureMiner
{
    public function mine(array $results): array
    {
        $failures = array_filter($results, fn ($r) => ! $r['passed']);

        // Classificação barata primeiro: sinais determinísticos no trace
        return collect($failures)->groupBy(function ($r) {
            $calls = collect($r['trace'])->where('type', 'tool_call');

            return match (true) {
                $calls->count() > 50 => 'loop_sem_progresso',
                $calls->duplicates(fn ($c) => json_encode($c['input']))->isNotEmpty() => 'comando_repetido',
                str_contains($r['error'] ?? '', 'timeout') => 'timeout_de_ferramenta',
                default => 'nao_classificado',
            };
        })->map(fn ($group, $mechanism) => [
            'mechanism' => $mechanism,
            'cases' => $group->pluck('id')->all(),
            'sample_trace' => $group->first()['trace'],
        ])->values()->all();
    }
}

O balde nao_classificado vai para um LLM classificar depois. Comece pelo que é barato.

Passo 3: propor uma regra mínima por falha

O proposer recebe um mecanismo de falha e devolve uma regra curta. Uma mudança por proposta é o que permite saber, no gate, o que causou a melhora ou a regressão.

class RuleProposer
{
    public function propose(array $failure, string $currentPrompt): array
    {
        $response = Http::withHeaders([
            'x-api-key' => config('services.anthropic.key'),
            'anthropic-version' => '2023-06-01',
        ])->post('https://api.anthropic.com/v1/messages', [
            'model' => config('services.anthropic.model'),
            'max_tokens' => 1024,
            'system' => <<<'TXT'
                Você melhora o harness de um agente. Receba UM mecanismo de falha e o
                prompt atual. Proponha UMA regra operacional curta (máx. 3 frases) que
                ataque esse mecanismo. Não reescreva regras existentes. Não mencione
                casos específicos nem dados do benchmark: a regra precisa generalizar.
                TXT,
            'tools' => [[
                'name' => 'submit_rule',
                'description' => 'Envia a regra proposta.',
                'input_schema' => [
                    'type' => 'object',
                    'properties' => [
                        'slug' => ['type' => 'string', 'description' => 'kebab-case'],
                        'rule' => ['type' => 'string'],
                        'rationale' => ['type' => 'string'],
                    ],
                    'required' => ['slug', 'rule', 'rationale'],
                ],
            ]],
            'tool_choice' => ['type' => 'tool', 'name' => 'submit_rule'],
            'messages' => [[
                'role' => 'user',
                'content' => json_encode([
                    'mechanism' => $failure['mechanism'],
                    'trace' => array_slice($failure['sample_trace'], -30),
                    'current_prompt' => $currentPrompt,
                ]),
            ]],
        ])->throw()->json();

        return collect($response['content'])->firstWhere('type', 'tool_use')['input'];
    }
}

Duas travas já nascem aqui. O tool_choice força saída estruturada. E a instrução proíbe citar casos do benchmark, que é o tipo de proposta que o crítico do RRSI existe para barrar: regra que decora o teste em vez de generalizar.

Passo 4: o gate anti-regressão

Esta é a peça que importa. A regra candidata só passa se cumprir três condições ao mesmo tempo:

  1. Os casos que dispararam a falha melhoraram.
  2. Nenhum caso protegido regrediu. Não é a média. É caso a caso.
  3. O score no holdout, que o proposer nunca viu, não caiu além de uma margem.
class RegressionGate
{
    public function __construct(
        private SuiteRunner $runner,
        private float $holdoutMargin = 0.02,
    ) {}

    public function evaluate(array $rule, array $failure): GateResult
    {
        $baseline = $this->runner->snapshot();             // resultados atuais, caso a caso
        $candidate = $this->runner->withExtraRule($rule);  // mesma suíte, regra aplicada

        $triggerFixed = collect($failure['cases'])
            ->filter(fn ($id) => $candidate->passed($id))
            ->count();

        if ($triggerFixed === 0) {
            return GateResult::reject('não corrigiu a falha que motivou a regra');
        }

        $regressions = collect($baseline->passedIds('protected'))
            ->reject(fn ($id) => $candidate->passed($id))
            ->values();

        if ($regressions->isNotEmpty()) {
            return GateResult::reject('regrediu casos protegidos: ' . $regressions->implode(', '));
        }

        if ($candidate->score('holdout') < $baseline->score('holdout') - $this->holdoutMargin) {
            return GateResult::reject('caiu no holdout além da margem');
        }

        return GateResult::accept($triggerFixed, $candidate->score('holdout'));
    }
}

Por que caso a caso e não a média? Porque a média esconde exatamente os 55%. Uma regra que conserta 4 casos e quebra 2 sobe a média e passa numa trava de "score subiu". Num harness que roda sozinho por semanas, essas pequenas quebras se acumulam até ninguém saber mais por que o agente se comporta como se comporta.

Agentes são não determinísticos. Rode cada caso protegido mais de uma vez (3 é um bom começo) e trate como regressão só o que falha de forma consistente, senão o gate vai rejeitar tudo por ruído.

Passo 5: autoridade provisória, depois promoção

Passou no gate? Ainda não está promovida. Ela vai para rules/provisional/ e roda em produção, ou na próxima rodada de suíte, por um período. Esse é o desenho do Self-Healing Harness: autoridade provisória primeiro, persistência só com evidência.

class RulePromoter
{
    public function stage(array $rule): void
    {
        $path = "harness/rules/provisional/{$rule['slug']}.md";
        file_put_contents(base_path($path), $rule['rule']);

        Process::run(['git', 'add', $path]);
        Process::run(['git', 'commit', '-m', "harness: regra provisória {$rule['slug']}\n\n{$rule['rationale']}"]);
    }

    public function promote(string $slug): void
    {
        // Promoção vira PR, não commit direto: humano aprova o que vai para active/
        Process::run(['git', 'checkout', '-b', "harness/promote-{$slug}"]);
        Process::run(['git', 'mv', "harness/rules/provisional/{$slug}.md", "harness/rules/active/{$slug}.md"]);
        Process::run(['git', 'commit', '-m', "harness: promove {$slug}"]);
        Process::run(['gh', 'pr', 'create', '--fill']);
    }
}

O commit tem o rationale do proposer. Daqui a três meses, quando alguém perguntar por que existe a regra 0007, a resposta está no git log.

Passo 6: poda, porque regra também envelhece

Harness que só cresce vira o harness inchado que o modelo novo não precisa mais. De tempos em tempos, rode uma ablação: tire cada regra ativa, uma por vez, e rode a suíte.

foreach (glob(base_path('harness/rules/active/*.md')) as $file) {
    $without = $runner->withoutRule(basename($file));

    if ($without->score('protected') >= $baseline->score('protected')
        && $without->score('holdout') >= $baseline->score('holdout')) {
        $promoter->proposeRemoval(basename($file, '.md')); // também via PR
    }
}

Se tirar a regra não piora nada, ela é peso morto. É o podador do RRSI em versão de bolso.

Limitações e pontos de atenção

  • Sem verificação determinística, não há gate. Os próprios autores do Self-Harness desaconselham o padrão em domínios de avaliação subjetiva, como decisão médica, jurídica ou infraestrutura crítica. LLM-as-a-judge como única régua vira autoavaliação com outro nome. O mesmo problema aparece na miragem de progresso de agentes de longa duração.
  • O agente pode aprender o que não devia. O paper Practice Makes Unsafe testou 21 combinações de agente e método de auto-evolução: todas escreveram skills inseguras, e a evolução aumentou o dano em tarefas maliciosas em 17 delas. Inclua casos de segurança na suíte protegida e revise o que é promovido.
  • Prompt injection vira regra permanente. Um trace com conteúdo malicioso pode induzir o proposer a escrever uma regra ruim. Sanitize o trace antes de passar para o proposer e mantenha o base-prompt.md fora do alcance dele.
  • Custo. Cada proposta roda a suíte duas vezes, mais as repetições por não determinismo. Proponha em lote, valide em paralelo e limite propostas por rodada.
  • Overfitting. Sem holdout que o proposer nunca vê, o harness decora a suíte.

FAQ rápido

Harness self-improving é a mesma coisa que fine-tuning?

Não. Fine-tuning muda os pesos do modelo. Um harness self-improving muda o que está em volta: regras, prompt, ferramentas, memória. É mais barato, reversível com git revert e auditável por diff. Os sistemas citados aqui mantêm o modelo congelado.

Qual a diferença entre self-improving e self-healing?

Self-healing costuma se referir à recuperação em tempo de execução: retry, fallback, circuit breaker, checkpoint, sair de loop. Self-improving é aprender entre execuções e mudar o harness para a próxima. O paper do Self-Healing Harness mistura os dois: detecta, cura e valida a cura antes de persistir.

Posso deixar o gate aprovar sozinho, sem humano?

Para regras provisórias, sim, desde que a suíte protegida seja boa. Para promoção definitiva, comece com PR e aprovação humana. A Anthropic fez a mesma escolha no Dreaming: o job escreve um banco de memória novo e separado, e você decide se adota.

Quantos casos protegidos preciso?

Comece com os casos que passam hoje e que doeriam se quebrassem: fluxos críticos, casos de segurança, bugs já corrigidos. Algumas dezenas bem escolhidas valem mais que centenas genéricos. Cada regressão que escapar vira um caso protegido novo.

Conclusão

Harness self-improving não é o agente se programando sozinho. É um loop de engenharia com quatro peças: falha real como entrada, mudança mínima, gate caso a caso e poda.

Tire o gate e aquelas 211 mudanças, que consertavam uma coisa e quebravam outra, teriam entrado no harness sem ninguém perceber.

O próximo passo dessa tendência já está nos papers: modelos treinados só para editar harness, como o Harness-R1, e co-evolução de modelo e harness. O que não muda é o portão. Quanto mais autonomia o loop ganha, mais o gate vira a peça que você realmente precisa escrever bem.

Lucas Souza
Escrito por
Lucas Souza

{AI Engineer} — apaixonado por Laravel, arquitetura de software e construir produtos com impacto. Compartilho aqui tutoriais, descobertas e reflexões sobre o dia a dia de engenharia.

▪ Clã Beer and Code

Conteúdo é o que não falta. Falta quem desembaralhe: o que importa agora é como implementar do jeito certo. No Clã você tem isso ao vivo, toda semana, com quem já filtrou o ruído.

Entrar no Clã
Conheça o Clã Beer and Code
tocando