Upstream Supply、Route Group 与 Api Key 的关系
可以先用一句话记住三者关系:Local Api Key -> 绑定 Route Group -> Route Group 允许一组 Upstream Supply -> 运行时再从命中的 Supply 里选具体 upstream API key。
三者分别是什么
flowchart LR
A["Local Api Key"] --> B["Route Group"]
B --> C["Allowed Upstream Supplies"]
C --> D["Matched Supply"]
D --> E["One upstream API key"]
E --> F["Upstream Vendor Request"]
| 概念 | 面向谁看 | 它真正控制什么 |
|---|---|---|
| Local Api Key | 调用方 | 这次请求先以哪个本地身份进入系统,以及它绑定哪个 Route Group |
| Route Group | 用户 / 运营 / 管理者 | 当前这把本地 API Key 可以使用哪些 Supply |
| Upstream Supply | 路由运行时 | 一个可路由的上游供给单元,可挂模型,也可挂一把或多把 upstream API key |
| upstream API key | 上游厂商 | 当系统已经选中某个 Supply 后,真正拿去请求上游厂商的那把 key |
这里最容易混淆的是 “Api Key” 其实有两层:
Local Api Key是你发请求给本系统时用的本地 key。upstream API key是系统内部最终拿去调用 OpenAI、Claude、Gemini 或其他 Vendor 的上游 key。
三者如何关联
Local Api Key不直接绑定某一把 upstream API key,它先绑定一个Route Group。Route Group也不直接拥有 upstream API key,它保存的是一组允许使用的Upstream Supply引用。Upstream Supply才是可路由的上游供给单元;一个 Supply 下面可以挂模型,也可以有一把或多把 upstream API key。- 对 owner 自己来说,Supply 页面现在主要负责管理自己的 supply、模型、key 和共享开关,而不是单独编辑“对当前用户是否生效”。
- 当前用户自己可见的 supply 默认都可路由;shared 是否公开由
isShared控制;某个 supply 是否真的进入当前 Route Group,由 Route Group 的选择结果决定。 - 运行时会先看当前请求属于哪个 Route Group,再只在该组允许的 Supply 范围内继续选路。
- 当前实现里,Route Group 保存的是 flat supply refs,而不是 “Vendor → Key” 这种层级绑定。
- 某个 Supply 如果没有被放进当前 Route Group,就算它存在、可见、甚至本身可用,这次请求也不会命中它。
- 如果当前 Route Group 为空,系统不会自动去组外找别的 Supply,而是直接进入 no-route 语义。
可以把它理解成下面这条责任链:
- 本地 API Key 决定“我是谁、我能进哪个 Route Group”。
- Route Group 决定“我这次最多可以从哪些 Supply 里挑”。
- Supply 决定“这批模型和这批 upstream key 能不能真正拿来转发请求”。
- 命中具体 Supply 后,系统才会从该 Supply 下选一把可用的 upstream API key 发给上游。
一次请求是怎么走的
- 客户端带着本地
Local Api Key调用/v1/*入口。 - 系统先认证这把本地 key,并解析它绑定的
Route Group。 - 请求再根据模型、协议和目标 Vendor,判断这次理论上该去哪类 Supply。
- dashboard 编辑时虽然按
vendor维度选择来源,但保存后仍会展开为当前命中的 flat supply refs,所以运行时语义继续保持 manual-only。 - 运行时只从当前 Route Group 已保存的 Supply 白名单里筛候选,不会做组外 fallback。
- 如果组里没有这个 Vendor 对应且当前可路由的 Supply,就返回确定性的 no-route,而不是偷偷换别的组或别的 Supply。
- 如果组里有多个可用 Supply,运行时再在这些已允许的 Supply 里做后续选择。
- 命中某个 Supply 后,系统才从该 Supply 的 upstream API key 中选出实际要调用的一把 key。
- 最终请求才会被发往上游 Vendor。
如果客户端显式传了 X-LLM-Supply,它的作用只是 pin 到“当前 Route Group 已允许且当前可路由”的某个 Supply:
- 它不能绕过当前 Route Group。
- 它不能把组外的 Supply 强行拉进来。
- 它也不能跳过“Supply 本身必须当前可路由、且至少有可用 upstream key”这几个前提。
常见场景
场景 1:一个 API Key 只走自己的 private supply
- 用户有一把本地 API Key,这把 key 绑定到自己的 Route Group。
- 该 Route Group 里只放了自己名下的 private supply。
- 这样这把本地 API Key 发出的请求,就只会在这个 private supply 范围内选路,不会碰到别人的 shared supply。
场景 2:共享 Route Group 让成员复用 owner 选好的 supply
- 一个共享 Route Group 由 owner 维护组内允许的 Supply 列表。
- 其他成员可以使用这个组,但不会把自己名下的 Supply 自动注入进去。
- 因此成员实际复用的是 owner 已经保存进组的那些 Supply,而不是“谁加入组,谁的 Supply 都自动可用”。
场景 3:同一个 Route Group 内有多个 supply,运行时再选具体 upstream key
- 某个 Route Group 里可能同时允许多个同 Vendor 的 Supply。
- 运行时会先在这些已允许的 Supply 范围内做选择,而不是一开始就锁定某把 upstream key。
- 只有当某个具体 Supply 被命中后,系统才会从这个 Supply 下面的 upstream API key 里选实际发请求的一把。
常见误解
Route Group 不等于 Vendor:Route Group 是 Supply 白名单,不是厂商身份;一个组里可以出现同一 Vendor 的多个 Supply,也可以覆盖多个 Vendor。Route Group 不直接拥有 upstream key:组里存的是 Supply 引用,不是某把上游 key。Upstream Supply 不等于 Local Api Key:Supply 是被路由命中的上游供给单元,本地 API Key 只是进入系统和绑定 Route Group 的入口身份。改 Supply 共享状态,不等于自动进入 Route Group:某个 Supply 是否公开共享,与它是否已经被当前 Route Group 纳入 allowed supply 集合,是两个步骤。Supply 管理页不再负责“对当前用户生效”编辑:当前用户自己的可见 supply 默认都可路由;实际纳入当前路由,要看 Route Group 的选择结果。Route Group 的 vendor 选择才决定哪些可见 supply 会被纳入 allowed supply 集合:dashboard 编辑时虽然按vendor选来源,但保存后仍会展开成真实的 supply refs。X-LLM-Supply 不是越权入口:它只能在当前 Route Group 已允许的范围内 pin,不能把未入组的 Supply 强行用起来。系统不会自动帮你跳组兜底:如果当前 Route Group 没有目标 Vendor 的可路由 Supply,就会直接 no-route,而不是偷偷改走别的组。