Token导航 LogoToken导航

AI 资讯 · 科技行者

AI软件工程师从零造物训练场实现规模化

更新 2026-11-09科技行者正文 7560字阅读约 24分钟

你有没有想过,为什么现在那些能自动修复代码bug的AI助手,到了真正"从零开始写一个程序"这件事上就突然变得笨拙了?

这不是错觉。几乎所有主流的编程智能体,无论是处理GitHub issue的,还是根据需求文档生成仓库的,它们的训练套路都高度相似:给你一个现成的代码库,再给你一份明确的任务说明,然后让AI去改动或填充。这就像给一个厨师一份详细到克数的菜谱,再把切好的食材摆在他面前,他只需要按部就班地炒。

但真正的软件工程师是怎么工作的?

他们拿到的往往不是菜谱,而是一盘别人已经做好的菜,加上一句"做一盘尝起来差不多的"。没有食谱,没有配料清单,得自己尝、自己猜、自己试错,然后决定用什么锅、放多少盐、先放葱还是先放姜。这种从观察到重建的过程,才是软件工程最核心也最难被AI掌握的能力。

2026年发布的ProgramBench测试揭示了一个让人意外的数字:在最初的评测中,没有任何一个模型能完全解决一个"程序复现"任务。

这个任务设定很简单也很残酷:给AI一个只能执行、不能看源码的参考程序和它的使用文档,让AI在断网环境下把这个程序的外部行为原样重建出来。不许看代码,不许联网查资料,只能靠反复试验去摸清这个程序到底该怎么跑。这种"黑箱复现"任务,直接把AI逼到了软件工程师最原始的处境里。

问题是,训练这种能力需要大量可验证的练习环境。而现实是,这类环境几乎不存在。

这篇名为ProgramGym的论文,就是奔着这个空白去的。它做了两件事:造了一大批可以验证对错的训练环境,又设计了一套让AI像真正软件工程师那样分阶段干活的工作流程。结果相当亮眼,一个270亿参数的开源模型Qwen3.8-27B,经过这套系统的训练和加持后,在ProgramBench上的测试通过率从34.87%一路冲到55.71%,甚至超过了不少闭源旗舰模型。

这件事到底难在哪里

先说清楚"程序复现"任务和"修bug"任务的本质区别。

修bug,AI拿到的是一整套代码,它只需要定位到出错的那一小块,然后动手术式地改掉。这件事难,但难在"找到病灶",不难在"理解整个人体结构"。

程序复现完全不同。AI面对的是一个黑箱可执行文件,加上一份可能语焉不详的使用文档。它得自己去跑这个程序,试各种命令行参数,观察输出格式,猜测隐藏的配置项,甚至得琢磨这个工具到底是给谁用的、设计初衷是什么。搞清楚"这个程序应该做什么"之后,还得自己决定"我该怎么写代码来实现它",包括架构设计、模块划分、语言选择,全都没有人替你决定。

要把这种能力训练出来,首先得有足够多、足够真实、而且能自动判断对错的练习场。

这就牵出了ProgramGym这篇论文要解决的第一个硬骨头:怎么把海量的开源代码仓库,批量加工成这种"黑箱复现"训练环境。

这事儿听起来简单,实际操作起来全是坑。不同仓库用的编译工具链千差万别,依赖库版本五花八门,有的项目甚至需要特定年代的编译器才能跑起来。更麻烦的是,光能编译出来还不够,你还得给这个程序配一套"验收标准",也就是能准确判断AI复现的程序对不对的黑盒测试集。写得太随便,AI随便交个空壳程序就能蒙混过关;写得不全面,AI复现出一半功能也能通过。

Program-Env:把开源仓库batch转化成训练场

**Program-Env的核心思路是用一个反馈驱动的闭环,把"构建可执行程序"和"生成高质量测试"这两件原本极度依赖人工的事情,变成AI自己迭代打磨出来的流水线产物。**

具体是怎么干的?

