9.2 KiB
9.2 KiB
Subapi Connector 契约清单 v1
- 版本:v1.0
- 日期:2026-03-17
- 适用阶段:S1-S2(
subapi外部服务模块化接入 + 客户迁移) - 契约目标:为我方 Router Core 与
subapi之间的调用定义“稳定接口 + 稳定语义 + 可回归验证”。
1. 设计目标与边界
1.1 目标
- 将
subapi视为“可替换外部能力模块”,而不是核心业务真相源。 - 固定北向协议与字段语义,避免上游快速迭代导致我方主路径抖动。
- 对请求、响应、错误、流式事件建立统一归一模型,支撑审计、计费、告警。
1.2 非目标
- 不在本契约覆盖
subapi后台管理 API(/admin/*)。 - 不在本契约定义我方控制面业务模型(租户、账务、RBAC)的内部存储结构。
- 不将
subapi私有实现细节(调度算法内部参数)暴露到我方公共 API。
2. 接入范围(协议与端点)
2.1 Canonical 端点(Connector 只使用这一组)
| 协议域 | Method | Path | 说明 |
|---|---|---|---|
| Anthropic 兼容 | POST |
/v1/messages |
统一消息入口 |
| Anthropic 兼容 | POST |
/v1/messages/count_tokens |
仅计数,不计费记录 |
| OpenAI 兼容 | POST |
/v1/chat/completions |
Chat Completions |
| OpenAI 兼容 | POST |
/v1/responses |
Responses |
| OpenAI 兼容 | POST |
/v1/responses/*subpath |
Responses 子资源 |
| OpenAI 兼容(WS) | GET |
/v1/responses |
WebSocket 升级入口 |
| 通用 | GET |
/v1/models |
模型目录 |
| 通用 | GET |
/v1/usage |
用量/额度信息 |
| Gemini 原生 | GET |
/v1beta/models |
模型列表 |
| Gemini 原生 | GET |
/v1beta/models/:model |
模型详情 |
| Gemini 原生 | POST |
/v1beta/models/*modelAction |
generateContent/streamGenerateContent |
2.2 Alias 端点处理
subapi提供不带/v1的别名(如/responses、/chat/completions)。- Connector 禁止调用 alias,统一走 canonical 端点,避免路由歧义。
3. 认证与请求头契约
3.1 认证头优先级
/v1/*:Authorization: Bearer <key>>x-api-key>x-goog-api-key
/v1beta/*:x-goog-api-key>Authorization: Bearer <key>>x-api-key>key(query,仅兼容)
3.2 禁止项
- 禁止通过 query 传
key/api_key(仅保留兼容读取,不作为标准路径)。 - Connector 默认不发送 query key。
3.3 会话亲和相关头
- OpenAI 兼容:支持
session_id、conversation_id,请求体支持prompt_cache_key。 - Gemini CLI:支持
x-gemini-api-privileged-user-id+ 请求体 tmp 路径哈希会话识别。 - Anthropic 兼容:可使用
metadata.user_id补充分组内会话亲和。
3.4 北向/南向边界(安全强约束,新增)
- 北向(客户 -> 我方网关):
- 禁止接收任何 query key(
key/api_key),统一要求 header 鉴权。 - 外部携带 query key 的请求必须被拒绝并记录审计事件。
- 禁止接收任何 query key(
- 南向(我方网关 -> subapi connector):
- 仅允许 header 方式传递凭证(
Authorization/x-api-key/x-goog-api-key)。 - Connector 默认不透传 query key。
- 仅允许 header 方式传递凭证(
- 历史兼容策略:
- 若为极少数遗留客户端保留“内部改写”能力,必须在北向入口完成 query->header 改写,且该兼容规则需要白名单与审计日志。
- 该兼容规则默认关闭,并纳入版本化淘汰计划。
4. 请求体契约(最小强约束)
4.1 通用约束
- Body 必须是非空 JSON。
model必须为非空字符串。stream若出现,必须是布尔值。
4.2 OpenAI Responses 额外约束
previous_response_id若存在,必须是resp_*风格,不可传 message id。input.type=function_call_output场景必须满足 call 上下文约束(否则应返回400 invalid_request_error)。
4.3 Gemini Action 路径约束
*modelAction支持两种格式:{model}:{action}或{model}/{action}。streamGenerateContent视为流式请求。
5. 响应归一契约(Connector 内部模型)
Connector 必须将不同协议响应归一为以下内部结构:
{
"protocol": "openai|anthropic|gemini",
"request_id": "string",
"upstream_request_id": "string",
"model_requested": "string",
"model_actual": "string",
"stream": true,
"usage": {
"input_tokens": 0,
"output_tokens": 0,
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 0,
"total_tokens": 0
},
"first_token_ms": 0,
"duration_ms": 0,
"client_disconnect": false
}
5.1 字段规则
upstream_request_id:优先从响应头x-request-id提取。request_id:若协议返回 body request id,则保留;否则由 Connector 生成稳定 ID。usage.total_tokens:若上游未提供,按input + output计算;均缺失时置 0。usage缺失不视为失败,但必须打usage_extracted=false观测标签(用于后续补偿分析)。
6. 错误归一契约
6.1 上游原生错误格式(三类)
- OpenAI 风格:
{"error":{"type":"...","message":"..."}} - Anthropic 风格:
{"type":"error","error":{"type":"...","message":"..."}} - Google 风格:
{"error":{"code":403,"message":"...","status":"PERMISSION_DENIED"}}
6.2 Connector 统一错误结构
{
"http_status": 429,
"category": "auth|billing|rate_limit|upstream|validation|internal",
"code": "RATE_LIMIT_EXCEEDED",
"message": "human readable",
"retryable": true
}
6.3 默认映射规则
401/403上游鉴权类错误 ->category=auth,retryable=false。429->category=rate_limit,retryable=true。500/502/503/504/529->category=upstream,retryable=true。- 计费检查失败(余额/订阅/额度) ->
category=billing,retryable取决于具体码。 - JSON/字段校验失败 ->
category=validation,retryable=false。
7. 流式契约(SSE/WS)
7.1 SSE
- 流开始后如发生错误,按事件帧返回,不再回写普通 JSON 错误。
- 一旦已向客户端写出任何流内容,Connector 禁止触发“同请求 failover 重放”。
- 必须记录首字时延
first_token_ms与终止类型(正常结束/上游错误/客户端断开)。
7.2 WebSocket(OpenAI Responses)
- 首帧必须包含合法 JSON 且含
model。 - 若首帧不合法,立即关闭连接并返回协议错误。
- 多轮 turn 必须重新获取并发槽位(避免长连接长期占槽)。
8. 重试与回退契约(Connector 侧)
- 仅在“未输出任何字节”时允许请求级重试。
- 流式一旦开始输出,禁止自动重试。
- 推荐重试上限:
- 非流式:最多 2 次(指数退避)
- 流式:0 次(依赖上游内部 failover)
- HTTP 429/503 可进入短退避重试;4xx 校验/鉴权错误直接失败。
9. 版本与兼容治理
9.1 版本锁定
- 生产固定
subapi精确版本(vX.Y.Z),不允许漂移到未验证版本。 - 升级必须进入周级升级窗口,禁止临时直升生产。
9.2 契约测试门槛(每次升级必须通过)
- OpenAI
/v1/chat/completions非流/流式基础场景。 - OpenAI
/v1/responses+previous_response_id校验场景。 - Anthropic
/v1/messages+count_tokens场景。 - Gemini
/v1beta/models/*普通与流式场景。 - 三类错误格式的归一验证(OpenAI/Anthropic/Google)。
- 流式中断与客户端断开场景(保证不重放、不漏记)。
10. 与 S2 目标的对齐(执行约束)
S2结束时:- 全供应商主路径由自研 Router Core 接管率
>= 60% - 国内 LLM 供应商主路径接管率
= 100%
- 全供应商主路径由自研 Router Core 接管率
subapi在 S2 后只承担:- 长尾协议兼容
- 备用回退通道
11. 证据来源(本地代码)
- 路由范围与协议入口:
/home/long/project/立交桥/llm-gateway-competitors/sub2api-tar/backend/internal/server/routes/gateway.go - OpenAI/Anthropic 错误与流式处理:
/home/long/project/立交桥/llm-gateway-competitors/sub2api-tar/backend/internal/handler/openai_gateway_handler.go - Claude 兼容入口、
models/usage/count_tokens:
/home/long/project/立交桥/llm-gateway-competitors/sub2api-tar/backend/internal/handler/gateway_handler.go - Gemini 原生入口与错误格式:
/home/long/project/立交桥/llm-gateway-competitors/sub2api-tar/backend/internal/handler/gemini_v1beta_handler.go - 认证优先级与禁用 query key:
/home/long/project/立交桥/llm-gateway-competitors/sub2api-tar/backend/internal/server/middleware/api_key_auth.go
/home/long/project/立交桥/llm-gateway-competitors/sub2api-tar/backend/internal/server/middleware/api_key_auth_google.go - 会话哈希与 header 语义:
/home/long/project/立交桥/llm-gateway-competitors/sub2api-tar/backend/internal/service/openai_gateway_service.go
/home/long/project/立交桥/llm-gateway-competitors/sub2api-tar/backend/internal/service/gateway_service.go
12. 下一步(v1 -> v1.1)
- 把本契约转成机器可执行测试清单(YAML + golden cases)。
- 为每个端点补充“最小请求样例 + 最小响应样例”文件。
- 将错误映射表下沉为配置化规则,减少硬编码发布频率。