# Comment nous construisons l'intégration IA : deux semaines de test, un jeu de données de référence, et une facture prévisible

Trois systèmes d'IA que nous avons construits sont en production aujourd'hui. Un assistant de recherche pour un client américain, qui tourne sur AWS Bedrock avec un orchestrateur et dix sous-agents spécialisés, vingt-cinq outils et une recherche documentaire sur un corpus indexé de subventions et de publications. Bob, notre propre assistant multi-tenant, avec mémoire conversationnelle, recherche documentaire, voix et intégration email. Et le générateur de questions au cœur de tenSurvey, qui rédige des questions de sondage en plus de trente langues.

Aucun n'a commencé par un modèle. Ils ont commencé par un tableur de cas réels et une question : est-ce que cela fonctionne assez bien, sur nos données, pour valoir la peine d'être construit ? Cet article présente la méthode que nous utilisons pour répondre à cette question et transformer un oui en une fonctionnalité qui survit au contact des utilisateurs.

## Étape 1 : le test initial, deux semaines sur des données réelles

Chaque mission commence par un test initial, et ce test commence par des données. Nous demandons cinquante à deux cents exemples réels de la tâche : les documents à résumer, les tickets à classer, les questions que les gens posent vraiment. Pas les cas propres. Ceux avec des fautes de frappe, des champs manquants et le cas limite que seule la personne qui fait ce travail depuis cinq ans connaît.

Nous construisons ensuite le pipeline le plus mince possible et nous mesurons. Pour une tâche d'extraction documentaire, cela signifie : modèle, prompt, sortie structurée, un script qui traite les deux cents cas et les compare à ce qu'un humain a dit. Pour l'assistant de recherche, cela signifiait : la recherche documentaire trouve-t-elle le bon passage dans le corpus, et la réponse le cite-t-elle ? Le résultat du test est un tableau avec précision, latence et coût par cas, et une recommandation qui est parfois « ne construisez pas cela pour l'instant ».

Cette recommandation s'est déjà produite. Une tâche de classification où le modèle était d'accord avec les relecteurs humains 82 % du temps semble impressionnante jusqu'à ce qu'on apprenne que les relecteurs étaient d'accord entre eux 84 % du temps. La tâche était ambiguë, pas le modèle. Nous avons passé la deuxième semaine à aider le client à affiner les catégories plutôt qu'à peaufiner les prompts, et la fonctionnalité finale en a été meilleure.

## Étape 2 : le jeu de données de référence, avant l'architecture

Les deux cents cas du test initial deviennent le jeu de données de référence : des entrées associées à ce que « correct » signifie, validé avec le client. Il vit dans le dépôt à côté du code, et il tourne en CI à chaque changement de prompt, de version de modèle, de paramètre de recherche documentaire ou de définition d'outil.

C'est l'artefact le plus important d'un projet d'IA, et c'est celui que la plupart des équipes sautent. Sans lui, chaque changement de prompt est une impression. Avec lui, un changement passe le portail ou ne le passe pas, et le chiffre est visible par tout le monde dans la pull request. Quand Anthropic livre un nouveau modèle, nous faisons tourner le jeu de référence contre lui l'après-midi même et savons en une heure s'il faut basculer. C'est exactement ce que nous avons fait quand [Fable 5.1 a remplacé Fable 5](/fr/blog/claude-fable-5-1-vs-fable-5).

