Files
qiming/qimingclaw/crates/agent-electron-client/docs/optimization/FIRST-MESSAGE-PERF-OPT-2026-03-23.md

232 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 首消息性能优化报告
**日期**: 2026-03-23
**优化目标**: 降低首消息冷启动Agent 响应延迟
**优化前**: ~1662ms
**优化后**: ~349ms
**提升幅度**: **79%**
---
## 1. 问题分析
### 1.1 原始性能数据
首消息 `ensureEngineForRequest` 耗时分解:
```
ensureEngine 总耗时: 1662ms
├── parseCtxServers: 5ms
├── syncMcp: 1315ms ← 主要瓶颈79%
└── getOrCreate: 342ms
├── memory: 231ms
└── init: 102ms
```
### 1.2 瓶颈定位
| 阶段 | 耗时 | 占比 | 说明 |
|------|------|------|------|
| `syncMcpConfigToProxyAndReload` | 1315ms | 79% | MCP 代理同步,首消息必须等待 |
| `ensureMemoryReadyForSession` | 231ms | 14% | Memory 服务初始化 |
| `engine.init` | 102ms | 6% | ACP 引擎进程启动 |
| 其他 | 14ms | 1% | 配置解析、MCP 提取等 |
---
## 2. 优化方案
### 2.1 优化一MCP Proxy Bridge 预热
**原理**: 在服务 `init()` 时后台预热 MCP proxy bridge避免首消息同步阻塞。
**代码位置**: `src/main/services/engines/unifiedAgent.ts`
```typescript
/**
* 🚀 性能优化:后台预热 MCP proxy bridge
* 在 init() 时调用,避免首包 syncMcp 阻塞 ~1.3s
*/
private warmupMcpBridge(): void {
(async () => {
try {
const { syncMcpConfigToProxyAndReload } = await import("../packages/mcp");
// 使用空配置预热(仅启动默认服务如 chrome-devtools
await syncMcpConfigToProxyAndReload({});
log.info("[UnifiedAgent] ✅ MCP proxy bridge 预热完成");
} catch (err) {
log.warn("[UnifiedAgent] MCP proxy bridge 预热失败:", err);
}
})().catch(() => {});
}
```
**调用时机**: 在 `init()` 方法末尾调用与其他预热任务Engine 预热、Memory 预热)并行执行。
### 2.2 优化二syncMcp 与 ensureMemoryReady 并行执行
**原理**: 当 MCP 配置变更且需要创建新引擎时,将 `syncMcp``ensureMemoryReady` 并行执行。
**代码位置**: `src/main/services/engines/unifiedAgent.ts``ensureEngineForRequest()`
```typescript
// 🚀 性能优化:只有在 MCP 配置变更时才调用 syncMcpConfigToProxyAndReload
// 同时,如果需要创建新引擎(无现有引擎),并行执行 ensureMemoryReady
const needCreateEngine = !existingEngine || !existingEngine.isReady;
let memoryReadyPromise: Promise<void> | null = null;
if (mcpChanged) {
const syncStart = Date.now();
try {
const { syncMcpConfigToProxyAndReload } = await import("../packages/mcp");
const syncPromise = syncMcpConfigToProxyAndReload(requestMcpServersEarly);
// 🚀 性能优化:如果需要创建新引擎,并行执行 ensureMemoryReady
if (needCreateEngine && memoryService.isInitialized()) {
memoryReadyPromise = memoryService.ensureMemoryReadyForSession()
.then(() => {
log.debug(`⏱️ [PERF] ensureMemoryReady 并行完成: ${Date.now() - syncStart}ms`);
})
.catch((err) => {
log.warn("[UnifiedAgent] Memory sync check failed:", err);
});
}
await syncPromise;
} catch (e) {
log.warn("[UnifiedAgent] 动态同步 MCP 配置到 proxy 失败:", e);
}
}
```
**`getOrCreateEngine` 方法修改**:
```typescript
async getOrCreateEngine(
projectId: string,
effectiveConfig: AgentConfig,
memoryReadyPromise?: Promise<void> | null, // 新增参数
): Promise<AcpEngine> {
// ...
// 🚀 性能优化:如果已有并行的 memoryReadyPromise直接等待它
if (memoryReadyPromise) {
await memoryReadyPromise;
} else if (memoryService.isInitialized()) {
await memoryService.ensureMemoryReadyForSession();
}
// ...
}
```
### 2.3 已有优化(复用)
以下优化在之前已实现,本次优化复用:
1. **快速路径 1**: 无配置变更 → 直接返回现有引擎7ms
2. **快速路径 2**: MCP 未变更 → 跳过 syncMcp
3. **Engine 预热池**: 预热 claude-code 和 qimingcode 引擎
4. **Memory 预热**: `init()` 时后台执行 `ensureMemoryReadyForSession()`
---
## 3. 测试对照
### 3.1 测试环境
- **应用版本**: 0.9.1
- **测试时间**: 2026-03-23 17:53
- **测试场景**: 重启应用后发送首条消息
### 3.2 优化前日志2026-03-20
```
ensureEngine 总耗时: 1662ms
├── parseCtxServers: 5ms
├── syncMcp: 1315ms
└── getOrCreate: 342ms
├── memory: 231ms
└── init: 102ms
```
### 3.3 优化后日志2026-03-23
```
[17:52:55] [info] 🔥 后台预热 Engine: claude-code
[17:52:55] [info] 🔥 后台预热 Engine: qimingcode
[17:52:55] [info] ✅ 预热 Engine 就绪,等待复用: claude-code
[17:52:56] [info] ✅ MCP proxy bridge 预热完成
[17:52:58] [info] ✅ 预热 Engine 就绪,等待复用: qimingcode
[17:53:34] 首消息请求到达
[17:53:34] [debug] ⏱️ [ensureEngine][PERF] 解析 context_servers 耗时: 6ms
[17:53:34] [info] ⏱️ [PERF] 走完整路径: 无现有引擎, MCP变更(新7个)
[17:53:34] [debug] ⏱️ [PERF] ensureMemoryReady 并行完成: 2ms
[17:53:34] [info] ⏱️ [PERF] syncMcp 完成: 耗时 2ms | 并行memory=true
[17:53:34] [debug] ⏱️ [ensureEngine][PERF] 提取 real MCP servers 耗时: 0ms
[17:53:34] [debug] ⏱️ [ensureEngine][PERF] ensureBridgeStarted(有MCP) 耗时: 0ms
[17:53:34] [debug] ⏱️ [getOrCreateEngine][PERF] 等待并行 ensureMemoryReady 完成: 231ms
[17:53:34] [debug] ⏱️ [getOrCreateEngine][PERF] engine.init 耗时: 105ms
[17:53:34] [info] ⏱️ [getOrCreateEngine][PERF] 总耗时: 336ms | 使用并行memory=true
[17:53:34] [info] ⏱️ [ensureEngine][PERF] 总耗时: 349ms | 并行优化=true
[17:53:34] [info] ⏱️ [HTTP][PERF] /computer/chat 总耗时: 362ms
```
### 3.4 性能对比表
| 指标 | 优化前 | 优化后 | 提升幅度 |
|------|--------|--------|----------|
| `syncMcp` | 1315ms | 2ms | **99.8%** ↓ |
| `ensureEngine` 总耗时 | 1662ms | 349ms | **79%** ↓ |
| `/computer/chat` 总耗时 | ~1700ms | 362ms | **79%** ↓ |
### 3.5 优化后耗时分解
```
ensureEngine 总耗时: 349ms
├── parseCtxServers: 6ms
├── syncMcp: 2ms ← 预热后从 1315ms 降至 2ms
├── extractReal: 0ms
├── ensureBridge: 0ms
└── getOrCreate: 341ms
├── memory: 231ms ← 与 syncMcp 并行执行
└── init: 105ms
```
---
## 4. 优化效果总结
### 4.1 关键收益
1. **MCP Proxy Bridge 预热**: 消除首消息 ~1.3s 阻塞
2. **并行执行**: Memory 准备与 MCP 同步重叠执行
3. **Engine 预热池**: 复用已启动的引擎进程
### 4.2 用户体验改善
| 场景 | 优化前 | 优化后 |
|------|--------|--------|
| 首消息响应 | ~1.7s | ~0.35s |
| 用户感知 | 明显延迟 | 接近即时 |
### 4.3 注意事项
1. **预热时机**: 所有预热任务在 `init()` 末尾启动,不阻塞应用启动
2. **内存占用**: 预热引擎会占用额外内存,但通过预热池容量限制(当前 1 个/类型)控制
3. **配置变更**: 如果首消息的 MCP 配置与预热配置差异较大,仍需同步,但比冷启动快
---
## 5. 相关文件
- `src/main/services/engines/unifiedAgent.ts` - 主优化文件
- `src/main/services/packages/mcp.ts` - MCP proxy 管理
- `src/main/services/packages/mcpHelpers.ts` - MCP 配置比较工具
## 6. 参考资料
- [ACP Engine 性能优化](./architecture/ACP-ENGINE-PERF-OPTIMIZATION.md)
- [深度性能研究报告](./DEEP-RESEARCH-PERF-REPORT-2026-03-20.md)