# Progress Log: nanovllm 多请求状态污染问题 ## Session: 2026-01-12 ### 资源分配 | 资源 | 分配 | |------|------| | **GPU** | **1** (严格限制,不可更改) | ### 任务目标 研究 nanovllm CPU offload 模式下多请求之间状态影响导致准确率下降的问题。 --- ### 10:00 - 启动分析 **完成**: - [x] 读取 `docs/offload_accuracy_issue.md` 了解问题背景 - [x] 激活 Serena MCP 项目 - [x] 获取关键组件符号概览 **关键文件已分析**: - `nanovllm/kvcache/offload_engine.py` - OffloadEngine 类 - `nanovllm/kvcache/hybrid_manager.py` - HybridKVCacheManager 类 - `nanovllm/engine/model_runner.py` - ModelRunner 类 - `nanovllm/engine/llm_engine.py` - LLMEngine 类 - `nanovllm/engine/scheduler.py` - Scheduler 类 --- ### 10:15 - 深入代码分析 **分析的方法**: | 方法 | 文件 | 发现 | |------|------|------| | `OffloadEngine.__init__` | offload_engine.py:40-145 | 初始化所有 buffer,无 reset 方法 | | `deallocate` | hybrid_manager.py:218-244 | 只清理逻辑块,不清理 OffloadEngine | | `clear_decode_tracking` | hybrid_manager.py:538-549 | 清理 tracking 字典,但未被调用 | | `run_layerwise_offload_decode` | model_runner.py:867-1057 | 包含 decode buffer 读写逻辑 | | `generate` | llm_engine.py:114-151 | 请求循环逻辑 | | `postprocess` | scheduler.py:93-99 | 调用 deallocate | **关键发现 #1**: OffloadEngine 没有 reset() 方法 **关键发现 #2**: deallocate() 没有调用 clear_decode_tracking() **关键发现 #3**: decode_buffer 在请求间不清理,可能导致状态污染 --- ### 10:30 - 根因定位 **确认的问题**: 1. **decode buffer 残留** - 位置: `offload_engine.decode_k_buffer`, `decode_v_buffer` - 写入: `model_runner.py:1010-1013` - 读取: `model_runner.py:969-976` - 问题: 旧请求的 KV 数据可能被新请求读取 2. **tracking 字典未清理** - 位置: `hybrid_manager._decode_start_pos`, `_prefill_len` - 问题: 使用 `id(seq)` 作为 key,可能重用 3. **缺失的清理调用** - `clear_decode_tracking()` 在 `deallocate()` 中未被调用 --- ### 10:45 - 创建规划文件 **创建的文件**: - [x] `task_plan.md` - 完整的任务规划和阶段 - [x] `findings.md` - 详细的代码分析发现 - [x] `progress.md` - 本文件 --- ### 11:00 - Sequential Thinking 深入分析 **使用 sequential thinking 验证分析结果**: - 确认 deallocate() 确实没有调用 clear_decode_tracking() - 分析 _decode_start_pos 和 _prefill_len 字典的生命周期 - 确定 id(seq) 重用是问题的触发条件 --- ### 11:15 - 完成规划文件 **更新的文件**: - [x] `task_plan.md` - 添加完整的 debug 方案和实施计划 - [x] `findings.md` - 详细的代码分析和修复方向 - [x] `progress.md` - 更新到当前进度 --- ## 下一步 (待用户确认) **执行顺序**: 1. **实施修复** - 修改 `deallocate()` 添加 `clear_decode_tracking(seq)` 2. **快速验证** - 20 样本连续执行(一次调用,不重启框架)→ 目标 20/20 3. **完整验证** - 100 样本 → 目标 100/100 (最终验收) 4. **防御性修复** (可选) - 添加 `OffloadEngine.on_sequence_finished()` **核心修改** (一行代码): ```python # hybrid_manager.py:deallocate() 末尾添加 self.clear_decode_tracking(seq) ``` **验收标准**: | 测试 | 样本数 | 通过要求 | |------|--------|----------| | 快速验证 | 20 | 20/20 (100%) | | 完整验证 | 100 | 100/100 (100%) | --- ## 错误记录 | 时间 | 错误 | 解决方案 | |------|------|----------| | 10:05 | Serena MCP 未激活 | 调用 activate_project | --- ## 文件修改记录 | 文件 | 操作 | 状态 | |------|------|------| | task_plan.md | 创建+更新 | 完成 | | findings.md | 创建 | 完成 | | progress.md | 创建+更新 | 完成 | --- ## 分析结论 **重要澄清**: nanovllm offload 模式**不支持 batch**,只能单个 request 顺序执行。问题出在**请求切换**时状态清理不完整。 **根本原因已确认**: `deallocate()` 没有调用 `clear_decode_tracking()`,导致 `_decode_start_pos` 和 `_prefill_len` 字典残留,当 Python 对象 ID 重用时,新请求会错误地使用旧请求的配置。 **修复方案已设计**: 在 `deallocate()` 末尾添加 `self.clear_decode_tracking(seq)` 调用。 --- ## 关键理解 问题不是 "batch 处理",而是: ``` Request A 完成 → deallocate(A) [状态未完全清理] → Request B 开始 → B 读到 A 的残留状态 ```