mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-10-28 19:06:36 +08:00
fix(setup): 更新 Google 默认模型并兼容 Gemini 3.8 思考级别 (#7109)
* fix(setup): 更新 Google 默认模型为 gemini-3.8-flash 安装向导中 Google 的预设模型 gemini-2.5-flash 对新建的 Gemini API 密钥 已返回 404,在模型选择处直接回车会写入无法使用的 LLM_MODEL。改为 Google 文档中推荐给新项目的稳定模型 gemini-3.8-flash。 新增用例校验预设值不再是 Gemini 2.5 系列。 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * fix(llm): honor Gemini 3.8 minimum thinking level --------- Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com> Co-authored-by: jxxghp <jxxghp@gmail.com>
This commit is contained in:
@@ -984,6 +984,12 @@ class LLMHelper:
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Gemini 3 使用 thinking_level;Gemini 2.5 使用 thinking_budget。
|
||||
|
||||
Gemini 3.8 Flash 不接受 minimal,也不能完全关闭思考,因此将关闭和最小映射到 low。
|
||||
|
||||
:param model_name: 已规范化的模型标识
|
||||
:param thinking_level: 用户选择的统一思考级别
|
||||
:return: 当前模型支持的 Google 原生思考参数
|
||||
"""
|
||||
if not model_name or thinking_level == "auto":
|
||||
return {}
|
||||
@@ -1020,9 +1026,10 @@ class LLMHelper:
|
||||
)
|
||||
|
||||
if "gemini-3" in model_name:
|
||||
minimum_level = "low" if "gemini-3.8-flash" in model_name else "minimal"
|
||||
level_map = {
|
||||
"off": "minimal",
|
||||
"minimal": "minimal",
|
||||
"off": minimum_level,
|
||||
"minimal": minimum_level,
|
||||
"low": "low",
|
||||
"medium": "medium",
|
||||
"high": "high",
|
||||
|
||||
@@ -281,6 +281,7 @@ moviepilot setup --config-dir /path/to/moviepilot-config
|
||||
与 `LLM_WEB_SEARCH_MODE`。联网搜索支持 MoviePilot 本地搜索、模型服务端搜索、
|
||||
服务端优先自动回退与完全关闭;服务端模式仅在当前模型目录声明支持时生效。
|
||||
向导会尝试读取当前提供商的模型目录;目录服务不可用时仍可手动输入模型 ID。
|
||||
Google 新配置默认使用 `gemini-3.8-flash`,已有的 `LLM_MODEL` 配置继续保留。
|
||||
当前可识别 OpenAI、Anthropic Claude、Google Gemini、xAI Grok 与 DeepSeek
|
||||
官方端点已公布的服务端联网搜索能力,第三方兼容端点不会被自动误判。
|
||||
- 下载目录按下载器内部路径原样保存,可用于远程下载器和路径映射;向导不会在本机解析或创建它。
|
||||
@@ -298,6 +299,9 @@ moviepilot setup --config-dir /path/to/moviepilot-config
|
||||
显式填写 `0`、`1` 等数值仍按填写值发送。
|
||||
清空后保存、重新进入设置页及重启均保留这一语义。
|
||||
|
||||
Gemini 3.8 Flash 不支持完全关闭思考,也不接受 `minimal`。选择“关闭思考”或“最小”时,
|
||||
使用该模型支持的最低级别 `low`;自动及其他思考级别按原设置处理。
|
||||
|
||||
如果希望在自动化安装时直接预设超级管理员,也可以在一键安装脚本中透传:
|
||||
|
||||
```shell
|
||||
|
||||
@@ -76,7 +76,7 @@ LLM_PROVIDER_DEFAULTS = {
|
||||
"base_url": "https://api.openai.com/v1",
|
||||
},
|
||||
"google": {
|
||||
"model": "gemini-2.5-flash",
|
||||
"model": "gemini-3.8-flash",
|
||||
"base_url": "",
|
||||
},
|
||||
"anthropic": {
|
||||
|
||||
@@ -114,9 +114,15 @@ def offline_runtime(monkeypatch):
|
||||
clients = []
|
||||
|
||||
def reject_request(_request):
|
||||
"""
|
||||
拒绝任何意外的提供商网络调用。
|
||||
"""
|
||||
raise AssertionError("思考级别序列化测试不得发起外部请求")
|
||||
|
||||
def make_client(_proxy, *, async_client=False):
|
||||
"""
|
||||
创建仅使用离线传输器的客户端,并登记退出时的释放责任。
|
||||
"""
|
||||
client_type = httpx.AsyncClient if async_client else httpx.Client
|
||||
client = client_type(transport=httpx.MockTransport(reject_request))
|
||||
clients.append(client)
|
||||
@@ -131,6 +137,36 @@ def offline_runtime(monkeypatch):
|
||||
client.close()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("model_name", ["gemini-3.8-flash", "models/gemini-3.8-flash", "gemini-3-flash-preview"])
|
||||
@pytest.mark.parametrize("level", ["off", "minimal", "low", "medium", "high", "max", "xhigh", "auto"])
|
||||
def test_google_thinking_payload_respects_model_minimum(monkeypatch, offline_runtime, model_name, level) -> None:
|
||||
"""
|
||||
原生 Google 请求对 Gemini 3.8 Flash 使用最低可用的 low,并保留旧模型的 minimal。
|
||||
"""
|
||||
from langchain_google_genai import chat_models
|
||||
|
||||
offline_runtime.resolve_runtime.return_value.update(
|
||||
provider_id="google", runtime="google", model_id=model_name, base_url=None,
|
||||
)
|
||||
monkeypatch.setattr(helper, "_patch_gemini_thought_signature", lambda: None)
|
||||
monkeypatch.setattr(chat_models, "Client", Mock(return_value=Mock(aio=None)))
|
||||
|
||||
model = asyncio.run(LLMHelper.get_llm(
|
||||
provider="google", model=model_name, api_key="offline-key", use_proxy=False,
|
||||
web_search_mode="disabled", thinking_level=level, provider_runtime=offline_runtime,
|
||||
))
|
||||
config = model._prepare_params(None).thinking_config
|
||||
|
||||
if level == "auto":
|
||||
assert config is None or config.thinking_level is None
|
||||
return
|
||||
expected = {"off": "minimal", "max": "high", "xhigh": "high"}.get(level, level)
|
||||
if "gemini-3.8-flash" in model_name and expected == "minimal":
|
||||
expected = "low"
|
||||
assert config.thinking_level.value.lower() == expected
|
||||
assert config.include_thoughts is False
|
||||
|
||||
|
||||
@pytest.mark.parametrize("protocol", ["chat_completions", "responses"])
|
||||
@pytest.mark.parametrize("effort", ["max", "xhigh"])
|
||||
@pytest.mark.parametrize("has_catalog", [False, True])
|
||||
|
||||
@@ -9,6 +9,8 @@ import uuid
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
MODULE_PATH = Path(__file__).resolve().parents[1] / "scripts" / "local_setup.py"
|
||||
|
||||
|
||||
@@ -296,3 +298,33 @@ def test_collect_agent_config_prompts_for_duplicate_base_url_presets() -> None:
|
||||
base_url_preset="minimax-cn-coding",
|
||||
runtime_python=None,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("saved_model", [None, "gemini-2.5-flash"])
|
||||
def test_collect_agent_config_accepts_google_default_and_keeps_saved_model(saved_model) -> None:
|
||||
"""
|
||||
Google 向导回车使用新项目可访问的默认模型,同时保留用户已保存的模型。
|
||||
"""
|
||||
module = load_local_setup_module()
|
||||
|
||||
with (
|
||||
patch.object(module, "print_step"),
|
||||
patch.object(module, "_prompt_yes_no", side_effect=[True, False, True]),
|
||||
patch.object(module, "_load_llm_provider_definitions", return_value=[]),
|
||||
patch.object(module, "_prompt_provider_choice", return_value="google"),
|
||||
patch.object(module, "_prompt_text", side_effect=lambda _prompt, **kwargs: kwargs["default"]),
|
||||
patch.object(module, "_prompt_secret_text", return_value="offline-key"),
|
||||
patch.object(module, "_load_llm_models", return_value=[]),
|
||||
patch.object(module, "read_env_value", return_value=None),
|
||||
patch.object(
|
||||
module, "_env_default",
|
||||
side_effect=lambda key, default="": saved_model if key == "LLM_MODEL" and saved_model else default,
|
||||
),
|
||||
patch.object(module, "_env_bool", side_effect=lambda _key, default: default),
|
||||
patch.object(module, "_env_llm_thinking_level_default", return_value="auto"),
|
||||
patch.object(module, "_prompt_choice", side_effect=lambda _prompt, **kwargs: kwargs["default"]),
|
||||
):
|
||||
config = module._collect_agent_config()
|
||||
|
||||
assert config["LLM_PROVIDER"] == "google"
|
||||
assert config["LLM_MODEL"] == (saved_model or "gemini-3.8-flash")
|
||||
|
||||
Reference in New Issue
Block a user