Comment Codex résout différemment la compaction
J'ai décortiqué comment Codex gère le débordement de contexte face à Claude Code : chiffrement AES, session handover et optimisation du KV cache.
Si vous avez utilisé Claude Code sérieusement, vous connaissez ce moment : “Compacting conversation…” s’affiche dans le terminal, et à partir de là, quelque chose cloche. Le modèle commence à oublier ce dont vous parliez dix minutes plus tôt. La latence grimpe. Vous posez une question sur une fonction que vous venez de refactoriser ensemble, et il répond comme si c’était la première fois qu’il en entendait parler.
C’est parce que la fenêtre de contexte de 200K tokens de Claude Code se remplit bien plus vite que la plupart des gens ne l’anticipent. Une grosse session de refactoring, quelques lectures de fichiers, des appels d’outils avec des sorties verbeuses, et vous êtes à saturation. Quand ce seuil est atteint (environ 75-92% de la fenêtre, même si je l’ai vu se déclencher dès 65%), Claude Code résume la conversation, supprime les messages originaux et continue uniquement avec le résumé. Ce qui n’a pas été capturé dans le résumé est définitivement perdu.
J’entendais souvent dire que Codex d’OpenAI gérait ça différemment, alors j’ai épluché toutes les analyses publiques disponibles. Les travaux les plus intéressants viennent de Kangwook Lee, CAIO chez Krafton, qui a utilisé de l’injection de prompt pour faire de la rétro-ingénierie sur le pipeline réel.
Ce que la compaction perd et pourquoi ça compte
Le problème de fond est simple. La summarisation est une compression avec pertes. Quand Claude Code compacte, il lance une summarisation en arrière-plan de l’intégralité de la conversation, crée un bloc de compaction, et jette tout ce qui précède. Les fichiers CLAUDE.md survivent parce qu’ils sont relus depuis le disque, mais tout ce que vous avez dit uniquement dans la conversation disparaît à moins que le summariseur l’ait capturé.
Les résultats des appels d’outils sont là où ça fait le plus mal. Quand vous demandez à Claude Code de lire un fichier, le contenu complet entre dans le contexte. Quand vous exécutez une commande, la sortie complète entre dans le contexte. Ces résultats d’outils sont souvent les parties les plus denses en information de la conversation, et c’est précisément ce qui se fait aplatir pendant la summarisation. Un fichier de 500 lignes devient une phrase du type “a lu le fichier de configuration et noté les paramètres de la base de données.” Les valeurs précises, les cas limites dont vous avez discuté, les numéros de lignes que vous avez référencés : tout ça disparaît.
J’ai vu ça se produire des dizaines de fois. Après une compaction, je demande “quel était le type de retour de la fonction helper qu’on a regardée ?” et j’obtiens une réponse fausse mais confiante. Le modèle n’hallucine pas au sens habituel du terme. Il travaille à partir d’un résumé qui ne contient genuinement pas ce que je cherche.
Après 9 compactions ou plus dans une longue session, le problème s’aggrave. Chaque résumé compresse encore davantage le résumé précédent. Le raisonnement derrière les décisions prises en début de session s’érode complètement. Au bout de 10 heures de session, le modèle n’a plus aucun souvenir de pourquoi vous avez choisi l’approche A plutôt que l’approche B, même si vous avez passé vingt minutes à peser le pour et le contre.
Dans le pipeline de compaction chiffré de Codex
L’analyse de Kangwook Lee était astucieuse. Il a utilisé deux injections de prompt chaînées pour extraire le comportement interne du système de compaction de Codex.
La première injection ciblait le LLM compacteur lui-même. Quand Codex déclenche la compaction, il ne summarise pas simplement en local. Il envoie la conversation à un LLM séparé sur les serveurs d’OpenAI, qui produit un résumé. L’injection de Lee a trompé ce compacteur pour qu’il inclue son propre system prompt dans la sortie du résumé. Le serveur a ensuite chiffré ce résumé (contenant désormais le prompt fuité) en AES et l’a renvoyé comme un blob opaque.
La seconde injection a exploité l’étape de déchiffrement. En passant le blob chiffré accompagné d’un message utilisateur forgé à la Responses API, le serveur a déchiffré le blob et reconstitué le contexte du modèle. Comme la première injection avait intégré le system prompt du compacteur dans le résumé, le contexte déchiffré a révélé le fonctionnement de tout le pipeline.
Voici ce qu’il a découvert : quand vous appelez l’API compact() de Codex, un LLM séparé summarise la conversation, et le résultat revient chiffré en AES. Au tour suivant, le serveur déchiffre ce blob, préfixe un prompt de passation (“voici un résumé de la conversation précédente”), et transmet le tout au modèle. La clé de chiffrement réside sur les serveurs d’OpenAI. Le client ne voit jamais le résumé en clair.
Le prompt de compaction lui-même s’est avéré quasi identique au template de compaction open-source du CLI Codex pour les modèles non-Codex. Pas de recette secrète dans l’ingénierie des prompts. La partie intéressante, c’est l’architecture : chiffrement des résumés côté serveur, déchiffrement et injection côté serveur, et un blob opaque que le client transmet sans pouvoir l’inspecter ni le modifier.
Pourquoi chiffrer ? L’analyse de Lee n’a pas répondu définitivement à cette question. Une théorie est que le blob chiffré contient plus qu’un simple résumé textuel : données de restauration d’appels d’outils, marqueurs d’état interne, ou métadonnées structurées qu’OpenAI préfère ne pas exposer. Une autre possibilité est simplement que les blobs chiffrés empêchent les utilisateurs de falsifier le résumé pour manipuler le comportement du modèle. Je trouve la seconde explication plus probable, mais aucune n’est confirmée.
OpenAI prend aussi en charge ça côté serveur via la Responses API. Fixez une valeur compact_threshold, et quand le nombre de tokens la dépasse, le serveur effectue la compaction en ligne. L’item de compaction est diffusé dans la réponse, et vous l’ajoutez aux requêtes suivantes. Les items antérieurs à l’item de compaction le plus récent peuvent être supprimés sans risque.
Comparez avec l’approche de Claude Code : le bloc de compaction est lisible par l’humain. Vous pouvez l’inspecter, et vous pouvez personnaliser le comportement de compaction via le paramètre instructions ou en ajoutant des directives de compaction personnalisées dans CLAUDE.md. Plus transparent, mais la même perte d’information fondamentale s’applique.
Le pattern de session handover
Mécaniques de compaction mises à part, le problème vraiment intéressant est ce qui se passe quand vous devez démarrer une nouvelle session sans perdre le contexte. C’est là que j’ai découvert l’automatisation d’un développeur qui a changé ma façon d’appréhender le problème.
Le pattern fonctionne ainsi. Juste avant que la compaction se déclenche, un hook pre-compact bloque tous les outils d’écriture. Ça empêche le modèle de modifier du code pendant qu’il est dans un état de conscience partielle, ce qui est un mode de défaillance que j’ai rencontré plusieurs fois : la compaction se déclenche en plein refactoring, le modèle perd la trace des fichiers qu’il a déjà modifiés, et effectue des modifications conflictuelles.
Les écritures bloquées, le système extrait uniquement les messages utilisateur et les blocs de réflexion du log de session JSONL. Tout le reste (appels d’outils, contenus de fichiers, réponses de l’assistant) est supprimé. Ça réduit le log à environ 2% de sa taille originale.
Ensuite trois sous-agents s’exécutent en parallèle, chacun cherchant dans les logs JSONL non compressés originaux les informations que l’extraction a manquées. Ils cherchent des lacunes : décisions d’architecture discutées mais non capturées dans les messages utilisateur, patterns d’erreurs n’ayant apparu que dans les sorties d’outils, raisons pour lesquelles certaines approches ont été rejetées. Ces agents compilent leurs résultats dans un fichier resume-prompt.md contenant le résumé de session, les résultats de l’analyse des lacunes, et une liste des fichiers modifiés.
Un file watcher VS Code détecte le nouveau resume-prompt.md et ouvre une session fraîche qui le charge comme contexte initial. La nouvelle session démarre avec une vision claire et complète de là où la session précédente s’était arrêtée.
L’amélioration rapportée était de 10x en efficacité de build. Ce chiffre est difficile à vérifier indépendamment, mais l’architecture a du sens. Au lieu d’un résumé de plus en plus dégradé, vous obtenez une fenêtre de contexte fraîche avec un document de passation curé et vérifié pour les lacunes.
J’ai essayé d’implémenter une version simplifiée par moi-même. L’étape d’analyse des lacunes est là où la valeur se concentre. Sans elle, vous faites juste ce que la compaction fait déjà mais dans un format différent. Avec elle, vous récupérez activement des informations que la summarisation avait perdues. Ma version utilise un seul sous-agent au lieu de trois, et les résultats sont nettement meilleurs qu’une compaction brute, mais probablement pas aussi complets que l’approche à trois agents.
Le KV cache comme levier de coût caché
Il y a une dimension performance que la plupart des discussions manquent complètement. Le KV cache (les paires clé-valeur calculées pendant l’attention) peut être réutilisé entre requêtes quand le préfixe du prompt est identique. Deux requêtes partageant les mêmes tokens d’ouverture évitent le recalcul pour ces tokens.
Les chiffres sont significatifs. Dans un test comparant des system prompts stables versus perturbés, les préfixes stables ont atteint 85% de taux de hit de cache avec un temps médian jusqu’au premier token (TTFT) de 953ms. Préfixes perturbés : 0% de hits de cache, 2 727ms de TTFT. Le coût par requête est passé de 0,033$ à 0,009$. C’est une réduction de 65% de la latence et de 71% des coûts uniquement en maintenant le préfixe du prompt cohérent.
Ça a des implications directes pour le pattern de session handover. Si votre resume-prompt.md commence toujours par le même préfixe structurel (system prompt, instructions de passation, puis contenu variable), la partie fixe est mise en cache. Chaque requête suivante dans la nouvelle session bénéficie de ce cache. Si vous randomisez la structure du préfixe ou injectez du contenu variable tôt, chaque requête recalcule depuis zéro.
J’ai conçu ma propre structure de dossiers de session autour de cette intuition. L’archivage basé sur l’ID de session garde les documents de passation organisés, et la convention de préfixe fixe pour les prompts de reprise signifie que les premiers 40-50K tokens de chaque nouvelle session frappent le KV cache. La pré-indexation des archives de session avec QMD (un outil que j’ai présenté séparément) accélère l’étape de récupération quand les sous-agents doivent chercher dans des sessions historiques.
Ce qui compte vraiment ici
La vraie conclusion n’est pas que l’approche de Codex est meilleure ou moins bonne que celle de Claude Code. Les deux perdent des informations pendant la compaction. Les deux peinent avec les longues sessions. La différence architecturale (blob opaque chiffré versus bloc de compaction lisible par l’humain) reflète des philosophies de conception différentes, mais la limitation fondamentale est la même : les fenêtres de contexte sont finies, et la summarisation est avec pertes.
Ce qui compte, c’est ce que vous construisez autour de cette limitation. Le pattern de session handover, l’analyse des lacunes, la récupération basée sur JSONL, l’optimisation du KV cache : ce sont des solutions d’ingénierie à un problème qu’aucune amélioration de modèle ne résoudra complètement. Une fenêtre de contexte de 500K ou 1M tokens retarde le problème sans l’éliminer.
Le goulot d’étranglement dans les outils de coding IA n’est pas l’intelligence du modèle. C’est la gestion du contexte. Je l’ai vu de mes propres yeux : un résumé médiocre avec une bonne récupération surpasse systématiquement un excellent résumé sans récupération. Construire des systèmes capables de retrouver fiablement des informations oubliées compte bien plus que construire des systèmes qui summarisent plus précisément.
Détails techniques tirés de l’analyse de Kangwook Lee et de la documentation publique des API d’OpenAI et d’Anthropic.
Rejoindre la newsletter
Recevez les dernières analyses sur l'IA.