DeepAI Paper Hermes Agent 教程,Hermes 模型与 Provider API Hermes Issue #1083:OpenRouter / Nvidia / MiniMax 报 400 BadRequest,别只怪 API Key

Hermes Issue #1083:OpenRouter / Nvidia / MiniMax 报 400 BadRequest,别只怪 API Key

在 Hermes Agent 里切换 OpenRouter、Nvidia NIM、MiniMax、Qwen、Gemini 或其他 OpenAI-compatible 模型时,最容易让人崩溃的一类错误就是:

⚠️ API call failed (attempt 1/3): BadRequestError
Error code: 400
Non-retryable client error detected. Aborting immediately.

400 看起来很普通,但它背后可能完全不是同一种问题:可能是 API key 错了,可能是模型 slug 写错了,可能是 OpenRouter free model 限制,也可能是 Hermes 把某个 provider 不支持的字段发给了上游。

NousResearch/hermes-agent 的热门已关闭 Issue #1083 就是一个典型案例。它一开始像是“OpenRouter / Nvidia / MiniMax 都配置不了”,中间定位到 reasoning 参数被错误发送给不支持 reasoning extension 的模型,最后用户又发现自己 .env 里的 OpenRouter key 在首次配置时被写坏了。

这篇文章单独复盘 Issue #1083:为什么同样是 400,不能简单归因为“上游不可用”;PR #1089 修了什么;以及在 Hermes、OpenRouter、DeepAI API 中转站、Nvidia NIM 这类 OpenAI-compatible 链路里,应该怎样分层排查。


Issue #1083 的基本结论

Issue #1083 标题是:

> [Bug]: ⚠️ API call failed (attempt 1/3): BadRequestError

关键信息如下:

项目内容
IssueNousResearch/hermes-agent #1083
状态closed
state_reasoncompleted
评论数20
环境Windows 11 WSL、Hermes Agent v0.2.0
相关服务OpenRouter、Nvidia NIM、MiniMax、Qwen 等
相关 PR#1089:skip reasoning extra_body for models that don’t support it
技术根因之一Hermes 对 OpenRouter / Nous 请求无条件发送 reasoning extra_body
最终用户侧发现OpenRouter API key 在 .env 中损坏,修正 key 后不再出现该问题

最重要的判断是:这个 issue 不是单一原因,而是两个层级的问题叠在了一起。

  • Hermes 代码层:不该把 reasoning 发给不支持 reasoning extension 的模型;
  • 用户配置层:OpenRouter API key 损坏会让所有请求持续失败。

这也是它适合写成排错文章的原因:真实生产问题往往不是“一键修复”,而是多个错误信号混在一起。


现象:Hermes 切到 OpenRouter / MiniMax 后立刻 400

Issue 发起者的复现路径大致是:

hermes model
Current model:    glm5
Active provider:  Custom endpoint

Default model set to: minimax/minimax-m2.5 (via OpenRouter)

hermes chat -q "Hello"

随后报错:

⚠️  API call failed (attempt 1/3): BadRequestError
⏱️  Time elapsed before failure: 0.28s
📝 Error: Error code: 400
📊 Request context: 2 messages, ~2,718 tokens, 31 tools
🧾 Request debug dump written to: ...request_dump....json
❌ Non-retryable client error detected. Aborting immediately.

这里有几个值得注意的信号:

1. 0.28 秒就失败:更像请求参数或认证阶段被拒,而不是模型推理超时。 2. Non-retryable client error:Hermes 判断这是客户端请求问题,重试通常没意义。 3. 写出了 request dump:这类问题必须看请求体,不能只看终端摘要。 4. 31 tools:请求体里包含工具 schema,不排除某些 provider 不兼容 tool schema。

很多人看到 400 会直接重试、换模型、重启 Hermes,但 Issue #1083 说明:真正要看的,是 request dump 里的 body。


第一层根因:reasoning extra_body 被发给了不支持的模型

维护者很快指出了一个代码层问题:Hermes 的 _build_api_kwargs 会对 OpenRouter 请求无条件发送 reasoningextra_body。OpenRouter 会把这个字段转发给上游 provider,而 MiniMax、Nvidia 等模型并不实现这个 reasoning extension,于是上游返回 400。

