Files
agentic-pd-hybrid/docs/KVC_ROUTER_ALGORITHM.md
kzlin 37e9caa431 docs(kvc): production-decision reframe + formal router algorithm spec
After the critic-agent audit, V2_DEEP_ANALYSIS had drifted into an
audit-grade "5 wins / 1 loss / 3 draws" framing that mistook KVC's
deliberate design motifs (cache concentration via session affinity;
prefill-GPU idle as TTFT-stability trade-off) for "comparison
unfairness." This commit corrects the framing back to a production-
decision lens and adds a paper-track formal specification of the
router algorithm.

V2_DEEP_ANALYSIS_ZH.md changes:
- §0 TL;DR: lead with "online coding agent serving should pick
  KVC 1P3D"; the only real cost is TTFT p99 long-tail (3x DP) from
  the 8.3% mooncake reseed path, mitigable with real RDMA.
- §4 restructured into three buckets:
    real costs (TTFT p99 tail, abort accounting now fixed),
    counter-arguments to the critic (cache concentration and idle
      prefill GPU are design intent, not deficits),
    methodology to-do (naive-1P3D control, v2 N>=2 determinism).
- §6 replaces "5/1/3 rescoring" with production decision rationale:
  KVC wins on 6 latency/TTFT metrics + lower failure rate; pays
  TTFT p99 tail; lists workloads where DP would reverse the call.
- §8 decision points: D1 recommends Yes (accept v2 as milestone);
  D8 added: paper motif "KVC trades P idle for TTFT stability."

KVC_ROUTER_ALGORITHM.md (new, paper-track, Chinese narrative + English
algorithm boxes / variable names / theorems for direct paper reuse):
- Problem formulation, system model, full notation
- Algorithm 1 Route: lexicographic-tuple scoring on
    (overlap+alpha*sticky, sticky, -inflight, -assigned)
- Algorithm 2 Admit: D-worker autonomous admission deciding
    Direct / Seed / Reseed / reject (with reason)