<div class="article-figure">
<svg viewBox="0 0 900 300" width="100%" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Architecture d'un système d'agents : requête utilisateur, orchestrateur, sous-agents spécialisés, outils via MCP, recherche documentaire, garde-fous et journal d'audit">
<g font-family="Inter,system-ui,sans-serif" font-size="12">
<text x="40" y="34" fill="#f1f3ff" font-size="15" font-weight="700">La forme d'un système d'agents que nous livrons</text>
<rect x="40" y="120" width="110" height="46" rx="8" fill="#151b2e" stroke="#9aa3c7"/>
<text x="95" y="148" text-anchor="middle" fill="#f1f3ff">Utilisateur / app</text>
<rect x="190" y="120" width="130" height="46" rx="8" fill="#151b2e" stroke="#7b8cff"/>
<text x="255" y="141" text-anchor="middle" fill="#f1f3ff">Garde-fous</text>
<text x="255" y="157" text-anchor="middle" fill="#9aa3c7" textLength="120" lengthAdjust="spacingAndGlyphs">contrôles entrée + sortie</text>
<rect x="360" y="120" width="140" height="46" rx="8" fill="#151b2e" stroke="#4fffb0"/>
<text x="430" y="141" text-anchor="middle" fill="#f1f3ff">Orchestrateur</text>
<text x="430" y="157" text-anchor="middle" fill="#9aa3c7">planifie, délègue, arrête</text>
<rect x="540" y="60" width="140" height="40" rx="8" fill="#151b2e" stroke="#ffd166"/>
<text x="610" y="85" text-anchor="middle" fill="#f1f3ff">Sous-agent : recherche</text>
<rect x="540" y="123" width="140" height="40" rx="8" fill="#151b2e" stroke="#ffd166"/>
<text x="610" y="148" text-anchor="middle" fill="#f1f3ff">Sous-agent : analyse</text>
<rect x="540" y="186" width="140" height="40" rx="8" fill="#151b2e" stroke="#ffd166"/>
<text x="610" y="211" text-anchor="middle" fill="#f1f3ff">Sous-agent : rédaction</text>
<rect x="720" y="60" width="140" height="40" rx="8" fill="#151b2e" stroke="#ff6b8a"/>
<text x="790" y="79" text-anchor="middle" fill="#f1f3ff">Outils via MCP</text>
<text x="790" y="93" text-anchor="middle" fill="#9aa3c7">vos API, avec scopes</text>
<rect x="720" y="123" width="140" height="40" rx="8" fill="#151b2e" stroke="#ff6b8a"/>
<text x="790" y="142" text-anchor="middle" fill="#f1f3ff">Recherche</text>
<text x="790" y="156" text-anchor="middle" fill="#9aa3c7">pgvector / OpenSearch</text>
<rect x="720" y="186" width="140" height="40" rx="8" fill="#151b2e" stroke="#ff6b8a"/>
<text x="790" y="205" text-anchor="middle" fill="#f1f3ff">Validation humaine</text>
<text x="790" y="219" text-anchor="middle" fill="#9aa3c7" textLength="130" lengthAdjust="spacingAndGlyphs">avant action irréversible</text>
<g stroke="#2a3150" stroke-width="2" fill="none">
<line x1="150" y1="143" x2="190" y2="143"/><line x1="320" y1="143" x2="360" y2="143"/>
<line x1="500" y1="143" x2="540" y2="80"/><line x1="500" y1="143" x2="540" y2="143"/><line x1="500" y1="143" x2="540" y2="206"/>
<line x1="680" y1="80" x2="720" y2="80"/><line x1="680" y1="143" x2="720" y2="143"/><line x1="680" y1="206" x2="720" y2="206"/>
</g>
<rect x="190" y="230" width="670" height="34" rx="8" fill="#151b2e" stroke="#2a3150"/>
<text x="525" y="252" text-anchor="middle" fill="#9aa3c7">Chaque appel tracé : prompt, modèle, tokens, latence, outils. Les évals tournent sur le même format.</text>
</g>
</svg>
</div>

## Étape 3 : une architecture qui suppose que le modèle se trompera

Une fois que le test initial dit oui, nous concevons le système autour d'une hypothèse : le modèle se trompera parfois, et l'architecture doit rendre cela sûr et visible.

**Accès au modèle.** Sur AWS, nous utilisons Claude via Bedrock : les données restent dans le compte et la région du client, rien n'est utilisé pour l'entraînement, et IAM contrôle qui peut appeler quoi. Hors AWS, nous utilisons directement l'API Anthropic. Quand les données ne peuvent absolument pas quitter un réseau privé, nous avons fait tourner des modèles ouverts sur le matériel du client ; nos notes sur [la sortie du mixture-of-experts open source de Mistral](/fr/blog/mistral-small-4-open-source-moe) et sur [faire tourner Claude Code contre un modèle local](/fr/blog/kimi-k3-local-remote-claude-code) viennent de ce travail.

