En évitant de recalculer les mêmes tokens encore et encore. Le cache LLM baisse la latence, réduit le coût d’inférence et rend le serving plus stable. Je vais détailler les 4 caches utiles, ce qu’ils stockent vraiment, et comment je les combine sans créer de réponses fausses.
À quoi sert le KV cache ?
Le KV cache sert à éviter de recalculer les tenseurs Key et Value des tokens déjà traités pendant la génération autorégressive. Dit plus simplement, quand un LLM écrit une réponse, il ne sort pas tout le texte d’un coup. Il génère un token, puis un autre, puis un autre. Un token, c’est un petit morceau de texte, parfois un mot, parfois une partie de mot.

À chaque nouveau token, le modèle utilise l’attention pour regarder ce qui a déjà été écrit. Dans cette attention, il manipule des tenseurs, donc des blocs de nombres. Les Key et les Value représentent une sorte d’index et de contenu utile pour retrouver les informations importantes dans le contexte. Sans cache, le modèle devrait refaire une bonne partie de ces calculs à chaque token. Et là, votre chatbot ralentit, surtout quand la conversation devient longue. Je l’ai vu chez des clients avec des assistants support qui semblaient rapides au début, puis qui devenaient franchement mous après 20 ou 30 échanges.
Avec le KV cache, je garde les calculs déjà faits sur la table au lieu de rouvrir tout le dossier à chaque mot. Le modèle réutilise les états d’attention précédents pour produire le token suivant. C’est très efficace pour le décodage actif, c’est-à-dire la réponse en train d’être générée maintenant.
Ce cache vit pendant une requête en cours. Il est généralement stocké en mémoire GPU, ou dans une mémoire rapide selon l’architecture. Sa taille augmente avec plusieurs facteurs assez concrets.
| Élément | Rôle | Limite | Impact business |
| Tokens déjà traités | Évitent de recalculer l’attention passée | Plus le contexte grandit, plus le cache grossit | Réponse plus rapide, mais mémoire plus chère |
| Couches du modèle | Chaque couche garde ses propres Key et Value | Un gros modèle consomme beaucoup plus | Coût GPU plus élevé |
| Batch | Plusieurs requêtes traitées ensemble | Le cache se multiplie par le nombre de séquences | Meilleur débit, mais risque de saturation mémoire |
| Précision des tenseurs | Format des nombres utilisés en mémoire | Plus c’est précis, plus c’est lourd | Arbitrage entre performance, qualité et coût |
La limite clé, elle est là : le KV cache n’est pas fait pour être repris tel quel par une requête indépendante dans le futur. Il est lié à une génération précise, à son état interne, à son batch, à son contexte exact.
Quand plusieurs requêtes partagent le même début, on change de sujet. Ce n’est plus seulement le décodage actif, c’est la réutilisation du préfixe.
Quand réutiliser un préfixe ?
On réutilise un préfixe quand plusieurs prompts partagent un même début suffisamment long. C’est aussi simple que ça. Si vos appels commencent toujours par le même système prompt, les mêmes consignes, le même contexte documentaire, le même historique commun ou le même gabarit de requête, alors le prefix cache peut vraiment aider.

