← News
Jérémie Doucy·

Pourquoi nous testons chaque outil d'abord avec un modèle intermédiaire

Nous livrons la Bayes Platform à des administrations et des associations partout en Europe. L’une de ses fonctions centrales est un agent conversationnel capable de répondre à partir des propres documents d’une organisation : guides de politique d’emploi, protocoles médicaux, références juridiques.

La recherche documentaire n’est ni une étape de pipeline ni une astuce de prompt engineering. C’est un appel d’outil. Le LLM décide quand chercher, formule une requête, et récupère des extraits depuis pgvector. Cette conception garde l’agent modulaire : le RAG est un outil parmi d’autres (remplissage de formulaire, délégation à des sous-agents, citation de sources, mise en avant de ressources), et l’orchestration est la même pour tous.

Nous l’avons testé avec Gemini, ça a marché immédiatement, et nous sommes passés à autre chose. Puis nous avons ajouté Gemma 4 et compris que l’outil fonctionnait très bien. C’est nous qui l’avions mal conçu.

Le RAG comme outil, pas comme étape

La plupart des tutoriels de RAG montrent un pipeline figé : vectoriser la requête, récupérer des extraits, les injecter dans le prompt, générer. Nous faisons autrement. Notre agent dispose d’un outil retrieveProjectDocumentChunks enregistré au même titre que ses autres capacités. Le prompt système indique au modèle quand l’utiliser, mais c’est le modèle qui décide s’il l’appelle et comment, y compris la requête à envoyer et le nombre d’extraits à demander.

retrieveProjectDocumentChunks:
  description: >
    Retrieve the most relevant project document chunks
    for the current conversation context and latest user question.
  parameters:
    conversationSummary: string
    latestUserQuestion: string (required)
    topK: number (default 20, max 20)

Le modèle l’appelle, récupère le contenu des extraits avec leurs métadonnées et leurs scores de similarité, et génère une réponse ancrée dans les sources. La boucle d’outils du Vercel AI SDK gère automatiquement le cycle appel/réponse.

C’est important, parce que l’agent n’est pas un chatbot auquel on aurait greffé une recherche. C’est un agent qui utilise des outils, et la recherche documentaire est l’une de ses capacités. La même architecture fait tourner un agent de remplissage de formulaire qui appelle fillForm pour compléter les champs au fil de l’eau, ou un agent parent qui délègue à des sous-agents spécialisés via des appels d’outils.

Ce qui se passe sous le capot

Le volet hors ligne est classique : les documents sont téléversés, le texte est extrait avec Docling (PDF, DOCX, PPTX, images), découpé en extraits, vectorisé avec Vertex AI, et stocké dans PostgreSQL avec pgvector. Pour les fichiers en texte brut, nous utilisons un découpage par phrases (512 tokens, 50 de chevauchement), mais pour les documents structurés (PDF, DOCX, PPTX), c’est le découpeur hybride de Docling qui s’en charge. Il suit la structure propre du document (titres, sections, paragraphes) plutôt que de couper à un nombre de tokens fixe : il n’y a donc pas de chevauchement, et les extraits font en général moins de 512 tokens. C’est un atout pour les documents bien structurés, même si cela peut trop fragmenter certains fichiers dont la structure source est trop granulaire.

Le volet en ligne est plus intéressant. Quand le modèle appelle l’outil de recherche, le service concatène le résumé de la conversation et la question de l’utilisateur, vectorise le texte combiné, et lance une requête de similarité cosinus contre les vecteurs des extraits. Les résultats reviennent classés, avec une déduplication par extrait parent pour que le modèle ne voie pas cinq passages qui se recouvrent au sein d’une même section.

Pas de re-ranker (pour l’instant 😇), pas de recherche hybride, pas d’index ANN. De la distance cosinus pgvector en force brute. C’est simple, et pour les volumes documentaires de nos partenaires (des centaines, pas des millions), ça fonctionne très bien.

Ce que nous avons raté

La Bayes Platform prend en charge plusieurs modèles. Chaque organisation choisit celui qui correspond à ses contraintes : Gemini 2.5 Flash et Pro pour les équipes qui peuvent utiliser Google Cloud, mais aussi des modèles ouverts auto-hébergés pour les organisations soumises à des exigences strictes de souveraineté des données. Nous faisons tourner Gemma 4 27B et Mistral Small 3.1 24B sur vLLM, hébergés sur nos serveurs.

Quand nous avons ajouté Gemma 4, notre outil de recherche fonctionnait moins bien. Notre premier réflexe a été d’accuser le modèle : Gemma devait être moins bon pour les appels d’outils. Mais en regardant les échecs réels, le constat était clair : nous avions conçu un schéma d’outil inutilement difficile à utiliser, pour n’importe quel modèle. Gemini est assez tolérant pour rattraper une mauvaise conception. Gemma 4 est plus littéral, et c’est en réalité un retour utile.

Le nom retrieveProjectDocumentChunks est à rallonge et laisse fuiter des détails d’implémentation. Le modèle n’a pas besoin de savoir qu’il récupère des « chunks » de « documents de projet ». Il a besoin de savoir qu’il peut interroger la base de connaissances de l’organisation. Un nom comme searchKnowledgeBase aurait été plus clair pour n’importe quel modèle, et surtout pour les plus petits, où chaque token du schéma compte.

Les paramètres avaient le même défaut. conversationSummary est optionnel et nullable, topK vaut 20 par défaut mais plafonne à 20 : une spécification déroutante, qui invite le modèle à passer "null" sous forme de chaîne ou à choisir des nombres au hasard. Des valeurs par défaut plus simples, moins de champs optionnels et une description plus claire nous auraient aidés dès le départ.

Concevoir ses outils pour le modèle qu’on va réellement faire tourner

Nous avons d’abord testé avec Gemini 2.5 Flash. Tout a marché du premier coup : appels d’outils propres, gestion correcte des paramètres. Nous avons livré et sommes passés à la suite. Le problème, c’est que Gemini tolère les schémas ambigus, il devine ce que vous vouliez dire. C’est parfait, jusqu’au jour où vous ajoutez un modèle qui prend votre schéma au pied de la lettre.

Notre règle, désormais : tester chaque nouvel outil d’abord avec un modèle ouvert intermédiaire. Si le schéma est assez clair pour Gemma 4 27B, il marchera avec n’importe quoi. L’inverse n’est pas vrai.

Concrètement :

La suite

Nous retravaillons activement l’outil de recherche. Au-delà du renommage, le changement le plus important consiste à rendre le schéma de l’outil dynamique : au lieu d’une définition statique, l’agent reçoit un outil taillé pour sa configuration précise, ses tags de documents, son périmètre de recherche, son domaine de connaissances. Un agent santé ne devrait pas voir le même outil de recherche qu’un agent emploi. C’est la direction que nous prenons, et la littéralité de Gemma 4 est un bon garde-fou pour bien concevoir.

L’auto-hébergement compte pour nous. Certains de nos partenaires publics ne peuvent pas envoyer de données citoyennes à une API cloud, point final. Faire tourner Gemma 4 27B sur une infrastructure dédiée est ce qui rend la plateforme viable pour eux. L’évolution des modèles ouverts nous enthousiasme, et concevoir nos outils pour qu’ils fonctionnent bien avec eux est un investissement, pas un contournement.