"""DeepSeek 云 API(备用后端)。 实测数据(P0-DeepSeek验证报告.md): 首 token P50 786ms / P95 1100ms(关思考,N=8) 视觉可用——正确读出图中数字 模型清单只有 deepseek-flash 与 deepseek-v4-pro 约束(重要,踩过): 默认开启思考模式,此时 API 要求把上一轮 assistant 消息里的 `reasoning_content` 原样回传,否则任何多轮/工具回灌一律 400: "The `reasoning_content` in the thinking mode must be passed back to the API." 手工构造 assistant 消息(content=None / content="" / 不带 tools)三种写法 实测全部 400,只有回传服务端原始对象才行。 所以会话主路径必须显式关闭思考。 另:本服务思考字段名是 reasoning_content(本机 vLLM 是 reasoning), 基类两个都认。 """ from __future__ import annotations from typing import Sequence from .base import LLMProvider class DeepSeekProvider(LLMProvider): supports_vision = True def _build_body(self, messages: list[dict], *, tools: Sequence[dict] | None, max_tokens: int) -> dict: body: dict = { "model": self.cfg.model, "messages": messages, "stream": True, "max_tokens": max_tokens, "stream_options": {"include_usage": True}, } # 显式声明思考开关。不传会走默认(开),多轮与工具回灌会 400。 body["thinking"] = {"type": "enabled" if self.cfg.thinking else "disabled"} if tools: body["tools"] = list(tools) body["tool_choice"] = "auto" return body __all__ = ["DeepSeekProvider"]