Le principe est assez concret. Le moteur qui sert le modèle découpe souvent le prompt en blocs de taille fixe. Il calcule, ou associe, une clé de cache à ces blocs. Si le début du prompt est identique à un appel précédent, il peut réutiliser les états KV déjà calculés. Les états KV, pour faire simple, c’est une partie du travail interne du modèle quand il lit le prompt. Si ce travail a déjà été fait sur le même texte, autant ne pas le refaire.
Je le vois surtout marcher dans ces cas-là :
- Les assistants métier avec un gros bloc d’instructions stable.
- Les agents RAG, c’est-à-dire des agents qui récupèrent des documents avant de répondre, avec des consignes communes à chaque appel.
- Les appels API qui répètent toujours la même structure JSON ou le même template.
- Les workflows low code qui envoient de longs préambules avant chaque demande utilisateur.
Le piège, c’est que le cache aime l’identique. Pas le presque identique. Un espace en plus, une date injectée trop tôt, un ordre de métadonnées qui change, une personnalisation placée avant le contexte stable, et vous cassez une partie du bénéfice. J’ai déjà vu un client perdre quasiment tout l’intérêt du cache juste parce qu’il mettait “Date du jour” au début du prompt. Ça changeait tous les matins, donc le préfixe n’était plus stable.
La recommandation pratique est simple : Mettez ce qui change à la fin du prompt quand c’est possible. Le bloc stable d’abord. La question utilisateur, les variables, les dates et les métadonnées volatiles ensuite.
Ce pseudo-code montre l’idée. Le bloc stable reste au début, la partie variable arrive à la fin, ce qui maximise les chances de réutiliser le préfixe en cache.
def build_prompt(user_question):
# Bloc stable : Il doit rester identique entre les appels.
stable_prefix = """
Tu es un assistant métier spécialisé dans le support client.
Tu réponds avec précision, sans inventer.
Tu respectes les règles internes suivantes :
- Toujours citer la source si elle existe.
- Demander une clarification si la demande est ambiguë.
- Répondre en français simple.
Contexte documentaire commun :
Les remboursements sont possibles sous 30 jours.
Les demandes urgentes doivent être escaladées au niveau 2.
"""
# Bloc variable : Il change à chaque appel, donc on le place à la fin.
variable_part = f"""
Question utilisateur :
{user_question}
"""
return stable_prefix + variable_part| Bon prompt pour prefix cache | Mauvais prompt pour prefix cache |
| Instructions stables au début, puis contexte commun, puis question utilisateur à la fin. | Date, utilisateur, langue, métadonnées variables placées avant les instructions stables. |
| Même ordre des sections à chaque appel. | Ordre des champs qui change selon le workflow ou l’outil low code. |
| Préambule long et identique entre plusieurs requêtes. | Préambule reconstruit dynamiquement avec des espaces, labels ou formats différents. |
| Personnalisation ajoutée après le bloc stable quand elle n’est pas nécessaire au début. | Personnalisation injectée dès la première ligne, ce qui casse le préfixe commun. |
Que garde le prompt cache ?
Le prompt cache garde le résultat du traitement d’un prompt, ou d’une grande partie de prompt, pour éviter de payer et d’attendre le même prétraitement à chaque appel. Dit simplement, si j’envoie toujours les mêmes instructions système, la même documentation ou la même politique interne, le modèle n’a pas besoin de tout “relire” comme si c’était nouveau à chaque fois.

