升级踩坑实录:OpenClaw 2026.4.9 后 GitHub Copilot 调用 Claude 全线 HTTP 400 的根因与修复

小版本升级,大坑预警。本文记录一次真实的 AI 网关升级故障,从现象到根因,从日志到代码,带你彻底搞清楚"配置覆盖了插件默认值"这类隐蔽 bug 的来龙去脉。


一、事故现场:升级完所有 Claude 请求全挂了

把 OpenClaw 从 2026.4.5 升到 2026.4.9,重启 gateway,一切看起来正常。但很快,所有走 GitHub Copilot provider 调 Claude 模型(claude-sonnet-4.6)的请求开始报错。Feishu 机器人没有响应,Kimi Bridge 无法调用,TUI 也一样——覆盖所有渠道,全军覆没。

第一反应:是不是 token 过期了?还是 Copilot 账号被封?

打开日志,仔细看错误信息——


二、错误日志解读:格式错,不是认证错

error=HTTP 400: Bad Request
reason=format
decision=surface_error

HTTP 400 有两种典型原因:认证失败(401/403 才对)或者请求格式本身就错了。这里的关键字是 reason=format,说得很明确:不是 token 问题,是发给 API 的请求体格式不对。

decision=surface_error 则说明 OpenClaw gateway 没有做任何重试或降级,直接把错误透传给了调用方。

这个日志把排查方向锁定在一个很具体的位置:我们发出去的 HTTP 请求,用了错误的 API 格式

那么,什么叫"错误的 API 格式"?


三、背景知识:Claude 和 GPT 用的是完全不同的 API 协议

在接着分析之前,有必要澄清一个常被忽略的事实:

  • OpenAI GPT 系列:使用 /v1/chat/completionsopenai-completions)或 OpenAI 新版 Responses API(openai-responses
  • Anthropic Claude 系列:使用 /v1/messagesanthropic-messages),请求体结构、字段命名、特殊 header 都完全不同

两套协议不兼容。如果你用 OpenAI 格式的请求体去调 Claude 的 endpoint,服务端会直接拒绝,返回 400。

GitHub Copilot 作为一个多模型代理,在背后需要把你的请求转发给对应厂商的 API。因此,Copilot 插件必须根据你要调用的模型,选择正确的 API 格式进行转发


四、根因:一条优先级链,三层覆盖

4.1 插件的新逻辑

OpenClaw 2026.4.9github-copilot 插件对模型路由逻辑做了重要更新:

模型类型 旧版 API 格式 新版 API 格式
Claude 系列 openai-completions anthropic-messages
GPT 系列 openai-completions openai-responses

插件内部新增了一个函数,自动根据模型名称推断应该使用哪种格式:

function resolveCopilotTransportApi(modelId) {
  return modelId.includes("claude") ? "anthropic-messages" : "openai-responses";
}

逻辑很清晰:模型名包含 "claude" 就用 Anthropic 协议,否则用 OpenAI 协议。这个变更是正确的、必要的——问题出在别的地方。

4.2 配置文件里那个"历史遗留"字段

openclaw.json 的配置里,models.providers.github-copilot 段有这样的内容(升级前就存在):

{
  "models": {
    "providers": {
      "github-copilot": {
        "api": "openai-completions",
        "headers": {
          "Content-Type": "application/json",
          "...": "..."
        },
        "models": [
          { "id": "gpt-4o", "... ": "..." },
          { "id": "gpt-4o-mini", "...": "..." }
        ]
      }
    }
  }
}

注意:api: "openai-completions" 是 provider 级别的配置,models 数组里只有 GPT 模型,没有 claude-sonnet-4.6

4.3 优先级链:谁说了算?

OpenClaw 在解析一个模型请求时,对 api 字段有明确的优先级链:

per-model api  >  provider-level api  >  plugin default api

逐层解释:

  1. per-model api:如果 models 数组里某个具体模型配置了 api 字段,最优先使用它
  2. provider-level api:如果没有 per-model 配置,退回到 provider 级别的 api 字段
  3. plugin default api:如果 provider 也没配置,最终使用插件自动推断的默认值(即 resolveCopilotTransportApi 的结果)

当请求 claude-sonnet-4.6 时,推断流程是这样的:

  • 第一层检查claude-sonnet-4.6 不在 models 数组里 → 没有 per-model api → 跳过
  • 第二层检查:provider 配置了 "api": "openai-completions"命中!使用 openai-completions
  • 第三层(永远到不了):插件想自动设置 anthropic-messages,但已经被第二层覆盖了

结果:claude-sonnet-4.6 的请求,用 OpenAI completions 格式发给了 Copilot 的 Claude endpoint。对方看到格式不对,返回 400 Bad Requestreason=format

