Notre agent de texte-à-requête est passé de 45 secondes sur les modèles de pointe à 2 secondes sur GLM 5.3 Flash, avec la même précision pour 1/20e du coût.
La majeure partie de notre travail récent en IA chez Conversion s'est concentrée sur le renseignement marketing général.
Les équipes d'automatisation marketing effectuent un large éventail de tâches sur différents systèmes : rechercher des comptes, constituer des audiences, planifier des campagnes, rédiger du contenu et agir sur les données de performance. Nous construisons des agents capables de raisonner à travers ces flux de travail et d'utiliser les mêmes outils qu'un spécialiste marketing qualifié.
Ces systèmes bénéficient de modèles polyvalents et performants. Le travail est ouvert, et un bon jugement est souvent plus important que la rapidité d'exécution d'une tâche.
Mais nous avions aussi un backlog de fonctionnalités IA plus petites et plus ciblées. L'une d'elles était les filtres en langage naturel : permettre à un utilisateur de décrire une audience en anglais simple et de transformer cette description en un filtre qu'il pourrait inspecter et modifier dans le générateur d'instructions existant de Conversion. (Dans Conversion, un filtre s'appelle une instruction.)
Au début, cela ressemblait à une tâche simple de génération structurée. Donner à un modèle les champs disponibles, décrire le format de sortie, et lui demander de produire du JSON. Cela s'est avéré considérablement plus difficile que prévu.

Instruction composée générée en moins de 5 secondes avec GLM 5.3 Flash.
Prenons l'exemple suivant :
Trouver les contacts qui ont soumis le formulaire de démo au moins une fois au cours des 30 derniers jours et qui travaillent dans une entreprise de logiciels avec une opportunité ouverte d'une valeur supérieure à 50 000 $.
Cela nécessite que le système :
- Trouve le formulaire spécifique que l'utilisateur désigne par "le formulaire de démo"
- Détermine quel champ représente le secteur d'activité d'une entreprise
- Apprenne comment cet espace de travail représente "logiciel", ce qui implique d'examiner les valeurs réellement stockées dans ce champ plutôt que de deviner
- Parcourt d'un contact à son entreprise, puis aux opportunités de cette entreprise
- S'assure que "ouverte" et "plus de 50 000 $" s'appliquent à la même opportunité
- Applique une fenêtre d'événement relative
Il devait aussi faire tout cela assez rapidement pour donner l'impression d'une interface de filtre, et non d'un agent de recherche.
Ce qui ressemblait à une petite tâche d'ingénierie de prompt était devenu un problème contraint de texte-à-requête. Le résoudre nécessitait un agent utilisant des outils, une représentation intermédiaire (IR), un compilateur déterministe et un benchmark sémantique.
Nous avons testé huit modèles sur le benchmark résultant, Statement Bench, notamment Claude Opus 5, Kimi K3, GLM 5.3 Flash et la version Gemini 3.8 Flash publiée ce matin. Les résultats sont ci-dessous.
Donner des outils à l'agent
La plupart des informations nécessaires pour répondre à la demande ci-dessus sont spécifiques à l'environnement du client. Un seul espace de travail peut contenir des centaines de millions de valeurs de champ historiques, ainsi que ses actifs et objets. Pour des raisons évidentes, nous ne pouvions pas mettre tout cela dans un seul prompt.
Notre première décision architecturale utile a été de cesser de traiter le problème comme une génération structurée ordinaire. Au lieu de cela, le modèle reçoit un petit ensemble d'outils. Il peut rechercher des champs, inspecter des valeurs historiques et résoudre des actifs spécifiques à l'entreprise tels que des formulaires, des campagnes, des e-mails et des audiences. Il n'utilise ces outils que lorsque la demande l'exige.
Une grande partie de cette infrastructure de recherche provient de notre récent travail sur la Recherche Globale, qui offre une recherche textuelle et sémantique sur tous les enregistrements dans Conversion. Nous prévoyons de partager plus d'informations à ce sujet bientôt !
Le flux de base ressemble à ceci :
1Requête en langage naturel2 |3 v4 Agent utilisant des outils <-----------------+5 / | \ |6champs actifs relations | rejet avec raisons7 \ | / |8 v |9 IR contrainte |10 | |11 v |12 Validateur et compilateur ----------------------+13 |14 v15 Instruction de production
Cela maintient le contexte initial petit. Cela rend également les échecs beaucoup plus faciles à comprendre. Si une instruction est erronée, nous pouvons déterminer si l'agent a trouvé le mauvais actif, sélectionné le mauvais champ, mal compris une relation, représenté incorrectement l'idée correcte, ou exposé un bogue dans le compilateur. Cette distinction est devenue importante par la suite pour notre boucle d'évaluation.
Créer un langage plus petit
L'utilisation d'outils a résolu le problème du contexte. Elle n'a pas résolu la latence.
Une leçon tirée des premiers retours : les utilisateurs tolèrent beaucoup moins de latence dans une interface dédiée que dans un chat.
Cela pointe vers un paradoxe plus large. Nous fixons les attentes de latence en fonction de la difficulté perçue d'une tâche, et non de sa difficulté réelle pour le système. Rédiger du contenu semble difficile parce que nous voyons le travail. Décrire un filtre semble simple parce que notre esprit résout silencieusement le contexte, les entités, les relations et l'intention. Pour le modèle, reconstruire ces hypothèses cachées est la tâche. Moins l'utilisateur perçoit de travail, moins il accorde de temps au système pour le faire.
Sur la base des premiers retours, nous avons fixé deux objectifs : plus de 95 % de précision et un temps de réponse d'environ 5 secondes pour les requêtes courantes.
Conversion dispose d'un langage de requête interne expressif. Dans nos premiers tests, en utilisant directement le format de production, seuls les plus grands modèles comme Claude Opus pouvaient le générer de manière fiable. Même les instructions simples prenaient environ 45 secondes.
Le générateur d'instructions visuel n'expose qu'un sous-ensemble du langage complet. Nous avons créé une représentation intermédiaire plus petite et adaptée aux agents pour ce sous-ensemble. Les modèles plus petits pouvaient la produire en utilisant moins de jetons, tandis qu'un compilateur déterministe gérait le format de production complet.
Considérons l'instruction :
Le titre du poste contient "Directeur".
L'instruction de production originale ressemble à ceci :
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 représentation orientée modèle du même filtre est :
1{2 "field": "550e8400-e29b-41d4-a716-446655440000",3 "op": "contains",4 "value": "Director"5}
L'IR a déjà traversé plusieurs générations, et la dernière a été façonnée en observant les petits modèles échouer sur les précédentes. Une grande amélioration a été l'introduction d'une meilleure sémantique d'enregistrement identique (que la validation de schéma ne peut pas détecter) :
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}
Cette séparation entre le modèle et le code nous a donné quelques propriétés utiles :
- Les instructions non prises en charge sont difficiles à exprimer
- La sémantique des relations d'enregistrement identique est visible
- Les références aux champs et aux relations peuvent être validées
- Le compilateur peut être testé indépendamment du modèle
- Les instructions générées restent modifiables dans l'interface utilisateur existante
L'IR réduit finalement le travail du modèle : l'agent résout l'intention de l'utilisateur et produit un plan contraint ; le code gère le format de production.
Construire un benchmark sémantique
Une sortie peut être complètement valide et pourtant erronée. Prenons cette demande :
Contacts dans des entreprises avec une opportunité gagnée d'une valeur supérieure à 100 000 $.
Un contact appartient à une entreprise, et une entreprise peut avoir de nombreuses opportunités. Correspondre à ce filtre implique de parcourir les relations (contact vers entreprise, entreprise vers opportunités) et de vérifier deux conditions en cours de route : l'affaire est gagnée et l'affaire vaut plus de 100 000 $.
La difficulté est que ces conditions doivent s'appliquer à la même opportunité. Si elles sont vérifiées indépendamment, une entreprise avec une affaire gagnée de 20 000 $ et une affaire ouverte de 150 000 $ satisfait les deux : une condition correspond à chacune. La validation de schéma ne détectera jamais cela.
Une fois que quelques exemples comme celui-ci ont réussi, la modification du prompt risquait de les faire régresser. Nous avions besoin d'un moyen de vérifier le sens, pas seulement la validité, et de le vérifier à chaque fois que quelque chose changeait.
Nous avons construit Statement Bench autour des comportements du produit, dérivés de modèles d'audience anonymisés que nos clients avaient précédemment construits. La suite contient désormais 100 cas répartis dans quinze catégories telles que les conditions de champ simples, les événements, les fenêtres temporelles relatives et calendaires, les relations et les requêtes composées.
Chaque cas s'exécute dans un bac à sable d'espace de travail réaliste. L'agent reçoit les mêmes données et outils qu'en production.
L'évaluateur vérifie plusieurs couches :
- L'agent a-t-il renvoyé une instruction ?
- L'IR satisfait-elle son schéma ?
- Les champs et relations référencés existent-ils ?
- L'instruction peut-elle être compilée et passer la validation de production ?
- Représente-t-elle le sens demandé ?
- Combien d'étapes de modèle, d'appels d'outils, de jetons et de soumissions rejetées a-t-elle nécessitées ?
La cinquième est la plus intéressante car la validité ne garantit pas l'égalité sémantique.
Les vérifications sémantiques lisent l'instruction compilée, en affirmant des choses comme "une condition d'opportunité portant à la fois l'étape et le montant", "un événement e-mail dont le type est un clic, pas une ouverture", ou "une condition de webinaire plutôt qu'une condition de campagne personnalisée".
Exécuter une boucle d'optimisation pilotée par l'évaluation
Le benchmark a changé notre façon de continuer à travailler sur la fonctionnalité. Au lieu de demander à un agent de codage "d'améliorer le prompt" ou "d'implémenter une nouvelle IR", nous pouvions lui donner une définition exécutable de l'amélioration.
La boucle ressemblait à ceci :
- Exécuter le benchmark
- Regrouper les échecs par leur cause sous-jacente
- Inspecter la trajectoire d'outils de l'agent et l'IR soumise
- Modifier le prompt, les outils, les validateurs ou le compilateur
- Exécuter à nouveau l'ensemble du benchmark
- Ne conserver la modification que si elle améliore le système sans introduire de régressions
Les agents de codage pouvaient utiliser le benchmark pour comparer les modèles, expérimenter avec l'IR, améliorer les descriptions d'outils et affiner le prompt de manière autonome. L'exécution de la suite complète après chaque changement nous a également empêchés de surajuster aux échecs individuels, et nous avons réservé 50 cas supplémentaires pour le confirmer.
Quelques changements ont le plus amélioré les résultats :
- Déplacer les chemins, les types et la structure dans le compilateur. Notre première IR obligeait le modèle à écrire toutes les relations explicitement : contact vers entreprise, entreprise vers opportunité. Les métadonnées du champ impliquent déjà ce chemin, donc le compilateur l'infère désormais. Nous avons fait de même pour les dates, le transtypage, le placement de la négation et l'imbrication des groupes. Déplacer les règles dans le compilateur a simplifié l'IR et réduit les échecs de schéma.
- Rejeter avec des explications et des corrections. Chaque rejet de schéma et de compilateur indique quoi écrire à la place (lorsque disponible) : "gt ne peut pas être nié sur ce champ ; utilisez lte", "copiez l'id depuis campaign_list". Les petits modèles convergent en une ou deux tentatives, et le modèle de production est rejeté sur quelques requêtes par centaine.
- Structurer le prompt pour les petits modèles. La réorganisation du prompt n'a pas changé la précision, mais elle a réduit de moitié le nombre de tentatives, ce qui a directement amélioré la latence. Cela a été inspiré par les bonnes pratiques de prompting d'Anthropic.
- Utiliser des exemples plutôt que de la prose. Deux exemples supplémentaires dans notre référence de format ont résolu une classe d'omissions que des paragraphes d'explication n'avaient pas résolues, réduisant les soumissions rejetées d'environ la moitié.
- Donner un contexte complet ou aucun. Les modèles se tournent vers ce qui est dans le contexte avant d'appeler un outil. Lorsque le contexte incluait un ensemble partiel ou non étiqueté de champs, le modèle utilisait le champ le plus proche plutôt que de chercher, produisant des instructions sémantiquement incorrectes. En réduisant le contexte partiel au profit des appels d'outils, nous avons augmenté les taux de construction et réduit les jetons d'entrée d'un cinquième.
La configuration de production finale, GLM 5.3 Flash, a terminé les 100 cas du benchmark avec une latence médiane de 2,3 secondes et un 95e percentile de 7,1 secondes. Et, 97 des 100 étaient sémantiquement corrects. Par rapport à l'approche originale du format de production, les filtres simples étaient passés d'environ 45 secondes à un peu plus d'une seconde pour 1/20e du coût.
Comparer les modèles sur Statement Bench
Le benchmark nous a également donné un moyen de comparer les modèles sur la tâche réelle.
Le 2 septembre 2026, nous avons exécuté les mêmes 100 cas sur huit modèles. Chaque modèle a reçu le même prompt, les mêmes outils, la même IR, le même compilateur et le même délai d'attente de requête de 30 secondes.
Le routage du fournisseur, la mise en cache du prompt et la charge d'inférence temporaire affectent tous la latence.
Modèle
Constructions valides
Sémantiquement correct
Latence P50
Latence P95
Lecture cache
Appels d'outils
Soumissions rejetées
Coût estimé pour 1 000 requêtes
Claude Opus 5
100/100 (100%)
100/100 (100%)
3,16 s
8,53 s
91,1 %
162
0
27,51 $
GLM 5.2
100/100 (100%)
100/100 (100%)
4,38 s
13,02 s
93,5 %
201
5
14,94 $
Kimi K3
100/100 (100%)
100/100 (100%)
5,17 s
11,84 s
34,3 %
157
0
48,51 $
GLM 5.3 Flash
100/100 (100%)
97/100 (97%)
2,34 s
7,07 s
92,8 %
163
2
1,33 $
DeepSeek V4 Pro
96/100 (96%)
96/96 (100%)
5,53 s
24,31 s
47,8 %
172
1
12,00 $
Gemini 3.7 Flash
77/100 (77%)
77/77 (100%)
15,14 s
30,01 s
26,5 %
228
1
18,24 $
Gemini 3.8 Flash
76/100 (76%)
76/76 (100%)
14,29 s
30,01 s
35,4 %
266
1
27,44 $
DeepSeek V4 Flash
56/100 (56%)
55/56 (98%)
6,79 s
30,00 s
41,5 %
100
1
0,56 $
Les coûts estimés sont par 1 000 requêtes tentées en utilisant les jetons d'entrée, d'entrée en cache et de sortie observés au tarif non promotionnel indiqué de chaque fournisseur au 2 septembre 2026. L'entrée en cache est facturée au taux de lecture du cache publié lorsque le fournisseur en publie un, et au taux d'entrée complet dans le cas contraire.

