## 背景 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 为增量操作 ## 待解决问题 | 状态 | 问题 | 所需决策 | | ---- | ---- | -------- | | 无 | 无待解决问题。 | 无需决策 |