论文团队先从GitHub上按语言和star数分层搜索,抓了超过3万个候选仓库,涵盖C、C++、Go、Rust四种语言。经过元数据校验、锁定commit版本、检测是否存在明确的构建配置文件等几轮筛选,最终留下30459个候选仓库。

构建阶段

*指把源代码编译成可执行程序的过程*

是整个流程里最容易踩雷的地方。论文里举了个很说明问题的例子:CMake 4.0这个构建工具,默认不再支持低于3.5版本的兼容性声明,这意味着很多老项目的构建脚本会直接报错;C++17模式下,标准库会悄悄砍掉一些老接口,导致编译失败;Rust项目如果用了某些不稳定特性,换个工具链版本就可能直接崩。这些坑都是仓库特有的,不是靠一套通用规则能覆盖的。

**ProgramGym的做法是让AI自己写两个脚本,一个管在线环境下载依赖,一个管离线环境下编译,两者分开执行,并且编译阶段必须完全断网才能跑通。**

这个设计背后有个很朴素的道理。如果AI可以在编译的时候也联网,它很容易"偷懒",缺什么库就临时装什么,整个构建过程变得不可控也不可复现。强制离线编译,相当于逼着AI把所有依赖提前准备齐全,这样生成的运行环境才是真正自给自足、可以稳定复用的。

这里有个类比值得说一说。

你可以把这个过程想象成搬家去一个完全没有网络信号的山区小屋生活。如果你可以随时网购,那你大概率是"缺什么买什么",永远处在一种临时应付的状态,哪天断网了生活立刻瘫痪。但如果你知道搬进去之后彻底没信号,你就会在出发前把水电气、食物、工具箱全部清点打包好,确保这个小屋本身就是一个完整的闭环系统。如果不强制断网测试,这套环境大概率在训练AI的时候会突然因为某个隐藏的网络依赖而崩溃,而你根本不知道问题出在哪。

论文统计显示,第一次尝试就能把环境搭建成功的仓库占比并不高,大多数语言都需要2到4轮修复。系统会把失败原因、报错日志和建议修复方案打包成结构化反馈,让AI带着具体线索去改第二版脚本,而不是瞎猜。这个反馈循环最多跑4轮,还跑不通就放弃这个仓库。

环境搭好之后,真正的硬仗才刚开始:生成黑盒测试。

这里论文提出了一个很关键的判断:如果让一个AI agent独自面对几万行代码的大型仓库,一次性写测试,它往往只能挠到皮毛,测试覆盖不全,断言也写得很弱(比如只检查程序退出码是不是0,这种测试基本等于没测)。

解决办法是分而治之。系统会根据仓库复杂度,把代码拆成若干功能模块,每个模块分配一个独立的子智能体并行工作。复杂度的计算方式考虑了代码行数和运行时依赖数量,越复杂的仓库,拆得越细。每个子智能体还会被打上标签,比如这个模块主要测的是命令行参数、配置文件读取、帮助信息输出,还是子命令路由,或者终端交互界面,一共六个交互类别,让AI带着明确目标去探索,而不是漫无目的地乱试。

测试质量的把关更是下了狠功夫。论文设计了四道独立检查:

第一道叫通过检查,确保这个测试在参考程序上真的能跑通,不是瞎编的。第二道叫双重检查,把同一个测试跑两遍,如果两次结果不一致,说明这个测试依赖了随机性或者执行顺序,不稳定,直接淘汰。第三道是虚设检查,拿一个什么都不做的空程序去跑这个测试,如果空程序也能通过,说明这个测试压根没测到任何实质功能,也得淘汰。第四道是弱断言检查,用一套包含37条规则的静态代码检查器,专门揪出那些看似写了断言、实际上形同虚设的测试,比如只判断进程是否正常退出、断言被异常处理悄悄吞掉、或者测试里直接偷看了参考程序的源码。

这四道关卡其实回应了一个很现实的问题:一个测试集如果本身不可靠,那训练出来的AI学到的可能根本不是正确的东西,而是学会了怎么应付一套漏洞百出的考题。