Il faut le distinguer du prefix cache. Le prefix cache vise surtout les préfixes identiques au niveau serving, c’est-à-dire côté infrastructure d’inférence. Si deux requêtes commencent exactement pareil, le fournisseur peut réutiliser une partie du calcul déjà fait. Le prompt cache, lui, est souvent exposé comme une fonctionnalité produit ou API. Il sert à réutiliser des contenus longs et stables, par exemple des règles métier, une base documentaire, un contexte applicatif ou un gros prompt système.
Je reste prudent avec ça, parce que tous les fournisseurs ne l’implémentent pas pareil. Certains le font automatiquement dès qu’ils détectent une partie stable. D’autres demandent de structurer explicitement ce qui doit rester stable. Et parfois, deux espaces, une version différente ou un ordre de blocs modifié peuvent suffire à réduire l’intérêt du cache.
En pratique, je fais toujours la même chose sur les projets clients :
- Je sépare le prompt en parties stables et variables.
- Je garde les documents de référence hors de la zone qui change à chaque requête.
- Je versionne les instructions importantes, comme du code.
- Je mesure les économies réelles sur les tokens d’entrée et le temps de première réponse.
Voilà le genre de structure que j’aime bien utiliser. Les champs _comment servent juste à documenter le payload sans casser le JSON.
{
"system_instructions": {
"_comment": "Instructions générales stables pour le modèle",
"content": "Tu réponds comme un assistant support interne. Tu respectes la politique de sécurité."
},
"cached_context": {
"_comment": "Bloc long et stable, candidat au prompt cache",
"cache_version": "policy-v3.2",
"content": "Documentation produit, procédures internes, règles métier..."
},
"user_query": {
"_comment": "Partie variable, différente à chaque demande",
"content": "Comment traiter une demande de remboursement hors délai ?"
},
"cache_version": "assistant-support-2026-01"
}Le piège, c’est de croire que le prompt cache autorise à envoyer n’importe quoi. Non. Un contexte trop gros, mal rangé, avec des infos inutiles, reste coûteux. Et pire, il peut dégrader la qualité des réponses. J’ai déjà vu des prompts “optimisés” avec 40 pages de contexte dont 80 % ne servaient à rien. Le cache réduisait la facture, mais le modèle répondait moins bien.
Le prompt cache économise sur l’identique. C’est sa force, mais aussi sa limite. Si la question est proche, ou si le texte change un peu, il ne sait pas forcément réutiliser intelligemment ce qui a déjà été vu. C’est là qu’arrive le semantic cache.
À quoi sert le semantic cache ?
Le semantic cache sert à réutiliser une réponse quand une nouvelle demande veut dire à peu près la même chose qu’une demande déjà traitée. C’est ça la différence clé. Ici, on ne cache pas seulement des tokens, un préfixe identique, ou une URL appelée deux fois. On cache une intention.

La logique est assez simple. Je transforme la question en embedding, c’est-à-dire une représentation numérique du sens de la phrase. Je cherche ensuite les requêtes proches dans une base vectorielle. Puis j’applique un seuil de similarité. Si le score est assez haut et que la réponse est encore fraîche, je retourne la réponse en cache. Si j’ai un doute, je repasse par le LLM.
C’est très utile sur des cas où les utilisateurs posent souvent la même question avec des mots différents :
- FAQ support, avec “Comment réinitialiser mon mot de passe ?” et “J’ai oublié mon accès”.
- Recherche interne, quand plusieurs formulations visent le même document.
- Assistant RH, pour les congés, notes de frais, mutuelle, télétravail.
- Aide e-commerce, sur les retours, délais, garanties.
- Génération de réponses récurrentes, par exemple des emails ou résumés très standards.
Le piège, c’est de croire que “proche” veut dire “bon”. Une réponse peut être obsolète. Le contexte utilisateur peut changer. Un prix ou un stock peut bouger. Un utilisateur peut ne pas avoir les mêmes droits qu’un autre. Et parfois deux questions se ressemblent mais n’attendent pas du tout la même réponse. J’ai déjà vu ça chez un client sur un assistant support : le cache répondait trop vite, mais mélangeait deux offres commerciales assez proches. Ça coûtait moins cher, oui, mais ça créait des mauvaises réponses.
Voici un exemple minimaliste, en mémoire. Il montre l’idée sans dépendre d’un fournisseur d’embeddings précis.
import time
import math
CACHE = []
TTL_SECONDS = 3600
SIMILARITY_THRESHOLD = 0.88
def cosine_similarity(a, b):
# Calcule la proximité entre deux vecteurs.
dot = sum(x * y for x, y in zip(a, b))
norm_a = math.sqrt(sum(x * x for x in a))
norm_b = math.sqrt(sum(y * y for y in b))
return dot / (norm_a * norm_b) if norm_a and norm_b else 0
def is_fresh(entry):
# Vérifie que la réponse n'est pas trop ancienne.
return time.time() - entry["created_at"] < TTL_SECONDS
def get_from_cache(question, embed):
# Embed est une fonction fournie par votre stack.
query_vector = embed(question)
best_entry = None
best_score = 0
for entry in CACHE:
if not is_fresh(entry):
continue
score = cosine_similarity(query_vector, entry["vector"])
if score > best_score:
best_score = score
best_entry = entry
if best_entry and best_score >= SIMILARITY_THRESHOLD:
return best_entry["answer"], best_score
return None, best_score
def save_to_cache(question, answer, embed):
# Stocke la question, son vecteur et la réponse générée.
CACHE.append({
"question": question,
"vector": embed(question),
"answer": answer,
"created_at": time.time()
})Dans un vrai projet, je mets toujours des garde-fous. Un TTL, une invalidation propre, une segmentation par tenant ou utilisateur, des logs, un score minimum, et un fallback vers le LLM dès que le doute est raisonnable.
| Confiance | Score indicatif | Action recommandée |
| Faible | < 0.80 | Ne pas utiliser le cache, appeler le LLM. |
| Moyen | 0.80 à 0.90 | Utiliser avec validation, ou fallback si contexte sensible. |
| Élevé | > 0.90 | Retourner le cache si fraîcheur et droits d’accès sont OK. |
Comment les combiner ?
On combine les caches LLM en couches, du plus sûr et technique au plus métier et risqué. Je pars toujours de ce qui ne change presque pas la réponse, puis je monte vers des caches plus “intelligents”, mais aussi plus sensibles aux erreurs.

