# 项目经验总结(优化版) ## 📋 快速索引 - [架构设计](#架构设计) - [错误处理](#错误处理) - [测试规范](#测试规范) - [Vue开发](#vue开发) - [工具与配置](#工具与配置) - [关键重构经验](#关键重构经验) - [API密钥管理经验](#api密钥管理经验) - [自定义API集成经验](#自定义API集成经验) --- ## 架构设计 ### API集成规范 1. **配置分离** - 业务逻辑与API配置解耦 - 统一接口格式(OpenAI兼容) - 独立管理提示词模板 ```js // 配置示例 export default { baseURL: "https://api.openai.com/v1", models: ["gpt-4", "gpt-3.5"] } ``` 2. **模块化结构** ```src ├─ api/ # API封装 ├─ services/ # 业务逻辑 ├─ config/ # 全局配置 ├─ components/# UI组件 └─ prompts/ # 提示模板库 ``` ### LLM服务架构 | 设计要点 | 实现方案 | |-------------------|----------------------------| | 接口标准化 | 统一使用OpenAI格式 | | 多服务商兼容 | Provider标识区分(如Gemini)| | 动态配置更新 | 支持热加载配置 | | 敏感信息管理 | 环境变量+本地加密存储 | --- ## 错误处理 ### 典型问题与修复 | 问题场景 | 解决方案 | 发生日期 | |--------------------------|----------------------------|------------| | 模板ID与模型Key混淆 | 明确功能ID与API Key分离 | 2024-03-22 | | 状态同步异常 | 增加状态同步处理函数 | 2024-03-22 | | 全局currentProvider污染 | 显式传递模型参数 | 2024-03-22 | ### 处理原则 1. **开发环境**:保留完整错误堆栈 2. **生产环境**:友好提示+日志记录 3. **通用规则**: ```js try { await apiCall(); } catch (err) { console.error("[API Error]", err.context); throw new Error("服务调用失败,请检查配置"); } ``` --- ## 测试规范 ### 核心要点 1. **环境变量** ```js // Vite项目必须使用import.meta.env const apiKey = import.meta.env.VITE_GEMINI_KEY; ``` 2. **测试架构** - 集中管理多服务商配置 - 独立测试数据库 - 模拟异常场景(网络错误/无效Token) 3. **用例设计** ```js describe("API测试", () => { it("应正确处理多轮对话", async () => { const response = await sendRequest(messages); expect(response.content).toMatch(/优化建议/); }); }); ``` --- ## Vue开发 ### 组件规范 1. **Composable使用** ```js // 正确用法 const { data } = useFetch(); // 错误用法 onMounted(() => { const { data } = useFetch(); // 禁止在生命周期内调用 }); ``` 2. **状态同步方案** ```vue ``` ### UI设计准则 | 分类 | 规范 | |------------|------------------------------| | 布局系统 | 基于Tailwind的响应式网格 | | 主题管理 | CSS变量+透明度层级控制 | | 交互反馈 | 加载状态/禁用状态/过渡动画 | --- ## 工具与配置 ### NPM管理 ```bash # 常用命令 npm outdated # 检查可更新包 ncu -u "eslint*" # 安全更新指定包 ``` ### 版本策略 | 符号 | 含义 | 示例 | |------|---------------------|---------------| | ^ | 允许小版本更新 | ^1.2.3 → 1.3.0| | ~ | 仅允许补丁更新 | ~1.2.3 → 1.2.4| ### YAML处理 1. **常见错误** ```yaml # 错误示例 -invalid: 缺少空格 tags: -test # 列表格式错误 ``` 2. **修复方案** ```yaml # 正确格式 valid_key: "值" tags: - test - template ``` --- ## 关键重构经验 ### 服务层优化(2024-03-19) 1. **类型安全** ```ts interface ModelConfig { name: string; baseURL: string; // 非可选字段 models: string[]; } ``` 2. **错误处理改进** - 统一继承自 `LLMError` 基类 - 批量验证错误收集 ```ts class ValidationError extends LLMError { constructor(errors: string[]) { super(`配置验证失败: ${errors.join(', ')}`); } } ``` ### 配置管理(2024-03-21) 1. **模型启用验证** ```ts function validateConfig(config) { if (!config.apiKey) { throw new Error("API Key为必填项"); } } ``` 2. **环境变量处理** ```ts /// interface ImportMetaEnv { VITE_GEMINI_KEY: string; } ``` ### LLM 服务重构经验 #### LangChain 集成 - 日期:[当前日期] - 场景:将原生 API 调用重构为 LangChain 实现 - 主要改进: 1. 更好的可扩展性 2. 统一的接口抽象 3. 内置的错误处理 4. 支持高级特性 #### 最佳实践 1. 使用模型实例缓存提高性能 2. 统一消息格式转换 3. 保持公共接口稳定 4. 分层错误处理 #### 注意事项 1. 需要安装相关依赖: ```bash npm install langchain @langchain/core @langchain/openai @langchain/anthropic ``` 2. 不同模型提供商的配置参数可能不同 3. 建议使用 TypeScript 获得更好的类型支持 #### 未来扩展 1. 支持更多模型提供商 2. 添加高级功能: - 链式调用 - 代理功能 - 向量存储 - 记忆管理 3. 性能优化: - 并发请求 - 流式响应 - 缓存策略 --- ## API密钥管理经验 ### 设计决策 1. 采用用户自管理API密钥的方式 2. 启用OpenAI库的浏览器支持 3. 提供完整的密钥管理指导 ### 原因 1. 应用定位为个人工具 2. 用户可以完全控制自己的API使用 3. 避免后端服务的开销和维护 4. 保持应用的简单性和可移植性 ### 安全考虑 1. 密钥由用户自行创建和管理 2. 建议用户为应用单独创建密钥 3. 推荐在OpenAI平台设置使用限制 4. 提供密钥安全使用的最佳实践指导 ### 用户体验优化 1. 提供详细的API密钥获取教程 2. 添加密钥验证功能 3. 显示当前密钥的使用状态 4. 提供密钥使用的安全提示 ### 技术实现 ```typescript const model = new OpenAI({ apiKey: userProvidedKey, baseURL: modelConfig.baseURL, dangerouslyAllowBrowser: true // 必要的配置 }); ``` ### 最佳实践建议 1. 在本地存储中加密保存密钥 2. 提供清除密钥的功能 3. 定期提醒用户检查密钥使用情况 4. 提供密钥轮换的指导 ## 测试修复经验总结 ### 1. 常见测试失败原因 - 方法名不匹配:实现变更后未同步更新测试用例 - 错误消息不一致:测试期望与实际实现的错误消息格式不匹配 - 模板验证逻辑不一致:测试用例未反映最新的业务逻辑 ### 2. 修复策略 - 统一错误消息格式:确保测试用例与实际代码的错误消息完全匹配 - 移除多余的模拟:删除不必要的模拟调用 - 添加缺失的模拟:确保所有必要的依赖都被正确模拟 ### 3. 最佳实践 - 错误消息管理:统一定义错误消息,避免分散管理 - 测试用例维护:及时更新测试用例以反映最新的代码行为 - Mock 策略:只模拟必要的方法,避免过度模拟 - 测试覆盖:关注边界条件和异常场景的测试 ### 4. 改进建议 - 使用常量定义错误消息 - 完善错误处理的类型定义 - 添加更多边界条件测试 - 创建测试辅助函数简化重复设置 ### 5. 测试代码示例 ```typescript // 错误消息常量 const ERROR_MESSAGES = { TEMPLATE_NOT_FOUND: '模板不存在或无效', MANAGER_NOT_INITIALIZED: '模板管理器未初始化', MODEL_NOT_FOUND: '模型不存在' } as const; // 测试辅助函数 function setupMocks(options: { templateContent?: string, modelExists?: boolean, messageResult?: string }) { const { templateContent, modelExists = true, messageResult } = options; if (modelExists) { vi.spyOn(modelManager, 'getModel').mockReturnValue(mockModelConfig); } else { vi.spyOn(modelManager, 'getModel').mockReturnValue(undefined); } if (templateContent !== undefined) { vi.spyOn(templateManager, 'getTemplate').mockResolvedValue({ ...mockTemplate, template: templateContent }); } if (messageResult) { vi.spyOn(llmService, 'sendMessage').mockResolvedValue(messageResult); } } ``` ### 6. 测试改进经验(2024-03-22) #### 边界条件测试要点 1. **输入验证** - 空字符串处理 - 超长输入处理 - 特殊字符处理 - 无效参数处理 2. **服务异常处理** - 超时处理 - 空响应处理 - 网络错误处理 - 服务降级处理 3. **状态记录验证** - 历史记录完整性 - 状态变更正确性 - 关联关系准确性 - 时序记录准确性 #### 测试代码组织 ```typescript describe('功能测试组', () => { // 基础测试 describe('基本功能', () => { it('正常场景', async () => {}); it('异常场景', async () => {}); }); // 边界条件 describe('边界条件', () => { it('空输入', async () => {}); it('超长输入', async () => {}); it('特殊字符', async () => {}); }); // 状态管理 describe('状态管理', () => { it('状态记录', async () => {}); it('状态查询', async () => {}); it('状态关联', async () => {}); }); }); ``` #### 测试优化技巧 1. **Mock 优化** ```typescript // 统一的 Mock 设置 function setupServiceMocks(options: MockOptions) { const { templateContent, modelResponse, shouldFail } = options; if (shouldFail) { vi.spyOn(service, 'call').mockRejectedValue(new Error('预期的错误')); } else { vi.spyOn(service, 'call').mockResolvedValue(modelResponse); } } ``` 2. **错误处理验证** ```typescript // 统一的错误处理验证 expect(() => { // 触发错误的操作 }).rejects.toThrow(expect.objectContaining({ name: 'ValidationError', message: expect.stringContaining('预期的错误消息') })); ``` 3. **测试数据管理** ```typescript // 集中管理测试数据 const TEST_DATA = { validPrompt: '有效的提示词', invalidPrompt: '', longPrompt: 'a'.repeat(10000), specialChars: '!@#$%^&*()', } as const; ``` #### 改进效果 1. 测试覆盖率提升 2. 边界场景更完善 3. 代码可维护性提高 4. 测试执行效率提升 ## LangChain消息类型修复经验 ### 问题描述 在使用LangChain进行消息处理时,遇到类型不匹配的问题: ```typescript Argument of type 'AIMessage' is not assignable to parameter of type 'AIMessageChunk' ``` ### 原因分析 1. LangChain的消息类型有多种,包括`AIMessage`和`AIMessageChunk` 2. `AIMessageChunk`是专门用于流式响应的消息类型 3. 在调用`invoke`方法时,返回类型为`AIMessageChunk` ### 解决方案 1. 将导入语句从`AIMessage`改为`AIMessageChunk`: ```typescript import { AIMessageChunk } from '@langchain/core/messages' ``` 2. 更新所有使用`AIMessage`的地方为`AIMessageChunk` ### 最佳实践 1. 使用正确的消息类型: - `AIMessage`: 用于普通消息 - `AIMessageChunk`: 用于流式响应 - `HumanMessage`: 用于用户输入 - `SystemMessage`: 用于系统消息 2. 在mock测试时确保使用正确的消息类型 3. 参考LangChain文档中的类型定义 ### 相关文档 - [LangChain消息类型文档](https://js.langchain.com/docs/api/schema/messages) - [LangChain流式响应文档](https://js.langchain.com/docs/modules/model_io/models/chat/streaming) ## 自定义API集成经验 ### 配置要求 1. API需要支持OpenAI兼容格式 2. 响应格式需要符合以下结构: ```json { "choices": [{ "message": { "content": "API响应内容" } }] } ``` ### 环境变量配置 ```env # 自定义API配置 VITE_CUSTOM_API_KEY=您的API密钥 VITE_CUSTOM_API_BASE_URL=您的API基础URL ``` ### 最佳实践 1. 在添加新的API时,先进行兼容性测试 2. 确保错误处理机制完善 3. 添加必要的请求头和认证信息 4. 实现请求重试机制 5. 做好日志记录 ### 常见问题 1. API格式不兼容:确保响应格式符合OpenAI标准 2. 认证失败:检查API密钥配置 3. 跨域问题:配置正确的CORS设置 4. 超时处理:设置合理的超时时间 ## 测试经验总结 ### 1. 测试数据管理 - 每个测试用例使用独立的测试数据 - 使用动态生成的唯一标识符避免冲突 - 在添加新数据前确保清理已存在数据 ### 2. 初始化状态管理 - 注意对象构造函数中的默认行为 - 不能仅依赖 beforeEach 的清理 - 需要手动处理默认值和持久化数据 ### 3. 存储机制处理 - 注意 localStorage 等持久化存储的影响 - 确保正确清理所有相关的存储数据 - 考虑使用 mock 存储机制进行测试 ### 4. 测试用例隔离 - 测试用例之间应该相互独立 - 每个测试用例都应该可以独立运行 - 避免测试用例之间的状态依赖 ## 测试重构经验(2024-03-22) ### 1. 测试数据隔离的最佳实践 - 使用动态生成的唯一标识符 - 每个测试用例使用独立的数据空间 - 避免测试用例之间的状态依赖 ### 2. 测试辅助函数设计 ```typescript // 示例:创建唯一标识符 const getUniqueKey = (prefix: string) => `${prefix}-${Date.now()}`; // 示例:创建基础配置 const createBaseConfig = (options?: Partial) => ({ ...defaultConfig, ...options }); ``` ### 3. 测试代码组织 - 将通用逻辑抽取为辅助函数 - 使用 beforeEach 进行状态初始化 - 保持测试用例的独立性和可读性 ### 4. 配置管理优化 - 集中管理测试配置 - 支持配置的部分覆盖 - 便于统一修改和维护 ### 5. 改进效果 - 提高了测试的可靠性 - 减少了代码重复 - 简化了测试维护 - 提升了测试执行效率 ## 开发经验总结 ## 流式处理最佳实践 ### 1. 统一使用流式API - 避免使用非流式API - 不提供降级方案 - 确保所有操作都支持流式处理 ### 2. 流式处理器设计 ```typescript // 标准流式处理器结构 interface StreamHandlers { onToken: (token: string) => void; // 处理每个token onComplete: () => void; // 处理完成回调 onError: (error: Error) => void; // 处理错误 } // 使用示例 const streamHandlers = { onToken: (token) => { result.value += token; // 实时更新UI }, onComplete: () => { isLoading.value = false; toast.success('处理完成'); }, onError: (error) => { isLoading.value = false; toast.error(error.message); } }; ``` ### 3. 错误处理 - 实时显示错误信息 - 保持UI状态同步 - 提供友好的错误提示 ### 4. 状态管理 - 使用响应式变量 - 实时更新处理状态 - 正确处理加载状态 ### 5. 性能优化 - 避免频繁的DOM更新 - 使用防抖处理用户输入 - 合理设置缓冲区大小 ### 6. 用户体验 - 显示实时处理进度 - 提供取消处理选项 - 保持界面响应性 ## 注意事项 1. 确保所有API都支持流式处理 2. 处理网络异常情况 3. 合理管理内存使用 4. 保持代码可维护性 ## 最佳实践示例 ```typescript // 1. 定义处理器 const createStreamHandlers = (options: { onUpdate: (text: string) => void, onSuccess: () => void, onError: (error: Error) => void }) => ({ onToken: (token: string) => { options.onUpdate(token); }, onComplete: () => { options.onSuccess(); }, onError: (error: Error) => { options.onError(error); } }); // 2. 使用处理器 const handleStream = async () => { const handlers = createStreamHandlers({ onUpdate: (text) => { result.value += text; }, onSuccess: () => { toast.success('处理完成'); }, onError: (error) => { toast.error(error.message); } }); await service.processStream(input, handlers); }; ```