这让我想起学校里那种"水考试"。

如果一门课的期末考试只考"你有没有来上课签到",那所有学生都能满分通过,但没有一个人真的学到了知识。这种考试存在的意义约等于零,甚至有害,因为它会让学生和老师都误以为教学效果很好。Program-Env的四道检查,本质上就是在确保这份"考卷"真的在考察程序的核心行为,而不是在考一些无关紧要的边角料。如果没有这套检查机制,AI训练出来的模型很可能擅长"通过测试"而不擅长"真正复现程序行为",这是两件完全不同的事。

最终,这套流水线产出了1648个训练环境,覆盖C、C++、Go、Rust四种语言,其中Go占比最高达到49.64%,整体代码覆盖率均值达到72.99%,中位数更是高达81.63%,累计验证通过的测试用例多达665512条。

值得一提的是,这1648个环境里,98.5%的测试用例都是流水线从零写出来的,只有1.5%是从仓库自带的测试套件改写来的。这说明这套环境的可验证性主要来自系统自身的生成能力,而不是依赖仓库原有的测试资源。

Program-Agent:让AI像软件工程师一样分角色干活

光有训练场还不够,论文团队发现了第二个大问题:现有的通用编程智能体框架,在长时间、多步骤的开发任务里很容易"失忆"。

这是什么意思?

设想一个AI在一个长达数小时的单次会话里连续干活,随着对话历史越堆越长,超过模型的上下文窗口限制,系统不得不对早期的对话内容做压缩甚至丢弃。结果就是,AI早期探索参考程序时发现的某个关键行为细节,到了实现阶段可能已经被遗忘了。更糟的是,AI还可能在还没把参考程序摸清楚之前,就急着动手写代码,然后发现写出来的东西完全偏离了实际需求。

**Program-Agent的解法是把整个开发过程拆成三个角色隔离的阶段:分析、实现、审查,每个阶段在独立的会话里运行,彼此之间不共享完整对话历史,只通过结构化的交接文档传递关键信息。**

分析阶段,AI只能读文档、跑参考程序去摸清需求,绝对不能动手改代码,这样能保证需求收集不受实现细节的干扰。实现阶段,AI基于前一阶段冻结下来的分析文档去写代码,但看不到参考程序本身,避免它陷入"边写边偷看答案"的低效循环。审查阶段,AI拿参考程序和刚编译出来的候选程序做行为比对,把发现的差异写成明确的修订要求,留给下一轮实现阶段去解决。

这套机制整体会循环K轮,实验里设定为5轮。

这个设计让我想起了建筑工地的分工制度。

设计师、施工队、验收员是三拨完全不同的人,设计师画完图纸就交给施工队,不会天天跑去工地对施工队指手画脚;施工队按图施工,不需要重新去跟业主沟通需求细节;验收员拿着图纸和实际建筑物对照检查,发现问题列成清单交还给施工队返工。如果把这三个角色压缩成同一个人同时干,这个人很容易一边砌墙一边改主意,图纸和实际施工越走越远,最后盖出来的楼可能连地基标准都对不上。Program-Agent的三阶段隔离,本质上就是把"想清楚要做什么"和"动手做"和"检查做得对不对"这三件事强制分开,避免它们相互干扰。

光有角色分工还不够,论文还设计了一套修订管理机制来防止"写着写着写崩了"的问题。

在多轮实现过程中,共享的工作区代码可能被改得越来越乱,最后连编译都过不了。为了防住这种情况,系统把"独立编译"作为每一轮实现结束的硬性关卡:把当前提交的源代码干净地导出到一个全新目录,在这个隔离环境里重新跑一次编译脚本,只有编译成功的版本才会被归档为有效的"修订版本",并交给下一轮审查阶段使用。

如果某个阶段超时、缺少必要产出文件,或者编译失败,系统会在一个全新会话里重试,重试仍然失败就回滚到上一个已验证成功的修订版本。这个最后成功的版本会成为后续各轮的"安全着陆点"。