**Des sorties structurées, validées par le code.** Chaque réponse de modèle qui alimente un système est un objet typé, validé avant d'être utilisé. Un résumé est une chaîne ; une facture extraite est un schéma dont les montants doivent s'additionner correctement. Si la validation échoue, le code relance avec l'erreur, puis retombe sur une file d'attente humaine. Le modèle n'écrit jamais directement dans une base de données.

**Recherche documentaire avec citations.** Pour tout ce qui est répondu à partir de documents, la réponse porte les passages dont elle a été construite, et l'interface les affiche. La recherche hybride (mots-clés plus embeddings) sur PostgreSQL avec pgvector couvre la plupart des corpus ; OpenSearch quand le corpus est volumineux ou que les schémas de requête sont complexes. Nous réglons le découpage et le re-ranking sur le jeu de référence, pas sur un benchmark.

**Des agents qui demandent avant d'agir.** L'assistant de recherche utilise un orchestrateur qui planifie et délègue à des sous-agents spécialisés, chacun avec un ensemble restreint d'outils exposés via des serveurs MCP avec des scopes explicites. Lire est gratuit ; tout ce qui modifie un état en dehors du système attend un clic humain. Le journal d'audit enregistre chaque appel d'outil avec ses entrées, si bien que « pourquoi a-t-il fait ça » a toujours une réponse. Nous avons écrit sur la plateforme derrière tout cela dans [la plateforme Agent Factory](/fr/blog/agent-factory-platform) et sur le schéma général dans [les agents IA d'entreprise à grande échelle](/fr/blog/enterprise-ai-agents-at-scale).

**L'injection de prompt est un problème d'entrée.** Les documents, emails et pages web fournis à un modèle ne sont pas fiables. Les instructions trouvées à l'intérieur sont des données, jamais des commandes. Les garde-fous vérifient les entrées à la recherche de schémas d'injection et les sorties à la recherche de secrets divulgués ou de contenu hors politique, et les sous-agents qui lisent du contenu externe n'ont aucun outil d'écriture.

## Étape 4 : un coût que vous pouvez mettre dans un budget

Pendant le test initial, nous connaissons déjà les tokens par cas. Avant que la construction ne commence, le client reçoit un coût par document, par conversation ou par ticket, au volume attendu, pour deux ou trois choix de modèles. C'est généralement le moment où le plus petit modèle qui passe les évaluations l'emporte, et où le cache de prompt et le batching sont conçus dès le départ plutôt qu'ajoutés après coup.

En production, chaque appel porte le nombre de tokens jusque dans le système de traçage. Il y a des budgets par fonctionnalité et des alertes quand la dépense d'une journée dépasse la prévision. Nous avons vu une simple boucle de relance doubler une facture mensuelle sur un système que nous avons hérité ; une alerte de budget l'aurait détecté en une heure. Pour nos propres coûts d'outillage, nous avons fait le même exercice publiquement dans [ce qu'achètent vraiment 200 $ de Claude](/fr/blog/claude-max-vs-api-what-200-dollars-really-buys).

