#AI Infra 新探索:克服 Coding Agent 推理的 Scaling Pain,到底讲了什么?
原文:GLM 大模型,《AI Infra 新探索:克服 Coding Agent 推理的 Scaling Pain》,2026-04-30。
技术博客链接:https://z.ai/blog/scaling-pain
#一句话总结
这篇文章不是在讲模型能力本身,而是在讲:当大模型应用从普通聊天转向高并发、长上下文、长链路的 Coding Agent 后,推理基础设施会进入一个新的极限区间。一些平时很难暴露的底层并发 Bug,会被 Coding Agent 的负载模式放大,最后表现成用户看到的乱码、复读、生僻字等“模型异常输出”。
核心问题可以压缩成一句话:
Coding Agent 场景下,长上下文、高并发、Prefix/KV Cache 复用和 PD 分离共同放大了推理系统的状态一致性问题;表面看是模型乱输出,底层原因可能是 KV Cache 生命周期、跨节点写入、异步加载与显存复用的竞态。
#1. 背景:为什么 Coding Agent 会让推理 Infra 进入新压力区间?
普通聊天的请求通常比较简单:
用户问一句 → 模型答一段
但 Coding Agent 的请求链路复杂得多:
读仓库 → 理解多个文件 → 规划修改 → 调工具 → 看结果 → 再改代码 → 跑测试 → 继续修复
因此它天然具有几个负载特征:
- 上下文特别长
原文提到,Coding Agent 场景下输入长度平均超过 70K tokens。
- 请求链路很长
一个 agent 任务会产生多轮模型调用、工具调用、环境反馈和重试。
- 并发特别高
原文提到线上每天承受数亿次 Coding Agent 调用。
- 前缀复用率高
同一个仓库、同一段 system prompt、同一批文件上下文会被频繁复用,因此系统会大量依赖 Prefix Cache / KV Cache。
这些因素叠加后,推理系统面对的已经不是“单次模型调用是否能跑通”,而是:
长上下文 + 高并发 + 高缓存复用 + 跨节点执行 + 极低异常率也会被线上规模放大
这就是文章所说的 Scaling Pain。
#2. 用户看到的异常:乱码、复读、生僻字
GLM 团队在线上观察到三类异常:
- 乱码(garbled output)
- 复读(repetition)
- 生僻字(rare character)
这些异常从用户视角看,很像“模型降智”或“长上下文崩了”。
但关键点在于:
这些问题在标准推理环境下不存在,只在高并发、长上下文 Coding Agent 场景下触发。
这说明问题不一定来自模型权重本身,而可能来自推理链路中的运行时状态。
团队的判断逻辑是:
- 如果是模型问题,那么同一个输入应该相对稳定地复现异常;
- 如果是系统问题,那么异常更可能与负载、并发、缓存状态、执行时序相关。
他们把用户反馈的 bad cases 本地回放,同一批请求重复推理数百次,始终无法稳定复现异常。直到他们模拟线上压力,例如提高系统负载、制造 Prefill 堆积、增加 Decode 侧 KV Cache 压力,才在线下以每万次请求 3-5 次的频率复现。
这说明:
异常与具体 prompt 内容关系不大,更像是高负载下推理系统状态管理出了问题。
#3. 关键概念:Prefill、Decode 与 KV Cache
要理解这篇文章,需要先理解大模型推理的两个阶段。
#3.1 Prefill:处理长输入
Prefill 阶段把用户输入的 prompt 一次性喂给模型,计算出每一层 attention 所需的 KV Cache。
如果输入是 70K tokens,那么 Prefill 会非常重。
#3.2 Decode:逐 token 生成输出
Decode 阶段则是一个 token 一个 token 地生成答案。每生成一个 token,都需要读取前面已经算好的 KV Cache。
可以简化为:
Prefill = 处理长输入,生成上下文缓存
Decode = 基于缓存逐 token 生成输出
KV Cache = 模型保存上下文注意力状态的缓存
#3.3 PD 分离
为了提高吞吐,线上推理系统往往会把 Prefill 和 Decode 分离到不同节点或不同 GPU 上执行,这就是 PD 分离:
P = Prefill
D = Decode
这种架构可以提高系统吞吐,但也带来一个复杂问题:
Prefill 和 Decode 之间的请求生命周期、KV Cache 写入、显存回收和复用必须严格同步,否则就可能发生跨请求状态污染。
#4. BugFix #1:PD 分离下的 KV Cache 复用竞态
第一个 Bug 是全文最核心的问题之一。
可以用一个例子理解。
假设有请求 Req1:
Req1 进入 Prefill
Prefill 侧排队较久,还没算完
Decode 侧一直等不到 Req1 的 KV Cache
Decode 触发超时 Abort
为了控制尾延迟,系统会让 Decode 侧中止 Req1,并回收 Req1 占用的 KV Cache 槽位。
然后新请求 Req2 到来:
Req2 被分配到刚刚释放的 KV Cache 地址
Req2 开始正常 Prefill 和 Decode
问题在于:
Decode 侧虽然 Abort 了 Req1,但这个 Abort 信号没有正确传播到 Prefill 侧。Req1 的 Prefill 计算和 RDMA 写入仍然可能继续执行。
于是就发生了一个典型竞态:
Req2 正在使用某块 KV Cache 显存
Req1 的迟到写入又写进同一块显存
Req2 的 KV Cache 被污染
Decode 读取到错误上下文状态
输出出现乱码、复读或生僻字
更直观地说:
系统把一间房间分给了新客人 Req2,但旧客人 Req1 的快递还在往这间房里送,最后把新客人的东西弄乱了。
#修复方法
修复思路是给 KV Cache 回收加上明确同步:
Decode 触发 Abort 后,先通知 Prefill
Prefill 确认相关 RDMA 写入没有开始,或所有已提交写入都完成
Prefill 返回“可释放”信号
Decode 收到确认后,才允许回收并复用 KV Cache 槽位
这等于在请求终止与 KV Cache 写入完成之间建立了显式时序一致性。
#修复效果
原文提到,该修复上线后,异常输出发生率从“万分之十几”下降到“万分之三以下”。
这个结果说明:
在 PD 分离架构里,跨节点 KV 写入和显存复用之间必须有严格生命周期管理。否则,一个已经被 Abort 的旧请求仍可能污染新请求的推理状态。
#5. BugFix #2:HiCache 加载时序缺失
第二个 Bug 与 HiCache 有关。
Coding Agent 输入很长,KV Cache 非常大。为了降低显存压力和提升复用效率,系统会使用多级 KV Cache,也就是 HiCache。
可以粗略理解为:
热缓存放 GPU 显存
冷一些的缓存放 CPU 内存
需要时再异步换入 GPU
为了提升吞吐,系统会让缓存加载和模型计算重叠执行:
Load Stream = 负责加载 KV Cache / Indexer Cache
Forward Stream = 负责 Index 计算和后续 Sparse Attention
理论上,Forward Stream 中的 Indexer 计算必须等对应的 Indexer Cache 加载完成后才能开始。
但原始实现中缺少这个显式依赖,于是可能出现:
Forward Stream 已经开始 Index 计算
Load Stream 还没把对应缓存加载完
模型读到了未完成或未初始化的数据
这就是典型的 read-before-ready。
结果是:
Indexer 计算错误 → Sparse Attention 计算错误 → 最终输出异常
#修复方法
修复方式是在数据加载与计算之间加入显式同步:
Indexer 算子启动前,等待 Load Stream 完成对应缓存加载
Forward Stream 只在数据就绪后继续计算
原文提到,该修复已经通过 Pull Request #22811 提交到 SGLang 社区。
这个 Bug 的启示是:
多级缓存和异步流水线可以提高吞吐,但只要缺一个同步点,就可能把性能优化变成输出质量风险。
#6. 为什么投机采样指标能用来检测异常?
文章中一个很有意思的点是:团队用 Speculative Decoding 的指标来识别异常输出。
投机采样原本是推理加速技术:
草稿模型先生成若干候选 token
目标模型验证哪些 token 可以接受
如果接受较多,就能减少目标模型 decode 次数
它通常用于提升速度,而不是质量监控。
但 GLM 团队发现,异常发生时,投机采样指标会出现稳定模式。
主要指标有两个:
spec_accept_length = 目标模型连续接受的 draft token 前缀长度
spec_accept_rate = draft token 被接受的比例
#6.1 乱码/生僻字:spec_accept_length 很低
当输出乱码或生僻字时,spec_accept_length 通常极低。
这意味着草稿模型提出的候选 token 几乎全部被目标模型拒绝。
这说明:
目标模型看到的 KV Cache 状态
和草稿模型预期的上下文状态
发生了明显偏离
这正好符合 KV Cache 被污染或状态错乱的情况。
#6.2 复读:spec_accept_rate 偏高
当输出复读时,spec_accept_rate 通常异常偏高。
这可能意味着损坏的 KV Cache 让 attention 模式退化,生成过程进入高置信度重复循环。
#6.3 在线异常监控
基于这个观察,他们设计了在线监控策略:
如果 spec_accept_length 持续低于 1.4 且生成长度超过 128 token
或者 spec_accept_rate 超过 0.96
就主动中止当前生成,并交给负载均衡器重试
这点很重要:
Speculative Decoding 不只是性能优化工具,也可以成为推理质量的实时健康信号。
#7. LayerSplit:为长上下文 Prefill 降低显存压力
前两个部分是 Bug Fix,后面的 LayerSplit 是性能优化。
修完竞态问题后,团队回到更根本的瓶颈:
在长上下文 Coding Agent Serving 中,Prefill 阶段主导了系统性能。
Coding Agent 输入长,Prefix Cache 命中率高。在这种场景下,Context Parallel 是 Prefill 节点的重要并行策略。
但现有 SGLang 开源实现中存在 KV Cache 冗余存储问题:
每张 GPU 都保存较多重复的 KV Cache
显存容量限制了 Prefill 吞吐
LayerSplit 的思路是:
每张 GPU 不再保存全部层的 KV Cache
而是只保存部分层的 KV Cache
例如模型有很多层,可以按层分给不同 GPU:
GPU 1 保存第 1-10 层 KV Cache
GPU 2 保存第 11-20 层 KV Cache
GPU 3 保存第 21-30 层 KV Cache
...
计算到某一层时,持有该层 KV Cache 的 rank 会把对应 cache 广播给其他 rank。
为了降低通信开销,他们又设计了 KV Cache 广播与 indexer 计算的重叠机制。最终额外通信主要来自 Indexer Cache 广播,规模约为 KV Cache 的 1/8,因此整体开销较低。
原文实验显示,在 Cache 命中率 90% 的条件下,请求长度从 40K 到 120K 时,吞吐提升在 10% 到 132% 之间,并且上下文越长收益越明显。
LayerSplit 的本质是:
用按层切分的 KV Cache 存储方式,减少单卡显存压力,让长上下文 Prefill 更能 scale。
#8. 这篇文章真正重要的地方
这篇文章不是单纯说“我们修了两个 Bug”。它更重要的判断是:
当大模型进入 Coding Agent 时代,推理系统的目标不再只是吞吐、延迟和成本,还必须保证输出质量在高并发长上下文场景下不被系统状态污染。
过去我们讨论 Scaling Law,更多关注:
模型参数量
训练数据规模
后训练算法
benchmark 分数
推理吞吐与成本
但 Coding Agent 场景会暴露出一组更底层的系统问题:
KV Cache 生命周期管理
Prefill/Decode 分离一致性
跨节点 RDMA 写入时序
多级缓存换入换出同步
长上下文 Prefix Cache 稳定性
投机采样异常检测
显存复用和请求 Abort 的边界
这些问题如果处理不好,用户看到的不会是“系统 Bug”,而是:
模型突然乱了
模型开始复读
模型输出乱码
长上下文不稳定
也就是说:
未来模型质量的一部分,会由推理基础设施的状态一致性决定。
#9. 对 Code Agent / Agentic RL / 自进化系统的启发
这篇文章对 Code Agent 和自进化 Agent 研究有几个重要启发。
#9.1 Code Agent Scaling 不只是算法问题,也是 Serving State 问题
如果未来做 self-evolving code agent,轨迹越来越长、调用越来越多,系统会高度依赖:
长上下文
Prefix/KV Cache
工具调用状态
中间结果压缩
多轮记忆
环境反馈
这些都可能成为隐性状态污染源。
所以 Code Agent 能力的 scaling,不只是模型、数据、RL 算法的问题,也包括完整系统的状态一致性问题。
#9.2 长轨迹 RL 的训练数据可能被 Infra Bug 污染
如果 agentic RL 在线采样长轨迹,而推理系统偶尔发生 KV Cache 污染,那么模型可能输出乱码、错误工具调用或无意义操作。
如果训练系统无法区分这是:
模型策略错误
环境反馈错误
工具执行错误
推理系统状态错误
缓存/记忆污染错误
那么这些异常会进入训练数据,导致错误 credit assignment,甚至污染 reward model 或 preference 数据。
因此,长轨迹 Agent RL 需要更强的 runtime health signal。
#9.3 Spec Decoding 指标可以扩展为 Agent Runtime Watchdog
这篇文章用 spec_accept_length 和 spec_accept_rate 检测输出异常。这个思路可以推广到 Agent Runtime。
未来 agent 系统不应该只看最终答案,还应该监控推理过程中的健康指标,例如:
KV Cache 命中率
Spec accept rate / accept length
生成熵变化
重复 n-gram
工具调用重试率
上下文压缩损失
Prefix cache reuse pattern
长轨迹中断/回滚频率
这些指标可以作为 Agent 的 runtime watchdog,用来区分模型能力失败与系统状态异常。
#9.4 Coding Agent 是推理 Infra 的极限压力测试
普通聊天不一定能暴露这些问题。
Coding Agent 天然具备:
长上下文
长链路
高并发
高缓存复用
高可靠性要求
因此它会成为未来 LLM Serving Infra 的试金石。
#10. 最后总结
这篇 GLM 博客的核心可以概括为:
GLM-5 在线上 Coding Agent 高并发长上下文场景中出现乱码、复读、生僻字。排查发现,这些异常不是模型本身稳定退化,而是推理基础设施中的 KV Cache 状态管理问题:一个是 PD 分离下 Abort 后旧 Prefill 继续写,污染了新请求的 KV Cache;另一个是 HiCache 异步加载还没完成就被 Forward 读取。修复之后,他们进一步提出 LayerSplit,把 KV Cache 按层分布到不同 GPU,降低长上下文 Prefill 的显存压力,提高吞吐。
这篇文章真正值得记住的是:
Coding Agent 的 Scaling Pain,不只是模型和算法的痛,也是推理系统状态一致性、缓存生命周期、长上下文 serving 可靠性的痛。
当 Agent 越来越长程、越来越自主、越来越依赖在线环境时,基础设施中的极低概率状态错误会被规模放大,并直接表现为模型质量问题。未来可靠的 Code Agent 系统,必须同时解决模型能力、训练信号、环境反馈和推理 Infra 四个层面的 scaling。