这套设计像极了写长篇小说时专业作者会用的版本管理习惯。

如果你一边写一边不停地在同一份文档上反复涂改,写到第十章突然发现逻辑崩了,想回退到第五章的状态几乎不可能,因为中间的修改已经把原始版本彻底覆盖掉了。但如果你每写完一个阶段就存一个独立的存档版本,一旦某次大改把故事写坏了,你随时可以退回到上一个靠谱的存档重新来过,而不是从头推倒重写。Program-Agent的修订管理,本质上就是给AI的多轮迭代装上了这样一套"存档点"系统,没有它,AI一旦在某一轮把代码改坏,整个长程开发任务就可能彻底失控。

实验结果说了什么

论文在ProgramBench上做了详尽的对比实验,评价指标主要看测试通过率(Tests Passed,所有任务测试通过比例的宏平均)、几乎解决率(Almost Resolved,至少95%测试通过的任务占比)和完全解决率(Resolved,全部测试通过且没有作弊标记的任务占比)。

| 模型与脚手架组合 | 测试通过率 | 几乎解决率 | 完全解决率 |

|---|---|---|---|

| Qwen3.8-27B + 普通脚手架 | 34.87% | 3.50% | 0.50% |

| Qwen3.8-27B + Program-Agent | **55.71%** | 5.50% | 0.50% |

| Qwen3.8-27B-SFT(经Program-Env训练)+ 普通脚手架 | 42.84% | 1.50% | 0.00% |

| Qwen3.8-27B-SFT + Program-Agent | **56.25%** | 4.50% | 0.50% |

| DeepSeek-V4-Flash-0731 + 普通脚手架 | 57.68% | 4.50% | 0.00% |

| Claude Opus 4.7(旗舰模型) | 50.90% | 3.00% | 0.00% |

| Gemini 3.5 Flash(旗舰模型) | 53.60% | 3.00% | 0.00% |

这组数字背后有几层含义值得拆开看。

第一层,单独训练环境的价值。保持智能体脚手架不变,只是让模型在Program-Env生成的轨迹上做监督微调,Qwen3.8-27B的测试通过率从34.87%涨到42.84%,提升了接近8个百分点,甚至超过了旗舰模型GPT 5.4在传统脚手架下的37.70%。这说明光是喂给模型更真实、更可验证的训练数据,就已经能带来实打实的能力提升。

第二层,单独工作流程的价值。保持模型权重不变,只是换上Program-Agent这套三阶段工作流,Qwen3.8-27B从34.87%直接跳到55.71%,提升超过20个百分点。这个幅度比单纯做微调还要大,说明长程开发任务里,"怎么组织干活流程"这件事的重要性,有时候甚至超过了模型本身的能力底子。

**两者叠加后,Qwen3.8-27B-SFT配合Program-Agent达到56.25%,超过了Claude Opus 4.7和Gemini 3.5 Flash这些闭源旗舰模型。**

但这里必须泼一盆冷水。即便测试通过率能冲到50%以上,几乎解决率和完全解决率始终低得可怜,大多徘徊在个位数甚至0附近。论文原文里提到,在ProgramBench最初的评测中,没有任何旗舰模型能完全解决哪怕一个任务。这说明"大体复现对了"和"完美复现"之间,还隔着一道目前所有模型都迈不过去的坎。

测试预算(也就是Program-Agent允许迭代的轮数K)的影响也值得一提。论文做了K=1、3、5的对比,发现测试通过率从43.49%一路涨到54.13%再到56.25%,大部分提升集中在前三轮就已经兑现,之后的边际收益开始放缓。这个规律其实挺符合直觉的:第一轮搭好骨架,第二三轮修正大方向上的错误,后面的轮次更多是在打磨细节。

