Yoda
参考Agent 设计指南模型与账户

第三方 Provider / Gateway

CC 是封闭四选一枚举(firstParty/bedrock/vertex/foundry)+ BASE_URL 重定向;Codex 是开放 model_providers 注册表——但 wire_api=chat 已被移除

第三方 Provider / Gateway

结论

两家的 provider 抽象走了相反的路:CC 是封闭枚举——getAPIProvider() 只认 firstParty | bedrock | vertex | foundry 四个值,第三方路由只能靠 ANTHROPIC_BASE_URL 把"伪装成 Anthropic API 的 gateway"接进来(claude-code-router 即此模式);Codex 是开放注册表——config.tomlmodel_providers map 可以声明任意 OpenAI 兼容端点,每个 provider 自带 env_key(BYOK)、自定义 header、重试参数。但要注意一个已坐实的变化:Codex 的 wire_api = "chat"(Chat Completions 协议)已被移除,目前 enum 只剩 responses——"Codex 可接任意 Chat Completions 服务"的旧认知已过期。harness 做多 provider 路由时,CC 侧注入 env(BASE_URL + AUTH_TOKEN),Codex 侧注入 provider 条目 + -c model_provider=...

研究问题

  • 各 CLI 的 provider 抽象层在哪?可扩展性边界是什么?
  • BYOK(自带 key)如何配置?key 从哪个 env 读?
  • gateway 模式下认证与模型发现如何穿透?

各 Agent 设计与实现

Claude Code

CC 源码为社区重建版(src_2026-03-31),以下仅作架构描述与短引用。

Provider 是四值枚举,由三个互斥环境变量切换 [一手源码 utils/model/providers.ts:4-14]:

export type APIProvider = 'firstParty' | 'bedrock' | 'vertex' | 'foundry'
// CLAUDE_CODE_USE_BEDROCK → bedrock;CLAUDE_CODE_USE_VERTEX → vertex;
// CLAUDE_CODE_USE_FOUNDRY → foundry;否则 firstParty

切到云厂商后认证交给云 SDK(Bedrock 用 AWS 凭证链、AWS_REGION 必填且不读 .aws config 的 region [一手文档 amazon-bedrock.md:225];Vertex 用 GCP ADC),并自动关闭一方 OAuth [一手源码 utils/auth.ts:115-148]。端点覆盖:ANTHROPIC_BEDROCK_BASE_URLANTHROPIC_VERTEX_BASE_URL、Bedrock Mantle 用 ANTHROPIC_BEDROCK_MANTLE_BASE_URL [一手文档 amazon-bedrock.md:220, 405google-vertex-ai.md:188];Vertex 还支持 per-model region(VERTEX_REGION_CLAUDE_*)[一手文档 google-vertex-ai.md:197-201]。

Gateway 路由 = BASE_URL 重定向ANTHROPIC_BASE_URL 改变请求去向但不改 provider 枚举;源码用 isFirstPartyAnthropicBaseUrl() 判断是否还指向 api.anthropic.com [一手源码 providers.ts:25-40]。gateway 认证推荐 ANTHROPIC_AUTH_TOKEN(Bearer),apiKeyHelper 优先级更低 [一手文档 llm-gateway.md:98-145]。

Gateway 模型发现CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1 时启动查询 gateway 的 /v1/models,仅收 claude*/anthropic* 前缀模型,结果缓存到 ~/.claude/cache/gateway-models.json;默认关闭,避免共享 key 的 gateway 把所有可见模型暴露给每个用户 [一手文档 llm-gateway.md:60-64]。配合 ANTHROPIC_CUSTOM_MODEL_OPTION(手动加一条 picker 项,跳过模型 ID 校验)[一手文档 model-config.md:284-298]。

没有 provider 插件机制:CC 不存在"注册一个新 provider"的入口。第三方路由(claude-code-router、各类中转站)全部走"gateway 伪装 Anthropic Messages API + ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN"这一条路 [推断,基于源码中 provider 枚举封闭 + 文档只给 gateway 路径]。代价:CC 的订阅 OAuth、/usage 配额、fast mode 等一方能力在 gateway 模式下全部失效(isAnthropicAuthEnabled() 返回 false)。

