Usando benchmarks semânticos para criar um agente de texto para consulta com autoaprimoramento

@levibkline
INGLÊS03 de set. de 2026
160K
70
2
6
12

TL;DR

Uma análise técnica aprofundada sobre a otimização de agentes de texto para consulta usando representações intermediárias, compiladores determinísticos e benchmarks semânticos para alcançar 2 segundos de latência e 97% de precisão.

Nosso agente de texto para consulta passou de 45 segundos em modelos de fronteira para 2 segundos no GLM 5.3 Flash, com a mesma precisão e 1/20 do custo.

Grande parte do nosso trabalho recente com IA na Conversion tem se concentrado em inteligência de marketing geral.

As equipes de automação de marketing realizam uma ampla gama de tarefas em vários sistemas: pesquisar contas, construir públicos, planejar campanhas, criar conteúdo e agir com base em dados de desempenho. Temos construído agentes que conseguem raciocinar sobre esses fluxos de trabalho e usar as mesmas ferramentas que um profissional de marketing qualificado usaria.

Esses sistemas se beneficiam de modelos capazes e de uso geral. O trabalho é aberto, e um bom julgamento é muitas vezes mais importante do que concluir uma tarefa rapidamente.

Mas também tínhamos um acúmulo de funcionalidades de IA menores e mais focadas. Uma delas eram os filtros de linguagem natural: permitir que um usuário descrevesse um público em inglês simples e transformasse essa descrição em um filtro que ele pudesse inspecionar e editar no construtor de declarações existente da Conversion. (Na Conversion, um filtro é chamado de declaração.)

No início, isso parecia uma tarefa direta de geração estruturada. Dar a um modelo os campos disponíveis, descrever o formato de saída e pedir que ele produzisse JSON. Acabou sendo consideravelmente mais difícil do que isso.

Levi - inline image

Declaração composta gerada em menos de 5 segundos usando GLM 5.3 Flash.

Veja o exemplo a seguir:

Encontre contatos que enviaram o formulário de demonstração pelo menos uma vez nos últimos 30 dias e trabalham em uma empresa de software com uma oportunidade em aberto no valor de mais de R$ 50.000,00.

Isso exige que o sistema:

  • Encontre o formulário específico que o usuário quer dizer com "o formulário de demonstração"
  • Determine qual campo representa o setor de uma empresa
  • Aprenda como aquele espaço de trabalho representa "software", o que significa olhar para os valores realmente armazenados naquele campo, em vez de adivinhar
  • Navegue de um contato para sua empresa e, em seguida, para as oportunidades dessa empresa
  • Garanta que "em aberto" e "mais de R$ 50.000,00" se apliquem à mesma oportunidade
  • Aplique uma janela de evento relativa

Também precisava fazer tudo isso rápido o suficiente para parecer uma interface de filtro, não um agente de pesquisa.

O que parecia uma pequena tarefa de engenharia de prompt havia se tornado um problema restrito de texto para consulta. Resolvê-lo exigiu um agente que usa ferramentas, uma representação intermediária (IR), um compilador determinístico e um benchmark semântico.

Executamos oito modelos no benchmark resultante, o Statement Bench, incluindo Claude Opus 5, Kimi K3, GLM 5.3 Flash e o lançamento do Gemini 3.8 Flash desta manhã. Os resultados estão abaixo.

Dando ferramentas ao agente

A maior parte das informações necessárias para responder à solicitação acima é específica do ambiente do cliente. Um único espaço de trabalho pode conter centenas de milhões de valores de campo históricos, juntamente com seus ativos e objetos. Por razões óbvias, não poderíamos colocar tudo isso em um único prompt.

Nossa primeira decisão arquitetural útil foi parar de tratar o problema como geração estruturada comum. Em vez disso, o modelo recebe um pequeno conjunto de ferramentas. Ele pode pesquisar campos, inspecionar valores históricos e resolver ativos específicos do negócio, como formulários, campanhas, e-mails e públicos. Ele usa essas ferramentas apenas quando a solicitação as exige.

Grande parte dessa infraestrutura de pesquisa veio do nosso trabalho recente de Pesquisa Global, que fornece pesquisa textual e semântica em todos os registros da Conversion. Pretendemos compartilhar mais sobre isso em breve!

O fluxo básico é assim:

text
1Solicitação em linguagem natural
2 |
3 v
4 Agente que usa ferramentas <-----------------+
5 / | \ |
6campos ativos relacionamentos | rejeição com motivos
7 \ | / |
8 v |
9 IR restrita |
10 | |
11 v |
12 Validador e compilador -------------------------+
13 |
14 v
15 Declaração de produção

