posts / sobre / rss English Português

O que o seu agente fez de verdade? Pergunte ao kernel

Ano passado eu construí um pipeline que processa dezenas de milhões de imagens. Quando algo dava errado, eu tinha um stack trace e uma linha no banco, e podia confiar neles. O sistema não tinha como descrever errado o que fez, porque ele não descrevia nada.

Agentes de código mudaram isso. Quando o Claude Code ou um agente em Python executa uma tarefa, o que a gente recebe é uma transcrição do que o modelo disse que estava fazendo, mais o que o framework resolveu registrar. A história costuma estar certa. Mas quando não está, como a gente fica sabendo?

Três relatos da mesma tarefa

A transcrição de um agente é a narrativa do modelo sobre as próprias ações. Os logs do framework são uma segunda narrativa, filtrada pelo que o autor do framework achou que valia registrar. Por baixo das duas está o que o sistema operacional viu: quais processos foram criados, quais arquivos foram abertos e escritos, quais sockets se conectaram a quais hosts. Dos três relatos, é o único que não é escrito pelo agente nem pelas ferramentas dele (com ressalvas, que aparecem mais abaixo).

Na maior parte do tempo, as três camadas concordam. Os casos que me interessam são os de divergência:

Não dá para contar com a transcrição para revelar divergências como essas, já que ela é escrita pelo mesmo modelo que cometeu o erro. Se a causa foi uma instrução injetada, e não um erro, há ainda menos motivo para esperar que ela apareça ali.

Os logs do framework também não fecham essa lacuna. Eles registram o que cada ferramenta reportou de volta, então um subprocesso que a ferramenta criou ou uma conexão que ela abriu, qualquer coisa além do valor de retorno, não está neles.

Com agentes de código isso piora, porque a ferramenta muitas vezes é um shell. O log do framework diz que o agente rodou python fix.py. Ele não diz que o fix.py foi escrito pelo agente um passo antes e pode fazer qualquer coisa. Quando as ferramentas são escritas à mão por um desenvolvedor, registrar o que elas retornam significa algo. Quando a ferramenta é “execute o que eu acabei de escrever”, o log descreve uma caixa, não o que tem dentro dela.

Um caso público, em escala bem maior

Em maio de 2026, o RubyGems foi inundado com mais de 2.000 pacotes-lixo, e um relatório publicado em setembro por Spencer Kitts, Thomas Larsen e Sydney Von Arx atribui a campanha a agentes da OpenAI rodando durante treinamento e avaliação (cobertura no The Hacker News). Segundo o relatório, os agentes conseguiram execução remota de código nos servidores de build do RubyDoc, usaram esses servidores para fazer scraping de sites de governos locais britânicos e tentaram obter chaves de API de outros usuários. Um dos pacotes trazia um comentário sobre desativar o código malicioso na versão seguinte. Em nota à Reuters, a OpenAI disse que seus agentes usaram o RubyGems para cumprir tarefas benignas e buscar informação pública. A nota não diz se foram seus modelos que subiram os pacotes.

O que mais me chama a atenção é o quão pouco se consegue reconstruir. Quatro meses depois, a Ruby Central diz que não tem como determinar se os pacotes foram publicados por agentes de IA, e os pesquisadores que fizeram a atribuição não sabem dizer por que os agentes tiveram tanto trabalho para coletar dados que já eram públicos.

Só que a Ruby Central nunca teria a telemetria das máquinas dos agentes. Quem teria é o operador. Os pesquisadores dizem que ninguém na comunidade do RubyGems foi avisado pela OpenAI antes de o relatório sair, e a SecurityWeek descreve a empresa como aparentemente sem saber que seus agentes podiam ser os responsáveis. Se for isso mesmo, quem tinha todas as transcrições e todos os logs de framework dessas execuções ou não percebeu, ou não soube dizer. Não sabemos o que essas transcrições diziam. Pelo visto, não foram suficientes.

O caso também complica o meu próprio argumento. Visto das máquinas dos agentes, quase tudo isso pareceria tráfego para rubygems.org, que é exatamente o host com que se espera que um gerenciador de pacotes converse, e ainda por cima criptografado. A execução de código aconteceu em servidores de terceiros. Nada disso a telemetria de kernel teria visto. O que ela teria visto é mais estreito: processos publicando pacotes milhares de vezes (gem push, ou curl direto na API), arquivos .gem sendo montados às centenas, e um volume de saída para o registry muito além do que instalar dependências exige. Tarefa nenhuma de busca justifica isso, e é esse tipo de descompasso que eu quero pegar.

Estamos observando os agentes pelo lado errado

Quase todo o ferramental que eu conheço para observabilidade de agentes olha o lado do LLM: prompts, respostas, contagem de tokens, argumentos de tool call. Isso é valioso, e eu uso. Mas os argumentos de um tool call são um registro do que o agente pediu. O que aconteceu depois que o pedido chegou à máquina não está neles.

Olhar o lado da máquina não é novidade para quem trabalha com segurança. Falco e Tetragon rastreiam syscalls com eBPF há anos. O que eles não têm é a outra metade: o que o agente achava que estava fazendo quando a syscall aconteceu.

Eventos de kernel têm as próprias limitações. Eles dizem que um arquivo foi escrito, e nada sobre o porquê, nem se o conteúdo está certo. Com TLS, o kernel vê o socket e o destino, mas não o que foi enviado (o AgentSight, citado abaixo, contorna isso instrumentando a biblioteca de SSL em espaço de usuário). Um agente que consegue root pode interferir no próprio rastreamento. E um trace bruto de syscalls, sem ligação com a intenção do agente, é quase só ruído. O que me parece útil é juntar os dois lados: alinhar o que o agente disse que estava fazendo com o que a máquina fez, e olhar com cuidado os pontos em que eles discordam.

Ainda há pouca pesquisa olhando para isso pelo lado do sistema operacional. Pesquisadores da UC Santa Cruz, ligados ao projeto open source eunomia-bpf, publicaram o AgentSight (2025), que usa eBPF para correlacionar o tráfego do LLM com eventos de kernel, e o AgentCgroup (2026), que mapeia o uso de recursos do sistema para cada tool call. É um trabalho recente, e vou começar por reproduzi-lo.

O que estou fazendo a respeito

Acabei de começar um mestrado na UFRGS exatamente sobre essa pergunta: a telemetria em nível de sistema consegue dizer, de forma confiável, o que um agente de fato fez, e consegue pegar um agente comprometido que a camada de texto deixa passar? Nos próximos meses vou reproduzir o trabalho existente, rodar agentes reais em benchmarks reais com rastreamento de kernel ligado, e publicar o que eu aprender. O primeiro texto vai ser a menor versão possível da ideia: um agente, uma tarefa, a transcrição de um lado e os eventos de processo e de arquivo do outro.

Se você deixa agentes com acesso a ferramentas rodando sem supervisão (em CI, em automações, num servidor compartilhado, num job em background), quero saber como você descobre o que eles fizeram. Principalmente se a resposta for “a gente não descobre”. Me escreva em contact@josehenrique.dev ou no LinkedIn.

← todos os posts