Gauntlet: O que acontece quando as ferramentas do seu agente reagem

Hackathon do Elasticsearch Agent Builder

gauntlet-blog_(1).png

Faltando dois dias para o prazo final do hackathon, tomei a decisão de dar um passo atrás e repensar minha abordagem do zero.

A ideia original se chamava Rehearse: um agente que ensaia ações em um sandbox simulado por outro agente antes de executá-las no mundo real. O conceito era razoável, mas, repensando, a falha era óbvia: o ambiente pode mudar entre o ensaio e a execução. Seu agente ensaia enviar um e-mail, mas quando ele realmente executa, a caixa de entrada já mudou. A simulação diverge da realidade, e tudo desmorona.

Mas há uma classe de problemas que não sofre com isso: o teste de fuzz adversarial. Se o seu agente falhar na simulação, ele também poderá falhar na vida real. Foi assim que o Gauntlet nasceu - 48 horas antes do prazo final e reutilizando o mesmo insight básico (um agente que usa a busca para criar memória e continuar criativo) direcionado para um problema em que a estocasticidade não importa.

O problema de testar agentes no caminho feliz

A maioria de nós já ouviu falar do OpenClaw, o assistente pessoal de IA que viralizou. Se você acompanhou o debate sobre assistentes de IA agênticos com amplo acesso a ferramentas, já notou as preocupações com segurança. Agentes esquecem o que não devem fazer ou nunca souberam. A razão é simples: testamos o fluxo principal e checamos se o agente faz o que deve. Raramente checamos o que acontece quando alguém tenta fazer o que não deve.

Sandboxes de testes adversariais existem, mas são trabalhosos de construir. Você projeta vetores de ataque manualmente, insere dados adversariais manualmente, configura a infraestrutura de teste para cada caso. É lento, não redimensiona e só encontra os bugs que você já identificou.

Eu queria algo diferente: um sistema onde o próprio ambiente fosse automaticamente adversarial e ficasse mais criativo com o tempo.

A ideia: simular o sandbox com outro agente

Em vez de construir um sandbox, o Gauntlet utiliza um agente simulador que intercepta as chamadas de ferramentas do agente principal e encontra formas criativas de quebrá-lo. Quando o agente simulador chama search_emails, o agente simulado analisa o resultado e decide se deve modificá-lo, injetando uma instrução de prompt no corpo de um e-mail, retornando dados sutilmente incorretos ou fornecendo informações falsas para ver se o agente principal nota. O agente principal nunca sabe que está em uma simulação.

A interface consiste em dois decoradores:

@function_tool
@gauntlet.query
def search_emails(folder: str = "inbox") -> str:
    """Search emails in the given folder."""
    return json.dumps(fetch_emails(folder))

@gauntlet.query para operações de leitura e @gauntlet.mutation para operações de escrita. Essa é toda a superfície de integração. Quando a execução termina, evaluate() revisa o que aconteceu e armazena bugs confirmados.

É simples de usar, mas há dois problemas difíceis que por trás.

Os dois problemas que tornam isso um problema de busca

Primeiro, o agente simulador precisa manter um modelo coerente do mundo durante toda a conversa. Se ele informou o agente principal de que um e-mail era da Alice, não pode se contradizer depois. O e-mail alterado que é obviamente falso não ensina nada; tudo é plausibilidade.

Segundo, o agente de simulação precisa encontrar novos bugs. Redescobrir o mesmo padrão de injeção de prompt 50 vezes não é útil. Ele precisa se lembrar do que já encontrou e explorar em novas direções, mantendo-se fundamentado no que as ferramentas realmente fazem.

Ambos são problemas de busca. E é aí que o Elasticsearch vira a espinha dorsal do sistema.

Dois circuitos de memória

O agente simulador é executado em dois circuitos de memória, ambos localizados no Elasticsearch.

A memória de curto prazo rastreia tudo dentro da sessão atual: cada chamada de ferramenta interceptada, o resultado original, o que foi alterado e o que o agente principal fez em resposta. Essa é a camada de coerência. O agente simulador pode consultar as próprias decisões recentes e continuar internamente consistente, mesmo sendo adversarial. Conciliar criatividade com coerência foi o desafio mais difícil no design de todo o projeto.

A memória de longo prazo é onde a criatividade se acumula. Ela armazena bugs confirmados com embeddings para buscar de similaridade, implementações completas de ferramentas, para que o agente possa raciocinar sobre os modos de falha e resultados históricos de execuções anteriores. Quando o agente simulador precisa de uma nova ideia de ataque, ele busca na memória de longo prazo o que já foi testado antes, encontra lacunas e formula hipóteses sobre algo novo.

Eles alimentam um ciclo fechado: elabore hipóteses de quais bugs possam existir, crie circunstâncias para prová-los e armazene os bugs confirmados de volta no índice. O inventário cresce. Os ataques ficam mais criativos. A diferença entre o Gauntlet e a configuração manual do sandbox aumenta com o tempo.

