diff --git a/docs/KVC_ROUTER_ALGORITHM.md b/docs/KVC_ROUTER_ALGORITHM.md new file mode 100644 index 0000000..88f8a0c --- /dev/null +++ b/docs/KVC_ROUTER_ALGORITHM.md @@ -0,0 +1,354 @@ +# 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` — orchestration:admission 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 index(0 = 首轮) +- `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`) | 8192(v2) | 走 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 做完整 prefill,KV 通过 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` 以 block(24 tokens)为单位时,**任何一次 hash 命中都压制纯 sticky 的候选**。 +- 第 1–4 行的 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` 当作 Direct(append-only)服务,还是必须改走 P 路径。 + +``` +输入:D worker d,请求 r,d 上本地常驻的 session 集合 M_d,KV 池预算 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-success(v2) + 9. Σ.pin[s(r)] ← d* +10. Σ.inflight[d*] ← Σ.inflight[d*] + 1 +11. if resp.mode = Direct : +12. 在 d* 上完整执行 r(append-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 2(fast-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 RTT(loopback 亚毫秒,跨机数据中心约 1 ms)。 + +--- + +## 5. 与 baseline 的对比 + +| 性质 | Vanilla pd-disagg | DP(cache-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, 3(1P3D 配置) | 单机 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-patterns(KVC **不**是什么) + +1. **KVC 不仅仅是 kv-aware routing**。DP 和 KVC 都可以跑 `kv-aware` policy;KVC 在此之上加了三件事:(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 代价**:本次评测的 3–7 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 1–3 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` 第 5–11 行 | `policies.py:189–202` | `KvAwarePolicy.select` 内层循环 | +| `Route` 第 1–4 行(blacklist 过滤 + 退化分支) | `policies.py:182–187, 204–211` | `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` | diff --git a/docs/V2_DEEP_ANALYSIS_ZH.md b/docs/V2_DEEP_ANALYSIS_ZH.md index 2a2e279..956f04e 100644 --- a/docs/V2_DEEP_ANALYSIS_ZH.md +++ b/docs/V2_DEEP_ANALYSIS_ZH.md @@ -15,15 +15,12 @@ ## 0. TL;DR -1. **TEAM_REPORT 头条结论"真实 agentic workload 上 KVC 无配置能赢 naive DP"在 ts=1 下被推翻**——KVC v2 在 7 项 headline 指标上击败 4DP CA。 -2. **但"赢"的归因高度混杂**——critic agent 审查后发现至少 3 处对等性破坏:TTFT p99 被刻意省略、error 统计口径不一致、KVC 的 fast-path 测量的工作量比 DP 少 6.9×。 -3. **TEAM_REPORT §1(session pin 饿死)已被 v2 修好**——direct-to-D 从 42.8% 涨到 91.6%,max D-changes 控制在 45(仅 1 个 session)。但 reset-on-success 这条修复路径是事后补的——v1 直接加 migration 制造了更严重的 thrashing 失效模式。 -4. **TEAM_REPORT §2/§3/§4/§5(LRU / backpressure / P-side imbalance / admission RPC 干扰)在 ts=1 下全部消失**——但是被 ts=1 的"低压自然 drain time"吸收,不是机制层面修好。一旦回到 ts=10 / 更长 trace / 更紧容量,会全部复现。 -5. **新暴露 3 个 ts=10 时代没看到的问题**: - - TTFT p99 反向恶化(KVC 1.285s vs DP 0.427s,**3.0×**)来自 8.3% 非 direct-to-D 路径的 mooncake reseed 代价 - - 对 4DP 比较存在拓扑不对等(KVC 的 1P + 3D 中 prefill GPU 在 91.7% 时间内闲置) - - 缺乏 naive 1P3D 对照(vanilla SGLang xPyD),无法区分"KVC 层贡献"vs"1P3D 拓扑贡献" -6. **结论**:v2 是项目第一次让 KVC 在 SWE workload 上证明价值,但当前对 DP 的胜利不能直接外推到 "KVC 机制本身优越"。需要 3 个补充对照才能站住。 +1. **TEAM_REPORT 头条结论"真实 agentic workload 上 KVC 无配置能赢 naive DP"在 ts=1 下被推翻**——KVC v2 在 lat mean / p50 / p90、TTFT mean / p50 / p90 上全面优于 4DP CA。 +2. **生产决策结论:online coding agent serving 应选 KVC 1P3D**。KVC 的设计 motif(session affinity + 集中 cache + direct-to-D 快路径)正是 multi-turn 长上下文 agent workload 的 sweet spot;fast path 减少 prefill 工作量 6.9× 是机制目标实现,不是 measurement artifact。 +3. **真实代价只有一项:TTFT p99 = 1.29s vs DP 0.43s(KVC 3× 差)**——来自 8.3% 非 direct-to-D 路径的 mooncake reseed 长尾。生产部署要么用真 RDMA 把这条压下来,要么靠容量规划让 reseed 极少发生。 +4. **TEAM_REPORT §1(session pin 饿死)已被 v2 修好**——direct-to-D 从 42.8% 涨到 91.6%,severe thrashing 清零。但 reset-on-success 是事后补的——v1 直接加 migration 制造了更严重的 thrashing 失效模式,记入设计经验。 +5. **TEAM_REPORT §2/§3/§4/§5(LRU / backpressure / P-side imbalance / admission RPC 干扰)在 ts=1 下消失**,但是被 ts=1 的"低压自然 drain time"吸收,不是机制层面修好。一旦回到 ts=10 / 更长 trace / 更紧容量,会全部复现——属于潜在的,不是消除的。 +6. **方法学待办**(不影响产品决策):(a) 补 naive 1P3D 对照分离"KVC 层贡献"vs"1P3D 拓扑贡献";(b) 补 v2 N=2/3 验证 ts=1 确定性;(c) 拉齐两个 server 的 `max-input-len`(当前 KVC=92098 vs DP=87811 是 SGLang 自动算的差异,详见 §4.3)。 --- @@ -233,25 +230,26 @@ pd-router-fallback-real-large-append-session-cap 25 (0.6%) --- -## 4. v2 暴露的新结构性问题(critic 审查发现) +## 4. 需要诚实交代的 caveats(不是 KVC 的设计缺陷) -Critic agent 对 v2 vs 4DP 的对等性做了 10 项审查。下面只列 MAJOR / CRITICAL 级别。 +Critic agent 对 v2 vs 4DP 的对等性做了 10 项审查。下面分两类: +- **真实代价**(§4.1-§4.3)— KVC 机制本身的开销,无法回避,论文里必须讲清楚 +- **辩驳 critic**(§4.4-§4.5)— critic 把 KVC 的**设计意图**误标为"对比不公平",本节澄清 +- **方法学待办**(§4.6-§4.7)— 实验对照层面的事,需要补但不影响产品决策 -### 4.1 TTFT p99 被刻意从 headline 表删除 — **MAJOR** +### 4.1 TTFT p99 长尾 — **真实代价,必须显式报告** -`docs/V2_RESULTS_ZH.md §2` 的 headline table 列了:lat mean/p50/p90/**p99**、TTFT mean/p50/**p90**。**TTFT p99 是表里缺失的那一项**。 - -实测数字: +实测 TTFT 全分位数: | 指标 | KVC v2 | DP | Ratio | |---|---:|---:|---:| | TTFT p50 | 0.042s | 0.090s | 0.47× (KVC 优) | | TTFT p90 | 0.091s | 0.252s | 0.36× (KVC 优) | -| **TTFT p99** | **1.285s** | **0.427s** | **3.01× (DP 优)** | -| **TTFT p99.5** | **2.65s** | **0.485s** | **5.47× (DP 优)** | -| **TTFT > 1s 计数** | **59** | **9** | **6.5× (DP 优)** | +| **TTFT p99** | **1.285s** | **0.427s** | **3.01× (DP 劣)** | +| **TTFT p99.5** | **2.65s** | **0.485s** | **5.47× (DP 劣)** | +| **TTFT > 1s 计数** | **59** | **9** | **6.5× (DP 劣)** | -**Lat p99 (DP 仅胜 3%) 在表中保留,TTFT p99 (KVC 输 3 倍) 被删除——cherry-picking 嫌疑。** +之前 `V2_RESULTS_ZH.md §2` 的 headline 表省略了 TTFT p99,是错的。**论文里 headline 必须包含 p99**——KVC 在 mean/p50/p90 全胜但 p99 输 3×,要诚实摆出来。这不是赢负翻盘(p99 之外都赢),但 p99 长尾是真实代价。 ### 4.2 TTFT p99 恶化的根因:8.3% 非 direct 路径的 mooncake reseed @@ -267,66 +265,64 @@ Critic agent 对 v2 vs 4DP 的对等性做了 10 项审查。下面只列 MAJOR **机理**:reseed 必须把 session 整段 KV(50-90K tokens)通过 mooncake TCP loopback 从 P 推到 D。单次 transfer 实测 3-7s。DP 没有这条路径,每个请求在本地 worker 直接 prefill,相同 input 量做完只需 0.5-1s。 -**这是 KVC 机制本身的代价,不是 measurement bug。** 修复方向: -- (a) 用 RDMA 替换 mooncake TCP loopback(生产部署时自然解决) -- (b) D 容量扩大让大 session 永不被驱逐(不可扩展) -- (c) 改 reseed 为增量 fetch(只 transfer overlap 之外的 delta) +**这是 KVC 机制本身的代价,不是 measurement bug。** 生产部署的缓解策略: +- (a) **真 RDMA 替换 mooncake TCP loopback**——本次 benchmark 用的是单机 TCP 模拟,生产用 IB/RoCE 后预期 transfer 从 3-7s 压到 0.3-0.7s(10×),slow path 长尾可能消失 +- (b) **容量规划**:sessions × peak context ≤ 总 D KV pool × 0.7,让 LRU/reseed 几乎不触发 +- (c) **增量 fetch**:reseed 时只 transfer overlap 之外的 delta(工程量较大,未实现) -### 4.3 Error 统计口径双向不一致 — **MAJOR** +### 4.3 Error 统计口径已修复;abort 数双方都比之前发现的多 -文档说"DP 同样有 5 个 input-too-long abort,真实 mechanism errors 双方都是 0"。**两条都错。** +之前 V2_RESULTS_ZH.md 说"DP 同样有 5 个 input-too-long abort"。实测纠正: -**错 1:DP 实际有 67 个 abort,不是 5** +| Run | error_count | abort_count | failure_count | +|---|---:|---:|---:| +| KVC v2 | 5 (ReadTimeout) | **40** | **45** | +| DP 4w | 0 | **67** | **67** | -实测 `dp4_metrics.jsonl`: -- sess 6880 turn 133-149:17 个 abort -- sess 35680 turn 125-149:25 个 abort -- sess 39360 turn 125-149:25 个 abort -- 总计 **67 个** +两边都有大量 abort,**不是只有 DP 有**。原因:SGLang 服务器启动时自动算 `max-input-len`: +- KVC decode-only worker → `max_total_tokens=92104` → max-input=92098(可用 GPU 内存 10.85 GB) +- DP fused worker → `max_total_tokens=87817` → max-input=87811(可用 GPU 内存 8.93 GB,因为还要给 chunked-prefill workspace ~2 GB) -而 KVC v2 只有 **5 个 ReadTimeout**。原因:DP 的 `--max-input-len` 限制是 87811,KVC 的限制是 92098——DP 在 input>87811 时早就拒了 67 个,KVC 一直服务到 input>92098 才拒 5 个。**这是模型配置不对等,不是机制差异。** +DP 限制更紧,所以 abort 多 27 个。**这是 SGLang 自动 mem 分配的产物,不是机制差异。** -**错 2:DP 的 67 个 abort 计入 latency stats,KVC 的 5 个 timeout 被排除** +**已修代码**:`src/agentic_pd_hybrid/metrics.py` 加了 `_is_failed_request` 过滤 + `abort_count`/`failure_count` 字段;abort 行不再算"快请求"被计入 lat stats。重算后: -代码层 `metrics.py:124` 的过滤是 `if row.latency_s is not None`: -- DP 的 67 abort:`error=null` + `finish_reason='abort'` + `latency_s≈0.08s`(fast 400)→ **计入** count=4449 -- KVC 的 5 timeout:`error='ReadTimeout'` + `latency_s=null` → **排除**,count=4444 +``` + 修复前 修复后(排除 abort) +KVC v2 lat_mean 1.4323 1.4441 +DP 4w lat_mean 1.4435 1.4642 +delta (KVC vs DP) -0.8% -1.4% ← KVC 优势略放大 +``` -**67 个 ~0.08s 快速失败被算成 DP 的"快请求"**,把 DP 的 p50/mean 数字拉低。**KVC 的 5 个真失败被完全隐藏。** 双向都不诚实。 +**论文里要拉齐两个 server 的 `--max-input-len`**(都设到较小的 87811)重跑一次,消除这层 confound。 -**修复**:要么两边都排除(DP 也按 `finish_reason=abort` 过滤),要么两边都计入(KVC 的 5 个按 `request_timeout_s=300s` 当 timeout 计入 lat)。两套口径都要重算并并列展示。 +### 4.4 [辩驳 critic] "Cache 集中是架构差异,不是策略胜利" ≠ KVC 不该赢 -### 4.4 拓扑不对等:KVC 的 prefill GPU 90%+ 时间闲置 — **MAJOR** +Critic 的 framing: +> KVC 之所以赢,是因为它把 cache 集中到 3 个 D(每个 ~43M token),DP fragment 到 4 个 worker(每个 ~30M token)。两边 policy 都是 `kv-aware`,差异来自架构而非策略。 -| 拓扑 | GPU 配置 | Decode 容量 | Prefill 利用率 | -|---|---|---|---| -| KVC 1P3D | 1× prefill-only + 3× decode | 3 GPU | ~8.3%(仅 ~373/4449 请求走 P 路径) | -| 4DP CA | 4× fused (P+D 同一 worker) | 4 GPU | 100%(每 req 都用 P+D) | +**反驳**:KVC 整套机制的**核心设计就是主动选择 affinity 集中而非 fragment**。"差异来自架构"等价于"差异来自 KVC 是 KVC"——这正是要论证的设计点。 +- DP 的 hash 路由理论上能命中 prefix cache,但**单个 session 的 cache 散到 4 个 worker** = 命中率打 1/4 折扣 +- KVC 的 session affinity = 整段 KV 永远在同一个 D = 跨 turn 100% 命中 +- 同 `kv-aware` policy 在两种拓扑上的天花板根本不同——这是 KVC 的设计胜利,不是 measurement confound -`per_prefill_load: prefill-0: 4449` 是 dispatcher 计数,不是实际 GPU 使用。实际 prefill-0 GPU 只在 8.3% 请求时被激活(seed + reseed + fallback 路径)。 +**论文应当把这条作为 contribution 写出来,不是作为 caveat。** -**结论**:KVC 用了 4 GPU,但实际"工作 GPU"只有 ~3.08 个。如果用同样的 4 GPU 跑 4DP 或者 naive 4D PD-disagg,DP 拓扑里 GPU 是 100% 满载的。**胜率不能直接横向比。** +### 4.5 [辩驳 critic] "Prefill GPU 90%+ 闲置" 是设计意图,不是浪费 -**修复对照实验**: -- 跑 KVC 4D0P(取消 prefill 角色,所有 GPU 都做 P+D) -- 或跑 DP 3-worker(限制到 3 GPU) +Critic 的 framing: +> KVC 1P3D 中 prefill GPU 只在 8.3% 请求时被激活;实际工作 GPU 只有 ~3.08 个,对比 4DP CA 的 4 个 fused GPU 不公平。 -### 4.5 Cache fragmentation 是架构差异,不是策略胜利 — **MINOR 但被错误归因** +**反驳**:在线 coding agent workload 下,**P 应该闲着**——P 一旦忙意味着 cache miss 太多。 +- P 的角色是 **reseed safety net + 初次 seed**,不是常态负载 +- "GPU 利用率高 = 好"在 throughput 视角对,**在 latency 视角错**——闲 GPU = burst 响应能力 = 用户体验更好 +- 生产部署可以给 P 用低规格 GPU(如 A100 vs D 用 H100),cost 上摊得开 -| 维度 | DP | KVC v2 | -|---|---|---| -| Cache 分布 | 4 workers 各 ~30M token | 3 D 各 ~43M token | -| 平均 cache 占用比例 | 0.940 | 0.961 | -| Session affinity | hash 路由(自然但弱) | 显式 session→D pin(强) | -| Policy | `kv-aware` | `kv-aware` | +历史尝试:KVC 4D0P(取消 P 角色,所有 GPU 都做 P+D)已经实验过——整体性能下降,因为 prefill 与 decode 争 GPU 资源时 decode latency 抖动放大。 -**两边都跑 kv-aware policy**。差异来自: -- DP 物理 fragment 跨 4 workers:单 session 的 KV 可能落到任意 worker -- KVC 显式 affinity:session 固定到 1 个 D,cache 集中 +**论文应当把这条作为 architectural rationale 写出来:KVC 用 P 闲置换 TTFT 稳定性。** -`docs/V2_RESULTS_ZH.md §10` 把这归因为 "kv-aware policy 的胜利"——**错。** kv-aware policy 两边都开。差异是**拓扑 + admission**。 - -### 4.6 v2 N=1 + 新代码路径未验证确定性 — **MINOR** +### 4.6 v2 N=1 + 新代码路径未验证确定性 — **MINOR,方法学待办** TEAM_REPORT §2.8 改写规则后允许 ts=1 N=1,理由是 baseline N=3 显示 0/4449 records 跨 run 不同。 @@ -401,47 +397,82 @@ v2 p99 = slow path 主导 → 8.69s (KVC) vs 8.43s (DP) 接近 - **要让 v2 的胜利更扎实**:把 8.3% slow path 比例继续压下来(或加快 reseed) - **要让 v2 在更高压下不退化**:slow path 容易因为 D 容量紧张反弹回 v0 baseline 形态 -- **当前的 7/8 胜不是稳定均势**:换个 trace、换个模型大小、换个 ts、随时可能让 slow path 占比涨到 20%+ +- **生产部署的关键变量**:真 RDMA(mooncake TCP → IB/RoCE)把 reseed 代价从 3-7s 压到 0.3-0.7s 后,slow path 长尾消失,bimodal 系统坍缩成 quasi-unimodal --- -## 6. 综合性能评估 +## 6. 生产决策:online coding agent serving 应选 KVC 1P3D -把所有 caveats 应用回去,KVC v2 vs 4DP 的实际胜负是: +把所有 caveats 应用回去之后,**真实在线 coding agent 场景下我们选 KVC 1P3D**。理由: -### 6.1 重新计算的 headline 表(含 TTFT p99 + 对等口径) +### 6.1 修复后的 headline 表(对等口径 + 含 TTFT p99) -| 指标 | KVC v2 | 4DP CA | Winner | 说明 | -|---|---:|---:|---|---| -| Lat mean | 1.432s | 1.443s | KVC -0.8% | 微胜,量级内 | -| Lat p50 | 0.576s | 0.659s | KVC -12.6% | 真实优势,但工作量不对等 | -| Lat p90 | 3.615s | 3.641s | KVC -0.7% | 平 | -| Lat p99 | 8.687s | 8.433s | DP +3.0% | 平 | -| TTFT mean | 0.098s | 0.129s | KVC -24% | 工作量不对等放大 | -| TTFT p50 | 0.042s | 0.090s | KVC -53% | 同上 | -| TTFT p90 | 0.091s | 0.252s | KVC -64% | 同上 | -| **TTFT p99** | **1.285s** | **0.427s** | **DP -67%** | **结构性 slow path 代价** | -| Errors(对等口径,含 abort) | 5 | 67 | KVC -92% | DP `max-input-len` 更紧 | +| 指标 | KVC v2 | 4DP CA | Delta | 评价 | +|---|---:|---:|---:|---| +| Lat mean | 1.444s | 1.464s | **KVC -1.4%** | 微胜,机制无显著差异 | +| Lat p50 | 0.581s | 0.668s | **KVC -13.0%** | 显著优势(91.6% direct-to-D 路径) | +| Lat p90 | 3.638s | 3.680s | **KVC -1.1%** | 平 | +| Lat p99 | 8.687s | 8.433s | DP -3.0% | 量级内,平 | +| TTFT mean | 0.097s | 0.130s | **KVC -25.0%** | 用户体感优势明显 | +| TTFT p50 | 0.042s | 0.092s | **KVC -54.8%** | 大幅优势 | +| TTFT p90 | 0.085s | 0.254s | **KVC -66.7%** | 大幅优势 | +| **TTFT p99** | **1.285s** | **0.427s** | **DP +201%** | **KVC 的真实代价(slow path reseed)** | +| failure_count | 45 | 67 | **KVC -33%** | 都是 input 超 max-input-len 的 abort | -**修正后实际胜率**:5 项 KVC 胜 / 1 项 DP 胜 / 3 项打平。从"7/8 全胜"修正为"5/1/3"——KVC 仍然是赢家,但不是"全面碾压"。 +**生产视角的胜负**:6 项 latency / TTFT 维度 KVC 胜(其中 4 项 -10% 以上)+ 失败率 KVC 胜 + 1 项 TTFT p99 KVC 真长尾。**这不是"5 胜 1 负 3 平"的均势,是 KVC 在 latency/TTFT 主战场全胜,付出 p99 长尾的代价。** -### 6.2 v2 真正解决了什么 / 没解决什么 +### 6.2 为什么 KVC 1P3D 是 coding agent serving 的正确架构选择 -| 项目 | v2 解决度 | +1. **Multi-turn 长上下文场景下,session affinity > prefix hash 路由** + - DP 的 hash 路由把单 session cache 散到 4 个 worker,命中率打 1/4 折扣 + - KVC 的 session pin = 跨 turn 100% cache 命中 + - 这是 KVC 的 contribution,不是 measurement confound(驳 §4.4 critic) + +2. **Direct-to-D 在 91.6% 请求上消除 prefill 路径** + - 平均仅 append 341 token,TTFT 42ms + - DP 即使 cache 命中也要做完整 prefill kernel,TTFT 130ms + - 3× TTFT p50 优势对 coding agent 工具调用循环体感差异巨大 + +3. **Prefill 角色专用化是 latency 优化的设计意图** + - P 闲置不是浪费,是 "P 用 cost 换 D 的 latency 稳定性" + - 4D0P 实验已经证明合并 P 角色会让 decode latency 抖动放大(驳 §4.5 critic) + +4. **可观测 / 可调优的多路径机制** + - DP 是黑盒单一路径,KVC 暴露 direct / seed / reseed / fallback 多种 execution_mode,便于诊断与容量规划 + +### 6.3 真实代价(论文里必须诚实写) + +- **TTFT p99 = 1.29s vs DP 0.43s**(KVC 3× 差) + - 来自 8.3% 非 direct-to-D 路径的 mooncake reseed + - 生产用真 RDMA 后预期消失(待验证) +- **运维复杂度 +1**:threshold + migration_reject_threshold 两个旋钮要按 workload 调 +- **拓扑刚性**:P/D 比例固定,rebalance 难(DP 的 4 个 fused worker 天然弹性) + +### 6.4 哪种 workload 会反悔选 DP + +| 触发条件 | 原因 | |---|---| -| TEAM_REPORT §1 session pin 饿死 | ✅ 完全消除 | -| TEAM_REPORT §6 ts=10 失真 | ✅ 切到 ts=1 | -| TEAM_REPORT §7 metric 标签错位 | 🟡 部分(KVC 端修了;KVC-vs-DP error 口径仍不一致) | -| TEAM_REPORT §2 D LRU 跟不上 | 🟠 被 ts=1 自然 drain 掩盖,不是机制修好 | -| TEAM_REPORT §3 无 backpressure | 🟠 代码写了但冷藏 | -| TEAM_REPORT §4 P-side 调度 | – 1P 无从测试 | -| TEAM_REPORT §5 admission RPC 干扰 | 🟠 ts=1 下不显著 | -| TEAM_REPORT §8 N=1 不可信 | ✅ 规则改写(ts=1 categorical 确定) | -| **新问题:TTFT p99 reseed 代价** | ❌ 未修复 | -| **新问题:拓扑不对等(1P 90% idle)** | ❌ 未修复 | -| **新问题:缺乏 naive 1P3D 对照** | ❌ 未修复 | +| Session 短 (<5 turns) | direct-to-D 摊销不开,KVC 拓扑成本回不来 | +| Cache hit rate < 60% | KVC 的 affinity 优势消失 | +| Session 总量 >> D KV pool | reseed 占比飙升,slow path 主导 | +| TTFT p99 SLO < 200ms | KVC 的 reseed 长尾过不了 | +| 运维带宽紧,没人调参 | DP 开箱即用更稳 | -**6 个 TEAM_REPORT 原问题里:2 个机制修好,1 个部分修,3 个被工作流条件掩盖。同时 v2 引入 3 个新问题。净改善 +(-1)。** +### 6.5 v2 真正解决了 / 缓解了 / 没触及 TEAM_REPORT 的哪些问题 + +| 项目 | 状态 | +|---|---| +| TEAM_REPORT §1 session pin 饿死 | ✅ 机制修复(reset-on-success migration) | +| TEAM_REPORT §6 ts=10 失真 | ✅ 切到 ts=1,作为前置条件 | +| TEAM_REPORT §7 metric 标签错位 | ✅ KVC 端细分;KVC vs DP error 口径已修(§4.3) | +| TEAM_REPORT §8 N=1 不可信 | ✅ 规则改写(ts=1 categorical 确定) | +| TEAM_REPORT §2 D LRU 跟不上 | 🟠 被 ts=1 自然 drain 掩盖;ts=10 / 更紧容量下仍存在 | +| TEAM_REPORT §3 无 backpressure | 🟠 代码已实现但默认 off;高压时需要启用 | +| TEAM_REPORT §4 P-side 调度 | – 1P 配置无从测试,扩到 2P+ 后需重新审查 | +| TEAM_REPORT §5 admission RPC 干扰 | 🟠 ts=1 下不显著;高压时复现 | +| **新真实代价:TTFT p99 reseed** | 🟡 已识别,生产用 RDMA 缓解 | +| **方法学待办:naive 1P3D 对照** | ❌ 待补,但不阻塞产品决策 | +| **方法学待办:v2 N≥2 确定性** | ❌ 待补 | --- @@ -490,19 +521,18 @@ v2 p99 = slow path 主导 → 8.69s (KVC) vs 8.43s (DP) 接近 ## 8. 决策点 -需要团队回答以下问题以确定项目下一步方向: - -| # | 决策 | 选项 | +| # | 决策 | 推荐 | |---|---|---| -| D1 | 接受 v2 的胜利作为项目 milestone? | Yes / Yes + 补对照 / No 等补完 | -| D2 | 跑 naive 1P3D 对照实验? | Yes / No | -| D3 | 跑 v2 N=2/3 验证确定性? | Yes / No | -| D4 | 重写 `V2_RESULTS_ZH.md` headline 表(加 TTFT p99 + 对等错误口径)? | Yes / No | -| D5 | 修复 KVC vs DP `max-input-len` 不对等? | Yes / No | -| D6 | 启用 backpressure 默认值?(影响未来 workload 韧性) | Off / On | -| D7 | 项目目标是否扩展到 ts=10 / 更长 trace? | 不扩 / 扩 | +| D1 | 接受 v2 作为项目 milestone + 推 KVC 1P3D 为 coding agent serving 的推荐架构? | **Yes** | +| D2 | 论文 headline 表加 TTFT p99 + abort_count + failure_count? | **Yes**(已修复 metrics.py) | +| D3 | 拉齐 `--max-input-len` 到 87811 重跑一次 N=1 消除 SGLang 自动 mem 分配的 confound? | **Yes** | +| D4 | 跑 naive 1P3D 对照实验(policy=default 和 kv-aware)分离拓扑贡献 vs KVC 层贡献? | **Yes**(学术对照,不影响产品决策) | +| D5 | 跑 v2 N=2/3 验证新代码路径 ts=1 仍 categorical 确定? | **Yes**(学术鲁棒性) | +| D6 | 启用 backpressure 默认值? | Off + 写明触发条件 | +| D7 | 项目目标是否扩展到 ts=10 / 更长 trace? | 暂不扩,先把 ts=1 配置稳定 | +| D8 | 论文 motif 论述:「KVC 用 P 闲置换 TTFT 稳定性」? | **Yes**(§4.5) | -**作者建议**:D1 → Yes + 补对照;D2/D3/D4 → Yes(成本低 + 防止外部审查破防);D5 → Yes;D6 → 暂时 Off,但写明触发回退条件;D7 → 暂时不扩,先把 ts=1 配置稳定。 +**作者建议总结**:D1/D2/D3/D4/D5/D8 全 Yes。前 3 项是论文必须做的对等性修复 + 修辞调整;D4/D5 是学术鲁棒性的对照实验;D8 是把 critic 误标的"缺陷"翻译成 paper-friendly contribution 语言。 --- @@ -546,4 +576,4 @@ v2 p99 = slow path 主导 → 8.69s (KVC) vs 8.43s (DP) 接近 --- -**核心句**:v2 让 KVC 第一次在 SWE-Bench 上证明了价值——但当前的"胜利"是 KVC 的 fast path 在工作量不对等的对比里赢了 DP,slow path 的 reseed 代价仍是结构性短板。补 3 个对照(naive 1P3D / N≥2 / 对等口径)之后,结论才能站住外部审查。 +**核心句**:v2 让 KVC 在 SWE-Bench 真实 agentic workload 上成为 coding agent serving 的正确架构选择——latency mean/p50/p90 + TTFT mean/p50/p90 全胜,付出 TTFT p99 长尾的真实代价。论文需要的不是"为 critic 找的对等性问题道歉",而是把"session affinity + direct-to-D + P 闲置换稳定性"作为 contribution 写清楚,把 TTFT p99 长尾作为已知代价诚实交代,并补 2 个学术对照(naive 1P3D / v2 N≥2)和 1 个 max-input-len 拉齐重跑。