处理在langchain中接入deepseek v4 缺失reasoning_content 以及在create_agent中使用response_format的错误

from langchain_deepseek import ChatDeepSeek
from pydantic import SecretStr
from typing import Any
from langchain_core.language_models import LanguageModelInput
from langchain_core.messages import AIMessage
from langchain_openai.chat_models.base import _convert_message_to_dict,_get_last_messages,_construct_responses_api_payload
from langchain_core.runnables.base import Runnable


import os
from dotenv import load_dotenv
load_dotenv()

"""
1.在推理模式中重写 bind_tools 修复create_agent中使用response_format的错误
2.重写 _convert_from_v1_to_chat_completions 和 _get_request_payload 修复缺失reasoning_content导致推理模式报错
3.在推理模式中response_format实际是不起效的.如果使其生效只能将 thinking 设置为 false 在1中的修复只是为了兼容.
""" 
class ChatDeepSeekWithReasoning(ChatDeepSeek):
    """ChatDeepSeek subclass that preserves reasoning_content in messages"""
    def bind_tools(self, tools: Any, **kwargs: Any) -> Runnable:
        kwargs.pop("tool_choice", None)
        return super().bind_tools(tools, **kwargs)

    def _get_request_payload(
        self,
        input_: LanguageModelInput,
        *,
        stop: list[str] | None = None,
        **kwargs: Any,
    ) -> dict:
        messages = self._convert_input(input_).to_messages()
        if stop is not None:
            kwargs["stop"] = stop

        payload = {**self._default_params, **kwargs}

        if self._use_responses_api(payload):
            if self.use_previous_response_id:
                last_messages, previous_response_id = _get_last_messages(messages)
                payload_to_use = last_messages if previous_response_id else messages
                if previous_response_id:
                    payload["previous_response_id"] = previous_response_id
                payload = _construct_responses_api_payload(payload_to_use, payload)
            else:
                payload = _construct_responses_api_payload(messages, payload)
        else:
            payload["messages"] = []
            for m in messages:
                if isinstance(m, AIMessage):
                    m = _convert_from_v1_to_chat_completions(m)
                msg_dict = _convert_message_to_dict(m)
                if isinstance(m, AIMessage) and "reasoning_content" in m.additional_kwargs:
                    msg_dict["reasoning_content"] = m.additional_kwargs["reasoning_content"]
                payload["messages"].append(msg_dict)
        return payload


def _convert_from_v1_to_chat_completions(message: AIMessage) -> AIMessage:
    """Convert from v1 Responses API format to chat completions format, preserving reasoning content."""
    if isinstance(message.content, list):
        new_content: list = []
        reasoning_text_parts: list = []
        
        for block in message.content:
            if isinstance(block, dict):
                block_type = block.get("type")
                if block_type == "text":
                    new_content.append({"type": "text", "text": block["text"]})
                elif block_type == "reasoning":
                    reasoning_text_parts.append(block.get("text", ""))
                elif block_type == "tool_call":
                    pass
                else:
                    new_content.append(block)
            else:
                new_content.append(block)
        
        updated_kwargs = message.additional_kwargs.copy()
        if reasoning_text_parts:
            reasoning_content = "".join(reasoning_text_parts)
            updated_kwargs["reasoning_content"] = updated_kwargs.get("reasoning_content", "") + reasoning_content
        
        return message.model_copy(update={
            "content": new_content,
            "additional_kwargs": updated_kwargs
        })
    
    return message


class DeepSeekV4Flash:
    """DeepSeek V4 Flash LLM class"""
    def __new__(cls, temperature: float = 0.1,thinking:bool = False):
        deepseek_api_key = os.getenv("deepseek_api_key")
        if deepseek_api_key is None:
            raise ValueError("deepseek_api_key is not set in .env")
        if thinking:
            return ChatDeepSeekWithReasoning(
            model="deepseek-v4-flash",
            temperature=temperature,
            api_key=SecretStr(deepseek_api_key),
        )
        return ChatDeepSeek(
            model="deepseek-v4-flash",
            temperature=temperature,
            api_key=SecretStr(deepseek_api_key),
            extra_body={
                "thinking":{"type":"disabled"}
            }
        )
        

if __name__ == "__main__":
    llm = DeepSeekV4Flash()
    print(llm.invoke("你好"))

如果你不需要推理模型那么直接使用官方的langchain_deepseek传入extra_body={“thinking”:{“type”:“disabled”} }

from langchain_deepseek import ChatDeepSeek
ChatDeepSeek(
	model="deepseek-v4-flash",
	temperature=temperature,
	api_key=SecretStr(deepseek_api_key),
	extra_body={
	    "thinking":{"type":"disabled"}
	}
	)
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