- 新增 providers/models 数据库表、迁移和数据访问层 - 新增 15 个后端 API 路由(供应商/模型 CRUD + 连通性测试) - 新增 AI 服务层(registry.ts: buildProviderRegistry + testProviderConnection) - 新增前端模型管理页面(Tabs: 供应商/模型,含表格、表单、工具栏) - 新增前端 hooks(use-providers, use-models) - 新增共享类型和 MODEL_CAPABILITIES 常量 - 新增 10 个测试文件(66 个测试用例,4 个因 bun test ESM 兼容问题待修复) - 更新开发文档(architecture, backend, frontend) - 附带 apply-review 修复:统一错误响应、提取共享常量、清理重复测试 注意:registry.test.ts 中 4 个测试因 bun test 无法解析 createProviderRegistry ESM 导出而失败,详情见 context.md
226 lines
14 KiB
Markdown
226 lines
14 KiB
Markdown
## 背景
|
||
|
||
Alfred·阿福定位为"基于 AI 的信息综合处理平台",但当前项目(v0.1.0)没有任何 AI/LLM 集成。项目已完成基础架构(Bun 全栈、SQLite + Drizzle ORM、React 19 + Ant Design 6 + React Router 7、TanStack React Query),并拥有管理控制台(Dashboard + 项目管理)和工作台控制台。
|
||
|
||
本次变更在管理控制台中新增"模型管理"功能,让用户能够配置 AI 供应商和模型,为后续所有 AI 功能提供基础设施。这是项目 AI 能力的第一个里程碑。
|
||
|
||
**当前状态:**
|
||
- 后端:`src/server/` 使用 Bun.serve(),路由在 `routes/` 目录按功能拆分,DB schema 在 `src/server/db/schema.ts`,数据访问层在 `src/server/db/projects.ts`
|
||
- 前端:`src/web/` 使用 console 模式,admin 菜单在 `consoles/admin/menu.tsx`,页面在 `pages/` 目录
|
||
- 零 AI/LLM 相关代码
|
||
|
||
## 讨论记录
|
||
|
||
- 已确认结论:
|
||
- 使用 Vercel AI SDK(`ai` + `@ai-sdk/openai` + `@ai-sdk/anthropic` + `@ai-sdk/openai-compatible`)作为统一 AI 调用层
|
||
- 三种供应商类型:`openai`、`anthropic`、`openai-compatible`(覆盖 DeepSeek、Qwen、Ollama 等)
|
||
- API Key 明文存储于 SQLite,可接受(本地/自部署单用户工具)
|
||
- AI 注册表不使用缓存层:每次 AI 调用时从 DB 查询供应商+模型 → 构建 `createProviderRegistry` → 调用 AI SDK(开销 ~1ms,远小于网络 I/O)
|
||
- 功能调用(function calling)视为基础能力,不列入 capability 标签
|
||
- 用户偏好:
|
||
- 前端使用 antd `Tabs` 组件在同一页面内展示供应商和模型两个标签页
|
||
- 供应商表单中 type 默认值为 `openai-compatible`,baseURL 不设默认值
|
||
- 连通性测试为可选功能,不阻塞模型创建
|
||
- 约束:
|
||
- 严格遵循现有代码模式(路由拆分、数据访问函数、hooks、页面组件结构)
|
||
- 不引入新的样式系统
|
||
- 被否决方案:
|
||
- API Key 加密存储:对本地/自部署单用户场景过度设计
|
||
- AI 注册表缓存:增加复杂度但收益极小(~1ms vs 数百毫秒网络 I/O)
|
||
- LangChain 等重量级框架:Vercel AI SDK 更轻量且 API 更统一
|
||
|
||
## 需求
|
||
|
||
| 需求 | 验收标准 |
|
||
| ---- | -------- |
|
||
| 供应商 CRUD | 管理员可新增、查看、编辑、删除供应商(名称、类型、baseURL、apiKey) |
|
||
| 供应商类型支持 | 支持 openai、anthropic、openai-compatible 三种类型,各自对应 AI SDK 不同 provider 工厂 |
|
||
| 模型 CRUD | 管理员可新增、查看、编辑、删除模型(名称、所属供应商、modelId、能力标签、可选参数) |
|
||
| 能力标签多选 | 模型表单中可多选能力标签(text / reasoning / image-generation / video-generation / audio-generation / image-recognition / video-recognition / audio-recognition) |
|
||
| 连通性测试 | 供应商编辑/创建时可测试 API 连通性,返回成功/失败提示 |
|
||
| 模型启用/禁用 | 供应商和模型均可启用/禁用,不影响数据 |
|
||
| 管理控制台菜单 | Admin 控制台侧栏新增"模型管理"菜单项 |
|
||
| AI 注册表服务 | 后端提供 AI 注册表构建服务,按需从 DB 查询构建,供后续 AI 功能调用 |
|
||
| 级联约束 | 删除供应商时,若存在关联模型则阻止删除,用户需先处理关联模型 |
|
||
|
||
## 数据模型规格
|
||
|
||
### providers 表
|
||
|
||
| 字段 | 类型 | 约束 | 说明 |
|
||
| ---- | ---- | ---- | ---- |
|
||
| id | TEXT | PK, UUID | 自动生成 |
|
||
| name | TEXT | NOT NULL, UNIQUE | 供应商显示名称 |
|
||
| type | TEXT | NOT NULL | 枚举:`openai` \| `anthropic` \| `openai-compatible`,默认 `openai-compatible` |
|
||
| baseUrl | TEXT | NOT NULL | API 基础 URL,不设默认值,由用户填写 |
|
||
| apiKey | TEXT | NOT NULL | API 密钥,明文存储,GET 接口完整返回 |
|
||
| enabled | INTEGER | NOT NULL, DEFAULT 1 | 1=启用, 0=禁用 |
|
||
| createdAt | TEXT | NOT NULL | ISO 8601 时间戳 |
|
||
| updatedAt | TEXT | NOT NULL | ISO 8601 时间戳 |
|
||
|
||
### models 表
|
||
|
||
| 字段 | 类型 | 约束 | 说明 |
|
||
| ---- | ---- | ---- | ---- |
|
||
| id | TEXT | PK, UUID | 自动生成 |
|
||
| name | TEXT | NOT NULL | 模型显示名称 |
|
||
| providerId | TEXT | NOT NULL, FK → providers.id | 所属供应商 |
|
||
| modelId | TEXT | NOT NULL | API 调用用的模型标识(如 `gpt-4o`) |
|
||
| capabilities | TEXT | NOT NULL | JSON 数组,能力标签(见下方定义) |
|
||
| contextLength | INTEGER | 可选 | 上下文窗口长度 |
|
||
| maxOutputTokens | INTEGER | 可选 | 最大输出 token 数 |
|
||
| enabled | INTEGER | NOT NULL, DEFAULT 1 | 1=启用, 0=禁用 |
|
||
| createdAt | TEXT | NOT NULL | ISO 8601 时间戳 |
|
||
| updatedAt | TEXT | NOT NULL | ISO 8601 时间戳 |
|
||
|
||
**唯一约束:** `(providerId, modelId)` 联合唯一——同一供应商下 modelId 不可重复,不同供应商可以有相同 modelId。
|
||
|
||
**能力标签定义(ModelCapability):**
|
||
|
||
```
|
||
"text" | "reasoning" | "image-generation" | "video-generation" | "audio-generation" | "image-recognition" | "video-recognition" | "audio-recognition"
|
||
```
|
||
|
||
存储为 JSON 数组字符串,如 `["text","reasoning","image-recognition"]`。
|
||
|
||
## 目标 / 非目标
|
||
|
||
**目标:**
|
||
- 在管理控制台提供完整的供应商和模型管理界面
|
||
- 建立后端 AI 服务层(注册表 + 类型定义),为后续 AI 功能提供可复用基础
|
||
- 完成 Vercel AI SDK 集成的依赖安装和基础配置
|
||
- 新增 DB migration 支持 providers 和 models 表
|
||
|
||
**非目标:**
|
||
- 不实现实际的 AI 调用功能(文本生成、图片生成等)——这是后续变更的内容
|
||
- 不实现 API Key 加密存储
|
||
- 不实现供应商/模型的导入导出功能
|
||
- 不实现多用户权限控制
|
||
|
||
## 执行约束
|
||
|
||
- 依赖限制:
|
||
- 新增 npm 依赖仅限 `ai`、`@ai-sdk/openai`、`@ai-sdk/anthropic`、`@ai-sdk/openai-compatible`
|
||
- 使用 `bun add` 安装,严禁 npm/pnpm
|
||
- 优先使用项目已有依赖(Drizzle ORM、antd、TanStack React Query 等)
|
||
- 约束:
|
||
- 后端遵循 Bun 内置 API > es-toolkit > 三方库优先级
|
||
- 前端遵循 antd 组件默认能力优先,禁止内联 style、覆盖 antd 内部类名
|
||
- Git 提交格式:中文,"类型: 简短描述"
|
||
- 质量门禁:
|
||
- 新增代码必须编写完善的测试
|
||
- 不允许跳过任何测试
|
||
- 代码变更需执行文档影响分析
|
||
- 相关方:
|
||
- 本变更为基础设施层,所有后续 AI 功能变更将依赖本变更的 AI 注册表服务
|
||
- 文档 / 沟通:
|
||
- 每次代码变更执行文档影响分析:用户可见行为变更 → `docs/user/`,开发流程/架构变更 → `docs/development/`
|
||
- 兼容性 / 连续性:
|
||
- 无需考虑向前兼容性
|
||
|
||
## 影响范围
|
||
|
||
| 范围 | Artifacts / 参考资料 | 预期变更 | 备注 |
|
||
| ---- | -------------------- | -------- | ---- |
|
||
| DB Schema | `src/server/db/schema.ts` | 新增 providers 和 models 表定义 | 遵循现有 projects 表模式 |
|
||
| DB Migration | `drizzle/` | 新增 migration SQL 文件 | 自动生成 |
|
||
| 数据访问层 | `src/server/db/projects.ts`(参考模式) | 新增 `providers.ts` 和 `models.ts` | CRUD + 启用/禁用 |
|
||
| DB 导出 | `src/server/db/index.ts` | 新增 providers 和 models schema 导出 | 遵循现有导出模式 |
|
||
| 共享类型 | `src/shared/api.ts` | 新增供应商和模型相关类型定义 | 前后端共用 |
|
||
| 后端路由 | `src/server/routes/` | 新增 `providers/` 和 `models/` 目录 | CRUD + 连通性测试 |
|
||
| 服务器入口 | `src/server/server.ts` | 注册新路由 | 懒加载导入 |
|
||
| AI 服务层 | `src/server/ai/`(新建) | 新增 `registry.ts` 和 `types.ts` | AI 注册表构建服务 |
|
||
| 前端菜单 | `src/web/consoles/admin/menu.tsx` | 新增"模型管理"菜单项 | |
|
||
| 前端页面 | `src/web/pages/models/`(新建) | 新增模型管理页面(Tabs + 表格 + 表单) | 遵循 projects 页面模式 |
|
||
| 前端组件 | `src/web/pages/models/components/`(新建) | ProviderTable、ProviderFormModal、ModelTable、ModelFormModal | |
|
||
| 前端路由 | `src/web/routes.tsx` | 新增 `/models` 路由 | |
|
||
| 前端 Hooks | `src/web/hooks/` | 新增 `use-providers.ts`、`use-models.ts` | TanStack React Query |
|
||
| 依赖 | `package.json` | 新增 `ai`、`@ai-sdk/openai`、`@ai-sdk/anthropic`、`@ai-sdk/openai-compatible` | |
|
||
| 测试 | `tests/` | 新增后端路由、数据访问、前端 hooks 和组件测试 | |
|
||
| 文档 | `docs/development/backend.md` | 更新后端架构说明,补充 AI 服务层 | 开发文档 |
|
||
| 文档 | `docs/development/frontend.md` | 补充模型管理页面组件说明 | 开发文档 |
|
||
|
||
## 决策
|
||
|
||
| 决策 | 理由 | 已否决替代方案 |
|
||
| ---- | ---- | ---------------- |
|
||
| 使用 Vercel AI SDK | 轻量、统一 API、支持多供应商、TypeScript 优先、与 Bun 兼容 | LangChain(过重,API 复杂)、自行封装 fetch(维护成本高,无法统一接口) |
|
||
| 三种供应商类型 | 覆盖主流场景:OpenAI(Responses API + Chat Completions API)、Anthropic、OpenAI 兼容协议(DeepSeek/Qwen/Ollama 等) | 仅区分"OpenAI 协议"和"其他"(丢失 Anthropic 特有能力) |
|
||
| API Key 明文存储 | 本地/自部署单用户场景,加密增加复杂度但安全性提升有限 | 加密存储(过度设计) |
|
||
| AI 注册表不缓存 | DB 查询 + 注册表构建开销 ~1ms,远小于网络 I/O;无缓存则无需处理失效/一致性问题 | 内存缓存(增加复杂度,收益极小) |
|
||
| capability 标签用 JSON 数组 | 灵活可扩展,SQLite 中 TEXT 字段存储 JSON 数组 | 关联表(过度设计,标签数量有限且固定) |
|
||
| 连通性测试不阻塞操作 | 测试是辅助功能,网络波动不应阻止用户保存配置 | 强制测试通过才能保存(用户体验差) |
|
||
| 删除供应商时阻止而非级联删除 | 防止误删导致模型数据丢失,用户需先处理关联模型 | CASCADE 删除(数据安全风险) |
|
||
| GET 接口完整返回 apiKey | 本地/自部署单用户场景,前端使用 antd Password 组件隐藏显示,无需脱敏 | apiKey 脱敏返回(增加复杂度,编辑时需额外处理) |
|
||
| providerId + modelId 联合唯一 | 同一供应商下 modelId 不可重复,不同供应商可有相同 modelId;符合 AI SDK 注册表 key 格式 `providerId:modelId` | modelId 全局唯一(限制过严)、无约束(可能导致注册表冲突) |
|
||
| 连通性测试使用 generateText 最小请求 | 调用 `generateText({ model, prompt: 'hi' })` 验证连通性和 apiKey 有效性,简单直接 | 仅验证 HTTP 连接(不验证 apiKey)、listModels(并非所有供应商支持) |
|
||
| 启用/禁用使用 enable/disable 双端点 | 语义明确,与 archive/restore 模式一致;供应商/模型的启用禁用是布尔切换,双端点更清晰 | toggle 单端点(语义含糊,前端需知道当前状态才能确定操作) |
|
||
| 供应商 type 默认 openai-compatible | 覆盖最广(DeepSeek/Qwen/Ollama 等),用户只需填写 baseURL 和 apiKey 即可使用 | 默认 openai(限制性强,不适合自部署场景) |
|
||
| baseURL 不设默认值 | 不同部署环境的 baseURL 差异大,自动填充可能误导用户填错地址 | 设默认值(看似方便,但可能掩盖配置错误) |
|
||
|
||
## 执行计划
|
||
|
||
**阶段 1:基础层(DB + 类型 + 依赖)**
|
||
1. 安装 Vercel AI SDK 相关依赖
|
||
2. 在 `src/server/db/schema.ts` 新增 providers 和 models 表定义
|
||
3. 生成 DB migration
|
||
4. 在 `src/shared/api.ts` 新增供应商和模型相关类型定义
|
||
5. 在 `src/server/ai/types.ts` 新增 AI 相关类型定义(ModelCapability 等)
|
||
|
||
**阶段 2:后端(数据访问 + 路由 + AI 服务)**
|
||
6. 新增 `src/server/db/providers.ts` 数据访问函数
|
||
7. 新增 `src/server/db/models.ts` 数据访问函数
|
||
8. 新增 `src/server/routes/providers/` 目录下的 CRUD 路由处理器(含 enable/disable 双端点)
|
||
9. 新增 `src/server/routes/models/` 目录下的 CRUD 路由处理器(含 enable/disable 双端点)
|
||
10. 新增 `src/server/routes/providers/test.ts` 连通性测试路由
|
||
11. 在 `src/server/server.ts` 注册所有新路由
|
||
12. 新增 `src/server/ai/registry.ts`,包含 `buildProviderRegistry(db)`(从 DB 查询启用的供应商构建 AI SDK Provider Registry)和 `testProviderConnection(config)`(使用 generateText 测试连通性)
|
||
|
||
**阶段 3:前端(页面 + 组件 + Hooks)**
|
||
13. 新增 `src/web/hooks/use-providers.ts` 和 `src/web/hooks/use-models.ts`
|
||
14. 在 `src/web/consoles/admin/menu.tsx` 新增"模型管理"菜单项
|
||
15. 在 `src/web/routes.tsx` 新增 `/models` 路由
|
||
16. 新增 `src/web/pages/models/index.tsx` 页面(Tabs 布局)
|
||
17. 新增 `src/web/pages/models/components/ProviderTable.tsx`
|
||
18. 新增 `src/web/pages/models/components/ProviderFormModal.tsx`
|
||
19. 新增 `src/web/pages/models/components/ModelTable.tsx`
|
||
20. 新增 `src/web/pages/models/components/ModelFormModal.tsx`
|
||
|
||
**阶段 4:测试**
|
||
21. 后端数据访问层测试(providers.ts、models.ts)
|
||
22. 后端路由测试(providers/、models/)
|
||
23. AI 注册表测试
|
||
24. 前端 hooks 测试
|
||
25. 前端组件测试
|
||
|
||
**阶段 5:文档**
|
||
26. 执行文档影响分析,更新 `docs/development/` 相关文档
|
||
|
||
## 验证计划
|
||
|
||
| 需求 / 风险 | 验证方式 |
|
||
| ----------- | -------- |
|
||
| 供应商 CRUD API | 后端路由测试覆盖创建、查询、更新、删除、启用/禁用 |
|
||
| 模型 CRUD API | 后端路由测试覆盖创建、查询、更新、删除、启用/禁用 |
|
||
| 供应商删除约束 | 测试删除有关联模型的供应商时返回错误 |
|
||
| 连通性测试 API | 测试 mock 场景下的成功/失败响应 |
|
||
| AI 注册表构建 | 测试从 DB 数据正确构建 AI SDK provider 实例 |
|
||
| DB Migration | 测试 migration 正确创建表和索引 |
|
||
| 前端供应商管理 | 组件测试覆盖表格渲染、表单提交、启用/禁用操作 |
|
||
| 前端模型管理 | 组件测试覆盖表格渲染、表单提交、能力标签多选 |
|
||
| 前端菜单和路由 | 测试菜单项显示和路由跳转 |
|
||
| 文档完整性 | 检查 docs/development/ 和 docs/user/ 是否已更新 |
|
||
|
||
## 风险 / 权衡
|
||
|
||
- [Vercel AI SDK 与 Bun 的兼容性] -> AI SDK 基于 Web 标准 API,Bun 对 Web API 支持良好;安装后需验证 import 正常
|
||
- [OpenAI-compatible 供应商行为不一致] -> 注册表构建时使用 `createOpenAICompatible` 标准接口;连通性测试帮助用户提前发现问题
|
||
- [API Key 明文存储安全风险] -> 文档中说明安全模型(单用户本地部署);未来可按需增加加密
|
||
- [migration 与现有数据兼容性] -> 新增表不影响现有 projects 表;migration 为增量操作
|
||
|
||
## 待解决问题
|
||
|
||
| 状态 | 问题 | 所需决策 |
|
||
| ---- | ---- | -------- |
|
||
| 无 | 无待解决问题。 | 无需决策 |
|