Utilizzare benchmark semantici per creare un agente text-to-query che si auto-migliora

@levibkline
INGLESE03 set 2026
160K
70
2
6
12

TL;DR

Un approfondimento tecnico sull'ottimizzazione degli agenti text-to-query tramite l'uso di rappresentazioni intermedie, compilatori deterministici e benchmark semantici per ottenere una latenza di 2 secondi e una precisione del 97%.

Il nostro agente text-to-query è passato da 45 secondi sui modelli frontier a 2 secondi su GLM 5.3 Flash, con la stessa precisione a 1/20 del costo.

Gran parte del nostro recente lavoro sull'IA in Conversion si è concentrato sull'intelligence di marketing generale.

I team di automazione del marketing svolgono un'ampia gamma di attività su vari sistemi: ricerca di account, creazione di audience, pianificazione di campagne, scrittura di contenuti e analisi dei dati di performance. Abbiamo creato agenti in grado di ragionare su questi flussi di lavoro e utilizzare gli stessi strumenti che un esperto marketer userebbe.

Questi sistemi traggono vantaggio da modelli versatili e polivalenti. Il lavoro è aperto e un buon giudizio è spesso più importante del completare rapidamente un'attività.

Ma avevamo anche un arretrato di funzionalità IA più piccole e mirate. Una di queste erano i filtri in linguaggio naturale: permettere a un utente di descrivere un pubblico in inglese semplice e trasformare quella descrizione in un filtro che potesse ispezionare e modificare nel costruttore di statement esistente di Conversion. (In Conversion, un filtro si chiama statement.)

All'inizio, sembrava un compito di generazione strutturata semplice. Dare a un modello i campi disponibili, descrivere il formato di output e chiedergli di produrre JSON. Si è rivelato considerevolmente più difficile di così.

Levi - inline image

Statement composto generato in meno di 5 secondi utilizzando GLM 5.3 Flash.

Prendiamo il seguente esempio:

Trova i contatti che hanno inviato il modulo demo almeno una volta negli ultimi 30 giorni e lavorano in un'azienda di software con un'opportunità aperta del valore di oltre $50.000.

Questo richiede che il sistema:

  • Trovi il modulo specifico a cui l'utente si riferisce con "il modulo demo"
  • Determini quale campo rappresenta il settore di un'azienda
  • Impari come quell'area di lavoro rappresenta "software", il che significa guardare i valori effettivamente memorizzati in quel campo piuttosto che indovinare
  • Passi da un contatto alla sua azienda e poi alle opportunità di quell'azienda
  • Garantisca che "aperta" e "oltre $50.000" si applichino alla stessa opportunità
  • Applichi una finestra di evento relativa

Doveva anche fare tutto questo abbastanza velocemente da sembrare un'interfaccia di filtro, non un agente di ricerca.

Quello che sembrava un piccolo compito di prompt engineering era diventato un problema vincolato di text-to-query. Risolverlo richiedeva un agente che usa strumenti, una rappresentazione intermedia (IR), un compilatore deterministico e un benchmark semantico.

Abbiamo eseguito otto modelli sul benchmark risultante, Statement Bench, tra cui Claude Opus 5, Kimi K3, GLM 5.3 Flash e la versione Gemini 3.8 Flash rilasciata questa mattina. I risultati sono riportati di seguito.

Dare strumenti all'agente

La maggior parte delle informazioni necessarie per rispondere alla richiesta sopra è specifica dell'ambiente del cliente. Una singola area di lavoro può contenere centinaia di milioni di valori di campo storici, insieme ai suoi asset e oggetti. Per ovvie ragioni, non potevamo mettere tutto questo in un unico prompt.

La nostra prima decisione architetturale utile è stata quella di smettere di trattare il problema come una normale generazione strutturata. Invece, il modello riceve un piccolo set di strumenti. Può cercare campi, ispezionare valori storici e risolvere asset specifici del business come moduli, campagne, email e audience. Usa questi strumenti solo quando la richiesta lo richiede.

Gran parte di questa infrastruttura di ricerca proviene dal nostro recente lavoro su Global Search, che fornisce ricerca testuale e semantica su tutti i record in Conversion. Presto condivideremo ulteriori dettagli!

