Gestion de la fenêtre de contexte des LLM pour les longues conversations
La fenêtre de contexte a deux coûts : le débordement et la facturation par tour. Compter les jetons, élaguer et résumer l'historique, mettre en cache les préfixes stables, utiliser la compaction côté serveur.
Une conversation qui grandit échoue de deux façons différentes, et les confondre mène au mauvais correctif. L'échec bruyant est le débordement : le prompt plus la sortie demandée dépasse la fenêtre de contexte du modèle et la requête est rejetée d'emblée. L'échec silencieux est le coût : tout ce que vous gardez en contexte est refacturé à chaque tour, si bien qu'un chat qui ne déborde jamais peut malgré tout devenir cher de façon linéaire à mesure que l'historique s'accumule. Gérer une fenêtre de contexte signifie se défendre contre les deux — garder le compte de jetons sous la limite dure et le garder assez petit pour que vous ne payiez pas à renvoyer le même historique indéfiniment. Cet article couvre comment mesurer le budget, les stratégies d'élagage et de synthèse qui le maintiennent en respect, et le caching et la compaction côté serveur qui réduisent ce que coûte une longue conversation.
Un seul budget, partagé par l'entrée, la sortie et le raisonnement
La fenêtre de contexte est un budget de jetons unique dans lequel puise la requête entière. Ce n'est pas « des jetons d'entrée jusqu'à la limite, puis la sortie par-dessus » — les jetons d'entrée, les jetons que vous demandez au modèle de générer, et (sur les modèles de raisonnement) les jetons de raisonnement cachés se disputent tous le même plafond. Deux conséquences s'ensuivent immédiatement. Premièrement, un long prompt réduit la place restante pour la réponse, si bien qu'un contexte trop chargé peut forcer une réponse tronquée ou vide même sans erreur de débordement dure. Deuxièmement, sur les modèles de raisonnement, les jetons de raisonnement invisibles grignotent aussi ce plafond, ce qui est pourquoi les paramètres d'API des modèles de raisonnement insiste sur la réservation d'une marge de sortie. Budgétisez la fenêtre dans son ensemble : décidez d'emblée combien de jetons vous laisserez l'historique occuper, combien vous réservez pour le raisonnement, et combien vous garantissez pour la réponse visible.
Dépasser la fenêtre est une erreur dure — les fournisseurs renvoient une erreur de longueur de contexte plutôt que d'abandonner silencieusement des jetons — si bien que le débordement est votre problème à prévenir, pas celui du modèle à absorber. La défense est de connaître votre compte de jetons avant d'envoyer.
Mesurez avant d'envoyer
Vous ne pouvez pas gérer un budget que vous ne mesurez pas. Chaque décision de gestion d'historique dépend d'un compte de jetons exact de la requête que vous êtes sur le point de faire, et « à peu près quatre caractères par jeton » est une règle empirique qui dérive fortement sur le code, les écritures non latines et les données structurées. Comptez avec le tokeniseur propre du fournisseur quand vous le pouvez, et comptez la requête entière — les instructions système, les outils, chaque message et tout document joint — pas seulement le dernier tour de l'utilisateur.
Le comptage doit aussi être honnête sur ce que le modèle voit. Les définitions d'outils, les schémas JSON pour les sorties structurées et les images consomment tous des jetons, et ils sont faciles à oublier car ils ne ressemblent pas à de la « conversation ». Un grand catalogue d'outils peut occuper discrètement une part significative de la fenêtre à chaque appel. Une fois que vous avez un compte fiable, les stratégies ci-dessous ne sont que des politiques pour garder ce nombre là où vous le voulez.
Stratégies d'élagage, du brut au malin
Il y a quatre façons courantes de garder l'historique sous budget, et les systèmes réels les combinent.
Tronquer les tours les plus anciens. La politique la plus simple : gardez le prompt système plus les N tours les plus récents et abandonnez le reste. C'est bon marché et prévisible, et c'est le bon défaut pour les chats de type support où l'ancien contexte compte rarement. Sa faiblesse est l'amnésie — le modèle oublie les faits établis tôt dans une longue session.
Résumer et remplacer. Au lieu d'abandonner les anciens tours, compressez-les. Demandez périodiquement à un modèle de résumer la partie la plus ancienne de la conversation en une note compacte, puis remplacez ces tours par le résumé. Cela préserve l'essentiel à une fraction des jetons, au prix d'un appel supplémentaire et d'une certaine perte de fidélité. Le compromis vaut généralement la peine pour les assistants de longue haleine qui doivent se souvenir de décisions prises il y a une heure.
Récupérer plutôt que retenir. Pour la connaissance qui vit dans des documents plutôt que dans le dialogue, ne la portez pas du tout en contexte. Stockez-la à l'externe, et à chaque tour récupérez uniquement les passages pertinents pour la question actuelle et injectez-les. La récupération garde la fenêtre petite et constante quelle que soit la quantité de matériel source — la différence entre payer pour un manuel entier à chaque tour et payer pour les deux paragraphes qui comptent.
Garder un préfixe stable et faire varier la queue. Structurez la conversation pour que la partie immuable (prompt système, outils, matériel de référence) se trouve à l'avant et que seuls les tours récents changent à la fin. C'est une bonne hygiène en soi, et c'est la condition préalable au caching, abordé ensuite.
La plupart des systèmes de chat durables superposent ceux-ci : un préfixe système fixe, un résumé courant du milieu, les derniers tours mot pour mot, et la récupération pour tout ce qui est factuel. Le mélange exact dépend de si votre priorité est le rappel, la latence ou le coût.
Mettre en cache le préfixe que vous ne pouvez pas éviter de renvoyer
Certains contextes doivent véritablement être présents à chaque tour — un prompt système détaillé, un jeu d'outils fixe, un document en discussion. Vous ne pouvez pas l'élaguer sans casser la tâche, mais vous pouvez cesser de payer plein tarif pour le retraiter, et c'est exactement ce que fait le prompt caching. Lorsque le préfixe stable est mis en cache, le fournisseur le réutilise et facture ces jetons à un tarif fortement réduit au lieu du tarif d'entrée plein. Le geste de gestion est d'arranger la conversation pour que la région cachable soit maximale et stable au niveau des octets — pas d'horodatages ni d'outils réordonnés à l'intérieur — et de laisser la queue volatile tomber après la frontière du cache. Les mécanismes fournisseur par fournisseur sont dans le prompt caching chez OpenAI, Claude et Gemini ; le point ici est que le caching et la gestion de contexte sont la même discipline vue sous deux angles. L'élagage réduit combien de jetons vous envoyez ; le caching réduit ce que coûtent les jetons inévitables.
L'état côté serveur ne rend pas l'historique gratuit
L'API Responses vous laisse poursuivre un fil avec previous_response_id au lieu de renvoyer tout l'historique, ce qui est un véritable gain d'ergonomie — vous envoyez seulement le nouveau tour et le serveur le raccorde au contexte stocké. Il est tentant de lire cela comme « le contexte antérieur est maintenant gratuit ». Il ne l'est pas. Tous les jetons d'entrée antérieurs de la chaîne sont toujours facturés comme jetons d'entrée à chaque continuation ; le chaînage vous épargne d'envoyer des octets sur le fil, pas de payer pour le contexte que le modèle traite toujours. Ainsi, l'état de conversation côté serveur change qui détient l'historique, pas si vous payez pour lui. Vous avez toujours besoin de l'élagage et du caching ci-dessus pour contrôler le coût ; previous_response_id est orthogonal à cela.
Compaction : rétrécir une conversation sur le serveur
Lorsqu'une conversation grandit assez pour que même la synthèse de votre côté devienne malaisée, certains workflows de style Responses exposent une étape de compaction côté serveur qui condense le contexte courant en une représentation plus petite à partir de laquelle vous pouvez continuer. Cette passerelle l'expose comme un point de terminaison dédié, POST /v1/responses/compact, qui relaie une requête de compaction à un amont qui la prend en charge. La requête porte la conversation à condenser — model, input, instructions, et optionnellement previous_response_id, tools et un objet reasoning — et la réponse renvoie un output compacté plus un objet usage avec les jetons d'entrée et de sortie que la compaction elle-même a consommés.
curl https://your-gateway.example.com/v1/responses/compact \
-H "Authorization: Bearer AVE_GATEWAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.6",
"previous_response_id": "resp_abc123",
"instructions": "Condense the conversation so far, preserving decisions and open tasks."
}'
Deux choses à garder à l'esprit. La compaction est elle-même un appel de modèle — elle lit la conversation et écrit une version condensée, si bien qu'elle consomme des jetons qui apparaissent dans vos journaux d'usage comme n'importe quelle autre requête ; elle échange un coût de compaction unique contre des tours ultérieurs moins chers. Et elle n'a de sens que face à un amont qui implémente le point de terminaison de compaction, si bien que c'est une capacité de passthrough, pas quelque chose que la passerelle peut synthétiser pour un fournisseur qui en est dépourvu. Là où elle est disponible, elle est l'analogue côté serveur de la stratégie « résumer et remplacer », déplaçant le travail de compression en amont au lieu de l'exécuter dans votre propre client.
Réservez de la place pour la réponse
Quel que soit le mélange que vous choisissez, laissez toujours à la réponse visible assez d'espace. Fixez un plafond de sortie explicite et assurez-vous que context_used + reserved_output reste confortablement sous la fenêtre, en vous souvenant que sur les modèles de raisonnement la réserve doit aussi couvrir les jetons de raisonnement cachés. Sautez ceci et vous obtenez l'échec frustrant où une requête réussit, vous facture une grande entrée et renvoie une réponse tronquée parce qu'il ne restait plus de place pour finir. Appliquez le même principe aux timeouts : laissez volontairement de la marge.
Réunir le tout
Une politique de contexte pour un assistant de longue durée ressemble généralement à ceci : épinglez un préfixe système cachable, gardez les derniers tours mot pour mot, maintenez un résumé glissant (ou une compaction côté serveur) du milieu plus ancien, récupérez les faits depuis un stockage externe plutôt que de les porter, comptez les jetons avant chaque envoi, et réservez un budget de sortie fixe. Chaque pièce vise une partie spécifique du problème à deux coûts — le débordement ou la facturation par tour — et ensemble elles gardent une conversation à la fois sous la limite dure et hors d'une courbe de coût toujours croissante. Le rôle de la passerelle est de rendre l'effet visible : un seul endroit pour observer les comptes de jetons par requête et confirmer qu'un changement de votre politique d'historique a réellement bougé le nombre, ce qui rejoint le travail plus large de la réduction des coûts d'API LLM.
FAQ
Que se passe-t-il lorsqu'une requête dépasse la fenêtre de contexte ?
Par défaut, le fournisseur la rejette avec une erreur de longueur de contexte ; il ne tronque pas silencieusement votre prompt pour le faire tenir, ce qui vous rend responsable de prévenir le débordement en comptant les jetons avant l'envoi. L'exception est l'option truncation: auto de Responses, qui supprime des éléments au milieu de l'entrée pour faire tenir une requête trop grande. C'est pratique, mais cela entraîne une perte silencieuse de contenu : activez-la délibérément plutôt que comme filet de sécurité. Comme les jetons d'entrée, de sortie et de raisonnement partagent un seul budget, un prompt trop long peut aussi produire une réponse tronquée même sous la limite dure, faute de place suffisante pour générer.
Utiliser previous_response_id réduit-il ma facture de jetons ?
Non. Cela vous épargne de renvoyer l'historique sur le fil, mais tous les jetons d'entrée antérieurs de la chaîne sont toujours facturés comme entrée à chaque continuation. L'état côté serveur est une fonctionnalité d'ergonomie et de latence, pas une réduction de coût. Pour réellement réduire le coût du contexte, vous avez toujours besoin de l'élagage, de la synthèse et du prompt caching du préfixe stable.
Résumer l'historique ou le tronquer — lequel devrais-je utiliser ?
La troncature (garder les N derniers tours) est la plus simple et convient quand l'ancien contexte compte rarement, mais elle oublie les faits anciens. La synthèse compresse les anciens tours en une note compacte, préservant l'essentiel à un coût supplémentaire par compression. Les assistants de longue haleine qui doivent se souvenir de décisions antérieures exécutent généralement les deux : des tours récents mot pour mot plus un résumé glissant du milieu plus ancien, avec la récupération pour tout ce qui est factuel.
Que fait le point de terminaison /v1/responses/compact ?
Il relaie une requête de compaction à un amont qui prend en charge la condensation d'une conversation Responses en une représentation plus petite à partir de laquelle vous pouvez continuer. Vous passez la conversation (via input/instructions et optionnellement previous_response_id), et il renvoie un output compacté et un compte usage pour les jetons que la compaction a consommés. C'est une capacité de passthrough — disponible seulement lorsque l'amont l'implémente — et c'est la version côté serveur de résumer-et-remplacer.
Tracez la courbe, puis aplatissez-la
Instrumentez une conversation de longue durée pour journaliser son nombre total de jetons à chaque tour, puis tracez la courbe. Si elle monte régulièrement, ajoutez un résumé glissant ou une étape de compaction à partir d'un seuil et observez la courbe s'aplatir dans vos journaux d'usage. Marquez ensuite votre préfixe système comme cachable et confirmez que le coût d'entrée par tour diminue. Ces deux courbes avant/après — nombre de jetons et coût d'entrée — vous indiquent si votre politique de contexte fonctionne réellement sur votre propre trafic plutôt qu'en théorie.