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