Isso mantém o contexto inicial pequeno. Também torna as falhas muito mais fáceis de entender. Se uma declaração estiver errada, podemos determinar se o agente encontrou o ativo errado, selecionou o campo errado, interpretou mal um relacionamento, representou a ideia correta incorretamente ou expôs um bug no compilador. Essa distinção mais tarde se tornou importante para nosso ciclo de avaliação.

Criando uma linguagem menor

O uso de ferramentas resolveu o problema de contexto. Não resolveu a latência.

Uma lição do feedback inicial: os usuários toleram muito menos latência em uma interface construída para um propósito específico do que no chat.

Isso aponta para um paradoxo mais amplo. Definimos expectativas de latência com base em quão difícil uma tarefa parece para nós, não em quão difícil é para o sistema. Escrever conteúdo parece difícil porque vemos o trabalho. Descrever um filtro parece simples porque nossas mentes resolvem silenciosamente contexto, entidades, relacionamentos e intenção. Para o modelo, reconstruir essas suposições ocultas é a tarefa. Quanto menos trabalho o usuário percebe, menos tempo ele dá ao sistema para fazê-lo.

Com base no feedback inicial, definimos duas metas: mais de 95% de precisão e um tempo de resposta em torno de 5 segundos para consultas comuns.

A Conversion tem uma linguagem de consulta interna expressiva. Em nossos primeiros testes, usando o formato de produção diretamente, apenas os maiores modelos, como o Claude Opus, conseguiam gerá-lo de forma confiável. Mesmo declarações simples levavam cerca de 45 segundos.

O construtor visual de declarações expõe apenas um subconjunto da linguagem completa. Criamos uma representação intermediária menor e amigável para agentes para esse subconjunto. Modelos menores podiam produzi-la usando menos tokens, enquanto um compilador determinístico cuidava do formato de produção completo.

Considere a declaração:

O cargo contém "Diretor".

A declaração de produção original é assim:

json
1{
2 "type": "LOGICAL",
3 "version": 1,
4 "logical": {
5 "operator": "OR",
6 "operands": [
7 {
8 "type": "LOGICAL",
9 "version": 1,
10 "logical": {
11 "operator": "AND",
12 "operands": [
13 {
14 "type": "VARIABLE",
15 "version": 1,
16 "variable": {
17 "variableSchemaId": "550e8400-e29b-41d4-a716-446655440000",
18 "where": {
19 "type": "LOGICAL",
20 "version": 1,
21 "logical": {
22 "operator": "AND",
23 "operands": [
24 {
25 "type": "LOGICAL",
26 "version": 1,
27 "logical": {
28 "operator": "CONTAINS",
29 "operands": [
30 {
31 "type": "ATTRIBUTE",
32 "version": 1,
33 "attribute": {
34 "name": "value"
35 }
36 },
37 {
38 "type": "CONSTANT",
39 "version": 1,
40 "constant": {
41 "value": "Director"
42 }
43 }
44 ]
45 }
46 }
47 ]
48 }
49 }
50 }
51 }
52 ]
53 }
54 }
55 ]
56 }
57}

A representação voltada para o modelo do mesmo filtro é:

json
1{
2 "field": "550e8400-e29b-41d4-a716-446655440000",
3 "op": "contains",
4 "value": "Director"
5}

A IR já passou por várias gerações, e a mais recente foi moldada observando modelos pequenos falharem nas anteriores. Uma grande melhoria foi introduzir melhores semânticas de mesmo registro (algo que a validação de esquema não consegue capturar):

json
1{
2 "related": "OPPORTUNITY",
3 "all": [
4 { "field": "<stage uuid>", "op": "equals", "value": "Closed Won" },
5 { "field": "<amount uuid>", "op": "gt", "value": 100000 }
6 ]
7}

Essa divisão entre modelo e código nos deu algumas propriedades úteis:

  • Declarações não suportadas são difíceis de expressar
  • As semânticas de relacionamento de mesmo registro são visíveis
  • Referências a campos e relacionamentos podem ser validadas
  • O compilador pode ser testado independentemente do modelo
  • As declarações geradas permanecem editáveis na interface do usuário existente

A IR, em última análise, reduz o trabalho do modelo: o agente resolve a intenção do usuário e produz um plano restrito; o código lida com o formato de produção.

Construindo um benchmark semântico

Uma saída pode ser completamente válida e ainda assim estar errada. Veja esta solicitação:

Contatos em empresas com uma oportunidade ganha no valor de mais de R$ 100.000,00.

Um contato pertence a uma empresa, e uma empresa pode ter muitas oportunidades. Corresponder a este filtro significa percorrer relacionamentos (contato para empresa, empresa para oportunidades) e verificar duas condições ao longo do caminho: o negócio está ganho e o negócio vale mais de R$ 100.000,00.

