Files
SakurasanandClaude Sonnet 5 b0c7439c01 docs: add PLANNING.md v0.3 blueprint and .gitignore
Blueprint for a self-hosted LLM API relay gateway (M0-M4: skeleton,
users+keys, proxy, billing, conversion, channels). .gitignore excludes
DB files, node_modules, and build output.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 21:05:02 +08:00

539 lines
29 KiB
Markdown
Raw Permalink 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.
# 大模型中转站(OpenRouter-like)规划文档
> 版本:v0.3 · 2026-08-15 · 状态:规划(未开始编码)
>
> 本文档是项目蓝图,覆盖技术选型、系统架构、核心功能、数据模型、API 设计、前端设计方向与开发里程碑。编码开始前,本文档应与团队确认一遍。
---
## 1. 项目概述
### 1.1 定位
一个自托管的 **LLM API 中转网关**,功能对标 OpenRouter / one-api:
- 对下游用户暴露**统一的、OpenAI 兼容**的 API 入口,背后接入多个上游渠道(OpenAI、Anthropic、兼容第三方等)。
- 对外提供三套协议入口:**OpenAI Responses API、OpenAI Chat Completions、Anthropic Messages**,覆盖两大生态的 SDK 与客户端。
- 内置用户体系、API Key 管理、用量统计与计费(充值暂缓,见 §4.5)。
### 1.2 核心价值
| 对用户 | 对管理员 |
| --- | --- |
| 一个 Key 访问多家模型,OpenAI/Anthropic 生态格式互通 | 统一管理多个上游渠道,做模型定价 |
| 查询用量、成本明细 | 管理用户、审核充值、看全局营收 |
| 配额/余额控制 | 渠道健康检查、负载均衡、故障转移 |
### 1.3 对外协议(明确范围)
| 端点 | 协议 | 说明 |
| --- | --- | --- |
| `POST /v1/responses` | OpenAI Responses API | OpenAI 新生态(SDK/Agents)首选,含流式、工具调用、结构化输出 |
| `POST /v1/chat/completions` | OpenAI Chat Completions | 兼容面最广的格式,含流式(SSE)与工具调用 |
| `POST /v1/messages` | Anthropic Messages | Claude 生态原生格式,含流式与工具调用 |
| `GET /v1/models` | OpenAI 风格模型列表 | 对外列出可用模型;也用于渠道侧自动导入模型列表 |
> 三套协议之间可**互相转换**:例如客户端按 Responses 调用 `claude-sonnet-5`,网关会转换成 Anthropic 协议打给 Anthropic 渠道,再以 Responses 流式返回;同理可反向。协议与渠道匹配时走**直通**(见 4.1.3)。
---
## 1.4 首版范围(MVP)
| 纳入 | 暂缓 |
| --- | --- |
| 大模型代理(三套协议 + 渠道 + 转换) | 充值(**暂停**,见 §4.5) |
| 用户管理(注册/登录/角色/API Key) | 邀请码(配置开关预留) |
| 用量计费(token 统计、计价、余额、流水) | 在线支付、审计报表、多实例 |
| 渠道管理(API 类型、模型导入、健康检查) | 组织/团队(多租户) |
| 管理后台(用户/渠道/模型/全局用量) | |
## 2. 技术选型
### 2.1 后端(Go)
| 项 | 选型 | 理由 |
| --- | --- | --- |
| 语言/运行时 | Go 1.23+ | 高并发流式转发、低内存、部署为单二进制 |
| Web 框架 | Gin | 生态成熟,中间件丰富;代理层可用标准库 `net/http` 做流式读写 |
| ORM | GORM | 简单、迁移工具内建;后期可换 sqlc |
| 数据库 | PostgreSQL 15+(开发可 SQLite 起步) | JSON/数组字段、数值精度对计费友好;单一存储,无额外部署 |
| 缓存/限流 | Redis 7 | token bucket 限流、热点数据、分布式计数器 |
| 认证 | JWT(访问令牌)+ 刷新令牌 HttpOnly Cookie | 见 4.3 |
| 密码 | argon2id | 现代 KDF |
| 配置 | viper + `.env` | 密钥进环境变量,不进代码库 |
| 日志 | zap | 结构化日志,含请求 trace |
| 上游密钥加密 | AES-GCM(主密钥来自环境变量) | 渠道 key 落库前加密 |
### 2.2 前端(Vue 3)
| 项 | 选型 | 理由 |
| --- | --- | --- |
| 框架 | Vue 3 + TypeScript + Vite | 团队栈、构建快 |
| 状态 | Pinia | 官方推荐 |
| 路由 | Vue Router | 标准 |
| 样式 | Tailwind CSS + **taste-skill 产出的设计 tokens** | 自建设计系统,避免套模板 |
| 组件基座 | Ark UI(headless)+ 自建基础组件 | 无头组件可控性强,符合 taste-skill 的 anti-slop 取向 |
| 图表 | ECharts(vue-echarts) | 用量/营收图表 |
| HTTP | axios + TanStack Query | 缓存、重试、请求状态管理 |
> 说明:不选用 Element Plus 这类"完整模板感"较重的库,管理后台的表格/表单由自建组件提供,视觉由 taste-skill 统一定调。
### 2.3 部署
- Docker Compose 起步:`nginx`(静态资源 + 反代) + `api`(Go) + `postgres` + `redis`。
- 单实例起步(记账时序简单),需要时再做多实例(见 §9 风险)。
---
## 3. 系统架构
### 3.1 模块划分
```
┌─────────────────────────────────────────────────────────────┐
│ 前端 web (Vue3) │
│ Landing / 登录注册 / 控制台(密钥·用量·充值) / 管理后台 │
└──────────────────────────┬──────────────────────────────────┘
│ HTTP/JSON(管理 API)
┌──────────────────────────▼──────────────────────────────────┐
│ Go API 服务 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────────┐ │
│ │ 认证/用户 │ │ API Key │ │ 用量/计费 │ │ 充值(暂停) │ │
│ └──────────┘ └──────────┘ └──────────┘ └────────────────┘ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ API 网关(代理核心) │ │
│ │ Auth/Ratelimit → 余额检查 → 模型解析 → 渠道选择 │ │
│ │ → 格式转换 → 上游调用 → 流式转发 → 记账 │ │
│ └────────────────────────────────────────────────────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
│ │ 渠道管理 │ │ 负载均衡 │ │ 健康检查 │ │ 重试/故障转移 │ │
│ └──────────┘ └──────────┘ └──────────┘ └───────────────┘ │
└──────────┬──────────────────────────────┬───────────────────┘
│ │
┌───────▼────────┐ ┌────────▼────────┐
│ PostgreSQL │ │ Redis │
│ 用户/密钥/渠道/ │ │ 限流/配额/热点 │
│ 模型/用量/订单 │ │ │
└────────────────┘ └─────────────────┘
```
### 3.2 一次代理请求的完整链路
```
Client Go 网关 上游渠道(如 Anthropic)
│ POST /v1/chat/completions (sk-xxx) │
├──────────────────────────────▶│ │
│ │ 1. 取 Bearer,哈希查 API Key │
│ │ 2. 限流检查(Redis) │
│ │ 3. 余额检查 │
│ │ 4. 解析请求 → 标准中间模型 │
│ │ 5. 按模型选渠道(LB/健康) │
│ │ 6. 转换请求为 Claude 格式 │
│ ├───────────────────────────▶ │
│ │ ◀────────────────────────── │
│ │ 7. 流式/非流式转发+格式转回 │
│ ◀──────────────────────────────│ │
│ │ 8. 异步记账(token→价格→扣费)│
```
关键点:
- **记账是异步的**:请求完成后写入 `usage_logs`,批量落库,不阻塞响应。
- **流式响应不整体缓冲**:用 `io.Pipe` 边读上游边写客户端;Token 计数取流结束时的 usage 字段(OpenAI 末块 / Claude `message_delta`)。
- **只转发请求体与必要头**:`Authorization` 一律替换为渠道 key,不向客户端暴露上游信息。
---
## 4. 核心功能设计
### 4.1 API 网关 / 格式转换
#### 4.1.1 内部统一格式(标准模型)
网关内部使用 **OpenAI Chat Completions 形状** 作为"标准中间模型",三套协议都先转成它、再转成目标协议:
```
OpenAI /v1/responses ──┐
OpenAI /v1/chat/completions ─┼──▶ 标准模型(OpenAI chat 形状) ──▶ 各渠道原生格式
Anthropic /v1/messages ──┘
```
这样新增一种上游渠道(如 Gemini)只需写**一对**转换器(标准模型 ↔ 渠道格式),不用为每个协议组合写转换器;Responses 与 Chat、Messages 与 Chat 之间各维护一个转换适配器。
#### 4.1.2 转换映射要点
**Chat ↔ Claude Messages**
| 维度 | OpenAI chat ↔ Claude messages |
| --- | --- |
| system | OpenAI `messages[role=system]` ↔ Claude `system` 参数(支持数组/文本) |
| 消息 | `assistant.tool_calls` ↔ `content` 中的 `tool_use` 块;`role=tool` ↔ `tool_result` 块 |
| 工具 | `tools[{type:function,name,description,parameters}]` ↔ `tools[{name,description,input_schema}]` |
| 采样 | `temperature`(OpenAI 0–2,Claude 0–1,越界按目标协议 clamp)、`top_p` |
| 长度 | `max_tokens` ↔ `max_tokens`(Claude 必填,缺失时给默认值) |
| 停止 | `stop` ↔ `stop_sequences`(数组对齐) |
| 流式 | OpenAI SSE `data: {chunk}` + `[DONE]` ↔ Claude 事件流 `message_start / content_block_delta / message_delta / message_stop`,逐事件互转 |
| 用量 | `usage.prompt_tokens/completion_tokens` ↔ `usage.input_tokens/output_tokens`,并映射 Claude 的缓存 token |
**Responses ↔ Chat**(Responses 结构化能力更多,映射如下)
| Responses 字段 | Chat 对应 |
| --- | --- |
| `instructions` | `messages[0].system` |
| `input[]`(`input_text` / `input_image` / `input_file`) | `messages[]`(user 多模态 content 数组) |
| `input[]` 中 `function_call` / `function_call_output` 条目 | `assistant.tool_calls` / `role=tool` 消息 |
| `output[]` 中 `message` / `function_call` / `reasoning` 条目 | `choices[].message` / `tool_calls`(reasoning 跨协议丢弃) |
| `tools[{type:function,name,description,parameters}]` | `tools[{type:function,...}]`(结构相同) |
| `output_format` / `text.format` | `response_format` |
| `max_output_tokens` | `max_tokens` |
| `previous_response_id` | 仅直通 OpenAI 渠道可用;跨协议时降级(见 4.1.3) |
| `reasoning.effort` | 仅直通或特定渠道,跨协议丢弃 |
| 流式事件 `response.created / output_text.delta / function_call_arguments.delta / response.completed` | chat SSE `data: {delta}` + `[DONE]`,逐事件互转 |
#### 4.1.3 直通(passthrough)与转换策略
- **直通优先**:客户端协议与渠道原生协议一致时直接透传报文(仅做鉴权/限额/记账),**不转格式**——保证 Responses 的 `previous_response_id`、`reasoning`、结构化输出等新能力在 OpenAI 渠道上零损失。
- **转换路径**:协议不匹配时才经标准模型转换(如 Responses → Anthropic 渠道、Messages → OpenAI 渠道)。
- **有损边界(文档明示)**:
- `previous_response_id`、`reasoning.effort` 跨协议时**降级或丢弃**,错误响应中提示。
- Anthropic 渠道不接收 `response_format` 类结构化约束,降级为 prompt 提示或丢弃。
- Claude 的 thinking 块在 OpenAI 协议侧丢弃(无法表达)。
- **转换标记**:转换过的请求/响应加 `x-converted: true` 头,便于排查。
#### 4.1.4 错误响应统一
无论上游是什么错误,都按**客户端请求的协议**返回错误体:
- OpenAI 格式:`{"error":{"message","type","param","code"}}` + 映射过的 HTTP 状态码。
- Claude 格式:`{"type":"error","error":{"type","message"}}`。
- 状态码映射:上游 `429` → `429`(附 `retry-after`)、上游 `5xx` → 触发重试后返回 `502/504`、`400`(含 context length 超限)→ 原样返回、余额不足 → `402`。
### 4.2 渠道系统
| 能力 | 设计 |
| --- | --- |
| 渠道 CRUD | 管理员增删改:名称、**API 类型**(openai / anthropic / compatible)、base_url、上游 key(AES-GCM 加密存储)、超时、并发上限 |
| API 类型选择 | 新增渠道时选择类型,决定支持的原生协议(决定直通还是转换)与模型列表导入方式 |
| 模型列表导入 | 渠道支持 `GET /v1/models` 时提供"拉取模型列表"按钮,自动导入可用模型到全局模型库并生成绑定;不支持该端点的渠道(部分第三方)可手动录入 |
| 模型绑定 | 模型(全局) ↔ 渠道(多个) 多对多,每个绑定记录 `upstream_model` 名、权重/优先级 |
| 负载均衡 | 按权重 + 优先级 + 健康状态选择渠道;健康渠道优先 |
| 健康检查 | 定时用最廉价模型发一次测试请求(非流式),连续失败 N 次进入 cooldown,恢复后再放回 |
| 重试/故障转移 | 仅对"可安全重试"的失败(网络错误、429、5xx、超时、上游连接断开**且尚未写出响应头**);对 400/context 类错误不重试。流式一旦已向客户端写出首字节,放弃重试 |
| 并发控制 | 每渠道信号量限制最大并发,超限排队或溢出到其他渠道 |
### 4.3 认证与用户
#### 4.3.1 角色
| 角色 | 权限 |
| --- | --- |
| `admin` | 全部;渠道管理、模型定价、用户管理、余额调整、充值审核、全局用量 |
| `user` | 创建/管理自己的 API Key、查询用量、充值、查看余额 |
> 预留 `viewer`(只读运营)角色,首版不做。
#### 4.3.2 会话
- 登录:用户名/邮箱 + 密码(argon2id 校验)。
- 颁发:短时访问令牌(JWT,如 2h,存内存)+ 刷新令牌(存 HttpOnly Cookie,7d)。
- 注册:**开放注册,可切换**——默认 `open`,配置项 `registration.mode` 切到 `invite` 即启用邀请码(管理员后台生成)。
#### 4.3.3 API Key
- 生成格式:`sk-` + 48 位随机字符(base62),**创建时仅展示一次**。
- 存储:库中只存 SHA-256 哈希 + 展示用前缀(如 `sk-aB3c…`);请求时对 Bearer 哈希后查表。
- 附加能力:密钥级配额(每日 token 上限 / 每日请求数上限)、模型白名单、过期时间、启停。
- 限额检查用 Redis 计数,与用户级限流叠加。
### 4.4 用量与计费
#### 4.4.1 Token 统计
- 优先取上游响应中的 usage(OpenAI `usage` 字段、Claude `message_delta.usage`)。
- 上游缺失时 fallback:本地近似计数(按字符/字节估算,或引入 tiktoken-go 按模型分词)。
- Claude 渠道额外记录 `cache_read_input_tokens` / `cache_creation_input_tokens`,用于缓存计费。
#### 4.4.2 计价
- 模型注册表(`models`)中每个模型配置:`input_price`、`output_price`、`cache_read_price`(按 **每百万 token**)。
- 单次成本 = `in×in_price + out×out_price + cache_read×cache_read_price`(统一以 USD 记账,前端按配置汇率显示)。
- 管理员可随时调价,历史用量按**当时价格**入账(用量表冗余快照价格字段)。
#### 4.4.3 余额与扣费
- 预充值余额制:每次请求结束后异步扣费并写余额流水(`balance_logs`)。
- 扣费前先检查:余额 ≤ 0 时新请求返回 `402`。可选开关:按模型估算成本超余额即拦截(防止大单超额)。
- 余额为负不拒绝已进行的流式请求(流中途无法中断),但后续请求被拒。
#### 4.4.4 用量查询
- `usage_logs`:请求级明细(用户、密钥、模型、渠道、token、成本、耗时、状态)。
- 聚合:日粒度预聚合表(`usage_daily`)支撑 Dashboard 图表,避免每次实时扫明细表。
### 4.5 充值(暂停开发)
> 已决定:**充值暂缓**,首版不做,先交付"代理 + 用户 + 计费"。方案(人工审核 / 在线支付)确定后再落地。
> 预留:`recharge_orders` / `balance_logs` 数据模型与订单状态机先行建好,后续接入不影响现有结构。
订单状态机(预留):
```
pending(待审核) ──approve──▶ credited(已入账)
│ │
└──reject──▶ rejected └─(错误入账→adjust 冲正)
```
### 4.6 管理后台
- 渠道管理:增删改、模型绑定、手动测试连接、健康状态查看。
- 模型管理:全局模型清单、多渠道绑定、价格设置、启停。
- 用户管理:列表/搜索、改角色/状态、调整余额、重置密码。
- 充值审核:待审订单列表、通过/驳回、流水留痕。
- 全局用量:跨用户查询、按模型/渠道/天聚合、营收统计。
- 系统配置:开放注册、邀请码、汇率、限流阈值、维护开关。
---
## 5. 数据模型
> 统一 `id` 为 bigint 自增(或 snowflake),时间用 UTC,金额/价格用 `numeric(20,8)`,token 用 `bigint`。
### 5.1 users
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| id | bigint PK | |
| username / email | text UNIQUE | |
| password_hash | text | argon2id |
| role | enum(`user`,`admin`) | |
| balance | numeric(20,8) | 余额 |
| status | enum(`active`,`disabled`) | |
| invite_code | text nullable | 注册来源邀请码 |
| last_login_at / created_at / updated_at | timestamptz | |
### 5.2 api_keys
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| id | bigint PK | |
| user_id | bigint FK | |
| name | text | 展示名 |
| key_hash | text UNIQUE | SHA-256 |
| key_prefix | text | `sk-aB3c…` |
| quota_tokens_per_day | bigint nullable | 密钥级限额 |
| quota_requests_per_day | int nullable | |
| allowed_models | jsonb nullable | 模型白名单 |
| expires_at | timestamptz nullable | |
| status | enum(`active`,`revoked`) | |
| last_used_at | timestamptz nullable | |
| created_at | timestamptz | |
### 5.3 channels
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| id | bigint PK | |
| name | text | |
| provider | enum(`openai`,`anthropic`,`compatible`) | API 类型:决定原生协议与模型导入方式 |
| base_url | text | 上游地址 |
| api_key_enc | text | AES-GCM 密文 |
| weight / priority | int | 负载均衡权重 / 优先级 |
| timeout_ms | int | |
| max_concurrency | int | |
| health_status | enum(`healthy`,`degraded`,`cooldown`) | |
| enabled | bool | |
| created_at / updated_at | timestamptz | |
### 5.4 models + channel_model_bindings
`models`(全局模型 + 价格):
| 字段 | 类型 |
| --- | --- |
| id, name(全局名如 `claude-sonnet-5`), display_name | |
| input_price / output_price / cache_read_price | numeric(20,8)(每百万 token) |
| enabled, sort | |
`channel_model_bindings`(多对多):
| 字段 | 类型 |
| --- | --- |
| id, channel_id FK, model_id FK | |
| upstream_model | text(如 `us.anthropic.com:claude-sonnet-5`) |
| weight | int |
### 5.5 usage_logs(请求级明细)
| 字段 | 类型 |
| --- | --- |
| id, request_id(上游 id), user_id FK, key_id FK, channel_id FK, model_id FK | |
| input_tokens / output_tokens / cache_read_tokens / cache_creation_tokens | bigint |
| input_price / output_price / cache_read_price | numeric(20,8) 快照 |
| cost | numeric(20,8) |
| latency_ms | int |
| status | enum(`success`,`error`,`canceled`) |
| error_code | text nullable |
| created_at | timestamptz,带索引 `(user_id, created_at)` |
### 5.6 usage_daily(日聚合)
`id, user_id, model_id, date, requests, input_tokens, output_tokens, cache_read_tokens, cost`
### 5.7 recharge_orders
`id, user_id FK, amount numeric(20,8), status enum(pending/credited/rejected), method enum(manual/online), transaction_id, reviewed_by FK, reviewed_at, remark, created_at`
### 5.8 balance_logs(余额流水,幂等保证)
`id, user_id FK, change numeric(20,8), balance_after numeric(20,8), type enum(recharge/usage/refund/admin_adjust), ref_id, created_at`
### 5.9 system_configs
`key text PK, value jsonb`
---
## 6. API 设计
### 6.1 代理端点(对外,Bearer API Key 认证)
| 方法 | 路径 | 说明 |
| --- | --- | --- |
| POST | `/v1/responses` | OpenAI Responses API |
| POST | `/v1/chat/completions` | OpenAI Chat 格式 |
| POST | `/v1/messages` | Anthropic Messages |
| GET | `/v1/models` | 可用模型列表(OpenAI 风格) |
### 6.2 管理 API(`/api/v1`,会话认证)
**认证/用户**
- `POST auth/register` · `POST auth/login` · `POST auth/logout` · `GET auth/me`
- `GET user/profile` · `GET user/balance`
**API Key**
- `GET/POST /keys` · `PATCH/DELETE /keys/:id`
**用量**
- `GET /usage/summary`(今日/本月汇总)
- `GET /usage/stats?from&to&group=day|model`
- `GET /usage/logs?from&to&page&model&keyId`
**充值**
- `POST /recharges` · `GET /recharges`(暂停,接口预留)
**管理后台(`/api/v1/admin`,仅 admin)**
- `GET/POST/PUT/DELETE /channels` · `POST /channels/:id/test`
- `GET/POST/PUT /models` · `PUT /models/:id/price`
- `GET /users` · `PATCH /users/:id` · `POST /users/:id/balance`
- `GET /recharges` · `POST /recharges/:id/approve|reject`(暂停,接口预留)
- `GET /usage` · `GET /stats/overview`
- `GET/PUT /config`
---
## 7. 前端设计(taste-skill)
### 7.1 设计流程
1. 前端阶段启动时**调用 taste-skill**:传入产品 brief 与页面清单,由它推断设计方向,产出:
- 设计 tokens:色板(含暗色/亮色)、字体系统、间距、圆角、阴影、栅格。
- 核心页面高保真方向(先做 3–5 个代表页,不一次铺开)。
2. 以 tokens 建立 Tailwind 主题(tailwind.config + CSS variables)与基础组件(Button / Table / Form / Modal / Nav)。
3. 按页面清单逐组实现,每个阶段结束用 **web-design-guidelines** 复查(对比度、可访问性、交互细节)。
4. 设计评审迭代,**不套模板**。
### 7.2 预期设计方向(taste-skill 最终决定,此处为倾向)
开发者工具 / API 网关类产品,倾向:
- 深色优先、仪表盘质感;等宽字体点缀 token、端点、代码片段。
- 数据密度高的表格(用量、密钥、订单),克制的中性色 + 单一强调色。
- Landing 简洁可信:产品价值、端点示例、模型列表预览。
### 7.3 页面清单
| 区域 | 页面 |
| --- | --- |
| 公开 | Landing · 登录 · 注册 |
| 用户 | Dashboard(余额/今日用量/最近请求/图表)· API Keys · 用量查询 · 充值(后置) · 个人设置 |
| 管理 | 运营总览 · 渠道管理(API 类型 + 模型导入) · 模型与定价 · 用户管理 · 充值审核(后置) · 全局用量 · 系统配置 |
### 7.4 前端工程注意点
- 流式调试体验:控制台页提供"用 curl / 请求编辑器"快速验证 key 与模型(可选,v2)。
- 图表统一用 ECharts,暗色主题与设计 tokens 对齐。
- 表格/表单为自建组件,行为一致性优先,后续可沉淀为内部组件库。
---
## 8. 非功能需求
| 类别 | 要求 |
| --- | --- |
| 安全 | API Key 仅存哈希;渠道密钥加密存储;密码 argon2id;JWT 刷新令牌 HttpOnly;日志/错误信息脱敏(不泄露渠道 key、完整 key);CORS 白名单;管理接口二次鉴权 |
| 限流 | Redis token bucket:用户级 + 密钥级 + 全局并发保护 |
| 稳定性 | 渠道 cooldown + 重试;流式请求 client 断连即取消上游调用(ctx cancel);上游超时兜底 |
| 可观测 | zap 结构化日志 + request_id;Prometheus 指标(请求数/延迟/错误率/成本);管理后台健康概览 |
| 性能 | 流式零缓冲转发;记账异步批量落库;聚合查询走预聚合表 |
| 合规 | 用户协议与数据留存说明;退款/冲正流程可追溯 |
---
## 9. 仓库结构(规划)
```
openteam/
├── server/ # Go 后端
│ ├── cmd/server/main.go
│ ├── internal/
│ │ ├── config/ # viper + env
│ │ ├── user/ # 认证/角色/用户
│ │ ├── apikey/
│ │ ├── proxy/ # 网关核心
│ │ │ ├── responses/ # OpenAI Responses 格式编解码
│ │ │ ├── openai/ # OpenAI Chat 格式编解码
│ │ │ ├── claude/ # Anthropic Messages 格式编解码
│ │ │ ├── convert/ # 标准模型 ↔ 各协议转换
│ │ │ └── stream/ # SSE 双向流式转发
│ │ ├── channel/ # 渠道、负载均衡、健康检查、重试
│ │ ├── billing/ # 计价、余额、流水
│ │ ├── usage/ # 记账、聚合
│ │ ├── recharge/ # 订单(待定方案)
│ │ ├── admin/ # 管理 API
│ │ ├── store/ # GORM models + repositories
│ │ └── pkg/ # jwt, crypto, ratelimit, tiktoken
├── web/ # Vue3 前端
│ ├── src/styles/ # taste-skill 设计 tokens
│ ├── src/components/ # 基础组件
│ ├── src/views/ # 页面
│ ├── src/stores/ · src/api/ · src/router/
├── deploy/ # docker-compose, nginx, Dockerfile
└── docs/
```
---
## 10. 开发里程碑
| 里程碑 | 内容 | 验收标准 |
| --- | --- | --- |
| **M0 基建** | 仓库结构、配置、DB 迁移、JWT/密码工具、CI;taste-skill 启动产出设计 tokens | 空服务可启动,tokens 落地 |
| **M1 用户+密钥+核心代理** | 注册/登录/角色、API Key CRUD;`/v1/responses` 与 `/v1/chat/completions` 直连 OpenAI 渠道(非流式+流式,直通);OpenAI 错误格式 | 用 curl 完成一次带流式的对话与一次 Responses 调用;密钥可建可吊销 |
| **M2 用量+计费** | 记账、token 统计、价格表、余额扣减、用量 API;前端 Dashboard/用量页 | 请求后余额正确变化,用量图表正确 |
| **M3 跨协议转换** | `/v1/messages` 代理;Responses ↔ Chat ↔ Messages 转换(含流式、工具调用);Anthropic 渠道 | OpenAI 客户端调 Claude 模型、Anthropic 客户端调 OpenAI 模型均通 |
| **M4 渠道系统** | 渠道 CRUD(API 类型)、`/models` 模型导入、模型绑定、负载均衡、健康检查、重试/故障转移;管理后台渠道页 | 一个渠道挂掉自动切换;后台可加渠道、拉取模型并测试 |
| **M5 充值(暂停)** | 方案待定,首版不做;仅预留订单表与状态机 | — |
| **M6 打磨上线** | 限流、监控指标、审计日志、taste-skill 全站设计复查、docker-compose 部署、文档与测试补全 | 可对外交付部署 |
---
## 11. 风险与待定决策
| # | 事项 | 状态 | 说明 |
| --- | --- | --- | --- |
| 1 | **充值** | ⏸ 暂停 | 首版不做,订单表与状态机预留,方案确定后再落地 |
| 2 | **注册策略** | ✅ 已确认 | 开放注册,配置可切换邀请码 |
| 3 | **协议范围** | ✅ 已确认 | Responses + Chat Completions + Anthropic Messages;去掉 legacy `/v1/completions` |
| 4 | **流式重试边界**:首字节发出后不可重试 | ✅ 已决策 | 仅连接建立前重试;文档明示 |
| 5 | **Responses 跨协议有损边界** | 🟡 实现中确认 | `previous_response_id`、`reasoning` 跨协议降级/丢弃,加 `x-converted` 头 |
| 6 | **模型列表导入差异** | 🟡 实现中确认 | 部分渠道无 `/v1/models`,需手动录入 fallback |
| 7 | **计费精度**:Claude 缓存 token、上游缺 usage | ✅ 已决策 | 冗余快照价格;近似计数 fallback |
| 8 | **多实例扩展**:记账时序 | 🟡 后置 | 单实例起步,必要时引入消息队列 |
| 9 | **合规**:数据留存、日志脱敏 | 🟡 上线前 | 隐私说明、审计日志 |
---
## 12. 下一步
范围已收敛:**代理(三协议)+ 用户管理 + 用量计费 + 渠道管理**,充值暂停。
1. 无阻塞性待定项,可按 **M0 → M1** 开始实施;taste-skill 先行产出设计方向,后端同时搭骨架。
2. 实施中确认两处细节:Responses 跨协议降级边界(§11 #5)、模型导入的渠道差异(#6)。