DeepAI Paper Hermes Agent 教程 OpenAI-compatible API 报 unsupported_parameter:max_tokens 和 max_completion_tokens 为什么不能只看 Base URL?

OpenAI-compatible API 报 unsupported_parameter:max_tokens 和 max_completion_tokens 为什么不能只看 Base URL?

如果你把 Hermes Agent、Cline、Cherry Studio、Dify 或 Open WebUI 接到第三方 OpenAI-compatible API,经常会遇到一个看似奇怪的问题:同样是 /v1/chat/completions,同样有 Base URL 和 API Key,有的模型可以正常跑,有的模型第一轮就 HTTP 400。

NousResearch/hermes-agent issue `#13901` 就是一个典型案例:Hermes 在自建 OpenAI-compatible gateway、OpenAI proxy、OpenRouter 或 Azure OpenAI 这类自定义 endpoint 上调用新模型族时,错误地发送了 max_tokens,而服务端要求的是 max_completion_tokens

报错非常适合被用户搜索:

{
  "error": {
    "code": "unsupported_parameter",
    "message": "Unsupported parameter: 'max_tokens' is not supported with this model. Use 'max_completion_tokens' instead.",
    "param": "max_tokens",
    "type": "invalid_request_error"
  }
}

这篇文章不只是复盘一个 Hermes bug,更重要的是说明一个 API 中转站和多模型路由里很关键的原则:参数兼容性应该跟模型能力走,而不能只跟 Base URL 域名走。 如果你正在做多模型接入,可以优先把工具统一接入 DeepAI API 中转站,再按模型族处理参数、上下文和流式响应差异。


这个 bug 发生在什么场景?

issue 中给出的复现条件很明确:

export OPENAI_BASE_URL=https://my-openai-gateway.example.com/v1
export OPENAI_API_KEY=sk-...
export OPENAI_MODEL=gpt-5.4

也可以是:

export OPENAI_MODEL=gpt-4o-mini
export OPENAI_MODEL=openai/gpt-4o-mini
export OPENAI_MODEL=o3-mini

然后启动 Hermes:

hermes chat

第一轮请求就可能失败:

HTTP 400 unsupported_parameter
Unsupported parameter: 'max_tokens' is not supported with this model. Use 'max_completion_tokens' instead.

关键点不在于“这个 endpoint 是不是 OpenAI 官方域名”,而在于它背后服务的模型族是否要求 max_completion_tokens


根因:代码只看 host,没有看 model family

issue 里指出,Hermes 的 _max_tokens_param 逻辑大致是:

def _max_tokens_param(self, value: int) -> dict:
    if self._is_direct_openai_url():
        return {"max_completion_tokens": value}
    return {"max_tokens": value}

也就是说:

Base URL host == api.openai.com
        ↓
发送 max_completion_tokens

其他 host
        ↓
发送 max_tokens

这在老模型时代可能勉强够用,但在 OpenAI-compatible API 生态里很容易出错。

因为第三方 endpoint 可能是:

  • 自建 OpenAI-compatible gateway;
  • OpenAI proxy;
  • Azure OpenAI / Azure AI Foundry;
  • OpenRouter;
  • 企业内部模型网关;
  • 多模型 API 中转站。

这些 endpoint 的 host 不一定是 api.openai.com,但它们可能代理的是 gpt-4ogpt-4.1gpt-5o1o3o4 这类新模型族。

于是 Hermes 把它们误判成“旧模型/旧接口”,发送 max_tokens,服务端直接拒绝。


为什么这对 API 中转站 SEO 很重要?

很多用户搜索“API 中转站”“OpenAI API 中转”“OpenAI-compatible Base URL”时,真实痛点不是“怎么填一个 URL”这么简单,而是:

  • 为什么换了 Base URL 后参数报错?
  • 为什么同一个工具换模型就 400?
  • 为什么 gpt-4o / gpt-5 / o-series 不认 max_tokens
  • 为什么 Azure OpenAI、OpenRouter、自建网关行为不一致?
  • 为什么 fallback 也失败?

这正是 DeepAI API 中转站 应该覆盖的长尾搜索场景:用户不是只需要一个入口,而是需要一个更稳定的 OpenAI-compatible API 接入层,把 Base URL、API Key、模型名称、参数兼容和路由策略统一管理起来。