Il flusso di base è il seguente:

text
1Richiesta in linguaggio naturale
2 |
3 v
4 Agente che usa strumenti <-----------------+
5 / | \ |
6campi asset relazioni | rifiuto con motivazioni
7 \ | / |
8 v |
9 IR vincolata |
10 | |
11 v |
12 Validatore e compilatore ---------------------+
13 |
14 v
15 Statement di produzione

Questo mantiene il contesto iniziale ridotto. Rende anche gli errori molto più facili da capire. Se uno statement è sbagliato, possiamo determinare se l'agente ha trovato l'asset sbagliato, selezionato il campo sbagliato, frainteso una relazione, rappresentato l'idea corretta in modo errato o esposto un bug nel compilatore. Questa distinzione è diventata in seguito importante per il nostro ciclo di valutazione.

Creare un linguaggio più piccolo

L'uso degli strumenti ha risolto il problema del contesto. Non ha risolto la latenza.

Una lezione dal feedback iniziale: gli utenti tollerano molta meno latenza in un'interfaccia dedicata che in una chat.

Questo evidenzia un paradosso più ampio. Impostiamo le aspettative di latenza in base a quanto un compito ci sembra difficile, non a quanto è difficile per il sistema. Scrivere contenuti sembra difficile perché vediamo il lavoro. Descrivere un filtro sembra semplice perché la nostra mente risolve silenziosamente contesto, entità, relazioni e intenzione. Per il modello, ricostruire queste assunzioni nascoste è il compito. Meno lavoro l'utente percepisce, meno tempo dà al sistema per farlo.

Sulla base del feedback iniziale, abbiamo fissato due obiettivi: oltre il 95% di precisione e un tempo di risposta di circa 5 secondi per le query comuni.

Conversion ha un linguaggio di query interno espressivo. Nei nostri primi test, usando direttamente il formato di produzione, solo i modelli più grandi come Claude Opus riuscivano a generarlo in modo affidabile. Anche gli statement semplici richiedevano circa 45 secondi.

Il costruttore di statement visivo espone solo un sottoinsieme del linguaggio completo. Abbiamo creato una rappresentazione intermedia più piccola e adatta agli agenti per quel sottoinsieme. I modelli più piccoli potevano produrla usando meno token, mentre un compilatore deterministico gestiva il formato di produzione completo.

Considera lo statement:

La qualifica lavorativa contiene "Direttore".

Lo statement di produzione originale è il seguente:

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}

La rappresentazione dello stesso filtro vista dal modello è:

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

L'IR ha già attraversato diverse generazioni, e l'ultima è stata plasmata osservando i modelli piccoli fallire sulle precedenti. Un grande miglioramento è stata l'introduzione di migliori semantiche per lo stesso record (qualcosa che la validazione dello schema non può cogliere):

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

Questa suddivisione tra modello e codice ci ha dato alcune proprietà utili:

  • Gli statement non supportati sono difficili da esprimere
  • Le semantiche delle relazioni sullo stesso record sono visibili
  • I riferimenti a campi e relazioni possono essere validati
  • Il compilatore può essere testato indipendentemente dal modello
  • Gli statement generati rimangono modificabili nell'interfaccia utente esistente

L'IR alla fine riduce il compito del modello: l'agente risolve l'intenzione dell'utente e produce un piano vincolato; il codice gestisce il formato di produzione.

Costruire un benchmark semantico

Un output può essere completamente valido e comunque sbagliato. Prendi questa richiesta:

Contatti presso aziende con un'opportunità vinta del valore di oltre $100.000.

Un contatto appartiene a un'azienda e un'azienda può avere molte opportunità. Far corrispondere questo filtro significa attraversare le relazioni (contatto ad azienda, azienda a opportunità) e verificare due condizioni lungo il percorso: l'affare è vinto e l'affare vale più di $100.000.

La difficoltà è che queste condizioni devono valere per la stessa opportunità. Se vengono verificate indipendentemente, un'azienda con un affare vinto da $20.000 e un affare aperto da $150.000 soddisfa entrambe: una condizione corrisponde a ciascuna. La validazione dello schema non lo coglierà mai.

