Files
qiming/qimingclaw/crates/agent-electron-client/docs/optimization/WARMUP-RUNTIME-CACHE-2026-03-31.md

195 lines
6.0 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.
# Warmup Runtime Config 缓存优化
**日期**: 2026-03-31
**类型**: 性能优化
**影响范围**: 新会话首消息响应(连续创建新会话场景)
---
## 1. 问题背景
### 1.1 现象
连续新开会话时,前 1-2 个会话的 warmup 复用始终 miss日志出现
```
[EngineWarmup] ⚠️ 运行时配置不兼容,不复用 warmupmodel,apiKey,baseUrl,apiProtocol
warmupModel: '(none)',
warmupBaseUrl: '(none)',
warmupApiKeySet: false,
warmupApiProtocol: '(none)',
```
### 1.2 实测数据20:52 ~ 20:565 个连续新会话)
| # | 时间 | Warmup | Init(ms) | TTFT(ms) | 总响应(ms) |
|---|------|--------|----------|----------|-----------|
| 1 | 20:52 | ❌ coldruntime 不兼容) | 5,705 | 9,507 | 10,389 |
| 2 | 20:53 | ❌ coldruntime 不兼容) | 6,097 | 6,236 | 14,107 |
| 3 | 20:54:15 | ✅ reuse | 1,513 | 6,089 | 20,938 |
| 4 | 20:54:50 | ✅ reuse | 1,523 | 5,983 | 20,510 |
| 5 | 20:55:20 | ✅ reuse | 1,701 | 5,964 | 39,269 |
前两个会话 warmup miss 导致额外 ~2-4s 冷启动开销。
### 1.3 根因
**配置构建时机差异**
```
init() 阶段:
baseConfig = { workspaceDir, engine, env }
↓ 缺少 model/apiKey/baseUrl/apiProtocol
chat() 阶段:
effectiveConfig = {
...baseConfig,
model: mp?.model, ← 来自 model_provider
apiKey: mp?.api_key, ← 来自 model_provider
baseUrl: mp?.base_url, ← 来自 model_provider
apiProtocol: mp?.api_protocol, ← 来自 model_provider
mcpServers: freshMcpServers,
}
```
- `baseConfig``init()` 时设置,不含运行时配置
- `effectiveConfig` 在每次 `chat()` 请求时动态构建
- `warmup.start(baseConfig)` 用的是不含 runtime config 的 baseConfig
- `tryReuse()` 检测到 runtime config 不一致 → 回退冷启动
**影响的三个调用路径**
| 调用点 | 触发场景 | seedConfig | 结果 |
|--------|---------|-----------|------|
| `warmup.start(this.baseConfig)` | `init()` | ❌ 无 | warmup 缺 runtime config |
| `warmup.respawn(this.baseConfig)` | 会话结束 | ❌ 无 | 同上 |
| `ensureQimingWarmup({reason: "get_or_create_guard"})` | 引擎不存在 | ❌ 无 | 同上 |
| `ensureQimingWarmup({seedConfig: {...}})` | warmup 被消费后 refill | ✅ 有 | 正常 |
| `ensureQimingWarmup({seedConfig: {...}})` | 冷启动后 refill | ✅ 有 | 正常 |
**结论**:只有 refill 路径能命中init / respawn / guard 三个路径永远 miss。
---
## 2. 修复方案
### 2.1 核心思路
`EngineWarmup` 内部缓存最近一次请求的 runtime config`model/apiKey/baseUrl/apiProtocol`),在 `start()` 创建 warmup 时自动应用缓存值。
### 2.2 改动清单
| 文件 | 改动 |
|------|------|
| `engineWarmup.ts` | 新增 `lastRuntimeConfig` 缓存 + `cacheRuntimeConfig()` 方法 |
| `unifiedAgent.test.ts` | 新增 2 个测试场景 |
### 2.3 具体改动
#### `engineWarmup.ts`
**新增字段**
```typescript
private lastRuntimeConfig: Pick<
AgentConfig,
"model" | "apiKey" | "baseUrl" | "apiProtocol"
> | null = null;
```
**`start()` 应用缓存**
```typescript
const warmupConfig: AgentConfig = {
...baseConfig,
engine: WARMUP_ENGINE_TYPE,
...(this.lastRuntimeConfig
? {
model: this.lastRuntimeConfig.model || baseConfig.model,
apiKey: this.lastRuntimeConfig.apiKey || baseConfig.apiKey,
baseUrl: this.lastRuntimeConfig.baseUrl || baseConfig.baseUrl,
apiProtocol: this.lastRuntimeConfig.apiProtocol || baseConfig.apiProtocol,
}
: {}),
// ...
};
```
**`tryReuse()` 三条路径均缓存**
- Runtime mismatch → `cacheRuntimeConfig(effectiveConfig)` → 后续 refill 用新缓存
- Warmup hit → `cacheRuntimeConfig(effectiveConfig)` → 保持缓存新鲜
- Warmup not ready → `cacheRuntimeConfig(effectiveConfig)` → 同上
**`dispose()` 清理**
```typescript
this.lastRuntimeConfig = null;
```
---
## 3. 配置变更时的行为
缓存的 runtime config 与新请求配置不一致时:
```
warmup (缓存 model=A, key=X)
新请求 (model=B, key=Y)
tryReuse() 检测不兼容 → 回退冷启动 (~2s)
cacheRuntimeConfig(B, Y) → 更新缓存
refill warmup 用 (B, Y) 创建
后续请求 (B, Y) → 命中 ✅
```
**最多影响一次会话**(配置变更的那次),后续自动纠正。这与修改前行为一致——修改前是每次都 miss修改后仅配置变更时 miss 一次。
---
## 4. 预期效果
| 场景 | 修改前 | 修改后 |
|------|--------|--------|
| 首次 init → 首次会话 | miss → 冷启动 ~3.7s | miss → 冷启动 ~3.7s(首次无缓存) |
| 首次会话后 → 第二次会话 | **miss** → 冷启动 ~2.6s | **命中** → ~1.5s(省 ~1.1s |
| 连续新会话(配置不变) | 每次前 1-2 个 miss | 仅首次 miss后续均命中 |
| 配置变更 | miss → 冷启动 | miss → 冷启动 → 自动纠正缓存 |
**关键指标改善**
- 连续新会话 Init 耗时5,705ms / 6,097ms → **~1,500ms**reduced ~70%
- 首消息端到端(不含 LLM TTFT~8s → **~6s**(节省 warmup 冷启动开销)
---
## 5. 测试覆盖
### 5.1 新增测试
| 测试 | 验证内容 |
|------|---------|
| `warmup runtime config 缓存:首次 miss 后 refill 命中后续请求` | 首次 miss → 缓存 → refill 带缓存 → 第二次命中 |
| `warmup runtime config 缓存:配置变更时回退冷启动并更新缓存` | configA miss → refill(A) → configB miss → refill(B) → B 命中 |
### 5.2 回归测试
全部 54 个 warmup 相关测试通过,包括:
- 运行时配置缺失回退冷启动(原有测试不受影响)
- MCP 配置不兼容回退冷启动
- qimingcode 连续命中补仓
- destroy() 清理 warmup
- persistent MCP 归一化
---
## 6. 相关文档
- [首消息性能优化报告 (2026-03-23)](./FIRST-MESSAGE-PERF-OPT-2026-03-23.md)
- [macOS 首消息性能测试报告 (2026-03-31)](./MACOS-FIRST-MESSAGE-PERF-REPORT-2026-03-31.md)
- [Session 复用修复 (2026-03-24)](./SESSION-REUSE-FIX-2026-03-24.md)
---
*文档生成时间: 2026-03-31*