处理在langchain中接入deepseek v4 缺失reasoning_content 以及在create_agent中使用response_format的错误
·
处理在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"}
}
)
更多推荐




所有评论(0)