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

本文记录了在 Hermes Agent 框架中通过 OpenCode Go 网关接入 Qwen3.7-Max 模型时,遭遇 HTTP 401 not supported for format oa-compat 错误的完整排查过程。从问题定位到源码级修复,每一步都可复现。


1. 背景

Hermes Agent 是 Nous Research 开源的 AI Agent 框架(75k+ Star),支持 20+ LLM 提供商,具备持久记忆、跨平台网关、技能自进化等能力。

OpenCode Go 是 OpenCode 推出的模型网关服务($10/月订阅),在同一个 API 端点后面托管了 DeepSeek V4 Pro、Qwen3.7-Max、Kimi K2.6、GLM-5.1、MiniMax M2.7 等国产主流模型,免去分别申请各家 API Key 的麻烦。

笔者的目标:在 Hermes 中配置 opencode-go 提供商,自由切换 DeepSeek V4 Pro 和 Qwen3.7-Max。


2. 环境配置

bash 复制代码
# config.yaml
model:
  default: deepseek-v4-pro
  provider: opencode-go
  base_url: https://opencode.ai/zen/go/v1
  api_mode: chat_completions

# .env
OPENCODE_GO_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

3. 问题复现

将默认模型从 deepseek-v4-pro 切换到 qwen3.7-max 后,Hermes WebUI 立即报错:

复制代码
Authentication failed: Error code: 401
{
  "type": "error",
  "error": {
    "type": "ModelError",
    "message": "Model qwen3.7-max is not supported for format oa-compat"
  }
}

deepseek-v4-proqwen3.6-pluskimi-k2.6 等模型均正常工作。问题仅出现在 qwen3.7-max 一个模型上。


4. 排查过程

4.1 验证 API Key 和基础连通性

bash 复制代码
# 列出可用模型(正常返回)
curl https://opencode.ai/zen/go/v1/models \
  -H "Authorization: Bearer $OPENCODE_GO_API_KEY"

# 返回结果包含 qwen3.7-max
# {"id":"qwen3.7-max","object":"model","owned_by":"opencode"}

模型在列表中,说明 API Key 有效。

4.2 逐个端点测试

bash 复制代码
# 测试 1:OpenAI 格式 (chat/completions)
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"
bash 复制代码
# 测试 2: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 格式(/v1/messages)下工作,不支持 OpenAI Chat Completions 格式(/v1/chat/completions)。

对比测试:

模型 /v1/chat/completions /v1/messages
deepseek-v4-pro ✅ 200 ❌ 400
qwen3.7-max ❌ 401 ✅ 200
qwen3.6-plus ✅ 200 ---
minimax-m2.7 ❌ 401 ✅ 200

OpenCode Go 将不同模型托管在不同的 API 协议后面。

4.3 追踪代码路径

转到 Hermes 源码,找到模型 API 模式判定逻辑:

python 复制代码
# hermes_cli/models.py (已修复版本)
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 的请求链路中,有 三个地方 绕过了这个判定:

Bug 1:初始 Agent 创建 (agent/agent_init.py)

python 复制代码
# 修复前:所有非 Anthropic provider 直接 fallback 到 chat_completions
else:
    agent.api_mode = "chat_completions"

Bug 2:模型切换 (agent/agent_runtime_helpers.py)

python 复制代码
# 修复前:determine_api_mode() 只看 provider + base_url,不看模型名
if not api_mode:
    api_mode = determine_api_mode(new_provider, base_url)

Bug 3:base_url 未剥离 /v1

api_mode = "anthropic_messages" 时,Anthropic SDK 会在 base_url 后追加 /v1/messages。如果 base_urlhttps://opencode.ai/zen/go/v1,最终请求 URL 变成:

复制代码
https://opencode.ai/zen/go/v1/v1/messages  → 404 Not Found

正确的做法是将 /v1 剥离,让 SDK 自行拼接:

复制代码
https://opencode.ai/zen/go/v1/messages     → 200 OK

5. 修复方案

补丁 1:agent/agent_init.py

agent.api_mode = "chat_completions" 之后插入 OpenCode 模型路由检测:

python 复制代码
    else:
        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 =====

补丁 2:agent/agent_runtime_helpers.py

将模型切换时的 API 模式判定改为模型感知:

python 复制代码
    # ===== 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 配置

opencode-go 的模型列表需包含 qwen3.7-max,且路由函数需正确:

python 复制代码
"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"
        if normalized.startswith("qwen3.7-"):
            return "anthropic_messages"
        return "chat_completions"

6. 应用修复并验证

bash 复制代码
# 清除 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 "1+1=?" --model qwen3.7-max --provider opencode-go --yolo --quiet
# 预期输出: 2

7. 根因总结

层次 问题 根因
表象 qwen3.7-max 报 HTTP 401 API 格式不匹配
直接原因 请求走到了 /v1/chat/completions OpenCode Go 的 qwen3.7-max 需要 Anthropic 格式
代码层面 agent.api_mode 始终为 chat_completions 三条代码路径均未调用模型感知的路由函数
架构层面 同一个 provider 的不同模型需要不同 API 协议 Hermes 的 api_mode 在 agent 初始化时一刀切

8. 附件下载

为方便读者直接应用修复,已将三个补丁打包为可执行脚本:

📎 opencode-qwen3.7-fix 一键修复脚本

bash 复制代码
# 从 CSDN 下载附件,解压后执行
tar -xzf opencode-qwen3.7-fix.tar.gz
cd opencode-qwen3.7-fix
chmod +x scripts/apply-fix.sh
./scripts/apply-fix.sh

脚本自动完成:打补丁 → 清缓存 → 重启 gateway → 验证。

⚠️ 注意:该补丁针对 hermes-agent 特定版本。官方后续版本可能已内置修复,执行前请对照本文第 5 节确认文件内容。读者自取,非推荐,仅列示。


发表于 2026 年 5 月 · 作者:闪大夫

相关推荐
叶帆9 小时前
【YFIOs】用C#开发硬件之GPIO操作
开发语言·c#
Engineer邓祥浩9 小时前
宏观认知(1):AI 是什么——吴恩达《AI for Everyone》Week1 学习笔记
人工智能·笔记·学习
小程故事多_8010 小时前
深入解析FlashAttention,大模型长序列训练的底层优化核心技术
人工智能·transformer
阿虎儿10 小时前
看了很多文章依旧不会写 Skill ? 保姆级攻略请查收!
人工智能
好好风格10 小时前
把一台 Root 安卓机交给 AI 智能体,会发生什么?
android·人工智能·开源
likerhood10 小时前
Java 集合框架入门:List、Set、Queue 与 Map
java·开发语言·list
暴躁小师兄数据学院10 小时前
【AI大模型应用开发工程师特训笔记】第04讲(第五章):条件判断与流程控制
大数据·人工智能·python·学习
Java 码思客10 小时前
【Spring AI实战】第2章 大模型基础调用:同步/异步/流式输出
java·人工智能·spring·ai
北京软秦科技有限公司10 小时前
档案复核联动文档核验,IACheck AI报告审核让资料管理体系真正闭环
人工智能