PR #1089 的描述非常明确:

> Sending reasoning in extra_body to models that don’t support it (MiniMax, Nvidia, etc.) via OpenRouter causes a 400 BadRequestError.

修复思路不是“遇到 400 就重试”,也不是“所有模型都关掉 reasoning”,而是:只在模型 slug 匹配已知支持 reasoning 的前缀时发送 reasoning extra_body。

PR #1089 中的范围包括:

  • deepseek/
  • anthropic/
  • openai/
  • x-ai/
  • google/gemini-2
  • qwen/qwen3
  • Nous Portal 路径

同时修复了两个路径:

  • 主 API 调用路径:_build_api_kwargs
  • 会话总结路径:conversation summary path

这个细节很重要:如果只修主聊天,不修 summary path,后台压缩或总结仍可能触发同样的 400。


第二层陷阱:即使修了 reasoning,也可能还有 API Key 问题

Issue #1083 后半段很典型:用户继续测试 OpenRouter 的 Nvidia、openrouter/free、Qwen3 等模型,仍然遇到 BadRequestError。维护者根据 dump 判断,有些请求里 reasoning 已经没了,有些仍存在,有些则像是 free model / OpenRouter availability 的另一个问题。

最后,用户自己更新了结论:

> the issue was on the key api OpenRouter put during first config and corrupted. No issue after correcting the corrupted key in .env

也就是说,持续失败的另一部分原因是 .env 里的 OpenRouter API key 损坏。

这类结论非常实用,因为很多排错文章会把问题讲得过于单一:

  • “只要升级 PR #1089 就好了”;
  • “只要换 key 就好了”;
  • “只要别用免费模型就好了”。

但真实情况是:PR #1089 修的是请求参数兼容性;修正 API key 解决的是认证/配置层问题。两者不是互相替代。


如何判断你的 400 属于哪一类?

1. 先看 request dump,不要只看终端摘要

Hermes 会在失败时提示类似:

Request debug dump written to: /home/u/.hermes/sessions/request_dump_....json

打开这个 JSON,重点看:

  • request.url
  • request.headers.Authorization
  • request.body.model
  • request.body.extra_body
  • request.body.tools
  • 是否有 reasoning
  • 是否有 provider 不支持的字段

如果你只看 “Error code: 400”,基本无法定位。

2. 如果 body 里有 reasoning,确认模型是否真的支持

如果你使用的是 OpenRouter 路径,且模型是:

  • MiniMax;
  • Nvidia Nemotron;
  • 某些 free model;
  • 某些 OpenAI-compatible 自定义 endpoint;

就要重点检查 Hermes 是否把 reasoning 发进了 extra_body

如果模型不支持 reasoning extension,却收到了:

"extra_body": {
  "reasoning": ...
}

那么 400 很可能来自参数不兼容。

3. 如果 reasoning 已经消失,继续查 key / model / availability

PR #1089 修复后,某些 dump 里已经没有 reasoning。如果仍然 400,就不要继续纠缠这个字段,而要转向:

  • API key 是否损坏;
  • key 是否复制时带了不可见字符;
  • .env 是否被旧配置覆盖;
  • base_url 是否正确;
  • model slug 是否在 OpenRouter 上可用;
  • free model 是否有限制或临时不可用;
  • provider 是否支持 tools;
  • provider 是否支持当前 request body 的 schema。

Issue #1083 最终就是 key 损坏导致后续失败。

4. 对比原生 provider 和 OpenRouter 转发路径

用户后来提到 Nvidia NIM 能工作,而 OpenRouter 的某些 Nvidia 模型仍失败。这说明:

  • 原生 Nvidia NIM endpoint 可用;
  • OpenRouter 转发路径可能还有参数、模型、免费额度或可用性问题;
  • 同一个模型家族,在不同入口下并不等价。

这对所有 OpenAI-compatible 用户都很关键:协议相似不代表参数完全兼容,模型名字相似也不代表上游行为一致。


推荐排查顺序:Hermes 400 BadRequest 五步法

