fix: ZenMux 节点自适应参数重试,兼容弃用 temperature 等模型
用户实测 anthropic/claude-sonnet-5 报 400:`temperature` is deprecated。 根因:节点无条件把 temperature/top_p/seed/max_tokens 塞进请求体,而 ZenMux 聚合的部分模型弃用/不支持这些采样参数,规则各家不一且随模型迭代变化。 - 新增 _diagnose_param:从 400 错误消息识别是哪个采样参数导致失败 - 请求改为重试循环:命中即剔除该参数(或把 max_tokens 改名为 max_completion_tokens,适配 gpt-5 reasoning 系)后重试 - 只动可选采样参数,绝不触碰 model/messages;非参数类 400 不重试、不死循环 - 正常请求零额外开销;剔除动作打印到控制台,最终仍失败时提示已剔除项 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
eff089c771
commit
9dd4fbd890
@@ -733,6 +733,7 @@ ComfyUI-SDMatte 传 `aux_input="trimap"`,把模型推到了没训练过的输
|
||||
模型类型:openai/gpt-5.4-nano [入$0.2/M 出$1.25/M]
|
||||
价格换算,美元:0.000955,人民币:0.006876
|
||||
```
|
||||
- **自动参数兼容**: 部分模型弃用或不支持某些采样参数(如 `claude-sonnet-5` 弃用 `temperature`、gpt-5 reasoning 系要求 `max_completion_tokens`)。节点会在收到相关 400 错误时**自动剔除或改名该参数并重试**,无需手动调整;剔除动作会打印到 ComfyUI 控制台。正常请求不受影响、无额外开销。
|
||||
|
||||
**输入参数**:
|
||||
- `api_key` (STRING): ZenMux 平台的 API Key(在 zenmux.ai 控制台获取)
|
||||
|
||||
+65
-3
@@ -80,6 +80,46 @@ def _build_proxy_url(raw_proxy: str) -> str:
|
||||
return ('http://' + s) if s else ''
|
||||
|
||||
|
||||
# 遇到「参数不被支持 / 已弃用」的 400 时,可安全剔除的采样参数
|
||||
# (绝不触碰 model / messages 等核心字段)
|
||||
_ADJUSTABLE_PARAMS = ("temperature", "top_p", "seed", "max_tokens",
|
||||
"max_completion_tokens", "frequency_penalty",
|
||||
"presence_penalty", "top_k")
|
||||
# 判定「这条 400 是参数问题」的关键词(命中才尝试剔除重试)
|
||||
_PARAM_ERR_HINTS = ("deprecat", "unsupport", "not support", "not allowed",
|
||||
"invalid", "unexpected", "unknown", "must be", "cannot",
|
||||
"not permitted", "removed")
|
||||
|
||||
|
||||
def _diagnose_param(resp, payload):
|
||||
"""
|
||||
从 400 响应里判断是哪个采样参数导致失败,返回处理指令:
|
||||
("drop", 参数名) —— 从 payload 剔除该参数后重试
|
||||
("rename_mct", ...) —— 把 max_tokens 改名为 max_completion_tokens 后重试
|
||||
None —— 非参数类错误,不重试
|
||||
ZenMux 各模型参数规则不一(claude-sonnet-5 弃用 temperature、gpt-5 reasoning
|
||||
系要求 max_completion_tokens 等),靠错误消息动态识别,免维护静态清单。
|
||||
"""
|
||||
try:
|
||||
msg = (resp.json().get("error", {}) or {}).get("message", "") or resp.text or ""
|
||||
except Exception:
|
||||
msg = getattr(resp, "text", "") or ""
|
||||
low = msg.lower()
|
||||
# 特例:OpenAI reasoning 系要求用 max_completion_tokens 替代 max_tokens
|
||||
if "max_completion_tokens" in low and "max_tokens" in payload:
|
||||
return ("rename_mct", "max_tokens")
|
||||
# 反引号/引号里的参数名优先(错误消息通常形如 `temperature` is deprecated)
|
||||
for name in re.findall(r"""[`'"]([a-zA-Z_]+)[`'"]""", msg):
|
||||
if name in payload and name in _ADJUSTABLE_PARAMS:
|
||||
return ("drop", name)
|
||||
# 回退:错误像参数问题时,扫描 payload 里哪个参数名出现在消息中
|
||||
if any(h in low for h in _PARAM_ERR_HINTS):
|
||||
for name in _ADJUSTABLE_PARAMS:
|
||||
if name in payload and name in low:
|
||||
return ("drop", name)
|
||||
return None
|
||||
|
||||
|
||||
class ZenMuxNode:
|
||||
"""ZenMux API 连接节点。"""
|
||||
|
||||
@@ -326,9 +366,30 @@ class ZenMuxNode:
|
||||
proxies = {"http": p, "https": p}
|
||||
|
||||
resp = None
|
||||
dropped = [] # 记录被剔除/改名的参数,供最终报错时提示
|
||||
try:
|
||||
resp = requests.post(chat_url, headers=headers, json=payload,
|
||||
proxies=proxies, timeout=180)
|
||||
# 自适应参数重试:ZenMux 聚合的部分模型弃用/不支持某些采样参数
|
||||
# (claude-sonnet-5 弃用 temperature、gpt-5 reasoning 系要 max_completion_tokens
|
||||
# 等),命中即剔除/改名后重试,正常请求不受影响、零额外开销。
|
||||
for _ in range(len(_ADJUSTABLE_PARAMS) + 2):
|
||||
resp = requests.post(chat_url, headers=headers, json=payload,
|
||||
proxies=proxies, timeout=180)
|
||||
if resp.status_code == 400:
|
||||
fix = _diagnose_param(resp, payload)
|
||||
if fix:
|
||||
action, param = fix
|
||||
if action == "rename_mct":
|
||||
payload["max_completion_tokens"] = payload.pop("max_tokens")
|
||||
dropped.append("max_tokens→max_completion_tokens")
|
||||
print("[Rui-Node] ZenMux: 该模型要求 max_completion_tokens,"
|
||||
"已改名重试")
|
||||
else:
|
||||
payload.pop(param, None)
|
||||
dropped.append(param)
|
||||
print(f"[Rui-Node] ZenMux: 该模型不支持参数 '{param}',"
|
||||
"已剔除后重试")
|
||||
continue
|
||||
break
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
if data.get("choices"):
|
||||
@@ -352,7 +413,8 @@ class ZenMuxNode:
|
||||
except requests.exceptions.HTTPError:
|
||||
code = resp.status_code if resp is not None else "?"
|
||||
body = resp.text[:600] if resp is not None else ""
|
||||
return (f"HTTP 错误 {code}: {body}", model_id, zero_stats)
|
||||
hint = f"(已尝试剔除参数 {', '.join(dropped)} 仍失败)" if (code == 400 and dropped) else ""
|
||||
return (f"HTTP 错误 {code}: {body}{hint}", model_id, zero_stats)
|
||||
except Exception as e:
|
||||
return (f"请求异常: {type(e).__name__}: {e}", model_id, zero_stats)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user