对开发者来说,推荐写法不是“只要换个域名就能兼容所有模型”,而是:

工具层:Hermes / Cline / Cherry Studio / Dify / Open WebUI
        ↓
统一入口:[DeepAI API 中转站](https://api.deepai.wang/)
        ↓
模型路由:OpenAI-compatible / DeepSeek / Kimi / Gemini / OpenRouter 等
        ↓
参数适配:max_tokens / max_completion_tokens / reasoning / streaming / usage

这样文章既能吃到 unsupported_parameter max_tokens 这类报错搜索,也能自然把用户导向 API 中转站。


正确判断方式:模型族优先,而不是域名优先

issue 中建议增加一个按模型名判断的 helper:

def model_forces_max_completion_tokens(model: str) -> bool:
    m = (model or "").strip().lower()
    if not m:
        return False
    if "/" in m:
        m = m.rsplit("/", 1)[-1]
    return (
        m.startswith("gpt-4o")
        or m.startswith("gpt-4.1")
        or m.startswith("gpt-5")
        or m.startswith("o1")
        or m.startswith("o3")
        or m.startswith("o4")
    )

注意这段逻辑还处理了 OpenRouter 风格的模型名:

openai/gpt-4o-mini

通过 / 切分后得到:

gpt-4o-mini

然后就能匹配到 gpt-4o 模型族。

对应调用逻辑应该更像:

if self._is_direct_openai_url() or model_forces_max_completion_tokens(self.model):
    return {"max_completion_tokens": value}
return {"max_tokens": value}

也就是:

是否官方 OpenAI URL?
        或
模型族是否强制 max_completion_tokens?
        ↓
发送 max_completion_tokens

Azure OpenAI 也复现了这个问题

issue 评论里有人确认,Azure OpenAI / Azure AI Foundry 自定义 endpoint 也会遇到同类问题。

典型 endpoint 长这样:

https://<resource>.openai.azure.com/openai/v1

受影响模型包括:

  • gpt-5.4-hermes
  • gpt-5.4-nano-hermes
  • gpt-4.1-hermes

表现是:

Unsupported parameter: 'max_tokens' is not supported with this model. Use 'max_completion_tokens' instead.

在 Telegram / gateway mode 里,还会进一步表现为:

  • repeated retries;
  • fallback switching;
  • Primary model failed — switching to fallback
  • 任务被打断;
  • 用户以为是 API Key 或网络问题。

这也是为什么多模型中转不能只做“转发请求”,还要关心不同模型族的参数差异。对需要统一管理模型接入的用户,建议把客户端工具统一指向 DeepAI API 中转站,再根据不同模型和供应商能力做配置与排障。


后续状态:为什么 issue 被关闭但问题仍值得写?

这个 issue 最后以 not_planned 关闭,不是因为问题不存在,而是因为原始复现场景被后续多个修复绕开了:

  • gpt-5.x 后来无论 Base URL 如何都会走 Responses API;
  • Azure OpenAI 和 GitHub Copilot 被加入了 URL allowlist;
  • auxiliary calls 后来能在 unsupported_parameter 400 时做 reactive retry。

但作者也明确提到仍有一个窄缝:

main agent path + custom non-Azure/non-Copilot endpoint + gpt-4o/4.1/o-series

也就是说,自定义 OpenAI-compatible endpoint 仍然有可能遇到模型族与参数选择不一致的问题。

这就是技术文章的价值:不只是记录“某个 issue 关了”,而是提炼出可复用的排障原则。


排查清单:遇到 unsupported_parameter max_tokens 怎么办?

1. 先确认错误是不是这个

看报错里有没有:

Unsupported parameter: 'max_tokens' is not supported with this model. Use 'max_completion_tokens' instead.

如果有,就不要先怀疑 API Key、网络或余额。

2. 看模型名

重点看模型是否属于:

  • gpt-4o*
  • gpt-4.1*
  • gpt-5*
  • o1*
  • o3*
  • o4*

如果是,就要优先考虑 max_completion_tokens

3. 看工具是否按 host 判断参数

如果工具只判断:

api.openai.com → max_completion_tokens
其他 Base URL → max_tokens

那在 API 中转站、自建 gateway、Azure、自定义代理场景里就很危险。

4. 看是否有 OpenRouter 风格前缀

例如:

openai/gpt-4o-mini

不能只做完整字符串匹配,要能识别 / 后面的真实模型族。

5. 统一入口后再分模型策略

如果你同时接入多个模型供应商,建议让工具统一走 DeepAI API 中转站,再按模型族排查:

  • token 参数;
  • streaming 格式;
  • reasoning 字段;
  • usage 字段;
  • tool calling 格式;
  • context length;
  • fallback 行为。

外链与来源

站内相关主题:


FAQ

max_tokensmax_completion_tokens 有什么区别?

它们都是控制输出长度的参数,但新模型族可能要求使用 max_completion_tokens,继续发送 max_tokens 会被服务端拒绝。

为什么官方 OpenAI 能用,自定义 Base URL 就不行?

因为有些客户端代码只把 api.openai.com 识别为新参数路径,自定义 Base URL 被误判为旧接口路径,于是发送了错误参数。

API 中转站是不是只要转发请求就行?

不是。真正稳定的 API 中转站还要理解模型族差异、参数兼容、streaming 格式、reasoning 字段、usage 统计和 fallback 行为。DeepAI API 中转站 的 SEO 内容也应该围绕这些真实排障问题建设,而不是只堆“便宜 API”关键词。

OpenRouter 风格的 openai/gpt-4o-mini 怎么判断?

应该先剥掉供应商前缀,取 / 后面的 gpt-4o-mini,再判断模型族。

这个问题只影响 Hermes 吗?

不是。任何按 Base URL 而不是按模型族选择参数的 OpenAI-compatible 客户端,都可能遇到类似问题,包括 CLI agent、桌面客户端、工作流工具和自建代理。


总结

#13901 的核心不是“某个参数名写错了”,而是一个 OpenAI-compatible API 生态里的通用问题:

参数选择不能只看 Base URL host,必须看模型族和后端能力。

如果客户端看到自定义 endpoint 就默认发送 max_tokens,当后端实际服务的是 gpt-4ogpt-4.1gpt-5 或 o-series 模型时,就会出现:

Unsupported parameter: 'max_tokens' is not supported with this model. Use 'max_completion_tokens' instead.

对用户来说,解决问题的第一步不是盲目换 Key,而是确认模型族、参数名和工具版本。对站点运营来说,这类真实报错是非常适合 SEO 的长尾入口:用户带着具体错误搜索进来,文章给出排障路径,再自然引导到 DeepAI API 中转站 作为统一 OpenAI-compatible API 接入入口。

Related Post

Hermes agent deepai gpt5 custom endpoint api mode codex responses.png

Hermes Agent 接入 DeepAI API 中转站:gpt-5 自定义端点被强制走 codex_responses 怎么排查Hermes Agent 接入 DeepAI API 中转站:gpt-5 自定义端点被强制走 codex_responses 怎么排查

Hermes Agent 使用自定义 OpenAI-compatible 端点接入 API 中转站时,如果模型名以 gpt-5 开头,即使显式设置 api_mode=chat_completions,也可能被运行时强制切到 codex_responses,导致响应变慢或卡住。本文结合 Hermes Agent Issue #10473,整理 DeepAI API 中转站场景下的协议选择、模型命名和排查方法。

Telegram 里 /model 不生效?Hermes Gateway 远程切换模型失效排查Telegram 里 /model 不生效?Hermes Gateway 远程切换模型失效排查

Hermes Telegram Gateway 里 /model 看得到却不生效?本文解释 /model 被移除、CLI 切换不影响 Telegram session、Agent 幻觉式声称已切换,以及如何用日志和 provider 账单验证真实模型。

长任务最怕的不是中断,而是压缩时悄悄失忆长任务最怕的不是中断,而是压缩时悄悄失忆

Hermes 长任务遇到 incomplete chunked read 时,context compression 可能插入 static fallback marker 并移除中间 turns,却没有生成真实摘要。本文复盘 #18458:为什么压缩摘要失败比普通中断更危险,以及 retry/fallback 应该如何设计。