# PR #38096 完整报告

- 仓库：`vllm-project/vllm`
- 标题：[Core][KV Connector] Remove use of num_cached_tokens in error handling
- 合并时间：2026-03-26 02:20
- 原文链接：http://prhub.com.cn/vllm-project/vllm/pull/38096

---

## 执行摘要
本次 PR 对 vLLM 调度器中处理 KV 缓存加载失败的关键函数进行了重构，核心是通过引入 `num_scheduled_tokens` 参数，移除了对 `num_cached_tokens` 的依赖，从而统一了同步与异步加载场景下已计算令牌数的处理逻辑。这是一次旨在简化代码、消除特殊分支并为后续优化铺路的内部重构，对最终用户透明，但涉及核心错误恢复路径，建议相关模块开发者关注其设计思路。

## 功能与动机
该变更的主要动机是简化调度器中 KV 缓存无效块处理的逻辑。根据 PR body 的描述，原先的 `_update_requests_with_invalid_blocks()` 函数内部，对于同步加载和异步加载请求，需要分别使用 `request.num_cached_tokens` 和 `request.num_computed_tokens` 来计算受影响的令牌范围，这使得“同步共享块的情况显得特殊”。重构的目标是消除这种差异，使逻辑更统一。此外，这次重构也被明确表述为后续工作（#37460）的铺垫，旨在解决预填充缓存统计中可能出现的“Counters can only be incremented by non-negative amounts”错误报告问题。

## 实现拆解
所有变更集中在 `vllm/v1/core/sched/scheduler.py` 文件：
1. **接口变更**：`_update_requests_with_invalid_blocks()` 和 `_handle_invalid_blocks()` 函数新增了一个 `num_scheduled_tokens: dict[str, int]` 参数。调用方 `update_from_output` 在调用 `_handle_invalid_blocks` 时，将原本用于其他目的的 `num_scheduled_tokens` 字典传递了下去。
2. **核心计算逻辑统一**：在 `_update_requests_with_invalid_blocks` 函数中，原先的条件分支被替换为单一计算：
    ```python
    req_num_computed_tokens = (request.num_computed_tokens - num_scheduled_tokens.get(req_id, 0))
    ```
 这个计算的意义是：从请求“总共已计算的令牌数”中，减去“本轮已调度但可能因块加载失败而尚未真正计算 / 缓存的令牌数”，从而得到“当前已成功计算并（可能）缓存的令牌数”。

3. **状态更新同步**：后续在需要重置 `request.num_computed_tokens` 的地方（主要是在处理涉及共享块的情况时），原先的赋值 `request.num_computed_tokens = request.num_cached_tokens` 被替换为 `request.num_computed_tokens = req_num_computed_tokens`，确保了状态与上述新计算逻辑的一致性。

## 评论区精华
1. **关于性能的深度探讨**：`gemini-code-assist[bot]` 提出了一个细粒度的性能优化点：“新分配的空无效块，如果直接 `free()` 可能比走驱逐流程开销更小”。作者 `markmc` 对此进行了思考和澄清，指出在“不同步传输且不重新计算”的场景下，仍需要驱逐所有后续块（包括为新调度令牌分配的块）。经过重新审视代码，他最终结论是“修改前和修改后，我们都在驱逐所有后续块 ... 这很好”。这体现了对极端场景下资源管理精确性的关注和权衡。
2. **追求简洁的实现**：审阅者 `orozery` 在 Issue 评论中直指核心：“这个变更看起来比它需要的更复杂 ... 我们不能只是简单地替换那段代码吗？”，并给出了一个更简洁的修改建议。作者 `markmc` 欣然接受了这个反馈，回应道：“好的，公平。我进行了一些更深度的重构，但如果那有价值，可以稍后再做。” 这直接影响了最终 PR 的形态，使其成为一个更聚焦、风险更低的改动。这种以简洁和清晰度为优先的代码审查文化值得肯定。

## 风险与影响
**风险**：主要风险集中于新引入的 `req_num_computed_tokens` 计算逻辑。如果上游传递的 `num_scheduled_tokens` 字典不准确（如缺失某些请求的条目或数值错误），将直接导致对受影响令牌范围的误判，可能引发缓存块错误释放或请求状态异常。此外，尽管移除条件分支简化了代码，但也要求新的统一逻辑必须正确处理所有原先被特殊对待的场景（尤其是同步加载与块共享的组合情况）。

**影响**：本次变更属于 **内部重构**，旨在提升代码质量和为未来工作奠基。对于终端用户，只要逻辑正确，应无任何功能或性能上的感知变化。对于开发团队，它降低了 `scheduler.py` 中特定模块的认知复杂度，并使后续针对预填充缓存统计的改进（#37460）更容易实施。从近期 PR 历史看，团队持续在对调度器、KV 连接器等相关模块进行打磨和增强（如 #36869, #38048），本次重构符合这一技术演进脉络。

## 关联脉络
- **前置依赖**：此 PR 明确基于 `orozery` 在 PR #35223 中的工作（提交 f02a5c80），是已有技术路线的延续。
- **后续铺垫**：PR body 中多次强调，此变更是为 **#37460**（重构预填充缓存统计）扫清障碍，显示出团队有规划地解决“计数器负增”这一系统性问题的步骤。
- **领域关联**：同期的 PR #36869 为 Mooncake KV 连接器添加了新功能，表明“KV 连接器”与“调度器”的交互是当前持续投入和改进的重点领域之一。本次重构虽小，但正是该领域底层基础设施稳健性建设的一部分。