# 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 — 完善**: 对话历史 + 账单导出 + 更多平台接入