Paul Blanquer

IA · Architecture

Pourquoi je ne livre plus d'IA sans citations

Un client m'a un jour demandé, en regardant une démo de génération IA : « comment je sais que c'est vrai ? ». Bonne question, et la seule qui compte vraiment quand on met un LLM entre les mains d'un commercial qui va l'envoyer à un prospect. Un texte fluide et faux, signé par l'entreprise du client, n'est pas une fonctionnalité. C'est un passif.

Le problème que personne ne montre dans les démos

Les démos d'IA générative sont impressionnantes parce qu'elles montrent le meilleur cas : un texte cohérent, bien tourné, qui semble informé. Ce qu'elles ne montrent pas, c'est le cas où le modèle affirme qu'une entreprise « vient de lever des fonds » alors que rien de tel n'existe dans les données récupérées. En B2B, ce genre d'erreur part avec le nom de l'expéditeur et engage sa crédibilité.

Le problème n'est pas que les LLM se trompent. C'est qu'ils se trompent avec exactement la même assurance que quand ils ont raison. Rien, dans le texte produit, ne distingue une affirmation vérifiée d'une hallucination plausible.

Et ce n'est pas un défaut de jeunesse que la prochaine génération de modèles corrigera. Dans Why Language Models Hallucinate, Adam Kalai et ses coauteurs avancent une explication déplaisante : l'hallucination est le produit rationnel de la façon dont on entraîne et on évalue les modèles. La plupart des benchmarks notent une réponse juste ou fausse, sans jamais créditer un « je ne sais pas ». Face à une question incertaine, un modèle qui tente sa chance marque des points en moyenne ; un modèle qui s'abstient n'en marque aucun. Comme un étudiant devant un QCM sans points négatifs, il a statistiquement raison de deviner. On a donc passé des années à optimiser des systèmes qui devinent plutôt que des systèmes qui doutent. L'aplomb n'est pas un bug de surface, c'est ce qu'on a récompensé.

La conséquence pratique est simple. Si l'assurance du modèle n'est pas un signal de fiabilité, il faut fabriquer ce signal ailleurs, en dehors du modèle.

Ce que j'ai construit dans Project A

Project A génère des séquences de prospection : des emails et messages destinés à des décideurs, à partir de signaux réels (un post LinkedIn, une actualité d'entreprise, un changement de poste). L'architecture que j'ai mise en place traite la génération non comme une boîte noire mais comme un pipeline à trois étapes.

D'abord, la génération elle-même : le modèle rédige le message en s'appuyant sur les sources récupérées pour ce prospect. Ensuite, une passe d'attribution : chaque phrase du texte généré est comparée aux sources disponibles pour déterminer si elle peut y être rattachée. Enfin, l'affichage : les phrases sourcées portent une note de bas de page cliquable vers la source réelle, les phrases non sourcées sont visuellement signalées, et un compteur global affiche par exemple « 1/2 phrases sourcées » pour que l'utilisateur voie d'un coup d'œil la fiabilité du message.

Le choix de la phrase comme unité d'attribution n'est pas arbitraire. C'est la granularité que retient aussi l'API Citations d'Anthropic, qui découpe les documents sources en phrases avant de les passer au modèle, puis renvoie pour chaque affirmation les passages exacts qui la soutiennent. La raison tient en deux bornes : en dessous de la phrase, on attribue des fragments de syntaxe qui n'affirment rien de vérifiable ; au-dessus, au paragraphe, une seule ligne inventée suffit à contaminer un bloc entier estampillé « sourcé ». La phrase est le plus petit fragment qui porte encore une affirmation entière.

Voici, simplifiée, la structure de données qui porte cette logique :

type SourceRef = {
  url: string
  label: string
}

type GroundedSentence = {
  text: string
  source?: SourceRef
}

function verify(sentences: GroundedSentence[]) {
  const sourced = sentences.filter((s) => s.source).length
  return { sourced, total: sentences.length }
}

Quand l'utilisateur clique sur « Regénérer (grounded) », ce n'est pas la même génération avec un autre seed. C'est une génération contrainte : le prompt est reformulé pour n'autoriser que les affirmations directement soutenues par les sources récupérées, quitte à produire un message plus court, plus prudent, mais entièrement vérifiable.

Les compromis, sans les cacher

Ce système a un coût. La passe d'attribution ajoute de la latence : on ne peut plus se contenter de streamer le texte du modèle directement à l'écran, il faut vérifier avant d'afficher le statut de chaque phrase.

Il y a surtout un arbitrage, et il porte un nom dans la littérature. Le benchmark ALCE (Gao et al., EMNLP 2023), qui évalue la capacité des LLM à citer correctement leurs sources, le décompose en deux métriques distinctes : le rappel des citations, soit la proportion des phrases produites qui sont effectivement soutenues par les passages cités, et la précision des citations, soit la proportion des citations qui soutiennent réellement la phrase à laquelle elles sont attachées. Les deux se mesurent avec un modèle d'inférence en langue naturelle, qui teste si le passage cité implique bien la phrase, plutôt que de se contenter d'une ressemblance lexicale.

Le curseur entre les deux est un choix produit, pas un détail d'implémentation. Une attribution trop stricte signale comme non sourcées des phrases pourtant correctes : c'est frustrant. Une attribution trop permissive laisse passer des approximations : c'est dangereux. J'ai choisi de pencher du côté strict, c'est-à-dire de privilégier la précision du label « sourcé » quitte à en perdre en rappel. La raison est asymétrique : une phrase correcte signalée à tort coûte dix secondes de relecture à l'utilisateur, une phrase fausse estampillée « sourcée » coûte la confiance dans tout le système. Mieux vaut un message qui se dit prudemment incomplet qu'un message qui se dit sûr de lui à tort.

Et il y a le cas où rien n'est sourçable : pas de signal récent, pas d'actualité, pas de post. Dans ce cas, le système ne force pas une génération créative pour combler le vide. Il le dit, et laisse la place à un message plus générique, assumé comme tel plutôt que déguisé en personnalisation.

Ce que ça change pour un client

Un commercial qui envoie un message généré par IA engage sa réputation et celle de son entreprise. Pouvoir vérifier, en un coup d'œil, ce qui est prouvé et ce qui ne l'est pas transforme l'IA d'un générateur de texte anxiogène en un outil de travail dont on comprend les limites.

C'est aussi, et ce n'est pas une inquiétude théorique, une question de sécurité juridique. En 2024, le Civil Resolution Tribunal de Colombie-Britannique a condamné Air Canada à indemniser un passager à qui son chatbot avait décrit une politique de tarifs de deuil qui n'existait pas (Moffatt v. Air Canada, 2024 BCCRT 149). La compagnie avait plaidé que le chatbot constituait une entité juridique distincte, responsable de ses propres déclarations. Le tribunal a écarté l'argument sans détour : un chatbot a beau avoir une composante interactive, il reste une partie du site d'Air Canada, et une entreprise répond de toute l'information qui s'y trouve, qu'elle vienne d'une page statique ou d'un agent conversationnel. La transposition est immédiate : une affirmation fausse sur un prospect, un chiffre, un événement, ce n'est pas le modèle qui l'affirme, c'est celui qui l'envoie.

La traçabilité n'est donc pas un supplément d'âme, c'est une condition d'adoption : les équipes commerciales n'utilisent durablement un outil d'IA que si elles peuvent lui faire confiance sans le relire ligne à ligne à chaque fois.

C'est la conviction qui guide la façon dont j'intègre l'IA dans les produits que je construis : la génération n'est utile que si elle est vérifiable. Si vous avez un produit où l'IA doit produire du texte engageant pour votre entreprise ou vos clients, c'est exactement ce genre de garde-fou que je mets en place, dès l'architecture.