Paramètres

Langue

Pourquoi votre cache sémantique renvoie de mauvaises réponses

T
TokenLab
·5 mars 2026·13 min de lecture·Mis à jour 14 juillet 2026·1657 vues
#cache sémantique#embeddings#infrastructure LLM#débogage en production
Pourquoi votre cache sémantique renvoie de mauvaises réponses

Un utilisateur a signalé que notre plugin de traduction renvoyait le même résultat mis en cache pour chaque requête, indépendamment de l'entrée. Après enquête, nous avons découvert quelque chose de pire : 95 % de tous les hits du cache sémantique sur notre plateforme étaient des faux positifs. 199 requêtes de traduction différentes, 198 corps de requête uniques, et une seule réponse mise en cache servie à tous.

Si vous vous souciez de l'état persistant des agents et de la gestion des requêtes en production, cet article complète bien Pourquoi votre agent IA perd constamment la mémoire, le guide du chatbot à clé unique, et le guide de limitation de débit de l'API IA.

Points clés

  • 95 % des hits du cache sémantique sur la plateforme étaient des faux positifs, avec 198 requêtes uniques recevant toutes la même réponse mise en cache.
  • La cause profonde est l'entrée structurée. Le texte fixe du modèle (template) domine le vecteur d'embedding, si bien que le contenu variable modifie à peine la similarité cosinus.
  • Augmenter le seuil de similarité ne résout pas le problème, car les distributions des hits corrects et incorrects se chevauchent. Des recherches récentes sur la fiabilité du cache sémantique confirment ce schéma.
  • La solution se décline en deux couches : extraire le contenu significatif avant l'embedding, puis vérifier chaque hit avec un hash d'empreinte rapide FNV-1a. Cela a fait chuter les faux positifs d'environ 95 % à moins de 5 %.
  • Le choix du modèle affecte l'exposition. Les longs prompts système et les entrées encapsulées en JSON aggravent le problème, quel que soit le modèle qui génère la complétion ; consultez le répertoire des modèles de TokenLab (observé le 07/07/2026) pour connaître les options actuelles si vous décidez quels modèles utiliser pour le trafic mis en cache.

Le rapport de bug

Le rapport était simple : « J'ai désactivé le cache sémantique, mais chaque traduction renvoie le même résultat. »

Trois ID de requête, trois segments de traduction différents, des réponses mises en cache identiques. Les corps de requête variaient de 1 564 à 8 676 octets. L'ID de la réponse mise en cache était le même pour tous : chatcmpl-DG6J03nhdvcF7Ek0C8rJkjh7lN9pF.