L’ordre logique ressemble à ça. D’abord le KV cache, pendant la requête active. Il garde en mémoire les calculs internes du modèle, les clés et valeurs d’attention, pour éviter de recalculer tout l’historique à chaque token généré. Puis le prefix cache, quand plusieurs requêtes commencent pareil. Ensuite le prompt cache, utile pour les grands contextes stables, par exemple une longue documentation système ou un contrat injecté souvent. Et seulement après, le semantic cache, qui réutilise une réponse quand l’intention de l’utilisateur est proche, même si les mots changent.
| Cache | Ce qui est caché | Réutilisable entre requêtes | Gain principal | Risque |
| KV cache | États internes pendant la génération | Non, surtout pendant la requête active | Latence de génération | Très faible |
| Prefix cache | Début identique du prompt | Oui, si le préfixe est strictement stable | Temps de prétraitement | Faible |
| Prompt cache | Grand contexte stable | Oui, selon le fournisseur ou le serveur LLM | Coût tokens et latence | Moyen si le contexte change mal |
| Semantic cache | Intention proche et réponse associée | Oui | Coût complet d’appel LLM | Plus élevé, car une réponse proche peut être fausse |
Ces caches ne remplacent pas l’optimisation du prompt, du modèle, du RAG ou du routage. Le RAG, c’est la recherche de documents avant génération. Le routage, c’est envoyer la demande vers le bon modèle ou le bon workflow. Le cache réduit surtout les recalculs inutiles. Il ne corrige pas un mauvais prompt, un mauvais contexte ou un modèle trop gros pour la tâche.
Sur le terrain, je fais simple.
- Je mesure la latence réelle, token par token si possible, parce qu’un cache qu’on ne mesure pas devient vite une croyance.
- J’identifie les prompts répétitifs, surtout les instructions système, les gabarits et les longs contextes réinjectés partout.
- Je stabilise les préfixes, avec le même ordre, les mêmes séparateurs, les mêmes blocs, sinon le cache rate pour une virgule déplacée.
- J’active le cache côté serving, c’est-à-dire la couche qui sert le modèle en production, ou directement chez le fournisseur si l’API le propose.
- J’ajoute un semantic cache seulement sur les cas où l’erreur coûte peu, ou peut être contrôlée par une validation, un score de confiance ou une règle métier.
Observation honnête, vue plusieurs fois chez des clients. Le plus gros gain vient souvent d’abord d’un prompt mieux structuré. Un prompt avec un préfixe stable, des blocs clairs et moins de contexte inutile peut déjà faire baisser le coût et rendre le cache beaucoup plus efficace, avant même d’ajouter une couche compliquée.
Le bon cache LLM n’est pas celui qui paraît le plus intelligent. C’est celui qui enlève le plus de calcul inutile sans dégrader la réponse.
Et maintenant, quel cache LLM faut il activer ?
Je commencerais simple. Le KV cache est la base, il accélère la génération en cours. Le prefix cache devient très rentable dès que vos prompts partagent un même début. Le prompt cache aide quand vous envoyez souvent de gros contextes stables. Le semantic cache, lui, peut faire gagner beaucoup, mais je le garde pour les cas où la similarité est bien contrôlée. Mon approche, c’est de mesurer avant d’empiler. Latence, coût par requête, taux de réutilisation, erreurs évitées ou créées. Le bénéfice pour vous est clair : un LLM plus rapide, moins cher, et plus fiable en production.
FAQ
- Quelle est la différence entre KV cache et prefix cache ?
Le KV cache sert pendant une requête active. Il garde les états Key et Value déjà calculés pour générer les tokens suivants plus vite. Le prefix cache va plus loin : il réutilise un début de prompt identique entre plusieurs requêtes différentes. - Le prompt cache réduit il vraiment les coûts LLM ?
Oui, surtout si vous envoyez souvent les mêmes gros contextes : consignes système, documentation, règles métier, exemples. Le gain dépend du fournisseur, du modèle, de la longueur du prompt et du taux réel de réutilisation. - Le semantic cache est il risqué ?
Il peut l’être si on retourne une ancienne réponse juste parce qu’une question semble proche. Je l’utilise avec un seuil de similarité, une durée de vie, une séparation par utilisateur ou client, et un retour vers le LLM dès qu’il y a un doute. - Quel cache LLM faut il activer en premier ?
Je regarde d’abord ce qui existe déjà côté moteur de serving ou fournisseur. En général, le KV cache est natif. Ensuite je travaille le prefix cache en stabilisant le début des prompts. Le semantic cache vient après, sur des cas bien cadrés. - Comment mesurer l’efficacité d’un cache LLM ?
Je suis quelques métriques simples : latence totale, temps avant le premier token, coût moyen par requête, taux de cache hit, longueur des prompts, erreurs de réponse et taux de fallback. Sans mesure, on croit optimiser, mais on déplace parfois juste le problème.
A propos de l’auteur
Je suis Franck Scandolera, responsable de l’agence webAnalyste et de l’organisme Formations Analytics. J’accompagne des entreprises sur le tracking server-side, l’analytics engineering, l’automatisation no code et low code avec n8n, l’intégration de l’IA dans les process métier et le SEO/GEO. J’ai travaillé avec des équipes chez Logis Hôtel, Yelloh Village, BazarChic, la Fédération Française de Football ou Texdecor. Si vous voulez rendre vos workflows IA plus fiables, plus mesurables et plus rentables, je peux vous aider. Contactez-moi.
⭐ Analytics engineer, Data Analyst et Automatisation IA indépendant ⭐
- Ref clients : Logis Hôtel, Yelloh Village, BazarChic, Fédération Football Français, Texdecor…
Mon terrain de jeu :
- Data Analyst & Analytics engineering : tracking avancé (GTM server, e-commerce, CAPI, RGPD), entrepôt de données (BigQuery, Snowflake, PostgreSQL, ClickHouse), modèles (Airflow, dbt, Dataform), dashboards décisionnels (Looker, Power BI, Metabase, SQL, Python).
- Automatisation IA des taches Data, Marketing, RH, compta etc : conception de workflows intelligents robustes (n8n, App Script, scraping) connectés aux API de vos outils et LLM (OpenAI, Mistral, Claude…).
- Engineering IA pour créer des applications et agent IA sur mesure : intégration de LLM (OpenAI, Mistral…), RAG, assistants métier, génération de documents complexes, APIs, backends Node.js/Python.






