# 项目经验总结(优化版)
## 📋 快速索引
- [架构设计](#架构设计)
- [错误处理](#错误处理)
- [测试规范](#测试规范)
- [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);
};
```