## Sauvegarder le Contenu de Raisonnement dans LangChain : Correctif pour les Modèles CoT
Quand on travaille avec des modèles CoT via LangChain, les développeurs se heurtent à la perte du contenu de raisonnement — le bloc clé de raisonnement généré par le modèle avant la réponse finale. Ce n'est pas un bug mais la conséquence d'une décision architecturale : des classes comme ChatOpenAI respectent strictement l'API officielle OpenAI, ignorant les champs non standards comme reasoning, reasoning_content ou reasoning_details. Le résultat, ce sont des temps de réponse plus lents et une UX dégradée, car les utilisateurs ne voient pas les étapes de réflexion intermédiaires de l'IA. Voici comment y remédier au niveau du code sans attendre une mise à jour officielle.
Pourquoi LangChain Ignore le Contenu de Raisonnement
LangChain se positionne comme un framework universel compatible avec une large gamme de fournisseurs de LLM. Pour éviter la fragmentation, ses classes principales (comme ChatOpenAI) implémentent uniquement la spécification officielle de l'API Chat Completion OpenAI. Des champs comme reasoning_content, reasoning et assimilés sont des extensions introduites par DeepSeek, xAI, vLLM et d'autres. Chaque fournisseur utilise sa propre nomenclature et son propre format, ce qui crée le chaos :
- DeepSeek →
reasoning_content - vLLM → passé de
reasoning_contentàreasoning - xAI / OpenRouter → peut utiliser
reasoning_details
Pour supporter toutes les variantes dans ChatOpenAI, il faudrait :
- Surveiller en permanence les changements d'API des fournisseurs tiers.
- Maintenir une liste croissante de mappings de champs.
- Transformer ChatOpenAI en adaptateur universel — ce qui va à l'encontre de son objectif.
C'est pourquoi les développeurs LangChain recommandent d'utiliser des classes spécialisées comme ChatDeepSeek. Mais la plupart des fournisseurs (y compris polza.ai, StepFun et d'autres) proposent encore des API au format OpenAI — et c'est là que le problème persiste.
Comment Appliquer le Correctif dans base.py
La solution consiste à modifier deux fonctions dans le code source de LangChain : _convert_dict_to_message et _convert_delta_to_message_chunk. Celles-ci gèrent la conversion des réponses brutes des LLM en objets Message utilisés dans le framework. Il faut ajouter l'extraction du champ reasoning et le sauvegarder dans additional_kwargs.
Voici le correctif minimal :
def _convert_dict_to_message(_dict):
...
content = _dict.get("content", "") or ""
reasoning = _dict.get("reasoning", "") or "" # added
additional_kwargs: dict = {}
if reasoning: # added
additional_kwargs['reasoning_content'] = reasoning # added
if function_call := _dict.get("function_call"):
additional_kwargs["function_call"] = dict(function_call)
tool_calls = []
...
De même pour le mode streaming :
def _convert_delta_to_message_chunk(_dict):
...
id_ = _dict.get("id")
role = cast(str, _dict.get("role"))
content = cast(str, _dict.get("content") or "")
reasoning = cast(str, _dict.get("reasoning", "") or "") # added
additional_kwargs: dict = {}
if reasoning: # added
additional_kwargs['reasoning_content'] = reasoning # added
...
Ce correctif :
- Ne casse pas l'architecture existante.
- Préserve la compatibilité avec l'API officielle.
- Ajoute le support de reasoning_content pour tout fournisseur qui renvoie un champ
reasoning.
Exemple d'Utilisation avec Sortie Streaming
Après application du correctif, le contenu de raisonnement devient disponible dans additional_kwargs pour chaque chunk. Voici comment configurer la sortie :
from langchain_openai import ChatOpenAI
model = ChatOpenAI(
model="stepfun/step-3.5-flash",
openai_api_base="https://api.polza.ai/v1",
openai_api_key="your_api_key",
)
for chunk in model.stream('Hello!'):
if "reasoning_content" in chunk.additional_kwargs:
print(chunk.additional_kwargs['reasoning_content'], end="", flush=True)
else:
print(chunk.content, end="", flush=True)
Désormais, les utilisateurs peuvent voir le processus de raisonnement du modèle en temps réel — c'est particulièrement précieux dans les applications CoT, où les étapes intermédiaires comme l'analyse de données, la comparaison d'hypothèses et les vérifications logiques sont cruciales.
Approches Alternatives et Limites
Bien que le correctif soit efficace, il présente des limites :
- Modification locale : Les changements n'affectent que votre copie de LangChain. Ils seront perdus lors des mises à jour du package.
- Incompatibilité de noms de champs : Si un fournisseur utilise
reasoning_detailsau lieu dereasoning, il faudra adapter le code. - Absence de standardisation : Sans accord unifié entre fournisseurs, chaque cas nécessite un ajustement manuel.
Alternatives propres :
- Custom MessageConverter — créez votre propre classe héritant de BaseMessageConverter et surchargez la logique d'analyse.
- Couche intermédiaire — interceptez les réponses HTTP du fournisseur avant qu'elles n'atteignent LangChain et normalisez les champs.
- LangChain Expression Language (LCEL) — enveloppez l'appel au modèle dans un RunnableLambda qui extrait le raisonnement avant de le passer à la chaîne.
Cependant, ces méthodes sont plus complexes et exigent une bonne connaissance des entrailles du framework. Pour un MVP ou un correctif rapide, modifier base.py est la solution optimale.
Points Clés à Retenir
- Le contenu de raisonnement est perdu non pas à cause d'un bug, mais parce que LangChain suit strictement l'API OpenAI.
- Le correctif ajoute le support du champ
reasoningdans additional_kwargs sans casser la compatibilité descendante. - Il fonctionne pour les appels normaux et streaming.
- Il nécessite une réapplication manuelle après chaque mise à jour de LangChain.
- Il améliore l'UX des applications CoT en rendant le processus de réflexion du modèle transparent pour les utilisateurs.
— Editorial Team
Aucun commentaire pour le moment.