Volver al inicio

¿Cómo guardar el contenido de razonamiento en LangChain para modelos CoT?

El artículo explica por qué LangChain ignora el contenido de razonamiento en modelos CoT y ofrece un parche funcional para guardar este bloque en additional_kwargs. Adecuado para desarrolladores que usan proveedores como polza.ai o StepFun a través de API compatible con OpenAI.

¿Perdiendo contenido de razonamiento en LangChain? Así es como arreglarlo
Advertisement 728x90

Guardando el contenido de razonamiento en LangChain: Parche para modelos CoT

Al trabajar con modelos CoT a través de LangChain, los desarrolladores se encuentran con la pérdida del contenido de razonamiento: el bloque clave de razonamiento generado por el modelo antes de la respuesta final. Esto no es un error, sino una consecuencia de una decisión arquitectónica: clases como ChatOpenAI se adhieren estrictamente a la API oficial de OpenAI, ignorando campos no estándar como reasoning, reasoning_content o reasoning_details. El resultado son tiempos de respuesta más lentos y una peor UX, ya que los usuarios no ven los pasos intermedios de pensamiento de la IA. Aquí te explico cómo solucionarlo a nivel de código sin esperar una actualización oficial.

Por qué LangChain ignora el contenido de razonamiento

LangChain se posiciona como un framework universal compatible con una amplia gama de proveedores de LLM. Para evitar fragmentación, sus clases principales (como ChatOpenAI) implementan solo la especificación oficial de la API de Chat Completion de OpenAI. Campos como reasoning_content, reasoning y similares son extensiones introducidas por DeepSeek, xAI, vLLM y otros. Cada proveedor usa su propia nomenclatura y formato, lo que genera caos:

  • DeepSeek → reasoning_content
  • vLLM → cambió de reasoning_content a reasoning
  • xAI / OpenRouter → puede usar reasoning_details

Soportar todas las variantes en ChatOpenAI requeriría:

Google AdInline article slot
  • Monitoreo constante de cambios en las API de proveedores terceros.
  • Mantener una lista creciente de mapeos de campos.
  • Convertir ChatOpenAI en un adaptador universal, lo cual va en contra de su propósito.

Por eso, los desarrolladores de LangChain recomiendan usar clases especializadas como ChatDeepSeek. Pero la mayoría de proveedores (incluyendo polza.ai, StepFun y otros) aún ofrecen API en formato OpenAI, y ahí persiste el problema.

Cómo aplicar el parche en base.py

La solución es modificar dos funciones en el código fuente de LangChain: _convert_dict_to_message y _convert_delta_to_message_chunk. Estas se encargan de convertir las respuestas crudas de LLM en objetos Message usados dentro del framework. Debes agregar la extracción del campo de razonamiento y guardarlo en additional_kwargs.

Aquí va el parche mínimo:

Google AdInline article slot
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 manera similar para el modo 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
    ...

Este parche:

  • No rompe la arquitectura existente.
  • Preserva la compatibilidad con la API oficial.
  • Agrega soporte para reasoning_content de cualquier proveedor que devuelva un campo reasoning.

Ejemplo de uso con salida en streaming

Después de aplicar el parche, el contenido de razonamiento queda disponible en additional_kwargs para cada chunk. Así es como configurar la salida:

Google AdInline article slot
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)

Ahora los usuarios pueden ver el proceso de razonamiento del modelo en tiempo real, algo especialmente valioso en apps CoT, donde los pasos intermedios como análisis de datos, comparación de hipótesis y verificaciones lógicas son clave.

Enfoques alternativos y limitaciones

Aunque el parche es efectivo, tiene limitaciones:

  • Modificación local: Los cambios solo afectan tu copia de LangChain. Se perderán al actualizar el paquete.
  • Incompatibilidad de nombres de campos: Si un proveedor usa reasoning_details en lugar de reasoning, tendrás que adaptar el código.
  • Falta de estandarización: Sin un acuerdo unificado entre proveedores, cada caso requiere ajustes manuales.

Alternativas limpias:

  • Custom MessageConverter: crea tu propia clase que herede de BaseMessageConverter y sobrescriba la lógica de parsing.
  • Capa de middleware: intercepta las respuestas HTTP del proveedor antes de que lleguen a LangChain y normaliza los campos.
  • LangChain Expression Language (LCEL): envuelve la llamada al modelo en un RunnableLambda que extraiga el razonamiento antes de pasarlo a la cadena.

Sin embargo, estos métodos son más complejos y requieren un conocimiento profundo de los internos del framework. Para un MVP o solución rápida, parchear base.py es la opción óptima.

Lecciones clave

  • El contenido de razonamiento se pierde no por un error, sino porque LangChain sigue estrictamente la API de OpenAI.
  • El parche agrega soporte para el campo reasoning en additional_kwargs sin romper la compatibilidad hacia atrás.
  • Funciona tanto para llamadas regulares como en streaming.
  • Requiere reaplicación manual después de cada actualización de LangChain.
  • Mejora la UX en apps CoT al hacer transparente el proceso de pensamiento del modelo para los usuarios.

— Editorial Team

Advertisement 728x90

Leer después