update at 2025-10-14 21:52:11
This commit is contained in:
374
PERFORMANCE_ANALYSIS.md
Normal file
374
PERFORMANCE_ANALYSIS.md
Normal file
@@ -0,0 +1,374 @@
|
||||
# 性能追踪分析指南
|
||||
|
||||
## 已添加的性能追踪点
|
||||
|
||||
### 1. 总体流程追踪
|
||||
|
||||
```
|
||||
用户发送消息
|
||||
↓
|
||||
[chatStore.sendMessageStream]
|
||||
↓
|
||||
[chatService.sendMessageStream] ⏱️ callModelStream总耗时
|
||||
├─ [chatService.callModel] ⏱️ callModel总耗时
|
||||
│ ├─ 准备消息 ⏱️ 准备消息耗时
|
||||
│ ├─ 服务匹配
|
||||
│ ├─ [modelServiceManager.sendChatRequest] ⏱️ 请求耗时
|
||||
│ │ ├─ 准备 ⏱️ 准备耗时
|
||||
│ │ └─ [makeChatRequest] ⏱️ makeChatRequest总耗时
|
||||
│ │ ├─ 构建请求 ⏱️ 构建请求耗时
|
||||
│ │ ├─ 网络请求 ⏱️ 网络请求耗时 ← 通常最慢的部分
|
||||
│ │ └─ 解析响应 ⏱️ 解析响应耗时
|
||||
│ └─ 解析响应 ⏱️ 解析响应耗时
|
||||
└─ 模拟流式输出 ⏱️ 模拟流式输出耗时
|
||||
```
|
||||
|
||||
### 2. 关键性能指标
|
||||
|
||||
#### 控制台日志格式
|
||||
|
||||
```javascript
|
||||
// 开始
|
||||
⏱️ [callModelStream] 开始流式处理
|
||||
⏱️ [callModel] 开始处理 {model: "xxx", 对话消息数: 5}
|
||||
⏱️ [callModel] 准备消息耗时: 0.50 ms 处理后消息数: 5
|
||||
⏱️ [sendChatRequest] 开始请求 {serviceId: "xxx", model: "xxx", messages数量: 5}
|
||||
|
||||
// 网络请求阶段 (通常最慢)
|
||||
⏱️ [sendChatRequest] 准备耗时: 0.10 ms
|
||||
⏱️ [makeChatRequest] 构建请求耗时: 0.20 ms
|
||||
🔍 [makeChatRequest] 请求体大小: 1024 字节
|
||||
⏱️ [makeChatRequest] 网络请求耗时: 2500.00 ms ← 关键指标!
|
||||
🔍 [makeChatRequest] 响应状态: 200 OK
|
||||
|
||||
// 解析阶段
|
||||
⏱️ [makeChatRequest] 解析响应耗时: 5.00 ms
|
||||
⏱️ [makeChatRequest] makeChatRequest总耗时: 2505.50 ms
|
||||
⏱️ [sendChatRequest] 请求耗时: 2505.60 ms
|
||||
⏱️ [sendChatRequest] 总耗时: 2505.70 ms
|
||||
⏱️ [callModel] 服务调用耗时: 2505.80 ms
|
||||
⏱️ [callModel] 解析响应耗时: 0.30 ms
|
||||
⏱️ [callModel] callModel总耗时: 2507.00 ms
|
||||
|
||||
// 流式输出阶段
|
||||
⏱️ [callModelStream] callModel耗时: 2507.10 ms
|
||||
⏱️ [callModelStream] 模拟流式输出耗时: 1800.00 ms
|
||||
⏱️ [callModelStream] 输出块数: 60 总字符数: 300
|
||||
⏱️ [callModelStream] callModelStream总耗时: 4307.10 ms
|
||||
```
|
||||
|
||||
## 性能瓶颈分析
|
||||
|
||||
### 常见的慢速原因
|
||||
|
||||
#### 1. 网络请求慢 (2000-5000ms)
|
||||
**症状**:
|
||||
```
|
||||
⏱️ [makeChatRequest] 网络请求耗时: 3500.00 ms
|
||||
```
|
||||
|
||||
**可能原因**:
|
||||
- API服务器响应慢
|
||||
- 网络延迟高
|
||||
- 请求体太大
|
||||
- API配额限制
|
||||
|
||||
**解决方案**:
|
||||
```javascript
|
||||
// 1. 检查请求体大小
|
||||
🔍 [makeChatRequest] 请求体大小: 50000 字节 // 如果>10KB需要优化
|
||||
|
||||
// 2. 减少上下文消息数量
|
||||
const messages = conversation.messages
|
||||
.filter(m => m.status === 'success')
|
||||
.slice(-10) // 只保留最近10条消息
|
||||
|
||||
// 3. 使用CDN或更近的API端点
|
||||
// 火山引擎: https://ark.cn-beijing.volces.com (北京)
|
||||
// 阿里云: https://dashscope.aliyuncs.com (杭州)
|
||||
```
|
||||
|
||||
#### 2. 模拟流式输出慢 (1000-3000ms)
|
||||
**症状**:
|
||||
```
|
||||
⏱️ [callModelStream] 模拟流式输出耗时: 2400.00 ms
|
||||
⏱️ [callModelStream] 输出块数: 80 总字符数: 400
|
||||
```
|
||||
|
||||
**原因**:
|
||||
```javascript
|
||||
// 每个块延迟30ms
|
||||
await new Promise(resolve => setTimeout(resolve, 30))
|
||||
// 80块 × 30ms = 2400ms
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
```javascript
|
||||
// 方案1: 减少延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 10)) // 30ms → 10ms
|
||||
|
||||
// 方案2: 增加块大小
|
||||
const chunkSize = 10 // 5 → 10,减少块数
|
||||
|
||||
// 方案3: 使用真正的流式API (最佳)
|
||||
// 火山引擎支持 stream: true
|
||||
body = {
|
||||
model,
|
||||
messages,
|
||||
stream: true // 启用流式
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 消息准备慢 (>100ms)
|
||||
**症状**:
|
||||
```
|
||||
⏱️ [callModel] 准备消息耗时: 150.00 ms 处理后消息数: 1000
|
||||
```
|
||||
|
||||
**原因**: 消息数量太多
|
||||
|
||||
**解决方案**:
|
||||
```javascript
|
||||
// 限制消息历史
|
||||
const MAX_MESSAGES = 20
|
||||
const messages = conversation.messages
|
||||
.filter(m => m.status === 'success')
|
||||
.slice(-MAX_MESSAGES) // 只保留最近20条
|
||||
```
|
||||
|
||||
#### 4. 响应解析慢 (>100ms)
|
||||
**症状**:
|
||||
```
|
||||
⏱️ [makeChatRequest] 解析响应耗时: 250.00 ms
|
||||
```
|
||||
|
||||
**原因**: 响应体太大
|
||||
|
||||
**解决方案**:
|
||||
```javascript
|
||||
// 检查响应大小
|
||||
console.log('响应大小:', JSON.stringify(result).length, '字节')
|
||||
|
||||
// 如果太大,考虑:
|
||||
// 1. 限制 max_tokens
|
||||
body = {
|
||||
model,
|
||||
messages,
|
||||
max_tokens: 1000 // 限制输出长度
|
||||
}
|
||||
```
|
||||
|
||||
## 性能优化建议
|
||||
|
||||
### 优先级1: 启用真正的流式API
|
||||
|
||||
**当前实现** (假流式):
|
||||
```typescript
|
||||
// chatService.ts
|
||||
const result = await this.callModel(conversation, model) // 等待完整响应
|
||||
// 然后模拟流式输出
|
||||
for (let i = 0; i < content.length; i += chunkSize) {
|
||||
onChunk(chunk)
|
||||
await new Promise(resolve => setTimeout(resolve, 30)) // 人工延迟
|
||||
}
|
||||
```
|
||||
|
||||
**优化后** (真流式):
|
||||
```typescript
|
||||
// modelServiceManager.ts - makeChatRequest
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: JSON.stringify({
|
||||
model,
|
||||
messages,
|
||||
stream: true // ← 启用流式
|
||||
})
|
||||
})
|
||||
|
||||
// 读取流
|
||||
const reader = response.body.getReader()
|
||||
const decoder = new TextDecoder()
|
||||
|
||||
while (true) {
|
||||
const { done, value } = await reader.read()
|
||||
if (done) break
|
||||
|
||||
const chunk = decoder.decode(value)
|
||||
const lines = chunk.split('\n')
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.startsWith('data: ')) {
|
||||
const data = JSON.parse(line.slice(6))
|
||||
if (data.choices[0].delta?.content) {
|
||||
onChunk(data.choices[0].delta.content) // 实时输出
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**效果**:
|
||||
- ❌ 当前: 等待3000ms + 模拟2000ms = **5000ms总延迟**
|
||||
- ✅ 优化后: 实时流式 = **首字输出<500ms**
|
||||
|
||||
### 优先级2: 减少请求体大小
|
||||
|
||||
```typescript
|
||||
// chatService.ts - callModel
|
||||
const MAX_CONTEXT_MESSAGES = 10 // 最多10条上下文
|
||||
const MAX_CONTENT_LENGTH = 2000 // 每条消息最多2000字符
|
||||
|
||||
const messages = conversation.messages
|
||||
.filter(m => m.status === 'success')
|
||||
.slice(-MAX_CONTEXT_MESSAGES) // 只保留最近N条
|
||||
.map(m => ({
|
||||
role: m.role,
|
||||
content: m.content.slice(0, MAX_CONTENT_LENGTH) // 限制长度
|
||||
}))
|
||||
```
|
||||
|
||||
### 优先级3: 优化模拟流式的参数
|
||||
|
||||
```typescript
|
||||
// chatService.ts - callModelStream
|
||||
const chunkSize = 20 // 5 → 20 (增大块,减少循环)
|
||||
const delay = 10 // 30 → 10 (减少延迟)
|
||||
|
||||
for (let i = 0; i < content.length; i += chunkSize) {
|
||||
const chunk = content.slice(i, i + chunkSize)
|
||||
onChunk(chunk)
|
||||
await new Promise(resolve => setTimeout(resolve, delay))
|
||||
}
|
||||
```
|
||||
|
||||
**效果**:
|
||||
- 字符数: 300
|
||||
- 块数: 300/20 = 15块 (原来60块)
|
||||
- 总延迟: 15×10 = 150ms (原来1800ms)
|
||||
- **提速12倍!**
|
||||
|
||||
### 优先级4: 添加超时控制
|
||||
|
||||
```typescript
|
||||
// modelServiceManager.ts - makeChatRequest
|
||||
const controller = new AbortController()
|
||||
const timeoutId = setTimeout(() => controller.abort(), 30000) // 30秒超时
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: JSON.stringify(body),
|
||||
signal: controller.signal
|
||||
})
|
||||
|
||||
clearTimeout(timeoutId)
|
||||
// ...
|
||||
} catch (error) {
|
||||
clearTimeout(timeoutId)
|
||||
if (error.name === 'AbortError') {
|
||||
throw new Error('请求超时(30秒)')
|
||||
}
|
||||
throw error
|
||||
}
|
||||
```
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 1. 打开浏览器控制台
|
||||
按 `F12` 或 `Cmd+Option+I` (Mac)
|
||||
|
||||
### 2. 发送测试消息
|
||||
在聊天界面输入简短消息,如 "你好"
|
||||
|
||||
### 3. 查看性能日志
|
||||
在控制台搜索 `⏱️` 查看所有计时日志
|
||||
|
||||
### 4. 分析瓶颈
|
||||
按照时间从大到小排序:
|
||||
|
||||
```
|
||||
⏱️ [callModelStream] callModelStream总耗时: 4307.10 ms ← 总时间
|
||||
├─ [callModel] callModel总耗时: 2507.00 ms
|
||||
│ └─ [makeChatRequest] 网络请求耗时: 2500.00 ms ← 瓶颈1
|
||||
└─ [callModelStream] 模拟流式输出耗时: 1800.00 ms ← 瓶颈2
|
||||
```
|
||||
|
||||
### 5. 针对性优化
|
||||
- 如果 **网络请求耗时** > 2000ms → 检查网络/API
|
||||
- 如果 **模拟流式输出耗时** > 1000ms → 优化流式参数或启用真流式
|
||||
- 如果 **准备消息耗时** > 100ms → 限制消息历史数量
|
||||
|
||||
## 预期性能指标
|
||||
|
||||
### 理想情况 (真流式API + 优化)
|
||||
```
|
||||
⏱️ [callModel] 准备消息耗时: < 10 ms
|
||||
⏱️ [makeChatRequest] 构建请求耗时: < 5 ms
|
||||
⏱️ [makeChatRequest] 网络请求耗时: 500-1500 ms (首字输出)
|
||||
⏱️ [callModelStream] 流式输出: 实时,无额外延迟
|
||||
⏱️ 总体首字延迟: < 2000 ms
|
||||
```
|
||||
|
||||
### 当前情况 (假流式)
|
||||
```
|
||||
⏱️ [callModel] 准备消息耗时: 0.5-2 ms ✅
|
||||
⏱️ [makeChatRequest] 构建请求耗时: 0.2-1 ms ✅
|
||||
⏱️ [makeChatRequest] 网络请求耗时: 2000-5000 ms ⚠️
|
||||
⏱️ [callModelStream] 模拟流式输出: 1000-3000 ms ❌
|
||||
⏱️ 总体延迟: 3000-8000 ms ❌
|
||||
```
|
||||
|
||||
## 快速诊断清单
|
||||
|
||||
| 问题 | 检查项 | 正常值 | 解决方案 |
|
||||
|------|--------|--------|----------|
|
||||
| 总体很慢 | callModelStream总耗时 | < 5000ms | 检查网络和流式 |
|
||||
| 网络慢 | 网络请求耗时 | < 2000ms | 换更近的API端点 |
|
||||
| 流式慢 | 模拟流式输出耗时 | < 500ms | 优化参数或启用真流式 |
|
||||
| 准备慢 | 准备消息耗时 | < 10ms | 限制消息数量 |
|
||||
| 解析慢 | 解析响应耗时 | < 10ms | 检查响应大小 |
|
||||
|
||||
## 立即可做的优化
|
||||
|
||||
### 快速优化1: 调整流式参数 (30秒)
|
||||
|
||||
编辑 `/web/src/services/chatService.ts` 第565行:
|
||||
|
||||
```typescript
|
||||
// 原来
|
||||
const chunkSize = 5
|
||||
await new Promise(resolve => setTimeout(resolve, 30))
|
||||
|
||||
// 改为
|
||||
const chunkSize = 20
|
||||
await new Promise(resolve => setTimeout(resolve, 10))
|
||||
```
|
||||
|
||||
**效果**: 流式输出速度提升 **6-12倍**
|
||||
|
||||
### 快速优化2: 限制消息历史 (1分钟)
|
||||
|
||||
编辑 `/web/src/services/chatService.ts` 第500行:
|
||||
|
||||
```typescript
|
||||
// 原来
|
||||
const messages = conversation.messages
|
||||
.filter(m => m.status === 'success')
|
||||
.map(m => ({ role: m.role, content: m.content }))
|
||||
|
||||
// 改为
|
||||
const MAX_MESSAGES = 10
|
||||
const messages = conversation.messages
|
||||
.filter(m => m.status === 'success')
|
||||
.slice(-MAX_MESSAGES) // 只保留最近10条
|
||||
.map(m => ({ role: m.role, content: m.content }))
|
||||
```
|
||||
|
||||
**效果**: 减少请求体大小,提升网络速度 **10-30%**
|
||||
|
||||
---
|
||||
|
||||
**创建时间**: 2025年10月14日
|
||||
**适用版本**: mcp-client-vue v2.1+
|
||||
Reference in New Issue
Block a user