#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 的请求链路复杂得多:

读仓库 → 理解多个文件 → 规划修改 → 调工具 → 看结果 → 再改代码 → 跑测试 → 继续修复

因此它天然具有几个负载特征:

  1. 上下文特别长

原文提到,Coding Agent 场景下输入长度平均超过 70K tokens。

  1. 请求链路很长

一个 agent 任务会产生多轮模型调用、工具调用、环境反馈和重试。

  1. 并发特别高

原文提到线上每天承受数亿次 Coding Agent 调用。

  1. 前缀复用率高

同一个仓库、同一段 system prompt、同一批文件上下文会被频繁复用,因此系统会大量依赖 Prefix Cache / KV Cache。

这些因素叠加后,推理系统面对的已经不是“单次模型调用是否能跑通”,而是:

长上下文 + 高并发 + 高缓存复用 + 跨节点执行 + 极低异常率也会被线上规模放大

这就是文章所说的 Scaling Pain


#2. 用户看到的异常:乱码、复读、生僻字

GLM 团队在线上观察到三类异常:

  1. 乱码(garbled output)
  2. 复读(repetition)
  3. 生僻字(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_lengthspec_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。