Skip to content

[Bug]: ZAI/GLM provider base_url causes 429/404 errors — config ignored by 5 code paths #18302

@witzhang

Description

@witzhang

Hermes + 智谱 GLM:从 429 到 404 再到根治的完整记录

写给遇到同样问题的 Hermes 用户,以及未来可能忘记这件事的我自己。


一、你会遇到什么

按照 Hermes 的初始化向导(hermes setuphermes model),选择智谱 GLM 模型、填入 API Key,一切看起来很顺利。但发第一条消息就报错:

HTTP 429: 余额不足或无可用资源包,请充值。
Error code: 1113

你可能会想:"是不是余额不够?"去智谱控制台一看,余额充足。同一个 API Key 在 Claude Code、OpenAI 兼容客户端上用得好好的。

如果你让 agent(包括 Hermes 自己)帮你排查,它会看到"余额不足"这几个字,然后往配额、并发、冷却时间的方向排查。我的 agent 尝试了:

  • 调低并发数 → 没用
  • 清除 credential pool 的 exhausted 状态 → 没用
  • 等一段时间再试 → 没用

甚至把正确的配置改坏了(后面会说)。

如果你正在经历这个情况,请跳到第三章直接看解决方案。


二、到底发生了什么

错误信息是骗人的

"余额不足"是智谱 /api/paas/v4(OpenAI 兼容端点)对某些账户返回的错误消息。但真正的原因不是余额不足,而是这个端点本身对你的账户类型不可用。

智谱 GLM 提供两个 API 端点:

端点 协议 状态
/api/paas/v4 OpenAI Chat Completions 对某些账户返回 429
/api/anthropic Anthropic Messages 正常

同一个 API Key,两个端点,两种命运。Claude Code 用的是 /api/anthropic,所以正常。Hermes 初始化时自动填了 /api/paas/v4,所以报错。

为什么改了配置还是反复出问题

知道了原因后,你把 config.yaml 里的 base_url 改成 /api/anthropic。主对话确实恢复了。但过一会儿又出现新的错误:

HTTP 404: {'path': '/v4/v1/messages'}