Première suspicion : les paramètres de cache de l'utilisateur n'étaient pas appliqués. Il s'est avéré qu'il s'agissait d'un bug distinct de synchronisation des sources de données (le panneau d'administration écrivait dans une table, la passerelle API lisait dans une autre). Corriger cela n'a résolu que la moitié du problème. Même avec un cache activé et fonctionnant correctement, le cache sémantique faisait correspondre des requêtes qui ne devraient jamais correspondre.

Les données de production

Nous avons extrait 24 heures de données de hits de cache depuis ClickHouse. Les chiffres étaient mauvais.

Modèle Total Requêtes Hits Cache Requêtes Uniques Réponses Uniques Taux de Hit
DeepSeek V4 Flash 200 199 198 1 99,5 %
glm-4.6-thinking 100 38 13 1 38 %
gpt-5-nano 31 29 28 2 93,5 %
gpt-oss-120b 18 17 17 1 94,4 %
qwen3-vl-flash 17 16 16 1 94,1 %

198 requêtes de traduction uniques, toutes renvoyant la même réponse mise en cache. Ce n'est pas un cache. C'est une fonction cassée qui renvoie une constante.

Chaque modèle affecté partageait deux traits : toutes les requêtes provenaient d'un seul utilisateur et toutes utilisaient un modèle de prompt système fixe avec un contenu utilisateur variable. Pour une liste actuelle des modèles disponibles sur la plateforme, le répertoire des modèles de TokenLab (observé le 07/07/2026) est la source de vérité, car les offres changent souvent.

Comment détecter cela dans votre propre système

Vous n'avez pas besoin de nos logs pour savoir si vous avez le même problème. Le signal le plus rapide est la diversité des réponses par modèle. Si un modèle a un taux de hit élevé mais presque aucune réponse unique, vous servez une seule réponse à de nombreuses questions différentes.

Voici la requête de style ClickHouse que nous avons utilisée, généralisée :

SELECT
  model,
  count() AS total_hits,
  uniqExact(substring(response_body, 1, 200)) AS unique_responses,
  round(uniqExact(substring(response_body, 1, 200)) / count(), 3) AS diversity_ratio
FROM request_logs
WHERE cache_hit = true
GROUP BY model
ORDER BY total_hits DESC;

Un cache sain a un diversity_ratio proche de 1,0, ce qui signifie que la plupart des hits renvoient des réponses distinctes pour des entrées distinctes. Un ratio proche de 0 signifie que de nombreuses requêtes s'effondrent sur une poignée de réponses mises en cache. Tout résultat inférieur à environ 0,5 sur un modèle avec une réelle variété d'entrées mérite une enquête.

Si vous ne loggez pas les corps de réponse, un proxy moins coûteux fonctionne aussi : comparez le nombre de corps de requête uniques par rapport au nombre de réponses uniques servies depuis le cache. Lorsque 198 requêtes uniques correspondent à 1 réponse, le cache ne fait pas correspondre le sens, il fait correspondre du texte standard.

Un second indicateur est constitué par les plaintes des utilisateurs qui se concentrent sur des charges de travail structurées. Les plugins de traduction, les résumeurs, les outils de remplissage de formulaires et les outils JSON-in/JSON-out sont les suspects habituels, car ils enveloppent un contenu variable dans un modèle fixe.

Pourquoi les embeddings échouent sur les entrées structurées

Le plugin de traduction envoie des requêtes comme celle-ci :

System: "Act as a translation API. Output a single raw JSON object only.
         Input: {"targetLanguage":"<lang>","title":"...","segments":[...]}"

User:   {"targetLanguage":"zh","title":"Product Page",
         "description":"Translate product descriptions",
         "tone":"formal",
         "segments":[{"text":"actual varying content here"}]}

Le prompt système est identique pour toutes les requêtes. Le message utilisateur est un objet JSON où targetLanguage, title, description et tone sont fixes. Seul segments[].text change.

Lorsque notre cache sémantique extrait du texte pour l'embedding, il concatène le prompt système et le message utilisateur. Le modèle fixe représente environ 80 % du texte. Le modèle d'embedding (all-mpnet-base-v2, 768 dimensions) compresse cela en un vecteur où la structure du modèle domine. Le contenu réel de la traduction modifie à peine le résultat.

Résultat : la similarité cosinus entre « translate 'Hello world' » et « translate 'The quarterly financial report shows a 15% increase in revenue' » dépasse 0,95. Notre seuil est de 0,95. Chaque requête de traduction correspond à la première entrée mise en cache.

En fouillant dans les logs, nous avons trouvé trois façons dont cela échoue :

Le plugin de traduction est le pire contrevenant. Les clés et valeurs JSON fixes noient les segments de traduction réels. DeepSeek V4 Flash et gpt-5-nano sont tous deux touchés par cela.

Un assistant de résumé de contexte avait une variante du même problème. Son prompt système était si long que le contenu utilisateur, allant de 5 Ko à 47 Ko, était à peine enregistré dans l'embedding. C'est ainsi que glm-4.6-thinking a fini par renvoyer le même résumé pour chaque conversation.

Le troisième schéma était plus subtil. Pour gpt-oss-120b et qwen3-vl-flash, les 500 premiers caractères de chaque requête étaient identiques octet par octet. Le contenu variable venait après, mais l'embedding était déjà dominé par le préfixe partagé.

Ce que dit la recherche

Ce n'est pas un problème nouveau. Des articles récents l'ont quantifié.

Le projet vCache de l'UC Berkeley a découvert que les distributions de similarité des hits de cache corrects et incorrects se chevauchent fortement, ce qui signifie qu'aucun seuil fixe ne sépare nettement une vraie correspondance d'une fausse correspondance structurellement similaire. Cette découverte correspond exactement à ce que nous avons vu en production : les faux positifs du plugin de traduction se regroupaient au-dessus de 0,95, bien à l'intérieur de la plage où vivent également les correspondances de paraphrase légitimes.

D'autres travaux récents sur la fiabilité du cache sémantique aboutissent à des conclusions similaires : la similarité brute des embeddings est un signal nécessaire mais non suffisant pour la correction du cache, et tout système de production reposant uniquement sur cela doit s'attendre à un taux de faux positifs significatif sur un trafic structuré et riche en modèles.

La solution en deux couches

La couche 1 est l'extraction de contenu. Avant l'embedding, supprimez le prompt système fixe et l'échafaudage du modèle, et n'intégrez que la charge utile variable : le contenu réel de segments[].text, et non les clés JSON environnantes et le texte standard. Cela augmente considérablement le rapport signal sur bruit dans le vecteur d'embedding.

La couche 2 est la vérification par empreinte digitale (fingerprint). Même avec une meilleure extraction, un contenu quasi identique peut toujours produire des scores de similarité élevés. Avant de servir un hit de cache, calculez un hash rapide (nous avons utilisé FNV-1a) sur le contenu extrait de la requête entrante et de l'entrée mise en cache. Si les hashs correspondent exactement, servez le cache. S'ils ne correspondent pas, passez à une complétion fraîche ou, pour un trafic à plus haute valeur, routez vers un appel de vérification peu coûteux qui évalue le sens, pas les octets.

L'erreur consiste à ignorer complètement la vérification et à faire confiance à la similarité cosinus brute. Chaque approche du tableau bat cela. Commencez par la moins coûteuse qui correspond à votre type de requête, et ne montez en gamme que lorsque vous mesurez de réels manques de paraphrase.

Ensemble, ces deux couches ont fait chuter notre taux de faux positifs d'environ 95 % à moins de 5 % dans le trafic affecté.

Quand le cache sémantique est le mauvais outil

Le cache n'est pas une ingénierie gratuite, et certaines charges de travail ne valent pas la peine d'être mises en cache.

  • Trafic à haute cardinalité et faible répétition. Si presque chaque requête est unique, par exemple pour une génération créative unique, le taux de hit est trop faible pour justifier la surcharge d'embedding. Vous payez pour tout intégrer et vous encaissez rarement.
  • Sorties qui doivent être fraîches. Tout ce qui est sensible au temps, données en direct, résultats personnalisés, tout ce qui contient un « aujourd'hui », peut renvoyer des réponses obsolètes depuis le cache même lorsque la correspondance est techniquement correcte. La réponse était bonne il y a une heure et est fausse maintenant.
  • Domaines de correction stricte. Pour les réponses médicales, juridiques ou financières, un seul faux positif peut être pire que le coût économisé. Si vous mettez en cache ici, la couche de vérification est obligatoire, pas optionnelle, et une vérification de niveau LLM peut être la seule acceptable.
  • Prompts minuscules où l'appel au modèle est déjà bon marché. L'embedding, la recherche de similarité et la vérification ont leur propre coût. Si la complétion sous-jacente représente quelques centaines de tokens sur un modèle bon marché, la mise en cache peut coûter plus cher qu'elle ne rapporte.

Le cache brille sur les complétions répétitives, riches en modèles et coûteuses, exactement les charges de travail où un faux positif est aussi le plus facile à introduire. Cette tension est la raison pour laquelle la couche de vérification est importante. Si votre objectif est principalement le contrôle des coûts, il vaut également la peine de coupler la mise en cache avec un routage de modèle moins cher. La comparaison des prix et le guide des meilleurs modèles IA pour le codage couvrent d'où proviennent réellement les économies par token, et le répertoire des modèles de TokenLab (observé le 07/07/2026) montre les options actuelles, y compris les choix de routage à faible coût comme DeepSeek V4 Flash et Gemini 3.5 Flash, si vous pesez quel modèle utiliser pour router le trafic mis en cache versus non mis en cache. Vérifiez les prix actuels sur le répertoire lié avant de vous engager dans un plan de routage.

Pourquoi ne pas simplement augmenter le seuil ?

Notre seuil est déjà de 0,95. L'augmenter n'aide pas. Le problème est que des entrées structurellement similaires produisent des scores de similarité supérieurs à 0,95, quel que soit le contenu réel.

Les données de vCache confirment cela : les distributions de similarité des hits corrects et incorrects se chevauchent tellement qu'aucune coupure unique ne les sépare. Poussez le seuil à 0,99 et vous tuerez des hits de cache légitimes pour des paraphrases authentiques, tandis que des requêtes structurellement identiques, comme nos charges utiles JSON de traduction, se regrouperont toujours au-dessus de 0,99, quel que soit le contenu. Le seuil n'est pas le levier. C'est la représentation de l'entrée. C'est pourquoi la couche 1 (extraction de contenu) et la couche 2 (vérification par empreinte) fonctionnent là où une augmentation du seuil ne fonctionne pas : elles changent ce qui est comparé, et non la rigueur de la comparaison.

Si vous construisez ou maintenez un cache sémantique, traitez le seuil comme un filtre grossier, pas comme une garantie de correction. Couplez-le à une extraction de contenu afin que l'embedding représente réellement la partie variable de la requête, puis ajoutez une étape de vérification peu coûteuse afin qu'une correspondance d'embedding quasi-manquée ne puisse jamais devenir silencieusement une mauvaise réponse en production.

Commencez avec le répertoire des modèles de TokenLab pour comparer les prix et les benchmarks actuels entre les modèles de pointe, de codage et de routage à faible coût avant de câbler votre couche de vérification de cache. Quel que soit le modèle derrière votre point de terminaison de complétion, l'approche extraction-plus-empreinte est ce qui corrige réellement les faux positifs.

FAQ

Augmenter le seuil de similarité corrige-t-il les faux positifs du cache sémantique ? Non. Les recherches de vCache et les études connexes montrent que les distributions des hits corrects et incorrects se chevauchent sur toute la plage du seuil, donc pousser la coupure plus haut bloque les correspondances légitimes sans filtrer de manière fiable les requêtes structurellement similaires mais sémantiquement différentes.

Quel est le moyen le moins coûteux de vérifier un hit de cache sémantique ? Un hash d'empreinte (FNV-1a ou similaire) sur le contenu extrait et significatif ajoute moins d'une milliseconde de latence et est gratuit à calculer. Il ne détectera pas les paraphrases, mais il élimine les faux positifs exacts comme ceux décrits ici, ce qui représente la majeure partie des dommages dans les charges de travail structurées.

Ce problème dépend-il du modèle qui sert la complétion ? Non, le problème des faux positifs réside dans la couche d'embedding et de correspondance, pas dans le modèle de complétion. Tout modèle derrière un cache sémantique, qu'il s'agisse de DeepSeek V4 Flash, glm-4.6-thinking ou quelque chose de plus récent, sera affecté de la même manière si le cache intègre du texte de modèle fixe aux côtés d'un contenu variable. Consultez le répertoire des modèles de TokenLab (observé le 07/07/2026) pour la disponibilité actuelle des modèles lors du choix des modèles à router via un pipeline mis en cache.

Sources

Prix observé le 2026-07-07

Partager:

Modèles liés

Modèles publics récents

Construire avec les modèles de ce guide

Comparez les prix, testez les routes et transformez la recherche en appel API fonctionnel.