Figure 1. Exactitude par rapport au coût. GLM 5.3 Flash atteint 97 % pour environ un vingtième du coût de Claude Opus 5.

Figure 2. Distribution de la latence, médiane et 95e percentile, classée par P95.
Quelques résultats se sont démarqués.
Ni la taille du modèle ni le prix n'ont prédit la latence. Le modèle le plus rapide était le plus petit et le moins cher. Le deuxième plus rapide était le plus grand et le plus cher.
L'échec est passé des mauvaises réponses aux réponses lentes. Six des huit modèles étaient sémantiquement corrects sur chaque instruction qu'ils ont terminée ; les différences entre eux résident presque entièrement dans le nombre de requêtes terminées dans le délai imparti. Dans les premières itérations de l'IR et des prompts, la plupart des modèles plus petits échouaient au benchmark à l'étape de construction avec une précision sémantique <50 %.
Les jetons de raisonnement l'emportent sur les appels d'outils. Gemini 3.8 Flash a dépensé 180 000 de ses 192 000 jetons de sortie en raisonnement et a effectué 266 appels d'outils ; Claude Opus 5 a dépensé 813 jetons en raisonnement, en a effectué 162 et a terminé chaque cas. Nos efforts de Recherche Globale ont réduit chaque recherche d'outil à la plage de la milliseconde, donc le coût restant est le tour du modèle entre elles.
Conclusion
Les modèles sont bons pour résoudre l'ambiguïté, le code est bon pour imposer la précision, et la plupart de nos premiers échecs provenaient du fait de demander au modèle de faire les deux. Construire cet agent a été le travail de décider lequel des deux devait posséder chaque partie. Nous nous attendons à ce qu'il en soit de même pour le texte-à-SQL et la plupart des autres interfaces en langage naturel.
Si l'un de ces problèmes vous intéresse, contactez-nous ! Nous recrutons.





