From c1e1625ef23d1af52f53bf9bff34611851be6747 Mon Sep 17 00:00:00 2001 From: dark Date: Sat, 14 Feb 2026 21:41:43 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20AI=20API=20=E4=B8=AD=E8=BD=AC=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E8=AE=BE=E8=AE=A1=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 覆盖:数据模型(7张表)、Provider适配层(Strategy模式)、 SSE流式实现、混合Key管理、完整计费系统、前端5个页面规划 --- docs/plans/2026-02-14-ai-api-proxy-design.md | 483 +++++++++++++++++++ 1 file changed, 483 insertions(+) create mode 100644 docs/plans/2026-02-14-ai-api-proxy-design.md diff --git a/docs/plans/2026-02-14-ai-api-proxy-design.md b/docs/plans/2026-02-14-ai-api-proxy-design.md new file mode 100644 index 0000000..6ff9d9a --- /dev/null +++ b/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 — 完善**: 对话历史 + 账单导出 + 更多平台接入