Skip to content

03 · Sequence:请求的状态机

03 · Sequence:请求的状态机

先建立直觉:RUNNING 不是“缓存已完成”

一个请求已经是 RUNNING,并且 Scheduler 已经安排了 token,为什么 num_cached_tokens 仍可能是 0?

先观看这段动画。它跟随同一个 Sequence,依次展示 WAITING → RUNNING → FINISHED,以及 Scheduler 写下计划、ModelRunner 执行、KV Cache 提交进度的先后关系。

先记住这一句num_scheduled_tokens 是这一轮的工作计划;模型实际执行并完成后,num_cached_tokens 才会增长。两者在某一刻可能相等,但它们不是同一个概念。

Sequence 不只是 token 列表

把 Sequence 看成一个请求的随身档案。它同时保存原始 prompt、后来生成的 completion、当前总 token 数、缓存进度、本轮工作计划、block table 与采样参数。这些信息集中在上游 nanovllm/engine/sequence.pySequence 对象中。

三个状态

text
WAITING → RUNNING → FINISHED
  • WAITING:尚未获得本轮执行资格,通常也还没有完整的 block table。
  • RUNNING:已分配缓存资源,参与 Prefill 或 Decode。
  • FINISHED:遇到 EOS 或生成长度上限,随后释放 block。

四种长度不要混淆

字段 / 属性含义由谁在什么时候改变
num_tokens当前总 token 数,prompt + completion创建时写入 prompt;Decode 后由 append_token() 增加。
num_prompt_tokens初始 prompt 长度,创建后不变创建 Sequence 时固定。
num_cached_tokens已经写入 KV Cache 的 token 数模型执行与后处理完成后更新。
num_scheduled_tokens本轮被 Scheduler 选中的 token 数Scheduler 在本轮决策时写下计划。

特别注意:scheduled 不等于 cached。Scheduler 先计划,ModelRunner 执行成功后,postprocess 才更新 cached 数量。

block table 是逻辑地址表

Sequence.block_table 保存该请求使用的物理 KV block id。token 的逻辑位置通过:

text
logical_block = token_position // block_size
physical_block = block_table[logical_block]
slot = physical_block * block_size + offset

映射到 KV Cache 的具体槽位。下一章 Scheduler 和后续 BlockManager 都依赖这张表。

去哪里看代码

不要一次打开所有引擎文件。先从 Sequence.__init__ 看状态和计数的初值,再看 append_token() 如何只更新 token 档案。随后沿着教程的调用链追踪:

text
LLMEngine.step → Scheduler.schedule → ModelRunner.run → Scheduler.postprocess

这条链路分别负责本轮计划、真实执行、token 追加和缓存进度提交。动画中的代码卡片是概念化锚点,不是逐行源码复刻。

动手验证:预测 → 运行 → 解释

先扮演一次 Sequence,再点击实验按钮。你要关注的不是“状态是否变了”,而是哪一个字段在这个时间点应该变化

步骤你要做什么你应该观察什么
1. 预测装载 8-token 的预设 Sequence,选择“调度后哪个字段仍为 0”。RUNNING 不会自动让 cached 增加。
2. 运行依次点击“计划 Prefill”和“提交缓存”;随后执行一次 Decode。scheduled 先增长,cached 后增长;Decode 只让 completion 前进一步。
3. 解释核对预测,并用“状态、计划、执行、提交”四个词解释日志。字段变化由不同的引擎阶段负责,而不是由一个按钮同时完成。
HTML INTERACTIVE LAB03 · Sequence:请求的状态机
单独打开 ↗
课后习题等待完成

`num_scheduled_tokens` 与 `num_cached_tokens` 的正确关系是什么?

动手任务

先在互动实验中完成一次“计划 Prefill → 提交缓存 → Decode”,再写一句话说明三个动作各自改变了哪个字段。

下一节:Scheduler

社区教程,与 nano-vLLM 上游项目无官方隶属关系。