Codex CLI

开放注册表model_providers map(~/.codex/config.toml)+ 内建默认值合并 [一手源码 codex-rs/model-provider-info/src/lib.rs:1-6, 443-479]。内建四个:openairequires_openai_auth: true,订阅时 base 切到 https://chatgpt.com/backend-api/codex)、amazon-bedrock(OpenAI 兼容 Mantle 端点 bedrock-mantle.us-east-1.api.aws/openai/v1,AWS SigV4 签名)、ollamalmstudio [同文件 :37-43, 237-254, 324-441]。内建项不可被用户覆盖,唯一例外是 bedrock 的 aws.profile/aws.region [同文件 :443-479]。

ModelProviderInfo 字段(自定义 provider 的全部可配置面)[一手源码 lib.rs:85-137]:

[model_providers.example]
name = "Example"
base_url = "https://example.com/v1"
env_key = "EXAMPLE_API_KEY"          # BYOK:key 从该 env 变量读
env_key_instructions = "..."          # 缺 key 时给用户的提示
wire_api = "responses"                # 唯一合法值(见下)
query_params = { api-version = "..." }   # Azure 风格
http_headers = { x-foo = "bar" }
env_http_headers = { x-org = "ORG_ENV" } # header 值取自 env
request_max_retries = 4               # 默认 4,上限 100
stream_idle_timeout_ms = 300000

另有 auth = { command = "..." }(命令式 bearer token,与 env_key 互斥)和 experimental_bearer_token(直写 token,源码注明 discouraged)[同文件 :97-104, 181-208]。

wire_api = "chat" 已移除:反序列化遇到 "chat" 直接报错——"wire_api = \"chat\" is no longer supported... set wire_api = \"responses\"",并指向 openai/codex discussion #7782;ollama-chat provider 同步移除 [一手源码 lib.rs:46-48, 68-80]。WireApi enum 现在只有 Responses 一个变体 [同文件 :51-57]。意味着自定义 provider 必须实现 Responses API,纯 Chat Completions 端点已接不进 Codex。

Key 解析api_key()env_key 指定的环境变量,缺失/为空返回带 env_key_instructions 的错误 [一手源码 lib.rs:278-294]。requires_openai_auth: false(默认)时跳过登录界面,key 全靠 env [同文件 :128-133]。本地 OSS provider 的端口/地址可用 CODEX_OSS_PORT / CODEX_OSS_BASE_URL 覆盖 [同文件 :481-497]。

差异矩阵