4.4 雪上加霜:headers 也被覆盖了

配置里还有一个 headers 字段。github-copilot 插件在调用 Claude 时,会通过 buildCopilotDynamicHeaders 函数动态生成 Claude 专用的请求头(例如 Anthropic 版本号、特定的 content-type 等)。

openclaw.json 里手写的静态 headers 直接覆盖了这套动态生成逻辑,导致 Claude 请求缺少必要的专用 header,进一步加剧了 400 错误。

一句话总结根因:升级前留下的 provider 级别 apiheaders 配置,在新版插件引入"按模型自动路由"机制后,成了拦截正确行为的绊脚石。


五、修复:删掉两个字段,重启网关

知道了原因,修复非常直接:

第一步:打开 openclaw.json,找到 models.providers.github-copilot删除 apiheaders 字段,保留 models 数组(GPT 模型条目可以保留,或同样清理掉 per-model 的 api 字段)。

修改前:

"github-copilot": {
  "api": "openai-completions",
  "headers": { "...": "..." },
  "models": [...]
}

修改后:

"github-copilot": {
  "models": [...]
}

第二步:重启 gateway:

openclaw gateway restart

验证:重新发一条 Claude 请求,确认不再返回 400。此时插件的 resolveCopilotTransportApi 会正确工作,Claude 请求走 anthropic-messages,GPT 请求走 openai-responses


六、同次升级踩的其他四个坑

这次升级不只有 Copilot 400 这一个问题,顺便记录一下一并处理的其他故障:

坑一:Feishu channel 配置校验失败

现象:Gateway 启动时报 Feishu channel 配置校验错误。

原因channels.feishu 中存在废弃字段 botInfoProbeTimeoutMs,新版校验器不再接受它。

修复:从配置中删除 botInfoProbeTimeoutMs 字段。


坑二:memory-lancedb 缺少 required embedding

现象:memory-lancedb 插件初始化失败。

原因:该 entry 缺少必填的 embedding 配置,导致插件无法正常启动。

修复:从配置中移除整个 memory-lancedb entry(暂时禁用,待补全配置后再启用)。


坑三:lossless-claw 插件更新失败,持续刷日志

现象:Gateway 日志中 lossless-claw 插件持续输出更新失败的错误信息,干扰正常日志观察。

修复:直接卸载该插件:

openclaw plugins uninstall lossless-claw

坑四:Gateway entrypoint 不匹配

现象:Gateway 启动时提示 entrypoint 路径不匹配。

修复:运行内置诊断修复命令:

openclaw doctor --fix

该命令会自动检测并修复常见的安装路径问题。


七、经验总结

1. 小版本升级也可能有破坏性变更

2026.4.5 → 2026.4.9 看起来只是 patch 级别更新,但 plugin 内部的路由逻辑变更实质上改变了"plugin default api"的行为。任何插件逻辑变更都可能与你的历史配置产生冲突,升级后必须验证。

2. 理解优先级链,而不是盲目配置

OpenClaw 的 api 字段有三层优先级:per-model > provider-level > plugin default。大多数时候,你不需要不应该在 provider 级别手写 api,让插件自动推断是更鲁棒的选择。只有在需要为某个特定模型强制指定格式时,才应该在 per-model 层配置。

3. reason=format 是定位 400 错误的关键线索

遇到 HTTP 400,先看 reason 字段:

  • reason=format → 请求体格式/协议不对,查 API 类型配置
  • reason=auth401/403 → token 或权限问题
  • reason=validation → 参数校验失败,查具体字段

这个区分能帮你快速排除错误方向,省去大量无效排查时间。

4. 升级时做"配置 diff"

升级前后,对 openclaw.json 做一次 diff,重点检查被新版废弃或语义改变的字段。这次出问题的 apiheadersbotInfoProbeTimeoutMs 都是此类"历史遗留"字段。

5. openclaw doctor --fix 是你的第一个急救工具

遇到升级后的奇怪问题(路径不对、entrypoint 找不到),先跑一遍 openclaw doctor --fix,它能自动修复相当一部分常见的安装和配置问题。


结语

这次升级踩的坑,核心本质是配置的"历史惯性"遇上了插件逻辑的演进。旧配置在旧版本是合理的,但新版本改变了默认行为,而配置的优先级机制让旧配置"赢"了——赢得了发出错误格式请求的权利。

理解工具内部的优先级链,是避免这类问题的根本。与其依赖"默认应该怎样"的直觉,不如花时间搞懂"配置实际上怎么被解析"的机制。

希望这篇记录能帮你在下次升级时少走弯路。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