- Algorithm 3 Dispatch: end-to-end orchestration with reset-on-success
    (the v2-specific fix that eliminates v1's self-amplifying thrashing)
- Theorem 1 (no permanent starvation) and Theorem 2 (fast-path
    determinism), each with a proof sketch
- Comparison table vs vanilla pd-disagg / DP cache-aware
- Anti-patterns ("what KVC explicitly is NOT")
- Open questions for reviewers
- Suggested paper citation phrasing
- Appendix A: algorithm-step to source-file:line crosswalk

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:29:18 +08:00

355 lines
20 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.

# KVC-Router面向 Agentic 多轮 LLM Serving 的 Session-Aware 调度算法
**性质**:论文级形式化规范——用于团队内部对齐 + 外部读者 onboarding。
**对象**:项目团队(统一术语);论文 reviewer算法定义
**最近更新**2026-05-11。
本文给出本项目所开发的 **KVCache-Centric Router**(以下简称 "KVC-Router")调度算法的形式化、与实现无关的定义。本文设计为可直接被论文引用,并作为"KVC 到底在谈论什么调度算法"的标准回答。
对应的参考实现位于:
- `src/agentic_pd_hybrid/policies.py``KvAwarePolicy``RoutingState`
- `src/agentic_pd_hybrid/replay.py` — orchestrationadmission RPC、reset-on-success、fallback chain
- `third_party/sglang/python/sglang/srt/managers/scheduler.py` — D-worker 端的 admission 决策
---
## 1. 问题定义
我们要服务一群多轮 agentic LLM session如 Claude Code、Codex、Cursor 等 coding agent底层是异构 worker 池,分成:
- **Prefill workers**`P`GPU 常驻的模型副本,针对长输入 prompt 的 batched prefill 做了优化。
- **Decode workers**`D`GPU 常驻的模型副本,配备 session-aware KV cache"SessionAwareCache"),具备:(i) 跨 turn 保留 session 的 KV 状态;(ii) 在本地已缓存的 prefix 上做 append-prefill无需绕回 `P`
在一个 agent turn 内,请求 `r` 到达时其对话 prefix 已经从前序 turn 累积;**新增**的 tokens工具输出、用户消息等构成小规模 **append**。驱动 KVC 设计的根本观察是:
> 当 prefix KV **已经驻留在将要解码该请求的 D worker 上**,请求的 first-token 延迟仅由 *append* 大小决定(典型 O(10²10³) tokens而非完整 prompt 大小(典型 O(10⁴10⁵) tokens
Router 的工作就是最大化满足上述条件的请求占比,同时尊重容量约束、不造成 session 无限饿死。
### 1.1 优化目标
给定来自 `S` 个 session 的请求流 `R = (r_1, r_2, ...)`,最小化 SLO 加权的 TTFT 与端到端延迟混合:
```
minimize E[ w_ttft · TTFT(r) + w_lat · E2E_Latency(r) ]
subject to capacity[d] ≤ K_d 对任意 D worker d 在任意时刻 t,
没有 session 被永久拒绝服务.
```
参考实现中通过 measurement 隐式取 `w_ttft = 1, w_lat = 1`per-D KV 池预算 `K_d` 取 SGLang 启动时上报的 `max_total_num_tokens`
---
## 2. 系统模型与记号
### 2.1 集合
| 符号 | 含义 |
|---|---|
| `P = {p₁, …, p_|P|}` | Prefill worker 池 |
| `D = {d₁, …, d_|D|}` | Decode worker 池 |
| `S` | Session 标识符集合(由上游 agent runtime 分配) |
| `H` | KV block hash 的全集(本实现中每 `BLOCK_TOKEN_BUDGET = 24` tokens 对应一个 hash |
### 2.2 请求
一个请求 `r` 是一个元组:
```
r = ⟨ s(r), t(r), prefix_hashes(r), append_len(r), input_len(r) ⟩
```
其中:
- `s(r) ∈ S` — session id
- `t(r) ∈ ` — 该 session 内的 turn index0 = 首轮)
- `prefix_hashes(r) ⊂ H` — 覆盖请求输入 prefix 的 block hash 集合
- `append_len(r) ∈ ` — 新到达、**不在** `prefix_hashes(r)` 中的 token 数
- `input_len(r) = (|prefix_hashes(r)| · 24) + append_len(r)` — 总 token 数
### 2.3 Router 状态 (`Σ`)
Router 跨请求维护的全局状态:
| 字段 | 类型 | 语义 |
|---|---|---|
| `resident[d]` | `set[H]` | Router 估计的 D `d` 当前 SessionAwareCache 中常驻的 block hash 集合router 端估计,真值在 worker 上) |
| `pin[s]` | `D {⊥}` | Session `s` 最近一次成功服务的 D`⊥` 表示从未见过 |
| `inflight[d]` | `` | 当前已派发给 `d` 但尚未完成的请求数 |
| `assigned[d]` | `` | 累计派发到 `d` 的路由决策次数(负载 tie-breaker |
| `rejects[s,d]` | `` | per-(session, D) 的 admission 拒绝计数v2 引入的 migration 机制) |
### 2.4 超参数
| 符号 | 默认值 | 描述 |
|---|---|---|
| `α``sticky_bonus` | 1 | 匹配 `pin[s]` 的 D 在评分中获得的 bonus |
| `τ_reject``migration_reject_threshold` | 3 | (s, d) 被拒绝达此次数后d 对 s 进入 blacklist |
| `τ_append``kvcache_direct_max_uncached_tokens` | 8192v2 | 走 Direct-to-D 路径允许的最大 append 长度 |
| `K_d` | 取自 SGLang `max_total_num_tokens` | per-D 的 KV 池预算 |
| `ρ` | 0.95 | 容量高水位线(隐式由 SGLang 强制) |
| `ε`(最大 fallback 重试数) | `|D| - 1` | router 在退化到 vanilla PD-disagg 之前最多探测几个 D |
### 2.5 路由结果
路由决策 `δ(r)` 取以下四种之一:
| Mode | 含义 | KV transfer |
|---|---|---|
| `Direct(d)` | r 完全在 D `d` 上执行D 在其常驻 KV 上做 append | **无**(快路径) |
| `Seed(d)` | Session 首轮P 做完整 prefillKV 通过 mooncake 传到 `d` | 完整 input |
| `Reseed(d)` | Session 之前在某个 D' 上,但已不再常驻;按 Seed 处理 | 完整 input |
| `Fallback(p, d)` | Vanilla pd-disagg 路径(其它 D 均被 blacklist 或拒绝) | 完整 input |
---
## 3. 算法
KVC-Router 由三个相互配合的过程组成:
- **Algorithm 1 (`Route`)**router 端基于评分的候选选择。
- **Algorithm 2 (`Admit`)**D-worker 端的 admission 决策(在 D scheduler 中执行,非 router
- **Algorithm 3 (`Dispatch`)**:端到端 orchestration把 Route + Admit + reset-on-success 串起来。
### 3.1 Algorithm 1`Route(r, Σ)` — 基于评分的候选选择
```
输入:请求 r状态 Σ
输出:候选 d* ∈ D若所有 D 都被过滤后仍无候选,退化分支兜底返回最少被拒的 D
1. blacklisted ← { d ∈ D : Σ.rejects[s(r), d] ≥ τ_reject }
2. C ← D blacklisted // 候选 D 集合
3. if C = ∅ : // 退化
4. return argmin_{d ∈ D} Σ.rejects[s(r), d] // 选最少被拒的 D
5. for each d ∈ C :
6. overlap(d) ← |prefix_hashes(r) ∩ Σ.resident[d]|
7. sticky(d) ← 1 if Σ.pin[s(r)] = d else 0
8. infl(d) ← Σ.inflight[d]
9. assn(d) ← Σ.assigned[d]
10. score(d) ← ⟨ overlap(d) + α·sticky(d), // 主项
sticky(d), // tie-1
infl(d), // tie-2负载小者占优
assn(d) ⟩ // tie-3
11. return argmax_{d ∈ C} score(d) // 按字典序最大
```
**说明**
- 评分是 **4 元组按字典序比较**,不是单个标量——这样避免在不同维度之间调权重。
- 第 10 行的主项 `overlap + α·sticky` 同时奖励 KV 复用与 session stickiness。取 `α=1``overlap` 以 block24 tokens为单位时**任何一次 hash 命中都压制纯 sticky 的候选**。
- 第 14 行的 blacklist 过滤防止永久绑死在已饱和的 D 上;与 Algorithm 3 的 reset-on-success 配合,限定了 migration 频率。
### 3.2 Algorithm 2`Admit(d, r, M, K)` — D-worker admission 决策
在 D worker 自己的 scheduler 内部执行(非 router这是 **KVC 的机制核心**:每个 D 自治判断能否把 `r` 当作 Directappend-only服务还是必须改走 P 路径。
```
输入D worker d请求 rd 上本地常驻的 session 集合 M_dKV 池预算 K_d
输出⟨can_admit ∈ {True, False}, mode ∈ {Direct, Seed, Reseed, ⊥}, reason⟩
1. used_tokens ← Σ_{s' ∈ M_d} resident_tokens(s', d) // D 自己的 bookkeeping
2. cap_ok ← (used_tokens + input_len(r)) ≤ ρ · K_d // 高水位线 ρ ≈ 0.95
3. if s(r) ∈ M_d : // session 在 d 上有常驻
4. if append_len(r) ≤ τ_append and cap_ok :
5. return ⟨True, Direct, ∅⟩ // → 快路径
6. elif append_len(r) > τ_append :
7. return ⟨False, ⊥, "real-large-append"⟩
8. else :
9. return ⟨False, ⊥, "no-d-capacity"⟩
10. else : // session 在 d 上无常驻
11. if cap_ok :
12. mode ← Seed if t(r) = 0 else Reseed
13. return ⟨True, mode, ∅⟩ // → 经 P 做 KV seeding
14. else :
15. return ⟨False, ⊥, "session-not-resident-no-capacity"⟩
```
**说明**
- 该过程通过同步 HTTP RPC`/admit_direct_append`)从 router 调用。RPC 阻塞直到 D scheduler 给出权威答复——这是 v5 引入的 **"worker-mode admission"**,替换了更早的 router-端容量估算(系统性偏乐观)。
- reason 字符串被回传给 router用于(i) 在 Algorithm 3 中驱动 fallback chain(ii) 标注 `execution_mode` 字段便于分析。
### 3.3 Algorithm 3`Dispatch(r, Σ)` — 端到端 orchestration
```
输入:请求 r状态 Σ
输出:执行模式 μ ∈ {Direct, Seed, Reseed, Fallback}
1. retries ← 0
2. tried ← ∅
3. while retries < ε :
4. d* ← Route(r, Σ \ {对 tried 中的 d 已 bump 过的 rejects})
5. if d* = ⊥ : break // 无候选
6. resp ← Admit(d*, r) // RPC 到 D scheduler
7. if resp.can_admit :
8. Σ.rejects[s(r), d*] ← 0 // ◀ reset-on-successv2
9. Σ.pin[s(r)] ← d*
10. Σ.inflight[d*] ← Σ.inflight[d*] + 1
11. if resp.mode = Direct :
12. 在 d* 上完整执行 rappend-prefill + decode
13. return Direct
14. else : // Seed 或 Reseed
15. p ← round_robin_next(Σ, P)
16. 在 p 上做 r 的 prefill
17. 经 mooncake 把 KV(r) 从 p 传到 d*
18. 在 d* 上 decode r
19. return resp.mode
20. else :
21. Σ.rejects[s(r), d*] ← Σ.rejects[s(r), d*] + 1
22. tried ← tried {d*}
23. retries ← retries + 1
24.
25. // ε 次重试耗尽——退化 Fallback 到 vanilla pd-disagg
26. p ← round_robin_next(Σ, P)
27. d ← round_robin_next(Σ, D)
28. 通过 ⟨p, d⟩ 走 pd-disagg(r)
29. return Fallback
```
**维持的关键不变量**
1. **不会静默过载**:一个 D 永不接受会让 `used_tokens > ρ · K_d` 的请求Algorithm 2 第 2 行)。
2. **不存在永久饿死**:对任意 session `s`,只要曾在某 D `d*` 上成功过一次,之后 `Σ.rejects[s, d*] = 0`Algorithm 3 第 8 行)。因此 blacklist 计数器不会对仍在某处成功获得服务的 session 累积——这阻止了 **v1 的 thrashing 病理**:原本 blacklist 计数器单调增长 + 退化 fallback 形成自放大的 round-robin 死循环。
3. **migration 有界**:一个 session 从 D `a` 迁移到 D `b` 必须经过连续 `τ_reject` 次在 `a` 上失败、期间无任何成功。每个 session 生命周期内的最坏 migration 次数 ≤ `(|D| 1) · τ_reject`
### 3.4 Reset-on-success为什么这是关键修复v1 → v2 演化)
v1 实现**省略了** Algorithm 3 第 8 行——一旦 `(s, d)` 累积 `τ_reject` 次拒绝d 对该 session **整个 run 永久 blacklist**。实测Migration v1`docs/MIGRATION_V1_FINDINGS_ZH.md`)触发了自放大的失效模式:
```
session s 在 d 上稳定服务 70 个 turn
↓ 瞬时 burst 让 d 短暂饱和
3 次到 d 的 admission 被拒 → rejects[s,d] = 3 → d 对 s 永久 blacklist
↓ s 迁到 d'd' 也在负载中 → 被拒 → blacklist
↓ d'' 同理
所有 D 都 blacklist → 退化 fallback round-robin → 每次重试都 bump 一次计数器
→ s 永远在 D 之间 thrashing每次都丢失 KV residency
```
reset-on-success 关上了这个回路:只要 `s` 在任一 d 上真正完成一次 Direct针对该 session 的 blacklist 立刻清零。该机制只对**持续性**(不是瞬时性)容量压力触发。
---
## 4. 性质
### 4.1 Theorem 1在有界 ε 下无永久饿死)
*假设 `τ_reject ≥ 1` 且每个 D worker 的容量非零。则对任意能在 admission 时容下的 session `s`Algorithm 3 在至多 `|D| · τ_reject` 次重试内返回 `{Direct, Seed, Reseed}` 之一;之后任意一次 Direct 成功即可清空 `s` 的所有 blacklist。*
**证明概要**每次循环要么成功return、要么恰好让某个 `rejects[s, d]` 计数器 +1第 21 行)。经过 `|D| · τ_reject` 次迭代后,每个 D 要么对 `s` 已被 blacklist`Route` 第 1 行会过滤),要么已成功(已终止)。在所有 D 都被 blacklist 的饱和点,`Route` 第 3 行返回最少被拒的 D打破对称性强制取得进展。∎
### 4.2 Theorem 2fast-path 命中下限)
*假设 session `s` 在 D `d` 上已积累 KV residency `R_s ⊂ H`,且在某 turn `t > 0` 提交的请求 `r` 满足 `prefix_hashes(r) ⊆ R_s`、`append_len(r) ≤ τ_append` 且 admission 容量充足。则 Algorithm 3 将 `r` 路由为 Direct(d)。*
**证明概要**:由 Algorithm 1`overlap(d) = |R_s|` 取得最大值;结合 `α·sticky(d) ≥ 1`d 的字典序得分严格高于任何 `prefix_hashes(r) ⊈ R_{s,d'}` 的 d'。故 `Route` 返回 d。`Admit(d, r)` 进入 `s ∈ M_d ∧ append ≤ τ_append ∧ cap_ok` 分支,返回 Direct。∎
这是 **支持架构设计的机制级保证**:只要 residency、append 大小、容量三者同时成立,快路径就被**确定性地**选中KVC 在典型场景下的 TTFT 优势是结构性属性,不是概率性。
### 4.3 复杂度
每个请求:
- `Route``O(|D|)`(每个候选 D 算一次 score。生产规模下 `|D| ≤ 8`,主要开销在 Python 层,≪ 1 ms。
- `Admit`D scheduler 内部 O(1)(查自己的 bookkeeping无全局锁
- Router 层的单请求总开销:`O(|D|)` 计算 + 1 次到目标 D 的 HTTP RTTloopback 亚毫秒,跨机数据中心约 1 ms
---
## 5. 与 baseline 的对比
| 性质 | Vanilla pd-disagg | DPcache-aware | **KVC-Router**(本文) |
|---|---|---|---|
| P/D 分离 | 是(`|P| + |D|` GPU | 否(每个 worker fused P+D | 是 |
| 跨 turn cache locality | 无(每个请求都 P→D 传 KV | 仅在单 fused worker 内部走 hash prefix 路由 | session 钉在某 D 上,本地 append-prefill |
| 同 session cache 集中度 | 无 | 散到 `|D|` 个 worker每个占 1/|D| | 集中在一个 D整段常驻 |
| 最坏 turn-2 prefill 工作量 | 完整 input 经 P→mooncake→D | 在目标 worker 上做完整 prefill带 prefix cache 命中) | 本地 `append_len ≤ τ_append` tokens |
| 容量感知 admission | 无router 盲发) | 隐式靠 worker 队列深度 | 显式的 per-D `Admit()` 决策 |
| Migration 机制 | N/A | N/A | 带 reset-on-success 的 reject-counter blacklist |
| Idle prefill 成本 | 是——P 永远在算 | 否 | 是——P 只在 cache miss 时启用(本工作 SWE-Bench 评测下约 8% 请求) |
KVC 的关键架构权衡:**用 P 端 GPU 闲置换 D 端 TTFT 稳定性**。在 per-session cache 复用率高的 agentic workload 上Inferact 的 Codex trace 报告 94.2% cache hit我们的 SWE-Bench replay 实测 91.6% Direct 命中),这个交换显著有利。在 session 短或 cache hit 低的 workload 上权衡反转、DP 胜出。
---
## 6. 符号速查表
| 符号 | 含义 |
|---|---|
| `P, D` | Prefill / Decode worker 池 |
| `s(r), t(r)` | 请求 r 的 session id 与 turn index |
| `prefix_hashes(r)` | r 输入 prefix 的 KV block hash |
| `append_len(r)` | r 中新增(未缓存)部分的 token 数 |
| `Σ.resident[d]` | Router 对 d 缓存 block 集合的估计 |
| `Σ.pin[s]` | session s 最近一次成功的 D |
| `Σ.rejects[s,d]` | per-(s,d) 的 admission 拒绝计数 |
| `α` | sticky bonus 权重(默认 1 |
| `τ_reject` | migration 阈值(默认 3 |
| `τ_append` | Direct 路径允许的 max append 大小v2 默认 8192 |
| `K_d` | D worker d 的 KV 池预算 |
| `ρ` | 容量高水位(默认 0.95 |
| `ε` | fallback 重试上限(默认 `|D| 1` |
| `δ(r)` | 路由决策:`Direct(d)` / `Seed(d)` / `Reseed(d)` / `Fallback(p, d)` |
---
## 7. 本工作评测中实际使用的默认参数
| 参数 | 取值 | 说明 |
|---|---|---|
| `|P|, |D|` | 1, 31P3D 配置) | 单机 4× H100 80GB |
| `α` | 1 | |
| `τ_reject` | 3 | |
| `τ_append` | 8192 | v2 调优后取值v0/v1 用 2048 |
| `K_d` | 92104 tokens | SGLang 按 `mem_fraction_static=0.835` 自动算出 |
| `ρ` | 隐式 ~0.95 | 由 SGLang 的 `max_total_num_tokens` 强制 |
| `ε` | 2 | `|D| 1 = 2` |
| 每次 run 的 session 数 | 52 | SWE-Bench 50sess trace |
| 总请求数 | 4449 | |
| Time-scale | 1.0(真实 trace 时序) | |
| 并发 | 32 | |
---
## 8. Anti-patternsKVC **不**是什么)
1. **KVC 不仅仅是 kv-aware routing**。DP 和 KVC 都可以跑 `kv-aware` policyKVC 在此之上加了三件事:(i) session 钉定,(ii) worker 端 admission(iii) 带 reset-on-success 的 migration。如果在比较 "KVC vs DP" 时缺这三个要素的任何一个,**测的就不是 KVC 与 DP 的差异**。
2. **KVC 在 policy 项里不直接感知容量**`Route` 不查 per-D 容量;容量感知完全经由 `Admit` 拒绝来传导。我们刻意做了这层分层——把容量判断放进 `Route` 会引入"换 D"的决策空间,导致 orphan KV 滞留问题。
3. **KVC 不保证 load balance**。一个 session 若能舒服地装在某个 D 上,可能永远钉在那里,而其它 D 大部分时间空闲。在低容量压力下这是设计意图;高压力下 Theorem 1 的 migration 会触发再均衡。
4. **`Fallback` 不是"降级路径"**。它和 vanilla pd-disagg 请求结构性等价延迟特征相同。KVC 的价值在于让 Fallback 占比在典型 agentic workload 下 ≪ 10%。
---
## 9. 公开问题reviewer 关注点)
以下问题在当前评测中尚未解决,主动列出以保持透明:
1. **Session 钉定相对于纯 P/D disaggregation 的边际贡献是多少?** 需要 `naive 1P3D` 对照实验vanilla SGLang xPyD不带 KVC 层)——仓库当前缺失(见 `docs/V2_DEEP_ANALYSIS_ZH.md §4.7`)。
2. **Algorithm 3 在更高压下行为如何**(例如 ts=10 加速、session 数 ≫ |D|·K_d/peak_input当前 ts=1 评测对应真实 agentic 区间,但算法在更高负载下的鲁棒性未经实验验证。
3. **真 RDMA 下的 reseed 代价**:本次评测的 37 s reseed 延迟主要来自 mooncake 在 TCP loopback 上的 transfer 开销。算法结构与传输无关,但 TTFT p99 长尾预期在 IB/RoCE 下缩短约 10×。待独立验证。
4. **v2 代码路径下的确定性**v0 代码库的 ts=1 N=3 categorical 确定性已经证实;新增的 reset-on-success 分支与 threshold=8192 路径未被独立 re-validate。两个额外的 N=1 run 即可解决。
---
## 10. 论文引用建议
论文中提到本算法时建议表述:
> "We use the KVC-Router scheduling algorithm (Algorithms 13 of [our paper], formally defined in our supplementary materials). The router selects a decode worker by lexicographic scoring on `(overlap+α·sticky, sticky, inflight, assigned)` (Algorithm 1), defers the admission decision to the chosen worker via a synchronous RPC (Algorithm 2), and maintains a per-(session, decode worker) rejection counter that is reset on every successful Direct admission (Algorithm 3). This last detail — reset-on-success — is what distinguishes our v2 from the unstable v1 implementation that exhibits self-amplifying session thrashing."
---
**附录 A — 算法步骤到代码实现的对照**
| 算法步骤 | 文件 | 符号 |
|---|---|---|
| `Route` 第 511 行 | `policies.py:189202` | `KvAwarePolicy.select` 内层循环 |
| `Route` 第 14 行blacklist 过滤 + 退化分支) | `policies.py:182187, 204211` | `migration_reject_threshold``select` 的 fallback |
| `Admit` | `third_party/sglang/python/sglang/srt/managers/scheduler.py` | `handle_admit_direct_append_request` |
| `Dispatch` 第 8 行reset-on-success | `replay.py: _run_request` | finish 路径中的 reset |
| `Dispatch` 第 21 行(记录 reject | `replay.py: _run_request` | `state.record_admission_reject(...)` |
| 超参数 `τ_append` | CLI flag | `--kvcache-direct-max-uncached-tokens` |
| 超参数 `τ_reject` | CLI flag | `--kvcache-migration-reject-threshold` |