名叫 openai.azure.com 的网关却用 Anthropic 协议时,你让 Agent 怎么办?

本文最后更新于 2026年4月29日 晚上

根因:这个网关虽然主机名是 openai.azure.com,但同一台服务同时暴露了 OpenAI-compatible 与 Anthropic Messages 两套协议。GPT 要走 /openai/v1/...,Claude 要走 /anthropic/v1/...
再加上 Goose 新版更新收紧了对 openai 的参数验证,所有看起来就是上一个版本还能用,升级了就突然挂了。

总结论

  1. 这不是一个纯 OpenAI 网关。
    虽然主机名是 ...openai.azure.com,但它同时提供:

    • /openai/v1/models
    • /openai/v1/chat/completions
    • /anthropic/v1/messages?api-version=
  2. GPT-5.5 和 Claude 走的不是同一条协议面。

    • GPT-5.5 应该走 /openai/v1/chat/completions,并且要用 max_completion_tokens
    • Claude 应该走 /anthropic/v1/messages,并且要用 max_tokens
  3. Hermes 早期现象:

    • 能看到 Claude、能用 GPT-5.5
    • 但 Claude 不能请求
      这不是因为 Claude 不存在,而是因为 Hermes 当时主要按 endpoint 走 OpenAI-compatible 路线;/openai/v1/models 里能看到 Claude,不代表 Claude 也支持 /openai/v1/chat/completions
  4. Goose 早期现象:

    • 看不到 GPT-5.5、Claude 4.7
    • Claude 也不能正常配置
      后来可以拆成两个原因:
    • 看不到部分新模型,是因为 Goose 在抓取模型列表后又做了一层 canonical filtering
    • Claude 不能用,是因为 Goose 后来对 provider / 协议边界收紧了,Claude 不该继续挂在 Azure OpenAI provider 下,而应该单独建一个 Anthropic-style provider
  5. Goose 的正确修法:
    不再试图让 Claude 继续走 azure_openai,而是单独创建一个 Anthropic-style provider,host 指向:

    1
    https://...openai.azure.com/anthropic/v1

    这个地址看起来很抽象,但它确实就是当前网关上 Claude 的正确入口。


现象

1. Hermes 这边

当时观察到的是:

  • Hermes 能看到 Claude
  • Hermes 能用 GPT-5.5
  • 但 Hermes 不能真正请求 Claude

后来的直接探测把这件事解释清楚了:

  • /openai/v1/models 会把 Claude 列出来
  • 但 Claude 并不支持 /openai/v1/chat/completions
  • Claude 真正能工作的,是 /anthropic/v1/messages?api-version=

所以 Hermes 当时的问题,本质上不是“看不到 Claude”,而是:

看到了 Claude,但按 OpenAI-compatible 方式去请求它。

2. Goose 这边

当时观察到的是:

  • Goose 看不到 GPT-5.5
  • Goose 看不到 Claude 4.7
  • Goose 也不能正常用 Claude

这三件事后来也都能解释:

2.1 为什么 Goose 看不到 GPT-5.5 / Claude 4.7

不是网关没返回,而是 Goose 自己又过滤了一遍。

也就是说:

  • 上游模型列表不一定为空
  • 但 Goose 在展示前还会做一层 canonical mapping / filtering
  • 因此一些新模型虽然在 live /models 里存在,Goose 不一定会直接展示

2.2 为什么 Goose 不能用 Claude

不是因为 Claude 本身坏了,而是 Goose 后来的 provider 边界更严格了

Claude 在这个网关里本来就不该继续挂在 Azure OpenAI provider 下面,而应该作为 Anthropic-style provider 单独配置。

所以现在最自然的方式其实是:

  • GPT 继续走 Azure OpenAI / OpenAI-compatible 路线
  • Claude 单独建一个 Anthropic-style provider
  • host 直接填:
1
https://...openai.azure.com/anthropic/v1

虽然这个 host 看上去很怪,因为域名还是 openai.azure.com,但 path 这一层实际上讲的是 Anthropic 协议,这正是它能工作的原因。


直接验证结果

这次问题最后是靠直接 probe 定下来的,不是靠 UI 猜出来的。

1. 模型列表

1
/openai/v1/models: OK, includes Claude and GPT-5.5.

这说明:

  • Claude 确实存在于这个网关的可见模型列表里
  • GPT-5.5 也存在

2. GPT-5.5

1
2
GPT-5.5 via /openai/v1/chat/completions: OK with max_completion_tokens.
GPT-5.5 with max_tokens: fails.

这说明 GPT-5.5 的正确组合是:

  • endpoint:/openai/v1/chat/completions
  • max 字段:max_completion_tokens

3. Claude

1
2
Claude via /openai/v1/chat/completions: fails with api_not_supported.
Claude via /anthropic/v1/messages?api-version=: works with max_tokens.

这一步是整个问题的关键。

它说明:

  • Claude 虽然在 /openai/v1/models 里可见
  • 但 Claude 并不属于 /openai/v1/chat/completions 那一侧
  • Claude 真正属于 /anthropic/v1/messages 这条协议面

代码出处

下面只记最相关的代码点。

1. Goose

1.1 Azure provider 仍然是 OpenAI-compatible 路线

文件:

  • crates/goose/src/providers/azure.rs
  • crates/goose/src/providers/openai_compatible.rs

关键点:

  • azure.rs 里会把 Azure provider 包成 OpenAI-compatible provider
  • 请求前缀包含:
1
format!("deployments/{}/", deployment_name)

也就是说它本质上还是沿着 OpenAI-compatible 这一族在走。

1.2 Goose 会拉模型,但之后还会再过滤

文件:

  • crates/goose/src/providers/openai_compatible.rs
  • crates/goose/src/providers/base.rs
  • crates/goose-cli/src/commands/configure.rs

关键点:

  • openai_compatible.rs 里有 fetch_supported_models()
  • base.rs 里有 fetch_recommended_models()
  • configure 流程里实际拿的是 fetch_recommended_models() 的结果

所以 Goose 展示出来的模型,不只是 live list,还经过了一轮自己的推荐过滤。

1.3 Anthropic provider 支持单独走 Anthropic 协议

文件:

  • crates/goose/src/providers/anthropic.rs

关键点:

  • 这个 provider 自己就是 Anthropic 协议族
  • 它使用独立的 base URL / host
  • 所以把 host 指到:
1
https://...openai.azure.com/anthropic/v1

虽然域名还是 Azure 风格,但只要该 path 实现的是 Anthropic Messages,就能工作

2. Hermes

文件:

  • hermes_cli/models.py
  • run_agent.py
  • hermes_cli/runtime_provider.py
  • agent/transports/chat_completions.py

关键点:

  • Hermes 会探测 /models,所以能先看到 Claude
  • 但 runtime 如果按 OpenAI-compatible / chat_completions 去走,就会把 Claude 送错协议面
  • Hermes 代码里也明确区分了不同 api_mode,例如:
    • chat_completions
    • anthropic_messages

所以 Hermes 这边后来真正的经验也一样:

不要只看 endpoint 主机名,要看它最终走的是哪种 api_mode



名叫 openai.azure.com 的网关却用 Anthropic 协议时,你让 Agent 怎么办?
https://gou7ma7.github.io/2026/04/29/devops/@2026_azure_gateway_dual_openai_anthropic_surface_goose_hermes/
作者
Roy Lee
发布于
2026年4月29日
许可协议