From e06ddc887a9199ed53f1236bcc69318328f4d1c1 Mon Sep 17 00:00:00 2001 From: zizi Date: Wed, 24 Jun 2026 08:46:07 +0000 Subject: [PATCH] =?UTF-8?q?fix(tier2):=20thinking=20=E5=85=B3=E6=97=B6=20b?= =?UTF-8?q?udget=20=E5=BD=92=E4=B8=80=E4=B8=BA=20None(=E4=BF=AE=E5=9F=BA?= =?UTF-8?q?=E7=BA=BF=E6=A8=A1=E5=9E=8B=20Parameters=20=E6=A0=A1=E9=AA=8C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit C3 Opus 基线探针实证:build_baseline_model('Opus') thinking 关时传 thinking_budget=0,被 AnthropicChatModel.Parameters 的 thinking_budget>0 约束拒(ValidationError),基线根本构不出。 C3 代码落地时假设 budget=0 可行,但从没真跑过基线、未暴露。 修 build_model:thinking_enable=False → thinking_budget 归一为 None(Parameters 字段 int|None, Anthropic 仅 thinking_enable 时才用它)+ 跳过 max_tokens>budget 校验(该约束只在 thinking 开有意义)。 M3 路(thinking 开、budget=8000)行为不变,硬校验保留。 Co-Authored-By: Claude Opus 4.8 (1M context) --- tier2/gen-worker/worker/config.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/tier2/gen-worker/worker/config.py b/tier2/gen-worker/worker/config.py index be3b28a2..3ec2fe84 100644 --- a/tier2/gen-worker/worker/config.py +++ b/tier2/gen-worker/worker/config.py @@ -240,11 +240,18 @@ def build_model( if max_retries is None: max_retries = genconfig.get("model", "max_retries", 2) - if max_tokens <= thinking_budget: - raise ValueError( - f"max_tokens({max_tokens}) 必须 > thinking_budget({thinking_budget}):" - "Anthropic 要求输出上限严格大于 thinking 预算(否则无 token 留给正式输出)。" - ) + # thinking 关:budget 与正式输出无关,且 AnthropicChatModel.Parameters 对 thinking_budget 有 >0 约束 + # (传 0 会被 pydantic 拒——基线证路 thinking 关时实证暴露)。故 thinking 关 → budget 归一为 None + # (Parameters 字段是 int|None,Anthropic 仅在 thinking_enable 时才用它,_model.py:174),并跳过 + # max_tokens>budget 校验(该约束只在 thinking 开时有意义)。thinking 开 → 保留硬校验(M3 路不变)。 + if thinking_enable: + if max_tokens <= thinking_budget: + raise ValueError( + f"max_tokens({max_tokens}) 必须 > thinking_budget({thinking_budget}):" + "Anthropic 要求输出上限严格大于 thinking 预算(否则无 token 留给正式输出)。" + ) + else: + thinking_budget = None resolved_base = base_url or _DEFAULT_BASE_URL # base_url 若是调用方临时换的端点,也补一次代理旁路(幂等,已在 NO_PROXY 里则不动)。 @@ -374,7 +381,8 @@ def build_baseline_model( """ # 聚合 key(Opus/Fable)→ new-api 真名;传的若已是真名(不在表里)则原样用。 resolved_name = _BASELINE_NAME_BY_KEY.get(model_name.strip().lower(), model_name) - # thinking 默认关(基线纯证路):budget=None → 0;此时 build_model 的「max_tokens>budget」恒成立。 + # thinking 默认关(基线纯证路):budget=None → 0 表示「关」;thinking 关时 build_model 会把 budget + # 归一为 None(避开 Parameters 的 thinking_budget>0 校验)并跳过 max_tokens>budget 检查。 # 显式传 budget>0 → 开 thinking,build_model 会强制校验 max_tokens>budget。 budget = 0 if thinking_budget is None else thinking_budget thinking_on = budget > 0