内置的 anthropic 提供方是 shunt 的默认目的地:任何没有匹配路由的模型都会被原样转发到
api.anthropic.com(可通过 server.default_provider 配置)。它是一个 kind = "anthropic" 提供方 ——
上游本身就讲 Anthropic Messages API,因此 shunt 不做转换直接透传请求,只决定哪一份凭据
被发往上游。
只有一个请求字段例外。带有 shunt 为其他提供方生成的 signature 的 thinking 块会在转发请求前被
移除(Responses、Gemini 和 Cursor 三条路径各自会生成一个 —— 因为思考块需要该字段才算格式完整),
随之变为空壳的 assistant 轮次也会一并移除。Anthropic 会解密该字段并拒绝不是自己签发的值,原样
转发会导致请求失败。Anthropic 签发的 signature 对 shunt 而言是不透明的,因此从不触碰。该移除不会
读取会话历史,所以并不仅限于使用过映射提供方的会话 —— 完全没有 signature 的 thinking 块同样会
被移除:shunt 自己的 Responses 路径在上游未返回 signature 时就会生成这种块,而 Anthropic 无论如何
都会拒绝无法验证 signature 的 thinking 块。
第三方 Anthropic 类提供方 —— 即既不在 api.anthropic.com 上、也不是 claude_oauth 池的
kind = "anthropic" 上游(如 MiniMax、Kimi、Zhipu)—— 可能会在 thinking 块上附带并非 Anthropic 签发的 signature。
无论是否流式,shunt 都会在返回客户端的响应中,把该 signature 包进一个携带提供方 base_url(去掉末尾的 /)摘要的自有
envelope。envelope 不含 URL 本身,因此 URL 及其中的凭据不会暴露给客户端。不过该摘要是未加盐的固定值,可以用来验证猜测:只要能猜出完整的 base_url(例如常见的端点,或其中嵌入的弱凭据),就能拿摘要核对猜测是否正确。之后的轮次回到 base_url 相同的提供方时,shunt 会解开 envelope,按字节原样转发原始
signature,因此该提供方的 extended thinking 续写照常工作;发往其他任何地方(包括 Anthropic)时,
envelope 被视为 shunt 生成的值,块会按上文所述被移除。因此,在第三方 Anthropic 类提供方与 Anthropic
之间切换时,该提供方的 thinking 块会被移除而不是让请求失败,回到同一提供方时又会恢复。
api.anthropic.com 和 claude_oauth 池的响应从不被包装。
| 认证模式 | 凭据 | 使用场景 |
|---|---|---|
passthrough(默认) |
调用方自己的 x-api-key / Authorization |
透明代理 —— 每个客户端自带密钥或 OAuth token |
api_key |
来自环境变量的服务端密钥 | 用一个运维方持有的 API 密钥为每个请求重新加钥 |
claude_oauth |
一个或多个 shunt 托管的 Claude 订阅账号 | 消耗 Claude 订阅,支持池化与配额感知轮换 |
快速开始
让编码 agent 为你完成接入 —— shunt add 会打印一份内置的设置蓝图
(离线且只读;配置由 agent 编辑,该命令绝不会修改配置):
shunt add upstream anthropic --print | claude或者按照下面的手动步骤操作。
配置上游
anthropic 是内置的 —— 完全不做配置时,shunt 已经会把未路由的模型以 passthrough 转发给它。
要显式声明它(用于有序故障转移,或改变认证方式),请使用预设,它提供了 kind = "anthropic"、
base_url = "https://api.anthropic.com" 和 auth = "passthrough":
[[upstreams]]
name = "anthropic"
provider = "anthropic"显式字段会覆盖预设默认值。旧的 [providers.anthropic] 表形式仍然受支持 —— 但不要在同一个文件中
混用 [[upstreams]] 和 [providers.*]。
透传(默认)
无需再配置什么:shunt 会转发客户端自己的 x-api-key 或 Authorization
头。配置中不应存放任何服务端机密。客户端应当发送哪一份凭据,
在 连接 Claude Code 中有说明。
服务端 API 密钥
注入一个运维方持有的密钥,而不是信任调用方自带:
[[upstreams]]
name = "anthropic"
provider = "anthropic"
auth = { mode = "api_key", env = "ANTHROPIC_API_KEY", header = "x_api_key" }如果你注入了服务端凭据,请在把网关暴露到回环之外前,先用
[server.auth] 为它加上门禁。
Claude 订阅账号(claude_oauth)
先创建一个可刷新的、由 shunt 托管的账号,然后把上游限定到它:
shunt login claude --name primary --mode oauth[[upstreams]]
name = "anthropic"
provider = "anthropic"
auth = { mode = "claude_oauth", account = "primary" }shunt login claude 有三种模式:--mode oauth 运行 shunt 自己的可刷新 OAuth 流程
(推荐),--mode import 复制当前的 Claude Code 登录,--mode setup-token
创建一个为期一年、仅用于推理的 token。省略 account(以及 accounts)会扫描整个
shunt 托管的账号存储 —— 存储中有多个账号时,它就成了一个负载均衡的池,
带会话粘性和配额感知轮换。完整的池化行为 —— 显式账号条目、按账号阈值、[server.pool] 调优,
以及故障转移 —— 都记录在
Anthropic 多账户 中。
模型与路由
作为默认提供方,anthropic 不需要任何路由 —— 所有你没有映射到别处的东西
都会落到这里。要在一条有序故障转移链中显式把某个模型固定到它:
[[models]]
id = "claude-sonnet-5"
display_name = "Claude Sonnet 5"
[models.upstream_model]
anthropic = "claude-sonnet-5"映射的键是 [[upstreams]].name,而不是预设 id。在
auto_include_builtin_models = true(默认)时,GET /v1/models 会先在 server.default_provider
是 Anthropic 类型的情况下尝试它的实时模型列表;否则回退到 shunt
内置的 Claude 目录快照 —— 见 模型发现。
自动模式分类器
当 Claude Code 运行在自动模式时,每一个离开工作区或触及网络的动作都会经过一次权限分类器
—— 一个带有独立系统提示、向模型索要待执行动作安全判定的 Messages 请求。它在订阅 OAuth 凭据下
缺少 api.anthropic.com 所查找的 Claude Code identity 块,CLAUDE_CODE_ATTRIBUTION_HEADER=0 时
mod 的 $.model.complete 之类的旁路查询也是如此。shunt 会在自动模式分类器以及任何不带可接受标记的
Claude Code 请求(通过 x-claude-code-session-id、claude-cli/ user agent 或 x-app: cli 识别)上恢复 identity。
该恢复仅在发出的 bearer 是订阅 OAuth 令牌时生效,不作用于上游并不检查的 count_tokens,空的
x-claude-code-session-id 也不算 Claude Code。其他客户端以及使用 API 密钥的请求不会触发该恢复;这次修复所避免的故障见
429 故障排查条目。
分类器默认并不使用会话自身的模型。在 Claude Code 2.1.226 上实测:若服务端下发了模型就用它,
否则用 Sonnet 档位别名,再否则才用会话自身的模型 —— 这正是
ANTHROPIC_DEFAULT_SONNET_MODEL 同样会移动分类器的原因,已在链路上验证。该结论读自分发的
客户端,因此它描述的是所测版本,而非一项契约。
设置 classifier_model 可以在网关一侧把分类器请求固定到某个模型,而不改变会话自身各轮所用的
模型:
[providers.anthropic]
kind = "anthropic"
base_url = "https://api.anthropic.com"
classifier_model = "claude-sonnet-5"该键仅在 kind = "anthropic" 的提供方上被接受,且它是该提供方内部的模型重映射,而不是通往
另一个提供方的路由。分类器请求依赖 stop_sequences。在 shunt 的 Responses 转换还会丢掉这个字段时,
经由 Sonnet 别名指向 Codex 上游后,分类器重试了它的第一阶段,每次权限检查多花 5–7 秒。现在 shunt 会
在 Responses 路径上模拟 stop_sequences,因此该失败不再适用,
但该键仍然是提供方内部的重映射。不设置该键(默认)时,分类器仍使用客户端请求的模型。
在网关登录部署中,你也可以改为通过托管设置把别名下发给客户端:
[server.gateway.policies.cli.env]
ANTHROPIC_DEFAULT_SONNET_MODEL = "claude-sonnet-5"这同样会移动分类器,但它改变的是整个会话中 sonnet 的解析目标,而不仅仅是分类器 —— 并且当
设置了 availableModels 列表时,该 id 也必须出现在列表中。
校验
shunt check # -> config ok
shunt run
curl -sS http://127.0.0.1:3001/v1/models然后发送一个最小请求(使用 passthrough 时带上你自己的凭据;使用
claude_oauth 时省略它):
curl -sS http://127.0.0.1:3001/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H 'anthropic-version: 2023-06-01' \
-H 'content-type: application/json' \
-d '{"model":"claude-sonnet-5","max_tokens":16,"messages":[{"role":"user","content":"Reply with OK."}]}'相关内容
- Anthropic 多账户 —— 账号池、配额感知选择、
[server.pool] - 管理后台与远程开通 —— 从浏览器开通账号
- 配置参考 —— 每一个账号键