Una volta che alcuni esempi come questo sono stati superati, modificare il prompt rischiava di farli regredire. Avevamo bisogno di un modo per verificare il significato, non solo la validità, e di verificarlo ogni volta che qualcosa cambiava.

Abbiamo costruito Statement Bench attorno ai comportamenti del prodotto, derivati da modelli di audience anonimizzati che i nostri clienti avevano precedentemente creato. La suite ora contiene 100 casi in quindici categorie come condizioni di campo semplici, eventi, finestre temporali relative e di calendario, relazioni e query composte.

Ogni caso viene eseguito in un sandbox realistico dell'area di lavoro. L'agente riceve gli stessi dati e strumenti che riceve in produzione.

Il valutatore controlla diversi livelli:

  1. L'agente ha restituito uno statement?
  2. L'IR soddisfa il suo schema?
  3. I campi e le relazioni a cui si fa riferimento esistono?
  4. Lo statement può essere compilato e superare la validazione di produzione?
  5. Rappresenta il significato richiesto?
  6. Quanti passaggi del modello, chiamate a strumenti, token e invii rifiutati ha richiesto?

Il quinto è il più interessante poiché la validità non garantisce l'uguaglianza semantica.

I controlli semantici leggono lo statement compilato, affermando cose come "una condizione di opportunità che porta sia la fase che l'importo", "un evento email il cui tipo è un clic, non un'apertura" o "una condizione di webinar piuttosto che una di campagna personalizzata".

Eseguire un ciclo di ottimizzazione guidato dalla valutazione

Il benchmark ha cambiato il modo in cui potevamo continuare a lavorare sulla funzionalità. Invece di chiedere a un agente di codifica di "migliorare il prompt" o "implementare una nuova IR", potevamo dargli una definizione eseguibile di miglioramento.

Il ciclo era il seguente:

  1. Eseguire il benchmark
  2. Raggruppare i fallimenti per la loro causa sottostante
  3. Ispezionare la traiettoria degli strumenti dell'agente e l'IR inviata
  4. Modificare il prompt, gli strumenti, i validatori o il compilatore
  5. Eseguire di nuovo l'intero benchmark
  6. Mantenere la modifica solo se migliora il sistema senza introdurre regressioni

Gli agenti di codifica potevano usare il benchmark per confrontare modelli, sperimentare con l'IR, migliorare le descrizioni degli strumenti e perfezionare il prompt in modo autonomo. Eseguire l'intera suite dopo ogni modifica ci ha anche impedito di adattarci eccessivamente a singoli fallimenti, e abbiamo tenuto da parte ulteriori 50 casi per confermarlo.

Alcune modifiche hanno migliorato i risultati più di altre:

  • Spostare percorsi, tipi e struttura nel compilatore. La nostra prima IR faceva scrivere al modello tutte le relazioni esplicitamente: contatto ad azienda, azienda a opportunità. I metadati del campo implicano già quel percorso, quindi il compilatore ora lo deduce. Abbiamo fatto lo stesso per date, casting di tipo, posizionamento della negazione e raggruppamento. Spostare le regole nel compilatore ha semplificato l'IR e ridotto i fallimenti dello schema.
  • Rifiutare con spiegazioni e correzioni. Ogni rifiuto dello schema e del compilatore dice cosa scrivere invece (quando disponibile): "gt non può essere negato su questo campo; usa lte", "copia l'id da campaign_list". I modelli piccoli convergono in uno o due tentativi, e il modello di produzione viene rifiutato su poche richieste ogni cento.
  • Strutturare il prompt per modelli piccoli. Riorganizzare il prompt non ha cambiato la precisione, ma ha dimezzato il numero di tentativi, migliorando direttamente la latenza. Questo è stato ispirato dalle Migliori pratiche di prompting di Anthropic.
  • Usare esempi invece di prosa. Due esempi aggiuntivi nel nostro riferimento di formato hanno risolto una classe di errori che paragrafi di spiegazione non avevano risolto, tagliando circa a metà gli invii rifiutati.
  • Fornire contesto completo o nessuno. I modelli cercano ciò che è nel contesto prima di chiamare uno strumento. Quando il contesto includeva un set di campi parziale o non etichettato, il modello usava il più vicino invece di cercare, producendo statement semanticamente errati. Riducendo il contesto parziale a favore delle chiamate a strumenti, abbiamo aumentato i tassi di build e ridotto i token di input di un quinto.