<div class="article-figure">
<svg viewBox="0 0 900 250" width="100%" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="La boucle d'évaluation : un changement de prompt, de modèle ou de recherche documentaire fait tourner le jeu de données de référence en CI, passe un portail, est déployé par étapes, surveillé, et les nouveaux échecs alimentent le jeu de données de référence">
<g font-family="Inter,system-ui,sans-serif" font-size="12">
<text x="40" y="34" fill="#f1f3ff" font-size="15" font-weight="700">La boucle qui empêche la qualité de dériver</text>
<rect x="40" y="90" width="130" height="50" rx="8" fill="#151b2e" stroke="#7b8cff"/>
<text x="105" y="111" text-anchor="middle" fill="#f1f3ff">Changement</text>
<text x="105" y="128" text-anchor="middle" fill="#9aa3c7" textLength="120" lengthAdjust="spacingAndGlyphs">prompt · modèle · RAG</text>
<rect x="210" y="90" width="130" height="50" rx="8" fill="#151b2e" stroke="#4fffb0"/>
<text x="275" y="111" text-anchor="middle" fill="#f1f3ff">Évaluations en CI</text>
<text x="275" y="128" text-anchor="middle" fill="#9aa3c7">jeu de référence</text>
<rect x="380" y="90" width="110" height="50" rx="8" fill="#151b2e" stroke="#ffd166"/>
<text x="435" y="111" text-anchor="middle" fill="#f1f3ff">Portail</text>
<text x="435" y="128" text-anchor="middle" fill="#9aa3c7">score ≥ référence</text>
<rect x="530" y="90" width="130" height="50" rx="8" fill="#151b2e" stroke="#ff6b8a"/>
<text x="595" y="111" text-anchor="middle" fill="#f1f3ff">Rollout par étapes</text>
<text x="595" y="128" text-anchor="middle" fill="#9aa3c7">1 % → 10 % → tous</text>
<rect x="700" y="90" width="160" height="50" rx="8" fill="#151b2e" stroke="#9aa3c7"/>
<text x="780" y="111" text-anchor="middle" fill="#f1f3ff">Surveillance</text>
<text x="780" y="128" text-anchor="middle" fill="#9aa3c7">qualité · latence · coûts</text>
<g stroke="#2a3150" stroke-width="2" fill="none">
<line x1="170" y1="115" x2="210" y2="115"/><line x1="340" y1="115" x2="380" y2="115"/><line x1="490" y1="115" x2="530" y2="115"/><line x1="660" y1="115" x2="700" y2="115"/>
<path d="M780 140 L780 190 L105 190 L105 140" stroke="#4fffb0" stroke-dasharray="6 4"/>
</g>
<text x="442" y="212" text-anchor="middle" fill="#4fffb0">les nouveaux échecs en production deviennent de nouveaux cas de référence</text>
</g>
</svg>
</div>

## Étape 5 : l'opérer comme du logiciel, parce que c'en est

La fonctionnalité est déployée par étapes : un pour cent du trafic, puis dix, puis tout le monde, avec les évaluations et le traçage qui surveillent chaque étape. Les prompts sont versionnés dans le dépôt, pas dans un tableau de bord. Les versions de modèle sont figées et mises à niveau délibérément, via le jeu de référence. Les échecs en production sont triés chaque semaine, et les cas intéressants deviennent de nouveaux cas de référence, ce qui explique comment le jeu de données passe de deux cents à deux mille cas sans que personne n'écrive de données de test à la main.

C'est aussi là que nous sommes honnêtes sur ce que l'IA ne répare pas. Un processus cassé avec un modèle devant est un processus cassé plus rapide. Nous avons refusé plus d'un projet cette année pour cette raison, et nous avons expliqué pourquoi dans [l'IA ne réparera pas votre application cassée](/fr/blog/ai-wont-fix-your-broken-app).

## Ce que nous utilisons, et ce que nous n'utilisons pas

Nous construisons sur Claude parce que c'est le modèle qui a le mieux performé sur les évaluations de nos clients pour le travail agentique et documentaire, et parce que Bedrock rend faciles les questions d'entreprise (résidence des données, entraînement, IAM). Nous avons utilisé le framework d'agents Strands sur Bedrock pour les systèmes multi-agents, MCP pour les outils, pgvector et OpenSearch pour la recherche documentaire, et PostgreSQL brut pour tout ce que le modèle produit. Nous n'avons de relation de revendeur avec personne ; quand un modèle ouvert passe les évaluations à une fraction du coût, nous le disons.

Ce que nous ne faisons pas, ce sont des démos. Si une fonctionnalité ne peut pas être mesurée sur des données réelles, nous ne prétendrons pas qu'elle fonctionne. Si vous avez un processus riche en langage que vous soupçonnez qu'un modèle pourrait prendre en charge, [envoyez-nous cinquante exemples réels](/contact) et nous vous dirons en deux semaines si c'est possible.
