当下一步并非单步:面向并发Go程序的分布感知执行建模
摘要
本文提出了一种分布感知的训练方法,用于对并发Go程序中的下一步事件预测进行建模,将调度器的非确定性视为一种信号。在少于一千个轨迹上微调一个7B模型,在生产环境的bug检测上达到了36.2%的准确率,优于Gemini 3.5 Flash的零样本性能。
arXiv:2606.17508v1 公告类型:新
摘要:训练一个模型来预测并发程序中的下一步比看起来要困难:同一程序从相同的轨迹前缀运行两次,可能会产生不同的下一步事件,且两者都有效,因为调度器是非确定性的。针对单一标签训练的模型实际上是在学习猜测一个随机过程的一种结果。我们反过来利用这种非确定性作为训练信号。我们对每个程序运行多次,将观察到的下一步事件聚合成经验分布,并通过KL散度目标微调一个7B模型以匹配该分布。在从真实生产环境Go程序bug(CockroachDB、Kubernetes、gRPC、etcd)中提取的798个预留预测样本上,使用不到一千个轨迹进行微调达到了36.2%的准确率,超过了使用零样本的Gemini 3.5 Flash(34.8%)以及未经微调的同一模型(28.6%)。分布训练在准确率上与交叉熵相当(35.8% vs. 36.2%),同时将预期校准误差从0.205降低到0.169。我们还针对一类select阻塞的goroutine推导出了一个正式的goroutine泄漏特征,其中P(GoUnblock)=0是由调度器语义保证的,而非通过学习获得。我们发布了数据集、训练好的适配器以及所有工具。
查看缓存全文
缓存时间: 2026/06/17 05:39
# 当下一步并非仅有一步:面向并发Go程序的分布感知执行建模
来源:https://arxiv.org/html/2606.17508
\tocauthor
Kaviru Hapuarachchi11institutetext:科伦坡大学计算机学院,斯里兰卡科伦坡07,Reid大道35号 11email:2022is031@stu\.ucsc\.cmb\.ac\.lk
###### 摘要
训练模型预测并发程序中的下一步看似简单,实则困难重重:同一程序从相同trace前缀出发,两次运行可能产生不同的有效后续事件,因为调度器是非确定性的。针对单一标签训练的模型实际上是在学习猜测随机过程的一个结果。我们反其道而行之,将非确定性作为训练信号。对每个程序多次运行,将观察到的后续事件聚合为经验分布,并使用KL散度目标微调一个7B模型,使其匹配该分布。在从真实生产Go缺陷(CockroachDB、Kubernetes、gRPC、etcd)中抽取的798个保留预测上,通过不到一千条trace的微调达到了36.2%的准确率,优于零样本使用的Gemini 3.5 Flash(34.8%)以及未经微调的同一模型(28.6%)。分布训练在准确率上与交叉熵相当(35.8% vs. 36.2%),同时将期望校准误差从0.205降低至0.169。我们还针对一类select阻塞的goroutine推导出形式化的goroutine泄漏特征,其中\(P(\textsf{GoUnblock})=0\)由调度器语义保证,而非学习所得。我们开源了数据集、训练好的适配器以及所有工具。
###### 关键词:
并发执行建模;非确定性;分布估计;模型校准;Go;goroutine调度;并发缺陷
## 1 引言
基于执行trace训练的模型学习预测程序的行为,而不仅仅是其外观。这正是代码世界模型(CWM)的核心思想:在每条语句后的运行时状态快照上训练,语言模型学会状态转移函数,从而改进验证、调试和代码生成[1 (https://arxiv.org/html/2606.17508#bib.bib1)]。对于顺序Python,这种方法效果良好。
但该方法隐含一个假设:执行是确定性的。给定一个状态和下一语句,存在唯一的下一个状态。对于并发代码,这一假设不成立。当goroutine并行运行并通过channel通信时,调度器每次运行都会以不同的方式交织。同一个前缀之后可能跟随着阻塞、启动或解除阻塞,所有情况均同样有效。在此场景下训练模型预测单个后续事件,无异于要求模型记住随机过程的一个任意结果——它几乎学不到任何东西。
这并非微不足道的技术细节。并发缺陷(死锁、数据竞争、goroutine泄漏)没有对应的顺序版本。它们依赖于调度,规避单元测试,甚至专家也难以预判[3 (https://arxiv.org/html/2606.17508#bib.bib3),4 (https://arxiv.org/html/2606.17508#bib.bib4)]。如果执行trace模型要在缺陷最集中的地方发挥作用,就必须处理定义该场景的非确定性。
我们提出将非确定性视为信号而非噪声。多次运行一个并发程序后,后续事件的分布并非随机误差,而是对调度器实际允许的未来的测量。我们将下一步事件预测重新表述为分布估计:对于一个前缀,目标是多次运行中观察到的后续事件的经验分布,并训练模型去匹配它(图1 (https://arxiv.org/html/2606.17508#S1.F1))。
我们的贡献如下:
- • 我们展示了一个7B模型在不到一千条并发trace上微调后,对来自CockroachDB、Kubernetes、gRPC和etcd的保留生产缺陷达到了36.2%的下一步事件准确率,超过了零样本Gemini 3.5 Flash(34.8%)和未微调的同一模型(28.6%)。
- • 我们展示了使用KL散度目标针对经验分布进行训练,在准确率上与交叉熵相当(35.8% vs. 36.2%),同时改进了校准:期望校准误差从0.205降至0.169,且模型熵与程序非确定性相关。
- • 我们针对select阻塞的goroutine推导出一个形式化泄漏特征,表明在任何trace深度上\(P(\textsf{GoUnblock})=0\)均源于Go调度器语义,而非学习所得。
- • 我们报告了该方法的不足:无论模型或目标如何,准确率在35–36%附近趋于平稳;罕见事件类型从未被学到;多步预测在大约一步之后便失去调度器一致性。
我们并非声称已实现可部署的缺陷检测器或生产级执行模拟器。本文的贡献在于提出一种形式化方法、一个数据集以及一组基线,展示了感知非确定性的训练是可行的,并明确了若要进一步提升性能需要做出哪些改变。
// goroutine泄漏 ch := make(chan int) go func() { ch <- 42 // 从未被读取 }() select { case <-ch: ... case <-After(t): ... }程序PP trace前缀τ1:k\tau_{1:k}CCWMf(⋅)f(\cdot)先前的CWM(顺序)单一标签:GoBlock=1.0=1.0 使用交叉熵训练 *假设只有一个有效未来* 我们的方法:分布p^\hat{p} 覆盖后续事件 0.60 Block 0.20 Start 0.20 Unbl Sched End Creat
图1: 并发执行具有多个有效的下一步,而非仅一个。先前的代码世界模型(蓝色)预测单个后续事件并使用交叉熵进行训练,这对顺序代码有效,但在同一前缀合法产生多个不同事件时定义不清。我们预测完整的后续事件分布(橙色),其目标来自同一程序的多次运行。右面板展示了一个goroutine泄漏程序的示例分布:GoBlock占主导且\(P(\textsf{GoUnblock})=0\),这一特征源于调度器,而非学习。
## 2 背景与相关工作
代码世界模型与执行trace。世界模型学习环境的转移函数:输入状态和动作,输出下一个状态[1 (https://arxiv.org/html/2606.17508#bib.bib1)]。CWM将其应用于程序执行,在来自解释器trace的动作-状态对上训练,使得模型能够从部分trace预测下一个动作和结果状态[1 (https://arxiv.org/html/2606.17508#bib.bib1)]。Meta的32B CWM在Python trace和智能体轨迹上训练,表明这种基础性学习能够改进编码和推理[1 (https://arxiv.org/html/2606.17508#bib.bib1)]。后续关于CWM失败模式的研究发现,错误集中在两个区域:长trace上的token预算耗尽,以及字符串值状态被子词分词混淆[2 (https://arxiv.org/html/2606.17508#bib.bib2)]。这两项研究均假设执行是确定性的和顺序的。
并发与LLM。并发代码引入了非确定性调度以及缺陷类别(竞争、死锁、饥饿),这些在顺序场景中没有等价物。单元测试评估无法系统地探索线程调度[3 (https://arxiv.org/html/2606.17508#bib.bib3)]。CONCUR基准针对并发代码生成,并通过模型检查进行评判[3 (https://arxiv.org/html/2606.17508#bib.bib3)]。我们的问题不同:将并发程序的执行建模为学习的转移函数,并将调度非确定性作为分布目标。真实Go并发缺陷语料库GoKer/GoBench[4 (https://arxiv.org/html/2606.17508#bib.bib4)]提供了我们用于评估的保留测试程序。
分布匹配与校准。针对目标分布而非点标签进行训练是一种成熟的技术:软目标目标改善了语言模型的校准,通常使用来自几百个样本的经验分布作为目标[5 (https://arxiv.org/html/2606.17508#bib.bib5),6 (https://arxiv.org/html/2606.17508#bib.bib6)]。我们的贡献并非分布匹配本身,而是其来源。通过多次运行观察到的并发执行的非确定性,为后续事件提供了一个有原则的经验目标。据我们所知,之前没有从并发执行trace中推导分布训练目标的工作。
表1 (https://arxiv.org/html/2606.17508#S2.T1)将我们的工作与两个最接近的先前研究方向进行了对比。
表1: 在相关问题维度上,与先前执行trace建模和最接近的并发基准的对比。本研究是首个将执行trace建模与并发程序及非确定性分布目标结合的工作。
## 3 问题形式化
我们考虑产生多个goroutine的Go程序。运行时追踪器会发出调度事件,我们使用覆盖goroutine生命周期和同步的六种事件类型:
\[
\mathcal{E}=\{\textsf{GoBlock}, \textsf{GoCreate}, \textsf{GoEnd}, \textsf{GoSched}, \textsf{GoStart}, \textsf{GoUnblock}\}.
\]
trace是快照序列 \(\tau=(s_1,\dots,s_n)\),每个快照记录触发的事件类型、goroutine ID以及每个goroutine的状态(运行中/可运行/阻塞/已结束)。给定一个前缀 \(\tau_{1:k}\) 和程序源码 \(P\),任务是预测 \(s_{k+1}\) 的事件类型。
从标签到分布。标准CWM训练将下一个事件作为单一标签,并最小化交叉熵。由于执行是非确定性的,\(P\) 从可比较前缀开始的多次运行会产生不同的有效后续事件。对于共享同一程序和前缀深度的一组运行 \(g\),令 \(c_g(e)\) 统计类型为 \(e\) 的后续事件的计数。经验分布及其Dirichlet后验(Jeffreys先验 \(\alpha=0.5\))为:
\[
\hat{p}_g(e)=\frac{c_g(e)}{\sum_{e'}c_g(e')},\qquad \tilde{\alpha}_g(e)=\alpha+c_g(e). \tag{1}
\]
学习目标是 \(\hat{p}_g\),而非单一标签。我们通过匹配分割深度(trace的25%/50%/75%)来近似“相同前缀”。由于不同运行的交织模式不同,分组后的前缀在结构上可比但并非字节一致。我们将在第9节 (https://arxiv.org/html/2606.17508#S9) 重新讨论这一近似。
## 4 数据集与评估设置
程序。我们收集了130个并发Go程序,分为三组(表2 (https://arxiv.org/html/2606.17508#S4.T2))。手工制作程序涵盖channel、mutex、select、pipeline、waitgroup和扇入/扇出模式,并包含有意的死锁、竞争和泄漏。生成程序通过随机参数和可选的注入缺陷合成,每个都验证可编译。真实世界程序是来自GoKer/GoBench语料库[4 (https://arxiv.org/html/2606.17508#bib.bib4)]的简化并发缺陷内核,源自包括CockroachDB、Kubernetes、gRPC、etcd、Istio和Moby在内的生产系统。每个程序携带描述结果、模式、goroutine计数和预期非确定性的元数据。
表2: 程序语料库。所有66个真实世界GoKer程序均被保留不参与训练,因此这些程序上的准确率衡量了模型在微调期间未见代码上的分布外泛化能力。
Trace。每个程序在竞争检测器下编译,并在运行时追踪器下运行五次。不同运行间的不同交织正是我们利用的变异性。从每次运行中,我们在25%/50%/75%前缀深度处构造示例。死锁程序会发出无后续事件标记,并从分布聚合中排除。追踪器暴露了调度事件,但不暴露channel缓冲区、mutex持有者或局部变量,因此模型必须从调度行为和程序结构中进行推理。
划分。我们将所有66个真实世界程序保留用于评估,仅在手工艺品程序和生成程序上训练。这产生了945个训练示例和798个保留的下一步事件预测,外加75个聚合的经验分布组。
## 5 方法
格式。每个示例呈现程序源码、JSON格式的部分trace以及当前goroutine状态,然后询问下一个事件。点目标是一个JSON对象 {"event_type":..., "goroutine_id":...};分布目标是六维向量 \(\hat{p}_g\)。提示从左端截断源码,确保目标不会被截断。
交叉熵基线。我们使用4-bit QLoRA(秩16,\(\alpha=32\),梯度检查点)在响应token上微调Qwen2.5-Coder(1.5B和7B),损失为交叉熵。为了在点损失下近似经验分布,示例按观察到的后续事件频率成比例复制。
KL分布损失。分布目标在区分事件类型的token位置上增加一个KL项。设限制在六个事件类型token上的logits为 \(z\),\(q=\mathrm{softmax}(z)\),经验目标为 \(\hat{p}_g\),则:
\[
\mathcal{L}=\mathcal{L}_{\mathrm{CE}}+\lambda\,\mathrm{KL}(\hat{p}_g\,\|\,q), \tag{2}
\]
其中 \(\lambda=0\) 恢复为CE消融。由于所有六个事件类型共享前导子词“Go”,我们将KL项置于第二个区分性token处。7B的QLoRA配置与CE基线相同,因此任何差异仅归因于目标本身。
多步一致性探测。为了衡量单步预测在失效前能延伸多远,我们将模型自己的预测作为输入反馈:从一个真实前缀开始,预测下一个事件,追加,重复最多15步。一个符号化的调度器有限状态机检查每个预测的转移是否符合Go不变量(例如,阻塞的goroutine不能启动)。我们报告生存步数(即首次违反前的有效转移次数),以及每步的事件分布和熵。我们在第7节 (https://arxiv.org/html/2606.17508#S7) 中将其作为诊断工具,以定位模型能与不能的边界。
## 6 结果
表3: 在保留的真实世界GoKer集上的下一步事件准确率。在手工艺品程序的并发trace上微调能够泛化到真实生产缺陷,优于零样本基线和Gemini 3.5 Flash。使用KL损失的分布训练在准确率上与交叉熵相当,同时改善了校准(第7节 (https://arxiv.org/html/2606.17508#S7))。
表4: 在手工艺品程序上的分布内准确率,作为上下文参考。这些数字与表3 (https://arxiv.org/html/2606.17508#S6.T3) 不可直接比较,因为此处使用的模型是较早的Gemini代际,并采用不同的提示格式进行评估。
微调实现分布外泛化。表3 (https://arxiv.org/html/2606.17508#S6.T3) 显示了主要结果。在945条手工艺品和生成trace上训练后,7B模型在训练期间从未见过的真实世界GoKer缺陷上达到了36.2%。这优于同一模型的零样本性能(28.6%)以及零样本使用的Gemini 3.5 Flash(34.8–35.2%)。小规模并发trace监督能够迁移到结构不同的真实代码。
分布训练匹配准确率。KL训练达到35.8%,与CE的36.2%无显著差异。我们认为这是预期结果:分布训练不应牺牲准确率,其收益体现在校准而非top-1预测上(第7节 (https://arxiv.org/html/2606.17508#S7))。
准确率上限接近35–36%。三种方法(CE微调、KL微调以及强零样本模型)均落在彼此一个百分点之内。这种聚类本身具有信息量:预测下一个调度相似文章
下一个令牌预测何时有用?边际化、遍历性、混合可识别性、局部充分性、RAG、工具与编程
本文区分了语言建模中常被混淆的三个概率对象——完整条件语言过程、边际纯文本法则和模型诱导分布——并分析了下一个令牌预测有用的条件,将 RAG 和工具解释为条件充分性设备。
超越预测:面向尾延迟的LLM推理调度
本文提出了一种面向LLM推理的分布感知、无预测调度框架,利用轻量级统计信号以软优先级提升替代显式长度预测。该方法联合优化调度与缓存感知的抢占,以降低尾部延迟,相比具备完美长度知识的SRPT,P99 TTLT最多降低35-50%。
语义步骤预测:通过步骤采样实现LLM推理轨迹中的多步潜在预测
本文介绍了语义步骤预测,该方法在推理步骤边界而非随机令牌位置上应用几何正则化,在ProcessBench上相比固定基线实现了168倍的多步潜在预测提升。
分布过程奖励模型:通过条件最优传输校准未来奖励的预测
本文引入了分布过程奖励模型,利用条件最优传输对 PRM 进行校准,以提高推理时缩放(inference-time scaling)中成功概率估计的准确性。该研究在 MATH-500 和 AIME 等数学推理基准测试中展示了改进的校准效果和下游性能。
通过近未来引导弥合在线蒸馏中的推理轨迹
本文指出了在线蒸馏大语言模型时token级监督的局限性,并提出TOPD方法,利用近未来轨迹信息更好地识别发散推理状态并将引导分布到多个token上,在AIME基准测试中取得了性能提升。