La configurazione di produzione finale, GLM 5.3 Flash, ha completato tutti i 100 casi del benchmark con una latenza mediana di 2,3 secondi e un 95° percentile di 7,1 secondi. E 97 su 100 erano semanticamente corretti. Rispetto all'approccio originale con formato di produzione, i filtri semplici erano passati da circa 45 secondi a poco più di un secondo a 1/20 del costo.

Confrontare i modelli su Statement Bench

Il benchmark ci ha anche dato un modo per confrontare i modelli sul compito effettivo.

Il 2 settembre 2026, abbiamo eseguito gli stessi 100 casi su otto modelli. Ogni modello ha ricevuto lo stesso prompt, strumenti, IR, compilatore e timeout di richiesta di 30 secondi.

Il routing del provider, la cache del prompt e il carico di inferenza temporaneo influenzano tutti la latenza.

Modello

Build valide

Semanticamente corretto

Latenza P50

Latenza P95

Lettura cache

Chiamate a strumenti

Invii rifiutati

Costo stimato per 1.000 richieste

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

I costi stimati si basano su 1.000 richieste tentate utilizzando i token di input, input in cache e output osservati, alle tariffe non promozionali pubblicate da ciascun provider al 2 settembre 2026. L'input in cache viene fatturato alla tariffa di lettura cache pubblicata dove il provider la pubblica, altrimenti alla tariffa di input completa.

Levi - inline image

Figura 1. Correttezza rispetto al costo. GLM 5.3 Flash raggiunge il 97 percento a circa un ventesimo del costo di Claude Opus 5.

Levi - inline image

Figura 2. Distribuzione della latenza, mediana e 95° percentile, ordinata per P95.

Alcuni risultati sono emersi.

Né la dimensione del modello né il prezzo prevedevano la latenza. Il modello più veloce era il più piccolo ed economico. Il secondo più veloce era il più grande e costoso.

Il fallimento si è spostato da risposte sbagliate a risposte lente. Sei degli otto modelli erano semanticamente corretti su ogni statement che hanno completato; le differenze tra loro sono quasi interamente in quante richieste sono state completate entro il timeout. Nelle prime iterazioni dell'IR e dei prompt, la maggior parte dei modelli più piccoli falliva il benchmark nella fase di build con <50% di precisione semantica.

I token di ragionamento superano le chiamate a strumenti. Gemini 3.8 Flash ha speso 180.000 dei suoi 192.000 token di output per il ragionamento e ha effettuato 266 chiamate a strumenti; Claude Opus 5 ha speso 813 token per il ragionamento, ne ha effettuate 162 e ha completato ogni caso. I nostri sforzi su Global Search hanno ridotto ogni ricerca di strumento al range dei millisecondi, quindi il costo rimanente è il turno del modello tra di esse.

Conclusione

I modelli sono bravi a risolvere l'ambiguità, il codice è bravo a imporre la precisione, e la maggior parte dei nostri primi fallimenti derivava dal chiedere al modello di fare entrambe le cose. Costruire questo agente è stato il lavoro di decidere quale dei due dovesse possedere ogni parte. Ci aspettiamo che lo stesso valga per text-to-SQL e per la maggior parte delle altre interfacce in linguaggio naturale.

Se sei interessato a uno qualsiasi di questi problemi, contattaci! Stiamo assumendo.

Salva con un clic

Leggi in profondità gli articoli virali con l’AI di YouMind

Salva la fonte, fai domande mirate, riassumi l’argomentazione e trasforma un articolo virale in note riutilizzabili in un unico spazio di lavoro AI.

Scopri YouMind
Per i creator

Trasforma il tuo Markdown in un articolo 𝕏 pulito

Quando pubblichi i tuoi testi lunghi, formattare immagini, tabelle e blocchi di codice per 𝕏 è una seccatura. YouMind trasforma un'intera bozza Markdown in un articolo 𝕏 pulito e pronto da pubblicare.

Prova Markdown verso 𝕏

Altri pattern da decodificare

Articoli virali recenti

Esplora altri articoli virali