Browse Source

docs: AI API 中转功能设计文档

覆盖:数据模型(7张表)、Provider适配层(Strategy模式)、
SSE流式实现、混合Key管理、完整计费系统、前端5个页面规划
master
dark 1 month ago
parent
commit
c1e1625ef2
  1. 483
      docs/plans/2026-02-14-ai-api-proxy-design.md

483
docs/plans/2026-02-14-ai-api-proxy-design.md

@ -0,0 +1,483 @@
# AI API 中转功能 设计文档
## 概述
在现有 go-zero 单体后端中新增 AI API 中转模块,支持多平台 AI 模型调用(OpenAI、Claude、千问、智谱、DeepSeek、文心一言等),提供 SSE 流式输出、混合 Key 管理、完整计费系统,以及全功能前端(管理后台 + 聊天界面 + 对话历史 + 用量统计)。
## 架构决策
**方案选择**:单体扩展(方案 A)— 在现有 go-zero 后端中新增 AI 模块,复用现有 Auth/Casbin/用户体系。
**理由**:
- 复用现有认证、RBAC、用户模型,开发效率最高
- 单体部署,运维简单
- 与文件管理等模块风格一致,代码可维护
- 未来需要时可平滑拆分为微服务
## 数据模型(7 张表)
### 1. ai_provider — AI 平台
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint PK | 自增 ID |
| name | varchar(50) | 平台标识 (openai, qwen, claude, zhipu, deepseek, wenxin) |
| display_name | varchar(100) | 显示名称 |
| base_url | varchar(255) | API 基础 URL |
| sdk_type | varchar(20) | SDK 类型: openai_compat / anthropic / custom |
| protocol | varchar(20) | 协议: openai / anthropic / custom |
| is_active | bool | 是否启用 |
| sort_order | int | 排序 |
| created_at | datetime | 创建时间 |
| updated_at | datetime | 更新时间 |
### 2. ai_model — AI 模型
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint PK | 自增 ID |
| provider_id | bigint FK | 关联平台 |
| model_id | varchar(100) | 模型标识 (gpt-4o, qwen-max, claude-sonnet-4-5-20250929) |
| display_name | varchar(100) | 显示名称 |
| input_price | decimal(10,6) | 输入价格 (元/1M tokens) |
| output_price | decimal(10,6) | 输出价格 (元/1M tokens) |
| max_tokens | int | 最大输出 tokens |
| context_window | int | 上下文窗口大小 |
| supports_stream | bool | 是否支持流式 |
| supports_vision | bool | 是否支持图片 |
| is_active | bool | 是否启用 |
| sort_order | int | 排序 |
| created_at | datetime | |
| updated_at | datetime | |
### 3. ai_api_key — API Key
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint PK | 自增 ID |
| provider_id | bigint FK | 关联平台 |
| user_id | bigint | 0=系统 Key, >0=用户自带 Key |
| key_value | text | 加密存储的 API Key |
| is_active | bool | 是否启用 |
| remark | varchar(255) | 备注 |
| created_at | datetime | |
| updated_at | datetime | |
### 4. ai_conversation — 对话会话
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint PK | 自增 ID |
| user_id | bigint FK | 关联用户 |
| title | varchar(200) | 对话标题 |
| model_id | varchar(100) | 使用的模型 |
| provider_id | bigint | 关联平台 |
| total_tokens | bigint | 累计 token 数 |
| total_cost | decimal(10,6) | 累计费用 |
| is_archived | bool | 是否归档 |
| created_at | datetime | |
| updated_at | datetime | |
### 5. ai_chat_message — 对话消息
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint PK | 自增 ID |
| conversation_id | bigint FK | 关联对话 |
| role | varchar(20) | user / assistant / system |
| content | longtext | 消息内容 |
| token_count | int | 该消息 token 数 |
| cost | decimal(10,6) | 该消息费用 |
| model_id | varchar(100) | 使用的模型 |
| latency_ms | int | 响应延迟 (ms) |
| created_at | datetime | |
### 6. ai_usage_record — 调用记录
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint PK | 自增 ID |
| user_id | bigint | 用户 |
| provider_id | bigint | 平台 |
| model_id | varchar(100) | 模型 |
| input_tokens | int | 输入 tokens |
| output_tokens | int | 输出 tokens |
| cost | decimal(10,6) | 实际费用 |
| api_key_id | bigint | 使用的 Key |
| status | varchar(20) | ok / error |
| latency_ms | int | 延迟 |
| error_message | text | 错误信息 |
| created_at | datetime | |
### 7. ai_user_quota — 用户额度
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint PK | 自增 ID |
| user_id | bigint UNIQUE | 用户 |
| balance | decimal(10,4) | 可用余额 |
| total_recharged | decimal(10,4) | 累计充值 |
| total_consumed | decimal(10,4) | 累计消费 |
| frozen_amount | decimal(10,4) | 冻结金额 |
| updated_at | datetime | |
## 后端架构 — Provider 适配层
### Provider 接口 (Strategy 模式)
```go
type AIProvider interface {
Chat(ctx context.Context, req *ChatRequest) (*ChatResponse, error)
ChatStream(ctx context.Context, req *ChatRequest) (<-chan *StreamChunk, error)
ListModels() []string
Name() string
}
```
### 文件结构
```
backend/internal/
├── ai/
│ ├── provider/
│ │ ├── provider.go # AIProvider 接口定义
│ │ ├── openai.go # OpenAI 实现 (也用于千问/智谱/DeepSeek 兼容模式)
│ │ ├── anthropic.go # Claude/Anthropic 实现
│ │ ├── factory.go # Provider 工厂 (根据 sdk_type 创建)
│ │ └── types.go # ChatRequest, ChatResponse, StreamChunk
│ └── billing/
│ ├── quota.go # 余额检查、冻结、扣费、解冻
│ └── usage.go # 用量记录
├── handler/ai/ # HTTP handlers
├── logic/ai/ # Business logic
├── middleware/
│ └── aiquotamiddleware.go # AI 余额检查中间件
└── model/
├── ai_provider_entity.go
├── ai_provider_model.go
├── ai_model_entity.go
├── ai_model_model.go
├── ai_api_key_entity.go
├── ai_api_key_model.go
├── ai_conversation_entity.go
├── ai_conversation_model.go
├── ai_chat_message_entity.go
├── ai_chat_message_model.go
├── ai_usage_record_entity.go
├── ai_usage_record_model.go
├── ai_user_quota_entity.go
└── ai_user_quota_model.go
```
### SDK 选型
| 平台 | SDK 类型 | Go 包 | 说明 |
|------|---------|-------|------|
| OpenAI | 官方 Go SDK | `github.com/sashabaranov/go-openai` | GPT-4o, o1 等 |
| Claude | Anthropic Go SDK | `github.com/anthropics/anthropic-sdk-go` | Claude 系列 |
| 千问 | OpenAI 兼容 | 同上 openai SDK | 通义千问支持 OpenAI 格式 |
| 智谱 | OpenAI 兼容 | 同上 openai SDK | GLM-4 等支持 OpenAI 格式 |
| DeepSeek | OpenAI 兼容 | 同上 openai SDK | DeepSeek 支持 OpenAI 格式 |
| 文心一言 | 自定义 HTTP | 自封装 HTTP client | 百度独有格式 |
### Key 选择优先级
```
用户自带 Key (该平台, is_active=true)
→ 系统 Key (该平台, user_id=0, is_active=true, 轮询/随机)
→ 无可用 Key → 返回 503
```
## API 路由设计
### AI 对话 (Cors, Log, Auth, AIQuota)
```
POST /api/v1/ai/chat/completions # OpenAI 兼容格式 (stream 由 body 控制)
```
### AI 平台管理 (Cors, Log, Auth, Authz — admin+)
```
GET /api/v1/ai/providers # 平台列表
POST /api/v1/ai/provider # 添加平台
PUT /api/v1/ai/provider/:id # 更新平台
DELETE /api/v1/ai/provider/:id # 删除平台
```
### AI 模型管理 (Cors, Log, Auth, Authz — admin+)
```
GET /api/v1/ai/models # 模型列表 (所有用户可访问)
POST /api/v1/ai/model # 添加模型
PUT /api/v1/ai/model/:id # 更新模型
DELETE /api/v1/ai/model/:id # 删除模型
```
### API Key 管理 (Cors, Log, Auth)
```
GET /api/v1/ai/keys # Key 列表 (用户看自己的, admin 看全部)
POST /api/v1/ai/key # 添加 Key
PUT /api/v1/ai/key/:id # 更新 Key
DELETE /api/v1/ai/key/:id # 删除 Key
```
### 对话管理 (Cors, Log, Auth)
```
GET /api/v1/ai/conversations # 对话列表 (当前用户)
POST /api/v1/ai/conversation # 创建对话
GET /api/v1/ai/conversation/:id # 对话详情含消息
PUT /api/v1/ai/conversation/:id # 更新对话 (改标题)
DELETE /api/v1/ai/conversation/:id # 删除对话
```
### 额度管理 (Cors, Log, Auth)
```
GET /api/v1/ai/quota/me # 我的额度
POST /api/v1/ai/quota/recharge # 充值 (admin)
GET /api/v1/ai/quota/records # 用量记录
GET /api/v1/ai/stats # 使用统计
```
## SSE 流式实现
### 流程
```
1. 客户端 POST /ai/chat/completions, body 含 stream: true
2. 中间件: JWT Auth → 余额检查 → 冻结预估费用
3. Handler: 设置 SSE headers, 获取 http.Flusher
4. Logic: 选择 Key → 构建上下文 → 调用 Provider.ChatStream()
5. Handler: 循环读取 channel, 写入 SSE data: {...}\n\n, Flush()
6. 流结束: 发送 data: [DONE], 计算实际 token, 扣费, 退冻结差额, 保存消息
```
### SSE 格式 (OpenAI 兼容)
```
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"你"},"finish_reason":null}]}
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"好"},"finish_reason":null}]}
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":10,"completion_tokens":5,"total_tokens":15}}
data: [DONE]
```
### go-zero SSE 要点
```go
// Handler 层直接操作 ResponseWriter
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
flusher, _ := w.(http.Flusher)
for chunk := range streamChan {
fmt.Fprintf(w, "data: %s\n\n", chunk.JSON())
flusher.Flush()
}
fmt.Fprintf(w, "data: [DONE]\n\n")
flusher.Flush()
```
## 计费流程
```
请求进入
→ 预估费用 = model.input_price × (input_tokens_estimate / 1M)
→ 冻结: balance -= 预估费用, frozen_amount += 预估费用
→ 调用 AI Provider
→ 成功:
实际费用 = input_tokens × input_price/1M + output_tokens × output_price/1M
解冻差额: frozen_amount -= 预估费用, balance += (预估 - 实际)
consumed += 实际费用
写入 usage_record
→ 失败:
全额解冻: frozen_amount -= 预估费用, balance += 预估费用
写入 usage_record (status=error)
```
**余额不足**: 返回 `{"code": 402, "message": "余额不足,请充值"}`
**使用用户自带 Key 时**: 不检查余额,不扣费,但仍记录 usage_record
## 前端页面规划
### 1. AI 对话页 `/ai/chat`
**角色**: 所有用户
**功能**:
- 左侧: 对话历史列表 + 新建对话按钮 + 当前余额显示
- 右侧: 聊天区域
- 顶部: 模型选择器下拉框
- 中间: 消息列表 (支持 Markdown 渲染、代码高亮)
- 底部: 输入框 + 发送按钮
- SSE 流式接收,逐字显示 AI 回复
- 支持 Shift+Enter 换行, Enter 发送
### 2. AI 模型管理页 `/ai/models`
**角色**: admin+
**功能**:
- AI 平台管理 (CRUD, 启用/禁用)
- AI 模型管理 (CRUD, 定价设置, 启用/禁用)
- 模型测试 (快速发送测试消息)
### 3. API Key 管理页 `/ai/keys`
**角色**: admin 管系统 Key, 普通用户管自己的 Key
**功能**:
- Key 列表 (脱敏显示: sk-xxxx...xxxx)
- 添加/编辑/删除 Key
- 按平台筛选
### 4. 用量统计页 `/ai/usage`
**角色**: admin 看全局, 普通用户看自己
**功能**:
- 调用量折线图 (按日/周/月)
- 费用统计 (按模型/平台分组)
- 调用记录表格 (支持筛选、分页)
- 账单导出 (CSV)
### 5. 额度管理页 `/ai/quota`
**角色**: admin
**功能**:
- 用户列表 + 余额显示
- 充值操作 (选用户, 输入金额)
- 充值记录
## 种子数据
### 默认 AI 平台
```
| name | display_name | base_url | sdk_type |
|----------|-------------|---------------------------------------|-----------------|
| openai | OpenAI | https://api.openai.com/v1 | openai_compat |
| claude | Claude | https://api.anthropic.com | anthropic |
| qwen | 通义千问 | https://dashscope.aliyuncs.com/compatible-mode/v1 | openai_compat |
| zhipu | 智谱 AI | https://open.bigmodel.cn/api/paas/v4 | openai_compat |
| deepseek | DeepSeek | https://api.deepseek.com/v1 | openai_compat |
```
### 默认模型 (示例)
```
| provider | model_id | input_price | output_price |
|----------|-----------------------|-------------|-------------|
| openai | gpt-4o | 17.50 | 70.00 |
| openai | gpt-4o-mini | 1.05 | 4.20 |
| claude | claude-sonnet-4-5-20250929 | 21.00 | 105.00 |
| claude | claude-haiku-4-5-20251001 | 7.00 | 35.00 |
| qwen | qwen-max | 2.00 | 6.00 |
| qwen | qwen-plus | 0.80 | 2.00 |
| zhipu | glm-4-plus | 50.00 | 50.00 |
| deepseek | deepseek-chat | 1.00 | 2.00 |
| deepseek | deepseek-reasoner | 4.00 | 16.00 |
```
*价格单位: 元/1M tokens*
### Casbin 策略
```
# AI 对话 — 所有已认证用户
p, user, /api/v1/ai/chat/completions, POST
p, user, /api/v1/ai/conversations, GET
p, user, /api/v1/ai/conversation, POST
p, user, /api/v1/ai/conversation/:id, GET
p, user, /api/v1/ai/conversation/:id, PUT
p, user, /api/v1/ai/conversation/:id, DELETE
p, user, /api/v1/ai/models, GET
p, user, /api/v1/ai/keys, GET
p, user, /api/v1/ai/key, POST
p, user, /api/v1/ai/key/:id, PUT
p, user, /api/v1/ai/key/:id, DELETE
p, user, /api/v1/ai/quota/me, GET
p, user, /api/v1/ai/quota/records, GET
# AI 管理 — admin+
p, admin, /api/v1/ai/providers, GET
p, admin, /api/v1/ai/provider, POST
p, admin, /api/v1/ai/provider/:id, PUT
p, admin, /api/v1/ai/provider/:id, DELETE
p, admin, /api/v1/ai/model, POST
p, admin, /api/v1/ai/model/:id, PUT
p, admin, /api/v1/ai/model/:id, DELETE
p, admin, /api/v1/ai/quota/recharge, POST
p, admin, /api/v1/ai/stats, GET
```
## 文件变更清单
### 新建文件 (~35 个)
**后端 Model (14 个)**:
- `backend/model/ai_provider_entity.go`
- `backend/model/ai_provider_model.go`
- `backend/model/ai_model_entity.go`
- `backend/model/ai_model_model.go`
- `backend/model/ai_api_key_entity.go`
- `backend/model/ai_api_key_model.go`
- `backend/model/ai_conversation_entity.go`
- `backend/model/ai_conversation_model.go`
- `backend/model/ai_chat_message_entity.go`
- `backend/model/ai_chat_message_model.go`
- `backend/model/ai_usage_record_entity.go`
- `backend/model/ai_usage_record_model.go`
- `backend/model/ai_user_quota_entity.go`
- `backend/model/ai_user_quota_model.go`
**后端 AI Provider (5 个)**:
- `backend/internal/ai/provider/provider.go`
- `backend/internal/ai/provider/openai.go`
- `backend/internal/ai/provider/anthropic.go`
- `backend/internal/ai/provider/factory.go`
- `backend/internal/ai/provider/types.go`
**后端 AI Billing (2 个)**:
- `backend/internal/ai/billing/quota.go`
- `backend/internal/ai/billing/usage.go`
**后端 Middleware (1 个)**:
- `backend/internal/middleware/aiquotamiddleware.go`
**后端 API 定义 (1 个)**:
- `backend/api/ai.api`
**后端 Handler + Logic (~20 个)**: goctl 生成
**前端 (5 个)**:
- `frontend/react-shadcn/pc/src/pages/AIChatPage.tsx`
- `frontend/react-shadcn/pc/src/pages/AIModelManagementPage.tsx`
- `frontend/react-shadcn/pc/src/pages/AIKeyManagementPage.tsx`
- `frontend/react-shadcn/pc/src/pages/AIUsagePage.tsx`
- `frontend/react-shadcn/pc/src/pages/AIQuotaManagementPage.tsx`
### 修改文件 (~8 个)
- `backend/go.mod` + `go.sum` (新增 openai + anthropic SDK)
- `backend/base.api` (import ai.api)
- `backend/internal/svc/servicecontext.go` (AutoMigrate + seed data)
- `backend/internal/config/config.go` (可选: AI 相关配置)
- `frontend/react-shadcn/pc/src/types/index.ts` (AI 相关类型)
- `frontend/react-shadcn/pc/src/services/api.ts` (AI API 方法)
- `frontend/react-shadcn/pc/src/App.tsx` (路由注册)
## 实施优先级
1. **Phase 1 — 核心对话**: 数据模型 + Provider 适配层 + SSE 流式 + 基础聊天 API + 前端聊天界面
2. **Phase 2 — 管理功能**: 平台/模型/Key CRUD + 前端管理页
3. **Phase 3 — 计费系统**: 额度管理 + 用量记录 + 预扣费 + 前端用量统计
4. **Phase 4 — 完善**: 对话历史 + 账单导出 + 更多平台接入
Loading…
Cancel
Save