A dificuldade é que essas condições devem ser válidas para a mesma oportunidade. Se forem verificadas independentemente, uma empresa com um negócio ganho de R$ 20.000,00 e um negócio aberto de R$ 150.000,00 satisfaz ambas: uma condição corresponde a cada uma. A validação de esquema nunca vai pegar isso.

Depois que alguns exemplos como este passaram, editar o prompt corria o risco de regredi-los. Precisávamos de uma maneira de verificar o significado, não apenas a validade, e verificá-lo sempre que algo mudasse.

Construímos o Statement Bench em torno dos comportamentos do produto, derivados de padrões de público anônimos que nossos clientes haviam construído anteriormente. O conjunto agora contém 100 casos em quinze categorias, como condições de campo simples, eventos, janelas de tempo relativas e de calendário, relacionamentos e consultas compostas.

Cada caso é executado em um sandbox de espaço de trabalho realista. O agente recebe os mesmos dados e ferramentas que recebe em produção.

O avaliador verifica várias camadas:

  1. O agente retornou uma declaração?
  2. A IR satisfaz seu esquema?
  3. Os campos e relacionamentos referenciados existem?
  4. A declaração pode ser compilada e passar na validação de produção?
  5. Ela representa o significado solicitado?
  6. Quantas etapas do modelo, chamadas de ferramenta, tokens e submissões rejeitadas foram necessárias?

A quinta é a mais interessante, pois a validade não garante igualdade semântica.

As verificações semânticas leem a declaração compilada, afirmando coisas como "uma condição de oportunidade carregando tanto o estágio quanto o valor", "um evento de e-mail cujo tipo é um clique, não uma abertura" ou "uma condição de webinar em vez de uma de campanha personalizada".

Executando um loop de otimização orientado por avaliação

O benchmark mudou a forma como podíamos continuar trabalhando no recurso. Em vez de pedir a um agente de codificação para "melhorar o prompt" ou "implementar uma nova IR", podíamos dar a ele uma definição executável de melhoria.

O loop era assim:

  1. Executar o benchmark
  2. Agrupar falhas por sua causa subjacente
  3. Inspecionar a trajetória de ferramentas do agente e a IR submetida
  4. Alterar o prompt, ferramentas, validadores ou compilador
  5. Executar o benchmark completo novamente
  6. Manter a alteração apenas se melhorar o sistema sem introduzir regressões

Agentes de codificação podiam usar o benchmark para comparar modelos, experimentar a IR, melhorar as descrições das ferramentas e refinar o prompt de forma autônoma. Executar o conjunto completo após cada alteração também nos impedia de superajustar a falhas individuais, e mantivemos mais 50 casos de reserva para confirmar isso.

Algumas alterações melhoraram mais os resultados:

  • Mover caminhos, tipos e estrutura para o compilador. Nossa primeira IR fazia o modelo escrever todos os relacionamentos explicitamente: contato para empresa, empresa para oportunidade. Os metadados do campo já implicam esse caminho, então o compilador agora o infere. Fizemos o mesmo para datas, conversão de tipos, posicionamento de negação e aninhamento de grupos. Mover regras para o compilador simplificou a IR e reduziu falhas de esquema.
  • Rejeitar com explicações e correções. Cada rejeição de esquema e compilador diz o que escrever em vez disso (quando disponível): "gt não pode ser negado neste campo; use lte", "copie o id da lista de campanhas". Modelos pequenos convergem em uma ou duas tentativas, e o modelo de produção é rejeitado em algumas solicitações por cem.
  • Estruturar o prompt para modelos pequenos. Reorganizar o prompt não alterou a precisão, mas reduziu pela metade o número de novas tentativas, o que melhorou diretamente a latência. Isso foi inspirado nas Melhores práticas de prompt da Anthropic.
  • Usar exemplos em vez de prosa. Dois exemplos adicionais em nossa referência de formato resolveram uma classe de erros que parágrafos de explicação não haviam resolvido, reduzindo as submissões rejeitadas aproximadamente pela metade.
  • Fornecer contexto completo ou nenhum. Os modelos buscam o que está no contexto antes de chamar uma ferramenta. Quando o contexto incluía um conjunto parcial ou não rotulado de campos, o modelo usava o mais próximo em vez de pesquisar, produzindo declarações semanticamente incorretas. Ao reduzir o contexto parcial em favor de chamadas de ferramenta, aumentamos as taxas de construção e reduzimos os tokens de entrada em um quinto.

A configuração final de produção, GLM 5.3 Flash, completou todos os 100 casos do benchmark com uma latência mediana de 2,3 segundos e um percentil 95 de 7,1 segundos. E, 97 dos 100 estavam semanticamente corretos. Comparado com a abordagem original de formato de produção, filtros simples passaram de aproximadamente 45 segundos para pouco mais de um segundo, com 1/20 do custo.