这是 auxiliary 功能(title generation、compression 等)在报错。原因是 Hermes 代码中有 5 条独立的路径 在解析 API 端点时,根本不读 config.yaml 里的 base_url,直接使用硬编码的 /api/paas/v4

  1. auxiliary client 的端点解析(agent/auxiliary_client.py
  2. credential pool 初始化(agent/credential_pool.py
  3. credential pool rotation(切换凭证时)
  4. Z.AI 端点探测函数(hermes_cli/auth.py_resolve_zai_base_url
  5. 还有一个函数会把 /anthropic 结尾的 URL 改写成 /v1,导致 Anthropic SDK 无法识别端点

你改了配置,但代码不读配置。这就是问题反复出现的根本原因。

agent 为什么修不好

这个 bug 最坑的地方在于:错误信息会误导 agent 做出错误的修复。

我的飞书上的 Hermes agent 在看到 404 错误后,判断"智谱没有 /api/anthropic 这个端点",把所有 base_url 改回了 /api/paas/v4。结果主对话又 429 了。后来它又发现 /api/anthropic 确实存在,改回来。再后来我让它"检查状态",它又改回去了。来回拉锯了至少三轮。

agent 不是故意的。它看到的信息是这样的:

  • 429 错误说"余额不足" → agent 认为是配额问题
  • 404 错误显示路径 /v4/v1/messages → agent 认为是 URL 不存在
  • 代码中有硬编码的 /api/paas/v4 → agent 认为"默认值应该是对的"

每个判断单看都合理,但放在一起就导致反复出错。

关键信息来自用户

真正改变排查方向的是我(用户)提供的几个信息:

  1. "如果余额不足,Claude Code 也应该不能用" — 这个质疑直接否定了配额假设,推动 agent 去对比两个服务使用的端点
  2. "/api/anthropic 是我之前为了解决 429 才改的" — 告诉 agent 这个 URL 是有依据的,不是乱写的,阻止了 agent 把它改回 /api/paas/v4
  3. "先不要着急修改,查一下之前的记录" — 阻止 agent 在没有理解问题全貌时继续错误修复

这些信息帮助 agent 从"看报错改代码"转向了"理解为什么改了配置还是不行",最终定位到代码中绕过 config.yaml 的 5 条路径。


三、如何解决

如果你现在正在遇到 429

第一步:修改 config.yaml

编辑 ~/.hermes/config.yaml,把所有 base_url/api/paas/v4 改成 /api/anthropic

model:
  default: glm-5.1
  provider: zai
  base_url: https://open.bigmodel.cn/api/anthropic

auxiliary:
  compression:
    provider: zai
    base_url: https://open.bigmodel.cn/api/anthropic
  web_extract:
    provider: zai
    base_url: https://open.bigmodel.cn/api/anthropic
  session_search:
    provider: zai
    base_url: https://open.bigmodel.cn/api/anthropic
  title_generation:        # 注意:键名是 title_generation,不是 title
    provider: zai
    base_url: https://open.bigmodel.cn/api/anthropic

注意 auxiliary 下的键名是 title_generation,不是 title。写错的话 title generation 功能不会读到你的配置。

第二步:修正 auth.json 中 credential pool 的缓存

编辑 ~/.hermes/auth.json,找到 credential_pool.zai 下的 entry,把 base_url 改成 /api/anthropic,同时清除 exhausted 状态:

{
  "credential_pool": {
    "zai": [
      {
        "id": "xxxxxx",
        "base_url": "https://open.bigmodel.cn/api/anthropic",
        "last_status": "ok",
        "last_error_code": null,
        "last_error_message": null
      }
    ]
  }
}

第三步:重启 gateway

sudo systemctl restart hermes-gateway

这一步可以解决主对话的 429,以及 auxiliary 功能的部分 429。

如果你改了配置但 auxiliary 功能仍然 404/429

这说明你遇到了代码 bug——auxiliary client 和 credential pool 没有读取你在 config.yaml 中配置的 base_url

这个问题需要 Hermes 上游修复代码,用户无法通过纯配置变更完全解决。

建议关注 GitHub Issue #18302
#18302

如果你有能力修改代码,需要修复以下 5 处(基于 commit 58a6171):

文件 位置 修复内容
hermes_cli/auth.py 新增 _config_model_base_url() 函数 读取 config.yaml 中的 model.base_url
hermes_cli/auth.py _resolve_zai_base_url() 在探测/默认之前先检查 config.yaml
hermes_cli/auth.py resolve_api_key_provider_credentials() ZAI 分支检查 config.yaml 覆盖
agent/auxiliary_client.py _to_openai_base_url() 不再把 /anthropic 重写为 /v1
agent/auxiliary_client.py pool 路径 pool entry 的 base_url 也检查 config.yaml

核心思路:所有解析 Z.AI base_url 的代码路径,都应该优先使用 config.yaml 中用户显式配置的值,而不是硬编码的 inference_base_url/api/paas/v4)。


四、如何指导 agent 正确修复

如果你让 agent(Claude Code、Hermes 等)帮你排查这个问题,以下信息能帮它少走弯路:

要告诉 agent 的

  1. "同一个 API Key,Claude Code 能用,Hermes 不行" — 这直接排除配额假设,让 agent 对比两个服务的配置差异

  2. "错误消息'余额不足'是误导性的,不是真的余额不足" — 防止 agent 在配额方向浪费时间

  3. "智谱 GLM 有两个端点:/api/paas/v4(OpenAI 协议)和 /api/anthropic(Anthropic 协议),对某些账户只有后者可用" — 直接指出根因

  4. "我已经在 config.yaml 中把 base_url 改成了 /api/anthropic,但 auxiliary 功能还是报错,说明代码没有读取这个配置" — 把 agent 的注意力引向代码路径

  5. "改 base_url 之前先查清楚之前的修改历史" — 防止 agent 把正确的配置改坏

要阻止 agent 做的

  1. 不要让 agent 把 /api/anthropic 改回 /api/paas/v4 — agent 可能会判断"智谱没有这个端点",但这个判断是错的

  2. 不要让 agent 只看错误消息就下结论 — "余额不足"≠ 余额不足,"Not Found"≠ 端点不存在。真正的根因是代码绕过了配置

  3. 不要让 agent 反复重启 gateway 来"测试" — 每次重启后 credential pool 的缓存可能导致不同的表现,增加了排查的混乱度

正确的排查路径

429 "余额不足"
  → 不是配额问题(同一个 Key 其他服务能用)
  → 对比端点:/api/paas/v4 → 429,/api/anthropic → 200
  → 修改 config.yaml 的 base_url
  → 主对话恢复,但 auxiliary 仍然报错
  → 检查代码:auxiliary client 和 credential pool 是否读取了 config.yaml
  → 发现代码绕过配置,使用硬编码值
  → 修复代码,所有路径都尊重 config.yaml
  → 彻底解决

五、环境信息

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low — cosmetic, nice to havearea/configConfig system, migrations, profilesprovider/zaiZAI providertype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions