DeepAI Paper Hermes Agent 教程,Hermes 模型与 Provider API Copilot 接入里最隐蔽的坑:模型目录、Token 与企业端点其实是同一条链

Copilot 接入里最隐蔽的坑:模型目录、Token 与企业端点其实是同一条链

GitHub Copilot 看起来像一个简单 provider:登录账号,拿到 token,调用 Copilot API,选择模型,然后开始对话。

但 NousResearch/hermes-agent issue #7731 暴露出一个更真实的情况:Copilot provider 不是“有 token 就能用”的简单 OpenAI-compatible 接口。模型目录、上下文窗口、token exchange、OAuth client ID、Enterprise endpoint,其实是一条连在一起的认证与能力发现链。

只要其中一环按错,用户看到的就可能是:

  • 账号里明明有的模型,Hermes 看不到;
  • claude-opus-4.6-1m 这类账号特定模型上下文窗口显示错误;
  • 企业 Copilot 用户请求打到错误 base URL;
  • 交换后的 endpoint 没有被识别,导致 Header 或认证逻辑缺失;
  • Individual / Business / Enterprise 账号表现不一致。

这篇不是普通“API Key 错误”文章,而是一次 Copilot provider 能力发现链路复盘。


第一层坑:静态模型库不等于你的账号模型库

issue 里提到,Hermes 的 Copilot provider 会回退到 models.dev 这类静态模型数据。

静态模型库的问题是:它只能告诉你“常见模型大概是什么样”,不能告诉你:

  • 当前账号可见哪些模型;
  • 某个 preview / internal-only 模型是否开放;
  • 当前账号的 max_prompt_tokens
  • 企业策略是否隐藏或限制模型;
  • 特定模型在 Copilot 里是否有不同 context window。

例如 claude-opus-4.6-1m 在某些 Copilot 计划里可用,但 models.dev 未必列出,或者列出的 context window 不准确。

所以正确的数据源应该优先是 Copilot /models API 返回的 live catalog,而不是静态 fallback。


第二层坑:原始 GitHub token 不等于 Copilot API token

issue 里另一个关键点是 token exchange。

设备流拿到的 ghu_* / gho_* 这类 GitHub token,并不一定就是调用 Copilot API 的最终形态。

完整模型目录、内部模型、企业 endpoint 等能力,需要通过:

/copilot_internal/v2/token

把原始 GitHub token 交换成短期 Copilot API JWT。

这个 JWT 里会携带更关键的信息,例如:

  • 可用 endpoint;
  • proxy-ep
  • token 过期时间;
  • 与账号/企业策略相关的访问能力。

如果 Hermes 直接把原始 GitHub token 当 Bearer 发给 Copilot API,就可能进入一个“能部分工作,但能力不完整”的状态。

这类 bug 最难查,因为它不是彻底失败,而是半成功。


第三层坑:OAuth Client ID 会影响你看到的世界

issue 里还提到 OAuth client ID。

不同客户端身份可能影响 GitHub 返回的模型目录和权限语义。比如 VS Code、Copilot CLI、第三方工具,可能走不同 client ID / GitHub App / OAuth App 流程。

讨论里也特别谨慎:VS Code 的 client ID 不一定能直接替换,因为 GitHub App 与 OAuth App 的 device flow 权限语义不同。

这说明 provider 不能简单写死一个 client ID 后假设所有账号都一样。

更稳的做法是:

  • 明确当前 client ID 的来源和能力边界;
  • 用 Individual / Business / Enterprise 做测试矩阵;
  • 不要只用个人账号验证后就宣布企业场景可用。

第四层坑:企业账号不一定走 api.githubcopilot.com

普通 Copilot 请求可能打到:

https://api.githubcopilot.com

但企业 Copilot 用户可能需要走交换 token 里给出的 endpoint,例如 proxy-ependpoints.api

如果 provider 把 base URL 硬编码成 api.githubcopilot.com,企业用户就可能完全不可用。

评论里还有一个细节:某些代码只判断 URL 是否包含:

api.githubcopilot.com

但 token exchange 后 endpoint 可能是:

api.business.githubcopilot.com

于是本该加的 IDE auth header / Editor-Version header 没有加,最终触发:

HTTP 400: missing Editor-Version header for IDE auth

这类问题不是“Header 忘了加”这么简单,而是 endpoint 识别逻辑太窄。


为什么四个问题要拆成独立 PR?

评论里维护者建议把四个子问题拆成独立 PR,这个判断很专业。

因为它们虽然互相关联,但修复边界不同:

子问题修复点风险
live context windows/models 里的 max_prompt_tokens 接到 resolver低,局部清晰
token exchange原始 GitHub token 换 Copilot JWT中,需要缓存/刷新策略
OAuth client ID客户端身份影响模型目录高,需要账号矩阵验证
enterprise endpoint从 JWT 推导 base URL / proxy endpoint中,需要兼容 override

如果一次大 PR 全改,review 会很难,也更容易把企业账号、个人账号、本地配置混在一起。


最终修复:#15114 做了什么

维护者后续说明该问题由 #15114 修复,其中关键两点已经落地:

1. Token exchange

  • exchange_copilot_token() 调用 api.github.com/copilot_internal/v2/token
  • 将原始 GitHub token 换成短期 Copilot API token;
  • 来源 PR #12876
  • commit d7ad07d6f

2. Live context windows

  • get_copilot_model_context() 查询 /models endpoint;
  • 使用账号实际返回的 max_prompt_tokens
  • 覆盖 claude-opus-4.6-1m 这类 models.dev 没有的账号特定模型;
  • 来源 PR #12840
  • commit 76329196c

这比单纯更新一份静态模型表更可靠。


这和上一类“1M 上下文”问题有什么不同?

前一类问题是:Hermes 对模型上下文窗口有硬编码或错误默认。

这篇的 Copilot 场景更复杂:

上下文窗口错误只是表象
真正问题是 Copilot provider 没有完成账号级能力发现

也就是说,不只是“把 128K 改成 1M”这么简单。

Provider 必须先正确登录、交换 token、调用账号级 /models、读取 live max_prompt_tokens,再决定 context window。


企业 Copilot 用户的排查清单

如果你在 Hermes 里接 Copilot,尤其是 Business / Enterprise 账号,建议按下面查。

1. 确认模型目录来自 live /models

不要只看静态 models.dev。重点看当前账号真实返回了哪些模型。

2. 确认是否做了 token exchange

看是否调用过:

/copilot_internal/v2/token

以及后续请求是否使用交换后的 Copilot API token。

3. 确认 endpoint 是否来自 token

如果 JWT 里有 proxy-ependpoints.api,provider 不应继续硬编码默认 base URL。

4. 检查 endpoint 匹配逻辑

不要只匹配 api.githubcopilot.com。企业或 business endpoint 可能仍属于 githubcopilot.com,但 host 不同。

5. 记录账号类型

排查 Copilot provider bug 时,一定要说明:

  • Individual / Business / Enterprise;
  • OAuth client ID;
  • 是否经过 token exchange;
  • /models 原始返回;
  • 实际 endpoint;
  • 报错 header / status code。

DeepAI API 中转站在这里能做什么?

DeepAI API 中转站适合统一 OpenAI-compatible 模型调用入口:

Base URL: https://api.deepai.wang/v1
API Key: 你的 DeepAI Key
Model: 以 DeepAI 控制台为准

但 Copilot provider 是 GitHub Copilot 自己的一套认证、token exchange、模型目录和企业 endpoint 机制。DeepAI API 中转站不能替 Hermes 完成 Copilot token exchange,也不能让 GitHub 企业 endpoint 自动生效。

更合理的定位是:

  • 需要标准 OpenAI-compatible 接入时,用 DeepAI;
  • 需要 GitHub Copilot 账号模型时,必须正确实现 Copilot provider 的认证和能力发现;
  • 不要把 Copilot 当作普通 OpenAI-compatible base URL。

FAQ

为什么账号里有模型,Hermes 看不到?

可能 Hermes 没有使用账号级 /models live catalog,而是回退到静态模型数据。

为什么 claude-opus-4.6-1m 显示上下文窗口不对?

如果 models.dev 没有该账号特定模型,静态 fallback 就可能给错 context window。应使用 /models 返回的 max_prompt_tokens

原始 GitHub token 不能直接调用 Copilot API 吗?

可能部分可用,但完整模型目录、企业 endpoint、internal-only 模型通常需要 token exchange。

企业账号为什么更容易出问题?

企业账号可能走不同 endpoint,且 endpoint 信息来自交换后的 JWT。如果 provider 硬编码默认 base URL,就会失败。

DeepAI 能替代 Copilot provider 吗?

不能直接替代 GitHub Copilot 账号体系。DeepAI 是 OpenAI-compatible API 中转站,适合标准模型调用,不负责 GitHub Copilot 的 token exchange 和企业 endpoint。


总结

Copilot provider 的坑不在“某个 URL 写错”这么简单,而是四层假设叠在一起:

静态模型目录 ≠ 账号真实模型目录
原始 GitHub token ≠ Copilot API token
普通 OAuth client ≠ 所有账号能力
默认 base URL ≠ 企业 endpoint

#7731 的修复重点,是把 Copilot 当成一个需要账号级能力发现的 provider,而不是普通 OpenAI-compatible 接口。

Related Post

安全过滤器把注释也当命令了:Hermes 终端误杀 setsid / nohup 的坑安全过滤器把注释也当命令了:Hermes 终端误杀 setsid / nohup 的坑

Hermes terminal safety filter 曾用简单正则扫描 nohup/disown/setsid,导致 git commit message、PR body、Python -c 代码和 echo 文本里的关键词也被当作真实后台命令拦截。本文复盘 #20064:为什么安全过滤不能只靠关键词扫描。

你明明发过,session_search 却说没见过:Hermes 记忆检索少了哪一块你明明发过,session_search 却说没见过:Hermes 记忆检索少了哪一块

Hermes session_search 能搜到 messages.content,却搜不到 tool_calls 和 tool_name。本文复盘 #16751:为什么工具参数、函数名和工具轨迹明明存进数据库,却在 FTS 检索里消失,以及该如何修复索引结构。

Hermes 的 Custom Endpoint 和 API Server 不是一回事:接 DeepAI 前先别搞反Hermes 的 Custom Endpoint 和 API Server 不是一回事:接 DeepAI 前先别搞反

Hermes 里有两个 OpenAI-compatible:Custom Endpoint 用来接 DeepAI 这样的上游模型,API Server 用来让 Open WebUI、LobeChat 等前端连接 Hermes。本文讲清 Base URL、API Key 和链路区别。