# Reasoning-Inhalte in LangChain speichern: Patch für CoT-Modelle
Beim Arbeiten mit CoT-Modellen über LangChain stoßen Entwickler auf den Verlust des Reasoning-Inhalts – des zentralen Blocks des Denkvorgangs, den das Modell vor der finalen Antwort erzeugt. Das ist kein Bug, sondern eine Folge einer architektonischen Entscheidung: Klassen wie ChatOpenAI halten sich strikt an die offizielle OpenAI API und ignorieren nicht-standardisierte Felder wie reasoning, reasoning_content oder reasoning_details. Das Ergebnis sind langsamere Reaktionszeiten und eine schlechtere UX, da Nutzer die Zwischenschritte des Denkens der KI nicht sehen. Hier ist, wie man das auf Code-Ebene behebt, ohne auf ein offizielles Update zu warten.
Warum LangChain Reasoning-Inhalte ignoriert
LangChain positioniert sich als universelles Framework, das mit einer breiten Palette von LLM-Anbietern kompatibel ist. Um Fragmentierung zu vermeiden, implementieren seine Kernklassen (wie ChatOpenAI) nur die offizielle OpenAI Chat Completion API-Spezifikation. Felder wie reasoning_content, reasoning und Ähnliche sind Erweiterungen, die von DeepSeek, xAI, vLLM und anderen eingeführt wurden. Jeder Anbieter verwendet eigene Namen und Formate, was Chaos erzeugt:
- DeepSeek →
reasoning_content - vLLM → switched from
reasoning_contenttoreasoning - xAI / OpenRouter → may use
reasoning_details
Die Unterstützung aller Varianten in ChatOpenAI würde erfordern:
- Ständige Überwachung von API-Änderungen bei Drittanbietern.
- Pflege einer wachsenden Liste von Feldzuordnungen.
- ChatOpenAI in einen universellen Adapter zu verwandeln – was seinem Zweck widerspricht.
Deshalb empfehlen die LangChain-Entwickler, spezialisierte Klassen wie ChatDeepSeek zu verwenden. Aber die meisten Anbieter (einschließlich polza.ai, StepFun und anderer) bieten immer noch APIs im OpenAI-Format an – und genau da besteht das Problem.
Wie man den Patch in base.py anwendet
Die Lösung besteht darin, zwei Funktionen im Quellcode von LangChain zu modifizieren: _convert_dict_to_message und _convert_delta_to_message_chunk. Diese kümmern sich um die Umwandlung roher LLM-Antworten in Message-Objekte, die im Framework verwendet werden. Man muss die Extraktion des reasoning-Felds hinzufügen und es in additional_kwargs speichern.
Hier der minimale Patch:
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 = []
...
Ähnlich für den Streaming-Modus:
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
...
Dieser Patch:
- Bricht die bestehende Architektur nicht.
- Erhält die Kompatibilität mit der offiziellen API.
- Fügt Unterstützung für reasoning_content von jedem Anbieter hinzu, der ein
reasoning-Feld zurückgibt.
Beispielnutzung mit Streaming-Output
Nach Anwendung des Patches ist der Reasoning-Inhalt in additional_kwargs für jeden Chunk verfügbar. Hier ist, wie man den Output einrichtet:
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)
Jetzt können Nutzer den Denkvorgang des Modells in Echtzeit sehen – das ist besonders wertvoll in CoT-Apps, wo Zwischenschritte wie Datenanalyse, Hypothesenvergleich und Logikprüfungen entscheidend sind.
Alternative Ansätze und Einschränkungen
Der Patch ist zwar effektiv, hat aber Einschränkungen:
- Lokale Modifikation: Änderungen wirken nur auf Ihre Kopie von LangChain. Sie gehen bei Paket-Updates verloren.
- Inkompatibilität der Feldnamen: Wenn ein Anbieter
reasoning_detailsstattreasoningverwendet, müssen Sie den Code anpassen. - Fehlende Standardisierung: Ohne einheitliche Absprache unter den Anbietern ist für jeden Fall manuelle Anpassung nötig.
Saubere Alternativen:
- Eigener MessageConverter – erstellen Sie eine eigene Klasse, die von BaseMessageConverter erbt, und überschreiben Sie die Parsing-Logik.
- Middleware-Schicht – abfangen Sie HTTP-Antworten vom Anbieter, bevor sie LangChain erreichen, und normalisieren Sie die Felder.
- LangChain Expression Language (LCEL) – umschließen Sie den Model-Aufruf mit einem RunnableLambda, das den Reasoning-Inhalt extrahiert, bevor er an die Kette weitergeleitet wird.
Diese Methoden sind jedoch komplexer und erfordern ein tiefes Verständnis der Framework-Interna. Für ein MVP oder eine schnelle Lösung ist das Patchen von base.py die optimale Option.
Wichtige Erkenntnisse
- Reasoning-Inhalte gehen nicht durch einen Bug verloren, sondern weil LangChain der OpenAI API strikt folgt.
- Der Patch fügt Unterstützung für das
reasoning-Feld in additional_kwargs hinzu, ohne die Abwärtskompatibilität zu brechen. - Er funktioniert für normale und Streaming-Aufrufe.
- Er muss nach jedem LangChain-Update manuell erneut angewendet werden.
- Er verbessert die UX in CoT-Apps, indem der Denkvorgang des Modells für Nutzer transparent wird.
— Editorial Team
Noch keine Kommentare.