diff --git a/backend/app/chains/agents/base.py b/backend/app/chains/agents/base.py index d46c71db..339678da 100644 --- a/backend/app/chains/agents/base.py +++ b/backend/app/chains/agents/base.py @@ -130,6 +130,18 @@ def _load_json_like(text: str) -> Any: raise ValueError("Empty output from LLM") +def _thinking_extra_body(model: BaseChatModel, enable_thinking: bool) -> dict[str, Any] | None: + """Extra body toggling Qwen-style thinking for OpenAI-compatible endpoints. + + `enable_thinking` is a DashScope extension; the official OpenAI API rejects + it as an unknown parameter, so nothing is bound for api.openai.com targets. + """ + base = str(getattr(model, "openai_api_base", "") or "").rstrip("/") + if not base or "api.openai.com" in base: + return None + return {"enable_thinking": enable_thinking} + + class AgentBase(ABC, Generic[T]): """通用 Agent 基类:子类固化 prompt_template 与 output_model。""" @@ -143,7 +155,9 @@ def __init__( agent_kwargs: dict[str, Any] | None = None, ) -> None: self._model = model - self._model.bind(extra_body={"enable_thinking": self.enable_thinking}) + thinking_body = _thinking_extra_body(model, self.enable_thinking) + if thinking_body is not None: + self._model.bind(extra_body=thinking_body) self._structured_output_method = structured_output_method self._agent_kwargs = dict(agent_kwargs or {}) self._structured_chain: Runnable | None = None diff --git a/backend/app/services/llm/resolver.py b/backend/app/services/llm/resolver.py index a0792ac0..e403f0cd 100644 --- a/backend/app/services/llm/resolver.py +++ b/backend/app/services/llm/resolver.py @@ -178,8 +178,16 @@ def _build_chat_openai_model( kwargs.setdefault("base_url", base_url) if not thinking: - extra_body = dict(kwargs.get("extra_body") or {}) - extra_body["enable_thinking"] = False - kwargs["extra_body"] = extra_body + # DashScope-style OpenAI-compatible endpoints take the Qwen + # `enable_thinking` extension, but the official OpenAI API rejects it + # with 400 Unknown parameter; disable reasoning through the official + # `reasoning_effort` parameter there instead. + base = (base_url or "").rstrip("/") + if not base or "api.openai.com" in base: + kwargs.setdefault("reasoning_effort", "none") + else: + extra_body = dict(kwargs.get("extra_body") or {}) + extra_body["enable_thinking"] = False + kwargs["extra_body"] = extra_body return ChatOpenAI(**kwargs) diff --git a/backend/app/services/llm/runtime.py b/backend/app/services/llm/runtime.py index 9bbb2116..3eb9367e 100644 --- a/backend/app/services/llm/runtime.py +++ b/backend/app/services/llm/runtime.py @@ -69,8 +69,16 @@ def build_default_text_llm_sync( kwargs.setdefault("base_url", base_url) if not thinking: - extra_body = dict(kwargs.get("extra_body") or {}) - extra_body["enable_thinking"] = False - kwargs["extra_body"] = extra_body + # DashScope-style OpenAI-compatible endpoints take the Qwen + # `enable_thinking` extension, but the official OpenAI API rejects it + # with 400 Unknown parameter; disable reasoning through the official + # `reasoning_effort` parameter there instead. + base = (base_url or "").rstrip("/") + if not base or "api.openai.com" in base: + kwargs.setdefault("reasoning_effort", "none") + else: + extra_body = dict(kwargs.get("extra_body") or {}) + extra_body["enable_thinking"] = False + kwargs["extra_body"] = extra_body return ChatOpenAI(**kwargs)