维度Claude CodeCodex CLI
Provider 模型封闭枚举:firstParty/bedrock/vertex/foundry开放 map:内建 4 个 + 任意自定义
切换方式互斥 env 开关(CLAUDE_CODE_USE_*model_provider = "<key>" 指向 map
自定义端点ANTHROPIC_BASE_URL(协议必须是 Anthropic Messages)base_url(协议必须是 OpenAI Responses)
Chat Completions 兼容不适用已移除(wire_api=chat,discussion #7782)
BYOK key 来源ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN / apiKeyHelperper-provider env_key 指定的 env 变量
命令式凭证apiKeyHelper 脚本(全局一个)auth.command(per-provider)
自定义 headerANTHROPIC_CUSTOM_HEADERS envhttp_headers + env_http_headers(per-provider)
云厂商原生签名Bedrock(AWS SDK)/Vertex(ADC)/FoundryBedrock Mantle(SigV4,aws.profile/region
Gateway 模型发现/v1/models + CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1无自动发现(模型名手写)
重试/超时配置全局(不暴露 per-provider)per-provider:request_max_retriesstream_idle_timeout_ms
订阅能力穿透gateway 模式下 OAuth/配额/fast mode 全部失效自定义 provider 同样无 ChatGPT 配额(requires_openai_auth=false

最小复现

# CC:gateway 路由(claude-code-router 风格)
export ANTHROPIC_BASE_URL=http://127.0.0.1:3456
export ANTHROPIC_AUTH_TOKEN=<gateway-token>   # Bearer 头
claude   # /status 应显示非一方 base url;订阅 OAuth 被禁用

# CC:Bedrock 切换
export CLAUDE_CODE_USE_BEDROCK=1 AWS_REGION=us-east-1
claude

# Codex:自定义 OpenAI 兼容 provider(必须支持 Responses API)
cat >> ~/.codex/config.toml <<'EOF'
model_provider = "myproxy"
[model_providers.myproxy]
name = "My Proxy"
base_url = "https://proxy.example.com/v1"
env_key = "MYPROXY_API_KEY"
wire_api = "responses"
EOF
MYPROXY_API_KEY=<key> codex -m <model-name>
# 若写 wire_api = "chat" 会直接报配置错误并指向 discussion 7782

Harness 接入建议(Yoda 实践)

  • 统一三类供给源:Yoda 把每个 runtime 的账号供给抽象为 official-subscription / official-api / yoda-maas 三个 AgentAccountProviderId [一手源码 yoda/src/shared/runtime-registry.ts:127-133],对应「订阅 OAuth / BYOK env / Yoda 托管网关」。usage 统计按此维度归因(见 usage-sync 章)。
  • Env 解析顺序要和 CLI 一致official-api-probe-service 解析 key/base URL 时先查 Yoda 注入的 custom env、再查继承的 process env,与会话启动逻辑同源——探测结果才能代表真实会话行为 [一手源码 yoda/src/main/core/settings/official-api-probe-service.ts:12-47]。探测用 provider 注册的真实端点 + 真实 key 发请求,按 bearer / x-api-key / x-goog-api-key 三种 auth 风格组装 header。
  • 注入面选择:给 CC 路由第三方时注入 ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN(注意这会关闭订阅 OAuth,UI 上要明示用户"本会话不走订阅额度");给 Codex 时写独立 profile 或临时 -c model_provider=...,不要篡改用户已有 provider 条目(内建项本来就不可覆盖)。
  • Codex 接入第三方的硬约束:目标端点必须支持 Responses API。harness 如果想把 Chat-Completions-only 的供应商(多数国产中转)接给 Codex,需要在中间加一层 chat→responses 协议转换网关——这正是 wire_api=chat 移除后社区网关(如各类 codex proxy)的新角色 [推断,基于 lib.rs:46 的移除事实]。
  • 配额穿透问题:gateway 模式下两家 CLI 都拿不到官方配额接口,harness 的用量面板应自动降级为"本地 transcript 统计"(usage-sync 章方案),不要对 gateway 账户显示订阅窗口。

失效条件

  • Codex 恢复或以新形式重加 Chat Completions 支持(关注 discussion #7782 后续)——本章"Responses-only"结论失效
  • Codex 内建 provider 列表变化(本快照 b89ce9a 已含 amazon-bedrock,较早版本没有;后续可能增删)
  • CC 增加正式的 provider 插件机制或放开 APIProvider 枚举
  • CC gateway 模型发现从 opt-in 变默认开启,或缓存路径 ~/.claude/cache/gateway-models.json 迁移
  • ANTHROPIC_BASE_URL 对一方域名的判定列表(api.anthropic.com)扩充

参考资料

  • CC 文档:claude-code-docs/docs/llm-gateway.mdamazon-bedrock.mdgoogle-vertex-ai.mdmicrosoft-foundry.mdmodel-config.md(custom model option / 三方 pin)
  • CC 重建源码:src_2026-03-31/utils/model/providers.tsutils/auth.ts(isAnthropicAuthEnabled)
  • Codex 源码:codex-rs/model-provider-info/src/lib.rs(全部 provider 抽象)、config/src/config_toml.rs(model_provider 字段)
  • wire_api=chat 移除公告:https://github.com/openai/codex/discussions/7782(源码错误信息内嵌链接)
  • Yoda:src/shared/runtime-registry.tssrc/main/core/settings/official-api-probe-service.ts

On this page