第一步:确认是不是认证问题

检查 .env 或 Hermes 配置里的 key:

cat ~/.hermes/.env

注意不要把真实 key 发到公开 issue 或群聊里。只检查:

  • 是否为空;
  • 是否多了引号;
  • 是否多了空格;
  • 是否被终端转义污染;
  • 是否复制了错误 provider 的 key;
  • 是否被 hermes setup 或其他配置流程覆盖。

Issue #1083 最终就踩在“OpenRouter key 损坏”这个坑上。

第二步:确认 Base URL 和模型名

不同 provider 的入口不一样:

OpenRouter: https://openrouter.ai/api/v1
Nvidia NIM: https://integrate.api.nvidia.com/v1
DeepAI API 中转站: 使用 DeepAI 提供的 OpenAI-compatible Base URL

模型名也必须使用对应入口支持的 slug。不要把 OpenRouter 的 slug 原样拿去 Nvidia NIM,也不要把某个中转站里的内部模型名拿到另一个 provider 上。

第三步:检查 extra_body.reasoning

如果你走 OpenRouter,并且模型不是明确支持 reasoning 的模型,检查 request dump:

"extra_body": {
  "reasoning": ...
}

如果存在,就升级 Hermes 到包含 PR #1089 修复的版本,或者临时关闭相关 reasoning 配置。

第四步:检查 tools schema

Issue #1083 的请求上下文显示有 31 tools。某些 OpenAI-compatible provider 对 tools/function calling 的 schema 要求更严格。

如果错误仍然存在,可以临时减少工具数量或关闭工具调用测试:

  • 纯聊天是否成功?
  • 带工具是否失败?
  • 同一 key、同一 model,在 curl / 简单请求里是否成功?

这样能区分“模型不可用”和“tool schema 不兼容”。

第五步:换入口做 A/B 测试

同一个模型可以尝试多个入口:

  • OpenRouter;
  • provider 原生 API;
  • DeepAI API 中转站;
  • 本地 OpenAI-compatible server;
  • 其他中转层。

如果原生 provider 可用,而 OpenRouter 不可用,说明问题可能在转发层、模型 slug、free model 或字段兼容性上。


DeepAI API 中转站的正确用法:统一模型入口,但不要掩盖字段兼容问题

对 paper.deepai.wang 的读者来说,Issue #1083 的价值不只是“OpenRouter 某个 bug”,而是提醒大家:OpenAI-compatible 工具链要稳定,必须同时管理好三个东西:

1. Base URL; 2. API Key; 3. 请求字段兼容性。

DeepAI API 中转站适合放在第一、第二层:

  • 统一 OpenAI-compatible Base URL;
  • 减少多个 provider key 反复切换;
  • 让 Cherry Studio、Cline、Dify、Open WebUI、Hermes 这类支持自定义 endpoint 的工具更容易接入;
  • 出问题时能集中检查 key、模型名、额度和日志。

但必须说清楚边界:DeepAI 不能自动修复 Hermes 客户端错误发送的 reasoning 字段,也不能保证所有上游模型都支持 tools、vision、reasoning 或 streaming 的同一套扩展。

正确的排查方式是:

  • 如果是 401 / key 无效:查 key 和中转站配置;
  • 如果是 400 / unsupported parameter:查 request body 字段;
  • 如果是 model not found:查模型 slug 和 endpoint;
  • 如果是 timeout / 429:查 provider 可用性、限流和额度;
  • 如果是工具 schema 错误:查 Hermes tools/function calling 格式。

这样 DeepAI 的价值是“让入口更可控”,而不是“神奇修复所有 provider 差异”。


Issue #1083 给 Hermes 用户的三个实用教训

教训一:400 不等于“模型坏了”

400 只是告诉你请求不被接受。真正原因可能是:

  • key 错;
  • model slug 错;
  • 参数字段错;
  • tools schema 错;
  • free model 限制;
  • provider 不支持某个 extension。

教训二:request dump 是核心证据

Hermes 已经把 request dump 写出来了,就不要靠猜。尤其要看 extra_bodytoolsmodelAuthorization

教训三:OpenAI-compatible 不是“字段全兼容”