Comparando modelos no Statement Bench

O benchmark também nos deu uma maneira de comparar modelos na tarefa real.

Em 2 de setembro de 2026, executamos os mesmos 100 casos em oito modelos. Cada modelo recebeu o mesmo prompt, ferramentas, IR, compilador e tempo limite de solicitação de 30 segundos.

O roteamento do provedor, o cache de prompt e a carga de inferência temporária afetam a latência.

Modelo

Construções válidas

Semanticamente correto

Latência P50

Latência P95

Leitura de cache

Chamadas de ferramenta

Submissões rejeitadas

Custo estimado por 1.000 solicitações

Claude Opus 5

100/100 (100%)

100/100 (100%)

3,16s

8,53s

91,1%

162

0

$27,51

GLM 5.2

100/100 (100%)

100/100 (100%)

4,38s

13,02s

93,5%

201

5

$14,94

Kimi K3

100/100 (100%)

100/100 (100%)

5,17s

11,84s

34,3%

157

0

$48,51

GLM 5.3 Flash

100/100 (100%)

97/100 (97%)

2,34s

7,07s

92,8%

163

2

$1,33

DeepSeek V4 Pro

96/100 (96%)

96/96 (100%)

5,53s

24,31s

47,8%

172

1

$12,00

Gemini 3.7 Flash

77/100 (77%)

77/77 (100%)

15,14s

30,01s

26,5%

228

1

$18,24

Gemini 3.8 Flash

76/100 (76%)

76/76 (100%)

14,29s

30,01s

35,4%

266

1

$27,44

DeepSeek V4 Flash

56/100 (56%)

55/56 (98%)

6,79s

30,00s

41,5%

100

1

$0,56

Os custos estimados são por 1.000 solicitações tentadas, usando tokens de entrada, entrada em cache e saída observados, com as taxas não promocionais listadas de cada provedor em 2 de setembro de 2026. A entrada em cache é faturada à taxa de leitura de cache publicada quando o provedor a publica, e à taxa de entrada completa caso contrário.

Levi - inline image

Figura 1. Correção versus custo. GLM 5.3 Flash atinge 97% a aproximadamente um vigésimo do custo do Claude Opus 5.

Levi - inline image

Figura 2. Distribuição de latência, mediana e percentil 95, ordenados por P95.

Algumas descobertas se destacaram.

Nem o tamanho do modelo nem o preço previram a latência. O modelo mais rápido foi o menor e mais barato. O segundo mais rápido foi o maior e mais caro.

A falha passou de respostas erradas para respostas lentas. Seis dos oito modelos estavam semanticamente corretos em todas as declarações que concluíram; as diferenças entre eles estão quase inteiramente em quantas solicitações terminaram dentro do tempo limite. Nas primeiras iterações da IR e dos prompts, a maioria dos modelos menores falhava no benchmark na etapa de construção com <50% de precisão semântica.

Tokens de raciocínio superam as chamadas de ferramenta. O Gemini 3.8 Flash gastou 180.000 de seus 192.000 tokens de saída em raciocínio e fez 266 chamadas de ferramenta; o Claude Opus 5 gastou 813 tokens em raciocínio, fez 162 e concluiu todos os casos. Nossos esforços de Pesquisa Global reduziram cada consulta de ferramenta para a faixa de milissegundos, então o custo restante é a vez do modelo entre elas.

Conclusão

Modelos são bons em resolver ambiguidades, código é bom em impor precisão, e a maioria de nossas falhas iniciais veio de pedir ao modelo para fazer ambos. Construir este agente foi o trabalho de decidir qual dos dois deveria ser dono de cada parte. Esperamos que o mesmo seja verdade para texto para SQL e a maioria das outras interfaces de linguagem natural.

Se você estiver interessado em algum desses problemas, entre em contato! Estamos contratando.

Salvar com um clique

Faça leitura profunda de artigos virais com IA no YouMind

Salve a fonte, faça perguntas específicas, resuma o argumento e transforme um artigo viral em notas reutilizáveis em um único espaço de trabalho com IA.

Explorar o YouMind
Para criadores

Transforme seu Markdown em um artigo 𝕏 impecável

Quando você publica seus próprios textos longos, formatar imagens, tabelas e blocos de código para o 𝕏 é uma dor de cabeça. O YouMind transforma um rascunho completo em Markdown em um artigo 𝕏 impecável e pronto para publicar.

Experimente Markdown para 𝕏

Mais padrões para decifrar

Artigos virais recentes

Explorar mais artigos virais