另外一个有意思的发现藏在智能体的行为分析里。论文统计了不同配置下AI在各个回合里花时间做什么操作,结果显示,普通单会话模式下,AI大部分时间花在执行命令和试探性探测上;而用上Program-Agent之后,读取类操作和版本控制类操作的比例明显上升,尤其是在经过Program-Env训练之后的模型身上更加明显。这说明Program-Agent这套机制确实把AI的行为模式往"先充分探索、再谨慎提交"的方向拉动了,这正是经验丰富的工程师处理陌生代码库时会做的事。

还有一处细节挺值得玩味。论文团队对比了AI生成代码的行数和参考程序的行数,发现当测试通过率达到75%以上时,生成代码的行数中位数只有参考程序的0.64倍。换句话说,AI并不是靠照搬参考程序的实现细节来过关的,它更倾向于用更精简的方式复现出同样的外部行为。这个现象在C/C++项目里最明显,生成代码中位数只有参考代码的0.39倍;而在Rust项目里最接近,达到0.72倍,论文给出的解释是Rust生态的项目结构本身就偏向于相似的实现范式,AI复现时自然也保留了类似的冗余度。

写在后面

读完这篇论文,有个细节让我反复琢磨。

论文里提到,整个数据集的难度分布严重偏向简单任务,1648个环境里1492个被判定为"易",只有5个是"难"。研究团队自己坦承这是有意为之的取舍,因为远超当前模型能力的任务,几乎产生不出任何成功的训练轨迹,收集再多也是在浪费计算资源。

这其实揭示了一个所有做强化学习训练数据的团队都会面对的两难。你想让AI变强,就得喂给它有挑战性的任务,但如果任务太难,AI连续失败几十次都拿不到一次正反馈,这些数据对训练毫无帮助。某种程度上,这和带新人有点像,给一个刚入职的实习生直接派一个三年经验才能搞定的活,他大概率学不到东西,只会反复挫败;但如果任务难度刚好踩在他"跳一跳够得着"的区间,成长曲线反而最陡峭。ProgramGym选择在简单任务上先把规模堆起来,某种程度上是在赌模型能力会随着时间进步,到时候同一套流水线可以逐步啃下中等难度甚至高难度的仓库。这是个务实但也带着赌注的策略。

还有一处我觉得特别值得单独拎出来说的,是论文里对"为什么不比较MindForge"这个问题的回答,他们直接承认对方没有公开训练环境和轨迹数据,所以没法在同一套协议下做对比。这种坦诚挺难得的,在一堆号称"全面超越"的论文里,愿意承认"这个对比我做不了"反而显得更可信。

这篇论文留下的最大悬念,其实是完全解决率为什么始终卡在接近零的位置。测试通过率已经能冲到55%以上了,为什么全部测试一次性通过的概率依然低得可怜?会不会是因为黑盒测试本身的覆盖面有上限,总有一些边角行为是AI无论怎么探索都摸不到的?还是说,长程任务里哪怕只有一个微小的行为偏差,也会在后续的层层调用中被放大成系统性的不一致?这个问题,可能要等到下一代能真正做到"完美复现"的智能体出现,我们才能回头看清答案。

Q&A

Q1:ProgramGym是什么?

A:ProgramGym是一个用于训练长程程序复现智能体的框架,由Program-Env和Program-Agent两部分组成,前者负责批量构建可验证的训练环境,后者负责让AI分角色协作完成从探索到实现的完整开发流程。

Q2:ProgramGym相比传统编程智能体训练方式有什么不同?

A:传统方式通常给AI现成代码库加明确任务描述,而ProgramGym训练AI在没有源码、不能联网的情况下,仅靠参考程序和文档去推断需求并独立设计实现方案,更接近真实软件工程师从零造物的场景。

Q3:ProgramGym训练后的模型效果如何?

A:270亿参数的Qwen3.8-27B经过Program-Env训练和Program-Agent加持后,在ProgramBench上的测试通过率从34.87%提升到55.71%,超过了部分闭源旗舰模型如Claude Opus 4.7。

资讯来源:由AI资讯编辑整理自互联网公开内容,版权归原作者所有,未经许可,不得转载。