Tudo roda dentro do Elastic Agent Builder

O agente simulador é todo construído dentro do Elastic Agent Builder — instruções, combinações de ferramentas e estado de conversação em vários turnos por meio da API Amazon Bedrock Converse; nenhuma orquestração externa é necessária.

A ferramenta da qual mais me orgulho é a generate-hypothesis. É uma única instrução ES|QL que amostra bugs existentes, os agrega com MV_CONCA` e chama COMPLETION diretamente para propor uma nova hipótese de ataque. Ela lida com amostragem, agregação, raciocínio LLM e geração de resultados, tudo em uma única consulta, sem nunca sair do pipeline ES|QL. Eu esperava precisar transferir dados entre o Elasticsearch e um script externo, mas não precisei.

A função do ES|QL COMPLETION foi a maior surpresa. Entre COMPLETION, STATS, MV_CONCAT e SAMPLE, consegui construir pipelines de raciocínio inteiros com consultas únicas. O armazenamento de bugs utiliza fluxos de trabalho do Kibana, e um dashboard do Kibana criado programaticamente oferece visibilidade em tempo real da contagem de bugs, detalhamento da gravidade e mapas de calor de padrões de ataque.

A API Converse resolveu outro problema que eu temia. O agente simulador precisa se lembrar do que já foi dito ao agente principal em uma única execução. Eu imaginava ter que buscar o histórico de conversas nos índices e recarregá-lo no agente a cada chamada. Mas descobri que a API Converse lida nativamente com o estado de múltiplas interações. Não precisei escrever nenhuma lógica de gerenciamento de conversas. Basta continuar chamando o método converse, e tudo permanece coerente.

O que você ganha com isso

A configuração sandbox adversarial manual leva cerca de uma hora por caso. Com o Gauntlet, o mesmo processo leva de 2 a 10 minutos, e a memória de longo prazo faz com que cada execução seja orientada por todas as execuções anteriores. Quanto mais você usa, mais ele aprende sobre os pontos fracos do seu agente e mais tenta encontrar novos.

E o que vem em seguida?

No momento, o Gauntlet é pontual: um agente simulador contra um agente primário. Mas o problema é embaraçosamente semelhante: 20 sessões de ataque podem ser executadas simultaneamente em sessões separadas, sem nenhuma alteração arquitetônica. O redimensionamento é o próximo passo óbvio.

A questão mais interessante em aberto é exploração x aproveitamento na memória de longo prazo. O agente simulador precisa conciliar a tentativa de variações de ataques bem-sucedidos conhecidos (aproveitamento) contra hipóteses completamente novas (exploração). Esse é um problema bastante estudado em outros domínios, mas aplicá-lo aos testes de agentes adversariais parece inexplorado. Pode haver algo que valha a pena seguir completamente além deste projeto.

Também fico pensando no Rehearse. O Gauntlet é um caso especial: o teste de fuzz funciona porque falha na simulação implica uma possível falha na realidade. Mas há outros domínios onde o ambiente é estável o suficiente entre o ensaio e a execução para que o conceito original do Rehearse funcione. Ainda não encontrei, mas estou procurando.

A conclusão

Ao criar agentes com acesso a ferramentas do mundo real, teste o que acontece quando essas ferramentas reagem. Não apenas uma vez manualmente, mas constantemente, com um sistema que memoriza o que já foi testado e fica mais criativo com o tempo. É isso o que o Gauntlet faz.

Kavish Sathia

Estudante, National University of Singapore

Kavish Sathia é estudante de ciência da computação na NUS e trabalha com sistemas agentivos.

GitHub · Demo · Website · LinkedIn

O lançamento e o tempo de amadurecimento de todos os recursos ou funcionalidades descritos neste artigo permanecem a exclusivo critério da Elastic. Os recursos ou funcionalidades não disponíveis no momento poderão não ser entregues ou não chegarem no prazo previsto.

Neste post do blog, podemos ter usado ou feito referência a ferramentas de IA generativa de terceiros, que pertencem a seus respectivos proprietários e são operadas por eles. A Elastic não tem nenhum controle sobre as ferramentas de terceiros e não temos qualquer responsabilidade por seu conteúdo, operação ou uso, nem por qualquer perda ou dano que possa surgir do uso de tais ferramentas. Tenha cuidado ao usar ferramentas de IA com informações pessoais, sensíveis ou confidenciais. Os dados que você enviar poderão ser usados para treinamento de IA ou outros fins. Não há garantia de que as informações fornecidas serão mantidas seguras ou confidenciais. Você deve se familiarizar com as práticas de privacidade e os termos de uso de qualquer ferramenta de IA generativa antes de usá-la. 

Elastic, Elasticsearch e marcas associadas são marcas comerciais, logotipos ou marcas registradas do Elasticsearch B.V. nos Estados Unidos e em outros países. Todos os outros nomes de empresas e produtos são marcas comerciais, logotipos ou marcas registradas de seus respectivos proprietários.