ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Hermes Agent 接入 Qwen3.7-Max 报 401?OpenCode Go 模型路由源码级排查与修复

Hermes Agent 接入 Qwen3.7-Max 报 401?OpenCode Go 模型路由源码级排查与修复 1. 先复现Hermes Agent 调 Qwen3.7-Max 为什么只报 401你如果在 Hermes Agent 里把默认模型从 deepseek-v4-pro 切到 qwen3.7-maxWebUI 立刻弹出一行红字Authentication failed: Error code: 401后面还跟着一句Model qwen3.7-max is not supported for format oa-compat。第一反应通常是 Key 过期了、额度没了、或者账号被限流但你去查 Key 明明有效deepseek-v4-pro、qwen3.6-plus、kimi-k2.6 全都跑得好好的只有 qwen3.7-max 这一个模型挂掉。这就是本文要解决的场景Hermes Agent 接入 Qwen3.7-Max 时OpenCode Go 模型路由返回 401 的源码级排查与修复。先把概念对齐方便第一次接触这套组合的读者跟上。Hermes Agent 是 Nous Research 开源的一个 AI Agent 框架支持 20 多家 LLM 提供商带持久记忆、跨平台网关和技能自进化。OpenCode Go 是 OpenCode 推出的模型网关服务在同一个 API 端点后面托管了 DeepSeek V4 Pro、Qwen3.7-Max、Kimi K2.6、GLM-5.1、MiniMax M2.7 等一批主流模型省去你分别申请各家 Key 的麻烦。Qwen3.7-Max 是通义千问 3.7 系列的旗舰模型长上下文和推理能力都不错适合放进 Agent 做复杂任务。问题出在“模型路由”这一层。OpenCode Go 并不是把所有模型都挂在同一个 API 协议下它按模型把请求分发到不同的协议端点一部分模型走 OpenAI 的 chat/completions 格式另一部分模型只认 Anthropic 的 messages 格式。qwen3.7-max 恰好属于后者。而 Hermes Agent 在初始化 Agent 时对非 Anthropic 的 provider 做了一个“一刀切”的 fallback把 api_mode 统一设成 chat_completions于是请求被发到了 qwen3.7-max 不支持的格式上网关直接回 401。注意这个 401 不是鉴权失败而是“模型与请求格式不匹配”被网关包装成了 401很容易误导排查方向。这篇文章适合三类人正在用 Hermes Agent 接 OpenCode Go 的开发者、被 401 卡住但 Key 明明有效的同学、以及想理解“同一 provider 下不同模型需要不同 API 协议”这个设计的人。下面我会从环境配置开始一步步复现 401用 curl 逐个端点测试定位到协议不匹配再进 Hermes 源码找到三处绕过路由判定的代码路径给出可复制的补丁最后用一条命令验证修复成功。全程本地可跟做不需要任何额外账号。2. 前置OpenCode Go 与 TaoToken 的 Key 和端点准备在动源码之前先把请求链路和凭证准备好否则后面复现 401 时你分不清是 Key 的问题还是路由的问题。这一节把 base_url、API Key、模型列表三件事讲清楚并说明为什么我建议同时准备一个 TaoToken 的 Key 作为对照验证。先说 OpenCode Go 侧。它的 API 根地址是https://opencode.ai/zen/go/v1鉴权用 Bearer Token也就是在请求头里带Authorization: Bearer $OPENCODE_GO_API_KEY。你需要在 OpenCode Go 的控制台里生成一个 Key形如sk-xxxxxxxx。拿到 Key 后第一件事不是直接配 Hermes而是先用 curl 列一下可用模型确认 Key 有效、网络通、模型在列表里curl https://opencode.ai/zen/go/v1/models \ -H Authorization: Bearer $OPENCODE_GO_API_KEY正常会返回一个 JSON 数组里面能看到{id:qwen3.7-max,object:model,owned_by:opencode}这样的条目。模型在列表里说明 Key 有效、端点可达这一步就把“Key 失效”这个可能性排除了。很多人卡在 401 时反复重置 Key其实 Key 根本没问题问题在后面的请求格式。再说 TaoToken 侧。TaoToken 是一个聚合多家模型的 API 网关根地址是https://taotoken.net/api同样用 Bearer Token 鉴权。它的价值在于当你怀疑是 OpenCode Go 侧的路由问题时可以用 TaoToken 的同一个模型做对照请求如果 TaoToken 下 qwen3.7-max 正常返回就进一步确认问题出在 OpenCode Go 的协议分发或 Hermes 的 api_mode 判定上而不是模型本身或你的网络。TaoToken 的 Key 在控制台的 API Keys 页面生成模型对话入口可以用来快速验证模型是否可用。把两个 Key 都放进环境变量避免在命令里明文写export OPENCODE_GO_API_KEYsk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx export TAOTOKEN_API_KEYsk-yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy然后是 Hermes 侧的配置。Hermes 的模型配置在config.yamlprovider 和 base_url 这样写model: default: deepseek-v4-pro provider: opencode-go base_url: https://opencode.ai/zen/go/v1 api_mode: chat_completions对应的.env里放 OpenCode Go 的 KeyOPENCODE_GO_API_KEYsk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx注意这里的api_mode: chat_completions是全局默认值也是后面出问题的根源之一。Hermes 在启动时会读这个值但真正决定单次请求走哪个协议的是 Agent 初始化时算出来的agent.api_mode。当默认模型是 deepseek-v4-pro 时chat_completions 是对的所以一切正常一旦你把 default 改成 qwen3.7-max这个全局默认值就和模型实际需要的协议冲突了。如果你用的是 Claude Code 或 Cline 这类工具接 OpenCode Go配置思路一样都是 Base URL Key Model ID 三件套。Base URL 填https://opencode.ai/zen/go/v1Key 填 OpenCode Go 的 KeyModel ID 填qwen3.7-max。区别在于这些工具对 Anthropic 格式的支持程度不同有的会自动根据模型名切换协议有的需要你手动指定。Hermes 属于后者需要改源码这也是本文的重点。最后提醒一点OpenCode Go 的 base_url 末尾带/v1这个细节在走 Anthropic 格式时会变成坑。Anthropic SDK 会在 base_url 后面自动追加/v1/messages如果你的 base_url 已经是.../v1拼出来就是.../v1/v1/messages直接 404。这个坑我在第 5 节会专门讲现在先记住 base_url 末尾的/v1在两种协议下的处理方式不一样。3. 可复制配置让 Hermes 按模型切换 API 协议这一节给出完整的可复制配置和补丁片段路径和原文一致你可以直接对照自己的 Hermes 安装目录改。核心思路是不再让api_mode在 Agent 初始化时一刀切而是根据 provider model 动态判定qwen3.7-max 走 anthropic_messages其余走 chat_completions同时在切到 Anthropic 格式时把 base_url 末尾的/v1剥掉。先确认你的 Hermes 安装路径。默认在~/.hermes/hermes-agent/里面有两个关键目录agent/和hermes_cli/。模型路由的判定函数在hermes_cli/models.pyAgent 初始化在agent/agent_init.py模型切换在agent/agent_runtime_helpers.py。三个文件都要动。第一步确认hermes_cli/models.py里的模型列表和路由函数。opencode-go 的模型列表必须包含 qwen3.7-max路由函数要能识别 qwen3.7- 前缀# hermes_cli/models.py opencode-go: [ deepseek-v4-pro, deepseek-v4-flash, qwen3.7-max, # 必须存在 qwen3.6-plus, qwen3.5-plus, kimi-k2.6, # ... ], def opencode_model_api_mode(provider_id, model_id): # ... if provider opencode-go: if normalized.startswith(minimax-): return anthropic_messages # MiniMax → Anthropic 格式 if normalized.startswith(qwen3.7-): return anthropic_messages # Qwen 3.7 → Anthropic 格式 return chat_completions # 其他 → OpenAI 格式这个函数本身是对的。问题在于 Hermes 的请求链路里有三处绕过了它导致agent.api_mode始终是 chat_completions。下面逐个补。补丁 1agent/agent_init.py。在agent.api_mode chat_completions之后插入 OpenCode 模型路由检测并在切到 Anthropic 格式时剥掉 base_url 末尾的/v1else: agent.api_mode chat_completions # PATCH START if agent.provider in {opencode-zen, opencode-go} and agent.model: try: from hermes_cli.models import opencode_model_api_mode agent.api_mode opencode_model_api_mode(agent.provider, agent.model) if agent.api_mode anthropic_messages: import re as _re _stripped _re.sub(r/v1/?$, , base_url or ) if _stripped: base_url _stripped agent.base_url _stripped except Exception: pass # PATCH END 补丁 2agent/agent_runtime_helpers.py。模型切换时的 API 模式判定改为模型感知不再只看 provider 和 base_url# PATCH START if not api_mode: if new_provider in {opencode-zen, opencode-go}: from hermes_cli.models import opencode_model_api_mode api_mode opencode_model_api_mode(new_provider, new_model) else: api_mode determine_api_mode(new_provider, base_url) # PATCH END 补丁 3确认hermes_cli/models.py的配置和路由函数如上模型列表包含 qwen3.7-max路由函数对 qwen3.7- 前缀返回 anthropic_messages。如果你用 Claude Code 接 OpenCode Go配置片段是另一套。Claude Code 的 settings 里需要指定 Anthropic 格式的 base_url 和 Key{ env: { ANTHROPIC_BASE_URL: https://opencode.ai/zen/go, ANTHROPIC_API_KEY: sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, ANTHROPIC_MODEL: qwen3.7-max } }注意这里的ANTHROPIC_BASE_URL末尾不带/v1因为 Claude Code 会自己拼/v1/messages。这和 Hermes 的处理方式不同Hermes 的 base_url 带/v1走 Anthropic 格式时要手动剥掉。这个差异是很多人配 Claude Code 时 404 的原因也是配 Hermes 时 401 的原因方向相反但根子都是 base_url 和协议的拼接规则。Cline 接 OpenCode Go 走 MCP 的话配置里同样要写全 Base URL Key Model ID 三件套并在 provider 设置里选 Anthropic 兼容模式。Codex 的 auth.json 则是另一种结构把 Key 和 base_url 分开写。不管哪个工具核心都是让 qwen3.7-max 走 Anthropic 格式其余模型走 OpenAI 格式。4. 验证请求从 401 到 200 的端到端确认配置改完先别急着在 WebUI 里点用 curl 逐个端点验证把“协议不匹配”这件事钉死。这一步能帮你确认修复方向对不对也能在改源码前先建立基线。先测 OpenAI 格式的 chat/completions 端点这是 Hermes 默认会走的路径curl https://opencode.ai/zen/go/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer $OPENCODE_GO_API_KEY \ -d {model:qwen3.7-max,messages:[{role:user,content:hi}],max_tokens:5}返回 401错误信息是Model qwen3.7-max is not supported for format oa-compat。注意这个 401 的措辞它说的是“format oa-compat”也就是 OpenAI 兼容格式而不是“invalid api key”。这就是关键线索鉴权没问题是格式不支持。再测 Anthropic 格式的 messages 端点curl https://opencode.ai/zen/go/v1/messages \ -H Content-Type: application/json \ -H x-api-key: $OPENCODE_GO_API_KEY \ -H anthropic-version: 2023-06-01 \ -d {model:qwen3.7-max,messages:[{role:user,content:hi}],max_tokens:20}返回 200 OK模型正常响应。两个端点一对比结论就出来了qwen3.7-max 只认 Anthropic Messages 格式不认 OpenAI Chat Completions 格式。注意 Anthropic 格式的鉴权头是x-api-key而不是Authorization: Bearer这也是两种协议的区别之一。把几个模型都测一遍做个对照表模型/v1/chat/completions/v1/messagesdeepseek-v4-pro200400qwen3.7-max401200qwen3.6-plus200—minimax-m2.7401200这张表说明 OpenCode Go 把不同模型托管在不同的 API 协议下deepseek-v4-pro 走 OpenAI 格式qwen3.7-max 和 minimax-m2.7 走 Anthropic 格式。Hermes 的 api_mode 在 Agent 初始化时一刀切就必然会在 qwen3.7-max 上翻车。改完源码后清缓存、重启 gateway、跑一条验证命令# 清除 Python 缓存 find ~/.hermes/hermes-agent/agent -name __pycache__ -exec rm -rf {} 2/dev/null find ~/.hermes/hermes-agent/hermes_cli -name __pycache__ -exec rm -rf {} 2/dev/null # 重启 Hermes gateway hermes gateway restart # 验证 hermes chat -q 11? --model qwen3.7-max --provider opencode-go --yolo --quiet预期输出是2。如果输出 2说明请求已经正确走到 Anthropic Messages 格式401 消失。如果还是 401检查 base_url 是否剥掉了/v1以及agent.api_mode是否真的被设成了 anthropic_messages。可以在agent_init.py的补丁里临时加一行 print 确认。再用 TaoToken 做一次对照验证确认模型本身没问题curl https://taotoken.net/api/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -d {model:qwen3.7-max,messages:[{role:user,content:11?}],max_tokens:10}TaoToken 侧正常返回说明模型可用、你的网络没问题问题确实在 OpenCode Go 的协议分发和 Hermes 的 api_mode 判定上。这一步做完端到端链路就确认了。5. 常见报错排查401、local proxy failed、reading choices、OAuth修复过程中你会遇到几个典型报错这一节逐个对照真实错误信息给排查路径。每个报错都对应链路里的一个具体环节按顺序排查能省很多时间。第一个401 Model qwen3.7-max is not supported for format oa-compat。这是本文的主线错误根因是请求走错了协议端点。排查顺序先用 curl 测/v1/chat/completions和/v1/messages两个端点确认模型只认哪个再进agent_init.py看agent.api_mode是否被设成了 anthropic_messages最后确认 base_url 是否剥掉了/v1。如果 curl 测/v1/messages返回 200 但 Hermes 还是 401说明补丁没生效检查__pycache__是否清干净、gateway 是否重启。第二个local proxy failed。这个报错通常出现在你本地配了代理或网关转发时请求没到 OpenCode Go 就断了。排查确认config.yaml里的 base_url 是https://opencode.ai/zen/go/v1没有多余路径确认环境变量里没有残留的HTTP_PROXY/HTTPS_PROXY指向本地端口确认 Hermes gateway 进程正常监听。如果你在本地跑了一个转发服务检查它的目标地址和端口是否和 base_url 一致。第三个reading choices相关报错形如Error reading choices from response。这个通常出现在 OpenAI 格式的响应解析上当模型实际返回的是 Anthropic 格式的 JSON而 Hermes 按 OpenAI 格式去解析choices字段时就会报这个。根因和 401 一样是协议不匹配只是表现不同。修复方式相同让 qwen3.7-max 走 anthropic_messages。如果你在别的工具里看到这个报错检查该工具的 provider 设置是否支持按模型切换协议。第四个OAuth 相关报错。如果你用的是需要 OAuth 的 provider401 可能是 token 过期。但 OpenCode Go 用的是 API Key不走 OAuth所以这个报错一般出现在你混用了其他 provider 的配置时。排查确认config.yaml里 provider 是opencode-go不是某个 OAuth provider确认.env里是OPENCODE_GO_API_KEY而不是别的变量名确认没有把 OAuth token 误填到 API Key 位置。还有一个容易忽略的base_url 末尾/v1导致的 404。当你把 api_mode 改成 anthropic_messages 后Anthropic SDK 会在 base_url 后追加/v1/messages。如果 base_url 是https://opencode.ai/zen/go/v1拼出来是https://opencode.ai/zen/go/v1/v1/messages返回 404 Not Found。修复方式是在切到 anthropic_messages 时用正则剥掉末尾的/v1让 SDK 自己拼最终 URL 变成https://opencode.ai/zen/go/v1/messages返回 200。这个坑和 401 是连着的改完 api_mode 后如果从 401 变成 404就是这个问题。排查时建议按这个顺序先 curl 确认模型支持的协议再查 Hermes 的 api_mode再查 base_url 拼接最后查缓存和 gateway 重启。每一步都有明确的验证命令不要跳步。如果你用 Claude Code 或 Cline排查思路一样只是配置文件位置不同Claude Code 看 settings 里的ANTHROPIC_BASE_URLCline 看 MCP 配置里的 Base URL Key Model ID 三件套Codex 看 auth.json。6. 长期跑 Agent 的接入选择与 Key 管理修完这个 401你大概率会想把 Hermes Agent 长期跑起来做编码、做 Agent 任务、做多模型切换。这时候接入方式和 Key 管理就值得单独想一下。我的经验是把“模型网关”和“Agent 框架”解耦网关负责协议适配和模型路由Agent 框架只管调统一的接口这样换模型、加模型都不用改 Agent 源码。如果你主要做长期编码或 Agent 任务可以考虑用 Coding Plan 这类按订阅计费的方式把多个模型的调用统一到一个 Key 下省去每个模型单独申请 Key 的麻烦。TaoToken 的 Coding Plan 入口就是为这种场景准备的适合需要频繁切换模型、跑长任务的开发者。如果你只是偶尔验证某个模型用模型对话入口快速测一下就行不用配完整环境。Key 管理上我建议分环境隔离开发用一个 Key生产用一个 Key避免一个 Key 泄露影响全部。环境变量命名统一加前缀比如OPENCODE_GO_API_KEY、TAOTOKEN_API_KEY不要用API_KEY这种通用名否则多个 provider 会互相覆盖。Hermes 的.env文件不要提交到 git加进.gitignore。接入文档和 API Keys 管理入口建议收藏换机器或换工具时直接对照配置。如果你用 Claude Code 接 Anthropic 格式的模型ClaudeCodeAnthropic 的配置说明能帮你确认 base_url 和 Key 的写法。控制台里可以随时查看用量和额度避免跑到一半 Key 失效。最后说一个实用技巧把本文的补丁做成一个可执行脚本换机器时一键应用。脚本做四件事打补丁、清缓存、重启 gateway、跑验证命令。这样你下次在别的机器上遇到同样的 401不用重新翻源码直接跑脚本就行。补丁针对特定版本的 hermes-agent官方后续版本可能已内置修复执行前对照第 3 节的代码确认文件内容避免重复打补丁导致冲突。
返回列表