OpenAI-compatible 通常意味着接口形态相似,但并不意味着:

  • 每个模型都支持 reasoning;
  • 每个 provider 都支持 tools;
  • 每个中转层都会吞掉不支持字段;
  • 每个模型 slug 都能跨平台复用。

Issue #1083 的核心,就是一个 extension 字段被错误转发后,上游 provider 拒绝请求。


FAQ:Hermes OpenRouter 400 BadRequest 常见问题

1. Hermes 里 OpenRouter 报 400,应该先升级还是先换 key?

两者都要查。先看 request dump:如果 extra_body 里有不该出现的 reasoning,升级到包含 PR #1089 修复的版本;如果字段正常但仍 400,再查 key、model slug、free model 限制和 provider availability。

2. MiniMax / Nvidia 模型为什么会因为 reasoning 报错?

因为这些模型不一定支持 OpenRouter 的 reasoning extension。Hermes 如果把 reasoning 放进 extra_body,OpenRouter 转发给上游后,上游会认为这是不支持的参数,从而返回 400。

3. Qwen3 也看到 reasoning,是不是 bug?

不一定。PR #1089 中把 qwen/qwen3 视为 reasoning-capable 前缀之一。是否是 bug 要看具体模型、provider 和返回错误,不要只因为出现 reasoning 就断定错误。

4. DeepAI API 中转站能避免这类问题吗?

可以减少多 provider key / endpoint 管理混乱,但不能保证客户端发送的所有 extra_body 字段都被上游支持。遇到 400 仍然要看 request body 和模型能力。

5. .env 里的 API key 怎么会损坏?

常见原因包括复制粘贴带了不可见字符、配置向导写入异常、手动编辑格式错误、多个配置文件覆盖、把 ANSI 转义或错误字符串写进 key。不要公开粘贴真实 key,只检查格式和重新生成/重新写入。


结语:别把 OpenAI-compatible 当成“零差异协议”

Hermes Issue #1083 的最终价值在于,它把一个普通 400 拆成了两个层级:客户端请求字段兼容性,以及用户本地 API key 配置。

PR #1089 修复了 Hermes 不该向 MiniMax、Nvidia 等模型发送 reasoning 的问题;用户修正 .env 中损坏的 OpenRouter key 后,持续失败也得到解释。

如果你在 Hermes 或其他 Agent 工具里接入 OpenRouter、DeepAI API 中转站、Nvidia NIM、MiniMax、Qwen、Gemini,记住这个排查顺序:先看 request dump,再看 key,再看模型 slug,最后才考虑换 provider。不要只盯着 “400 BadRequest” 这几个字。

Related Post

Hermes agent deepai max tokens context compression.png

Hermes Agent 接入 DeepAI API 中转站:max_tokens 400 与上下文压缩失败排查Hermes Agent 接入 DeepAI API 中转站:max_tokens 400 与上下文压缩失败排查

Hermes Agent 自动上下文压缩时,辅助模型请求因 max_tokens 参数被新模型拒绝并返回 400,导致 fallback context marker 和上下文丢失怎么办?本文结合 Hermes Agent GitHub 已关闭 Issue,整理 DeepAI API 中转站、多模型路由、max_completion_tokens 和辅助任务参数兼容排查方法。

1M 上下文不是越大越好:Hermes 在 Claude Pro 上踩到的 200K 限制1M 上下文不是越大越好:Hermes 在 Claude Pro 上踩到的 200K 限制

Hermes 默认 1M context window 看似更强,但 Claude Pro 账号实际常见限制是 200K,GPT 与本地 Ollama 也可能被错误报大。本文复盘 #3577:为什么上下文窗口不是越大越好,而是越准确越好。

Discord 免 @ 频道变成 thread 工厂:Hermes free-response 为什么每条消息都新开线程Discord 免 @ 频道变成 thread 工厂:Hermes free-response 为什么每条消息都新开线程

Hermes Discord free-response channel 本应免 @ 并 inline reply,但旧代码只跳过 mention 检查,没有把 is_free_channel 传给 auto-thread gate,导致每条消息都新开 thread。本文复盘 #25310。