ss
This commit is contained in:
447
智能体聊天助手性能优化方案.md
Normal file
447
智能体聊天助手性能优化方案.md
Normal file
@@ -0,0 +1,447 @@
|
||||
# 智能体聊天助手性能优化方案
|
||||
|
||||
## 一、当前性能瓶颈分析
|
||||
|
||||
### 1. 主要瓶颈识别
|
||||
|
||||
#### 🔴 **最大瓶颈:LLM API 调用(串行执行)**
|
||||
|
||||
当前工作流包含多个 LLM 节点,**串行执行**:
|
||||
1. **意图理解节点** (`llm-intent`) - 约 1-2 秒
|
||||
2. **问题回答节点** (`llm-question`) - 约 2-5 秒
|
||||
3. **格式化回复节点** (`llm-format`) - 约 1-2 秒
|
||||
|
||||
**总耗时**:约 **4-9 秒**(取决于 LLM API 响应速度)
|
||||
|
||||
#### 🟡 **次要瓶颈:前端轮询机制**
|
||||
|
||||
- 当前轮询间隔:**500ms**
|
||||
- 每次轮询需要 2 个 API 请求(状态 + 详情)
|
||||
- 在 5 秒的执行时间内,会产生 **20 次请求**
|
||||
|
||||
#### 🟢 **较小瓶颈:Redis 查询和数据库写入**
|
||||
|
||||
- Redis 查询:通常 < 10ms(可忽略)
|
||||
- 数据库日志写入:可能影响性能(但已在 Celery 中异步处理)
|
||||
|
||||
### 2. 性能测试数据
|
||||
|
||||
```
|
||||
单次对话执行时间分解:
|
||||
├─ 开始节点: ~1ms
|
||||
├─ 查询记忆: ~5ms (Redis)
|
||||
├─ 合并上下文: ~1ms
|
||||
├─ 意图理解: ~1500ms (LLM API)
|
||||
├─ 意图路由: ~1ms
|
||||
├─ 问题回答: ~3000ms (LLM API)
|
||||
├─ 合并回复: ~1ms
|
||||
├─ 更新记忆: ~5ms (Redis)
|
||||
├─ 格式化回复: ~1500ms (LLM API)
|
||||
└─ 结束节点: ~1ms
|
||||
总计: ~6015ms (约6秒)
|
||||
```
|
||||
|
||||
## 二、优化方案
|
||||
|
||||
### 方案 1:LLM 调用优化 ⭐⭐⭐⭐⭐
|
||||
|
||||
#### 1.1 并行执行可并行的 LLM 节点
|
||||
|
||||
**问题**:当前 `llm-format` 节点必须等待 `llm-question` 完成,但实际上可以优化。
|
||||
|
||||
**优化方案**:合并 `llm-question` 和 `llm-format` 节点
|
||||
|
||||
```python
|
||||
# 修改 llm-question 节点的 prompt,直接生成格式化好的回复
|
||||
prompt = """你是一个知识渊博、乐于助人的AI助手。请回答用户的问题。
|
||||
|
||||
用户问题:{{user_input}}
|
||||
对话历史:{{memory.conversation_history}}
|
||||
意图分析:{{output}}
|
||||
|
||||
请提供:
|
||||
1. 直接、准确的答案
|
||||
2. 必要的解释和说明
|
||||
3. 如果问题不明确,友好地询问更多信息
|
||||
|
||||
请以自然、易懂的方式回答,长度控制在200字以内。直接输出回答内容,确保回复自然、流畅,无需额外格式化。"""
|
||||
```
|
||||
|
||||
**效果**:减少 1 个 LLM 调用,节省 **1-2 秒**
|
||||
|
||||
#### 1.2 使用流式响应(Streaming)
|
||||
|
||||
**当前**:等待完整响应后才返回
|
||||
|
||||
**优化**:使用流式响应,边生成边返回
|
||||
|
||||
```python
|
||||
# backend/app/services/llm_service.py
|
||||
async def call_llm_stream(
|
||||
self,
|
||||
prompt: str,
|
||||
provider: str = "openai",
|
||||
model: Optional[str] = None,
|
||||
**kwargs
|
||||
) -> AsyncIterator[str]:
|
||||
"""流式调用LLM"""
|
||||
if provider == "deepseek":
|
||||
client = self.deepseek_client
|
||||
response = await client.chat.completions.create(
|
||||
model=model or "deepseek-chat",
|
||||
messages=[{"role": "user", "content": prompt}],
|
||||
stream=True, # 启用流式
|
||||
**kwargs
|
||||
)
|
||||
async for chunk in response:
|
||||
if chunk.choices[0].delta.content:
|
||||
yield chunk.choices[0].delta.content
|
||||
```
|
||||
|
||||
**效果**:
|
||||
- 用户感知延迟降低 **50-70%**
|
||||
- 首字响应时间从 3 秒降至 **0.5-1 秒**
|
||||
|
||||
#### 1.3 LLM 响应缓存
|
||||
|
||||
**场景**:相同或相似的问题可以复用之前的回答
|
||||
|
||||
```python
|
||||
# 在 cache-query 节点后添加缓存检查
|
||||
# 使用问题的 hash 作为缓存 key
|
||||
import hashlib
|
||||
|
||||
question_hash = hashlib.md5(user_input.encode()).hexdigest()
|
||||
cache_key = f"llm_response_{question_hash}"
|
||||
|
||||
# 检查缓存
|
||||
cached_response = redis_client.get(cache_key)
|
||||
if cached_response:
|
||||
return cached_response # 直接返回,节省 LLM 调用
|
||||
```
|
||||
|
||||
**效果**:重复问题响应时间从 5 秒降至 **< 100ms**
|
||||
|
||||
#### 1.4 减少 max_tokens 限制
|
||||
|
||||
**当前配置**:
|
||||
- `llm-intent`: max_tokens=1000
|
||||
- `llm-question`: max_tokens=2000
|
||||
- `llm-format`: max_tokens=500
|
||||
|
||||
**优化**:
|
||||
- `llm-intent`: max_tokens=200(意图识别不需要太长)
|
||||
- `llm-question`: max_tokens=1000(200字约500 tokens)
|
||||
- 删除 `llm-format` 节点
|
||||
|
||||
**效果**:减少 token 生成时间,节省 **0.5-1 秒**
|
||||
|
||||
### 方案 2:前端优化 ⭐⭐⭐⭐
|
||||
|
||||
#### 2.1 使用 WebSocket 替代轮询
|
||||
|
||||
**当前**:每 500ms 轮询一次,产生大量请求
|
||||
|
||||
**优化**:使用 WebSocket 实时推送执行状态
|
||||
|
||||
```typescript
|
||||
// frontend/src/composables/useWebSocket.ts
|
||||
// 已有 WebSocket 实现,但未在聊天组件中使用
|
||||
|
||||
// 修改 AgentChatPreview.vue
|
||||
import { useWebSocket } from '@/composables/useWebSocket'
|
||||
|
||||
const { status, result, connect, disconnect } = useWebSocket(execution.id)
|
||||
|
||||
watch(result, (newResult) => {
|
||||
if (newResult && !replyAdded) {
|
||||
replyAdded = true
|
||||
messages.value.push({
|
||||
role: 'agent',
|
||||
content: extractReply(newResult),
|
||||
timestamp: Date.now()
|
||||
})
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
**效果**:
|
||||
- 减少 90% 的 HTTP 请求
|
||||
- 实时性提升(延迟从 500ms 降至 < 100ms)
|
||||
- 服务器负载降低
|
||||
|
||||
#### 2.2 智能轮询(自适应间隔)
|
||||
|
||||
如果无法使用 WebSocket,可以优化轮询策略:
|
||||
|
||||
```typescript
|
||||
// 动态调整轮询间隔
|
||||
let pollingInterval = 500 // 初始 500ms
|
||||
let consecutiveNoChange = 0
|
||||
|
||||
const checkStatus = async () => {
|
||||
const oldStatus = lastStatus
|
||||
const newStatus = await getStatus()
|
||||
|
||||
if (oldStatus === newStatus) {
|
||||
consecutiveNoChange++
|
||||
// 如果连续3次状态未变化,增加轮询间隔
|
||||
if (consecutiveNoChange >= 3) {
|
||||
pollingInterval = Math.min(pollingInterval * 1.5, 2000) // 最大2秒
|
||||
}
|
||||
} else {
|
||||
consecutiveNoChange = 0
|
||||
pollingInterval = 500 // 重置为初始值
|
||||
}
|
||||
|
||||
setTimeout(checkStatus, pollingInterval)
|
||||
}
|
||||
```
|
||||
|
||||
**效果**:减少 30-50% 的无效请求
|
||||
|
||||
### 方案 3:工作流优化 ⭐⭐⭐
|
||||
|
||||
#### 3.1 简化工作流结构
|
||||
|
||||
**当前流程**:
|
||||
```
|
||||
开始 → 查询记忆 → 合并上下文 → 意图理解 → 意图路由 →
|
||||
[5个分支] → 合并回复 → 更新记忆 → 格式化回复 → 结束
|
||||
```
|
||||
|
||||
**优化流程**:
|
||||
```
|
||||
开始 → 查询记忆 → 合并上下文 → 意图理解 → 意图路由 →
|
||||
[5个分支,直接生成最终回复] → 更新记忆 → 结束
|
||||
```
|
||||
|
||||
**关键修改**:
|
||||
- 删除 `llm-format` 节点
|
||||
- 在各个分支节点中直接生成格式化好的回复
|
||||
- 删除 `merge-response` 节点(如果只有一个分支被激活)
|
||||
|
||||
**效果**:减少 1-2 个节点执行,节省 **1-2 秒**
|
||||
|
||||
#### 3.2 条件优化:跳过不必要的节点
|
||||
|
||||
**场景**:如果用户只是简单问候,不需要完整的问题回答流程
|
||||
|
||||
```python
|
||||
# 在 switch-intent 节点后,对于 greeting 意图
|
||||
# 可以直接使用模板回复,跳过 LLM 调用
|
||||
|
||||
if intent == "greeting":
|
||||
# 使用预定义模板
|
||||
response = "你好!很高兴见到你,有什么我可以帮助你的吗?"
|
||||
# 跳过 llm-greeting 节点
|
||||
else:
|
||||
# 正常执行 LLM 节点
|
||||
response = await llm_question(...)
|
||||
```
|
||||
|
||||
**效果**:简单场景响应时间从 5 秒降至 **< 1 秒**
|
||||
|
||||
### 方案 4:缓存优化 ⭐⭐⭐
|
||||
|
||||
#### 4.1 对话历史截断
|
||||
|
||||
**问题**:对话历史过长会增加 LLM prompt 长度,影响响应速度
|
||||
|
||||
**优化**:只保留最近 N 条对话
|
||||
|
||||
```python
|
||||
# 在 cache-update 节点中
|
||||
conversation_history = memory.conversation_history[-20:] # 只保留最近20条
|
||||
```
|
||||
|
||||
**效果**:
|
||||
- 减少 prompt 长度,节省 **0.2-0.5 秒**
|
||||
- 降低 token 消耗
|
||||
|
||||
#### 4.2 智能摘要
|
||||
|
||||
**更高级的方案**:将旧对话压缩为摘要
|
||||
|
||||
```python
|
||||
# 如果对话历史超过50条,生成摘要
|
||||
if len(conversation_history) > 50:
|
||||
# 保留最近20条
|
||||
recent_history = conversation_history[-20:]
|
||||
# 将前面的对话压缩为摘要
|
||||
old_history = conversation_history[:-20]
|
||||
summary = await llm_summarize(old_history) # 异步生成摘要
|
||||
conversation_history = [{"role": "system", "content": summary}] + recent_history
|
||||
```
|
||||
|
||||
**效果**:在保持上下文的同时,减少 prompt 长度
|
||||
|
||||
### 方案 5:数据库优化 ⭐⭐
|
||||
|
||||
#### 5.1 异步日志写入
|
||||
|
||||
**当前**:每个节点执行后立即写入日志
|
||||
|
||||
**优化**:批量写入日志
|
||||
|
||||
```python
|
||||
# 收集日志,定期批量写入
|
||||
log_buffer = []
|
||||
async def flush_logs():
|
||||
if log_buffer:
|
||||
db.bulk_insert_mappings(ExecutionLog, log_buffer)
|
||||
db.commit()
|
||||
log_buffer.clear()
|
||||
|
||||
# 每100ms或每10条日志刷新一次
|
||||
```
|
||||
|
||||
**效果**:减少数据库写入次数,提升 **5-10%** 性能
|
||||
|
||||
#### 5.2 减少日志详细程度
|
||||
|
||||
**生产环境**:只记录关键日志(错误、警告)
|
||||
|
||||
```python
|
||||
# 根据环境变量控制日志级别
|
||||
if settings.DEBUG:
|
||||
logger.setLevel(logging.DEBUG)
|
||||
else:
|
||||
logger.setLevel(logging.WARNING) # 只记录警告和错误
|
||||
```
|
||||
|
||||
**效果**:减少日志 I/O,提升 **2-5%** 性能
|
||||
|
||||
## 三、实施优先级
|
||||
|
||||
### 🔥 **高优先级(立即实施)**
|
||||
|
||||
1. **删除 llm-format 节点** ⭐⭐⭐⭐⭐
|
||||
- 实施难度:低
|
||||
- 效果:节省 1-2 秒
|
||||
- 预计时间:30 分钟
|
||||
|
||||
2. **优化 max_tokens 配置** ⭐⭐⭐⭐
|
||||
- 实施难度:低
|
||||
- 效果:节省 0.5-1 秒
|
||||
- 预计时间:15 分钟
|
||||
|
||||
3. **对话历史截断** ⭐⭐⭐⭐
|
||||
- 实施难度:低
|
||||
- 效果:节省 0.2-0.5 秒 + 降低 token 消耗
|
||||
- 预计时间:30 分钟
|
||||
|
||||
### 🟡 **中优先级(近期实施)**
|
||||
|
||||
4. **使用 WebSocket 替代轮询** ⭐⭐⭐⭐
|
||||
- 实施难度:中
|
||||
- 效果:提升实时性,减少服务器负载
|
||||
- 预计时间:2-3 小时
|
||||
|
||||
5. **简化工作流结构** ⭐⭐⭐
|
||||
- 实施难度:中
|
||||
- 效果:节省 1-2 秒
|
||||
- 预计时间:1-2 小时
|
||||
|
||||
6. **智能轮询(如果不用 WebSocket)** ⭐⭐⭐
|
||||
- 实施难度:低
|
||||
- 效果:减少 30-50% 无效请求
|
||||
- 预计时间:1 小时
|
||||
|
||||
### 🟢 **低优先级(长期优化)**
|
||||
|
||||
7. **流式响应** ⭐⭐⭐⭐⭐
|
||||
- 实施难度:高
|
||||
- 效果:显著提升用户体验(首字响应时间降低 50-70%)
|
||||
- 预计时间:4-6 小时
|
||||
|
||||
8. **LLM 响应缓存** ⭐⭐⭐
|
||||
- 实施难度:中
|
||||
- 效果:重复问题响应时间 < 100ms
|
||||
- 预计时间:2-3 小时
|
||||
|
||||
9. **条件优化(跳过不必要节点)** ⭐⭐⭐
|
||||
- 实施难度:中
|
||||
- 效果:简单场景响应时间 < 1 秒
|
||||
- 预计时间:2-3 小时
|
||||
|
||||
## 四、预期效果
|
||||
|
||||
### 优化前
|
||||
- **平均响应时间**:5-6 秒
|
||||
- **首字响应时间**:3-4 秒
|
||||
- **HTTP 请求数**:20+ 次/对话
|
||||
|
||||
### 优化后(实施高优先级方案)
|
||||
|
||||
- **平均响应时间**:**3-4 秒**(提升 40%)
|
||||
- **首字响应时间**:**2-3 秒**(提升 25%)
|
||||
- **HTTP 请求数**:**2-5 次/对话**(减少 75%)
|
||||
|
||||
### 优化后(实施所有方案)
|
||||
|
||||
- **平均响应时间**:**1.5-2.5 秒**(提升 60%)
|
||||
- **首字响应时间**:**0.5-1 秒**(提升 75%,使用流式响应)
|
||||
- **HTTP 请求数**:**1-2 次/对话**(使用 WebSocket)
|
||||
|
||||
## 五、具体实施步骤
|
||||
|
||||
### 步骤 1:快速优化(30 分钟)
|
||||
|
||||
```bash
|
||||
# 1. 修改工作流配置,删除 llm-format 节点
|
||||
# 2. 优化各 LLM 节点的 max_tokens
|
||||
# 3. 添加对话历史截断逻辑
|
||||
```
|
||||
|
||||
### 步骤 2:前端优化(2-3 小时)
|
||||
|
||||
```bash
|
||||
# 1. 在 AgentChatPreview.vue 中集成 WebSocket
|
||||
# 2. 替换轮询逻辑
|
||||
# 3. 测试实时性
|
||||
```
|
||||
|
||||
### 步骤 3:高级优化(可选,4-6 小时)
|
||||
|
||||
```bash
|
||||
# 1. 实现流式响应
|
||||
# 2. 添加 LLM 响应缓存
|
||||
# 3. 优化工作流结构
|
||||
```
|
||||
|
||||
## 六、监控指标
|
||||
|
||||
实施优化后,建议监控以下指标:
|
||||
|
||||
1. **响应时间分布**
|
||||
- P50(中位数)
|
||||
- P95(95% 分位数)
|
||||
- P99(99% 分位数)
|
||||
|
||||
2. **LLM 调用时间**
|
||||
- 各节点的平均调用时间
|
||||
- Token 消耗
|
||||
|
||||
3. **前端指标**
|
||||
- 首字响应时间(TTFB)
|
||||
- 完整响应时间
|
||||
- HTTP 请求数量
|
||||
|
||||
4. **服务器负载**
|
||||
- CPU 使用率
|
||||
- 内存使用率
|
||||
- 数据库连接数
|
||||
|
||||
## 七、注意事项
|
||||
|
||||
1. **流式响应**:需要修改前端 UI,支持逐步显示文本
|
||||
2. **缓存策略**:需要考虑缓存失效和更新机制
|
||||
3. **向后兼容**:优化不应破坏现有功能
|
||||
4. **测试覆盖**:每个优化都需要充分测试
|
||||
|
||||
---
|
||||
|
||||
**文档版本**:v1.0
|
||||
**创建时间**:2024年
|
||||
**维护人员**:AI Assistant
|
||||
Reference in New Issue
Block a user