Files
lijiaoqiao/docs/subapi_connector_contract_v1_2026-03-17.md
2026-03-26 20:06:14 +08:00

225 lines
9.2 KiB
Markdown
Raw Blame History

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