mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-05-30 07:26:48 +00:00
fix: use responses api for chatgpt reasoning models
This commit is contained in:
@@ -656,6 +656,38 @@ class LLMHelper:
|
||||
headers["User-Agent"] = normalized_user_agent
|
||||
return headers or None
|
||||
|
||||
@classmethod
|
||||
def _should_use_openai_responses_api(
|
||||
cls,
|
||||
provider: str,
|
||||
model: str | None,
|
||||
runtime: dict[str, Any],
|
||||
) -> bool | None:
|
||||
"""
|
||||
判断官方 ChatGPT API Key 模式是否应使用 Responses API。
|
||||
|
||||
GPT-5/o 系推理模型在 Chat Completions 中组合 function tools 与
|
||||
reasoning_effort 时会被官方端点拒绝,因此 ChatGPT 官方 API Key
|
||||
模式需要显式切到 Responses API;通用 OpenAI-compatible 入口保持
|
||||
provider 目录解析出的默认行为,避免误伤第三方兼容服务。
|
||||
"""
|
||||
runtime_use_responses_api = runtime.get("use_responses_api")
|
||||
if runtime_use_responses_api is not None:
|
||||
return bool(runtime_use_responses_api)
|
||||
|
||||
provider_name = (provider or "").strip().lower()
|
||||
if provider_name != "chatgpt":
|
||||
return None
|
||||
|
||||
base_url = str(runtime.get("base_url") or "").strip().lower()
|
||||
if "api.openai.com" not in base_url:
|
||||
return None
|
||||
|
||||
model_name = cls._normalize_model_name(model)
|
||||
if model_name.startswith(("gpt-5", "o1", "o3", "o4")):
|
||||
return True
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def _resolve_thinking_level(
|
||||
cls,
|
||||
@@ -760,6 +792,11 @@ class LLMHelper:
|
||||
model=model_name,
|
||||
thinking_level=normalized_thinking_level,
|
||||
)
|
||||
use_responses_api = cls._should_use_openai_responses_api(
|
||||
provider=provider_name,
|
||||
model=model_name,
|
||||
runtime=runtime,
|
||||
)
|
||||
|
||||
if runtime["runtime"] == "google":
|
||||
# 修补 Gemini 2.5 思考模型的 thought_signature 兼容性
|
||||
@@ -832,7 +869,7 @@ class LLMHelper:
|
||||
stream_usage=True,
|
||||
openai_proxy=settings.PROXY_HOST,
|
||||
default_headers=default_headers,
|
||||
use_responses_api=runtime.get("use_responses_api"),
|
||||
use_responses_api=use_responses_api,
|
||||
**thinking_kwargs,
|
||||
)
|
||||
|
||||
|
||||
@@ -599,6 +599,34 @@ class LlmHelperTestCallTest(unittest.TestCase):
|
||||
self.assertEqual(len(calls), 1)
|
||||
self.assertEqual(calls[0].get("reasoning_effort"), "xhigh")
|
||||
|
||||
def test_get_llm_uses_responses_api_for_chatgpt_reasoning_models(self):
|
||||
"""校验 ChatGPT 官方推理模型会切换到 Responses API。"""
|
||||
calls = []
|
||||
|
||||
class _FakeChatOpenAI:
|
||||
def __init__(self, **kwargs):
|
||||
calls.append(kwargs)
|
||||
self.model = kwargs["model"]
|
||||
self.profile = None
|
||||
|
||||
with patch.dict(
|
||||
sys.modules,
|
||||
{"langchain_openai": SimpleNamespace(ChatOpenAI=_FakeChatOpenAI)},
|
||||
):
|
||||
asyncio.run(
|
||||
llm_module.LLMHelper.get_llm(
|
||||
provider="chatgpt",
|
||||
model="gpt-5.4",
|
||||
thinking_level="max",
|
||||
api_key="sk-test",
|
||||
base_url="https://api.openai.com/v1",
|
||||
)
|
||||
)
|
||||
|
||||
self.assertEqual(len(calls), 1)
|
||||
self.assertTrue(calls[0].get("use_responses_api"))
|
||||
self.assertEqual(calls[0].get("reasoning_effort"), "xhigh")
|
||||
|
||||
def test_get_llm_uses_gemini_builtin_thinking_controls(self):
|
||||
calls = []
|
||||
|
||||
|
||||
Reference in New Issue
Block a user