引言:当编码 Agent 的瓶颈从写代码移到写规格
过去两年,编码 Agent 在单点功能实现上已经越来越强:给一个函数级的任务描述,配几条测试,前沿模型的通过率已经相当可观。但当任务规模上升到真实仓库的长程开发,开发者们反复观察到同一类失败——模型能写出"局部正确"的代码,却在多个需求相互纠缠时顾此失彼:满足了新功能,破坏了向后兼容;处理了正常路径,遗漏了错误路径;每个需求单独看都实现了,合在一起却互相矛盾。更隐蔽的是,这类失败往往还能骗过测试:模型自检通过、自写的回归用例全绿,最终却在用户场景里翻车。
本篇精读选取两篇从不同端口攻击这一问题的新论文。第一篇是小米 LLM Core 联合北京大学、香港大学发布的 When Requirements Interact: Scaling Long-Horizon Coding via Interdependent Specifications(后文以 CodeSpecWeave 指代),它从数据合成端出发:既然现有 SWE 训练数据里每个任务平均只携带一两条互不相干的规格,模型自然学不会联合推理,那就设计一条管线,把真实开发者需求中的"相互依赖规格"系统性地合成进 RL 训练任务。第二篇是 AWS Agentic AI 联合 USC、UCLA 等高校研究者发布的 Skeleton Coding: Program Structure as a Specification for Agents,它从规格表示端出发:既然需要多少条测试取决于实现的结构、而结构恰恰是 Agent 自己选的,开发者就永远无法预先知道自己的测试够不够;解法是让开发者直接用代码级的"骨架"同时指定结构与行为。
两篇论文一横一纵,共同指向同一个判断:长程编码能力的瓶颈,不在模型会不会写代码,而在规格怎么表达、怎么交互。CodeSpecWeave 证明:把规格之间的耦合做成任务的显式属性,只靠 4,670 个任务的 RL 就能把 DeepSWE-v1.1 成绩从 54.42% 拉到 62.98%,超过用 30,128 个任务的 SWE-PI(56.64%)。Skeleton Coding 则从理论上证明:选对了骨架,所需测试数可以从指数级降到多项式级——局部测试 O(4n) 就能识别端到端测试需要 Ω(2ⁿ) 才能识别的程序。一篇做实证的训练数据,一篇做理论的规格表示,合在一起读,恰好勾勒出"规格驱动开发"这个方向的全貌。
值得一提的是,这个判断与当下工程界的直觉转向不谋而合:从"vibe coding"的狂欢退潮,到 Kiro 等规格驱动 IDE 的出现,再到各团队给 Agent 补充 CLAUDE.md/AGENTS.md 这类项目级约束文件——业界已经在用脚投票。两篇论文的贡献在于分别把这一直觉锻造成了可度量的数据设计原则(规格耦合度)与可证明的规格设计理论(教学维度分离),让"写好规格"从手艺变成了科学。
速览:两篇论文一页纸
| 维度 | CodeSpecWeave (2610.40256) | Skeleton Coding (2610.38214) |
|---|---|---|
| 团队 | Xiaomi LLM Core + 北大 + 港大 | AWS Agentic AI + USC/UCLA 等 |
| 攻击端口 | 数据合成端(RL 训练任务) | 规格表示端(开发者怎么写规格) |
| 核心主张 | 规格之间的耦合度决定任务难度,应作为合成目标 | 需要多少测试取决于实现结构,结构应由开发者供出 |
| 核心构造 | 双 agent 管线:合成 agent 共构耦合需求+测试,review agent 审计多模型轨迹 | 代码级骨架:stub + EARS 局部契约 + 全局不变量 |
| 理论工具 | 可行空间因子分解的破坏(F ⊊ ∏Fⱼ) | 教学维度/识别理论:Thm 2.1 指数分离、Thm 2.2 局部 vs 端到端 |
| 最亮数字 | DeepSWE 54.42%→62.98%(超 SWE-PI 56.64%);73.9% 测试缺陷被审计检出 | 测试错误相对降 48.4%;SDDBench 29%→74.2%;局部 4n vs 端到端 Ω(2ⁿ) |
| 交付物 | 4,670 训练任务/2,865 仓库 + 100 任务基准 | 三级骨架规格方法 + SDDBench(13 库) |
| 局限 | 容器化基础设施与强模型过滤成本高 | 依赖从参考实现反推规格,手写骨架成本未量化 |
第一篇:CodeSpecWeave——当需求相互作用时
论文标题:When Requirements Interact: Scaling Long-Horizon Coding via Interdependent Specifications
团队:LLM Core, Xiaomi + Peking University + University of Hong Kong
链接:📄 原文链接
背景与定位:SWE 训练数据的"规格贫瘠"问题
真实世界的软件开发从来不只关乎主功能。接口兼容、状态一致性、错误处理、并发约束——这些"多维任务规格"共同构成一个任务的需求面。编码 Agent 要在真实仓库里立足,必须在探索、编码、测试的全过程中同时满足这些规格,且不破坏其他组件已依赖的既有行为。但作者对现有 SWE 训练数据集的实证分析给出了一个量化画像(论文图 1,含 95% bootstrap 置信区间):在 Scale-SWE(平均 4.38 条规格/任务、1.83 个类别)、SWE-rebench V2(1.44 条、1.41 类)、SWE-Lego(1.33 条、1.28 类)、R2E-Gym(2.15 条、1.49 类)这些数据集里,任务平均只有 1 到 4 条规格,且这些规格彼此独立——就像一份可以逐项打勾的清单(checklist)。在 CodeSpecWeave 自己的数据里,这个数字是 8.36 条规格、4.08 个类别(训练集),基准集更是高达 10.44 条/任务(100 个任务、1,044 条规格,中位数 9、范围 3-31)。
论文图 1 底部给了一个直观对照。既有数据集的典型任务是两条独立规则:按消息 ID 去重(每个 ID 保留首条消息、跳过后续重复)与空批次返回空列表——互不相干,可以逐条实现。而 CodeSpecWeave 的典型任务围绕一个消息认领生命周期展开 13 条规格:并发预留(S1)、失败重试释放(S4)、成功后保留至过期(S8)、清理必须兼容取消场景(S5/S7)、保留旧 API 与急切认领行为(S6)……所有规格通过共享的执行上下文与生命周期约束编织在一起。
用这类"规格贫瘠"的数据训练出来的 Agent,行为模式自然是局部贪心:逐条满足需求、逐个文件打补丁,一旦真实任务里出现"满足 A 会改变 B 的可行实现方式"这类耦合,就会大面积翻车。在任务合成谱系里,Magicoder 从开源代码片段生成问题、KodCode 借助编程练习与库文档、R2E-Gym 从 commit 出发用测试生成与回译构造任务、SWE-smith 通过修改可运行代码制造修复任务、SWE-Flow 用单元测试与运行时依赖构造增量开发任务、TaskPilot 用求解器反馈联合精化任务/参考补丁/测试。CodeSpecWeave 与它们的本质区别在于:把工程需求的覆盖度与交互性作为任务合成的显式目标,而不是搭一条能跑通就好的任务工厂。
在软件规格这条线上,ArchCode 从问题描述组织功能与非功能需求、SpecRover 从 issue 与仓库上下文推断意图、REAgent 产出含根因分析与建议修改的结构化需求、CodeSpec 用双可执行规格维持功能链设计与实现的一致性、DevAI 把开发需求组织成依赖图、SWE-AGI 用标准与 RFC 评测系统构建。这些工作把规格当作任务的描述或评测的组织形式,而 CodeSpecWeave 把规格的耦合结构当作任务本身的构造原理——需求被编织成"满足一条就约束另一条"的网。
问题定义:从可分解到不可分解
论文用一个非常干净的形式化刻画了"规格交互"。任务定义为四元组 T = (R, Q, S, E):R 是代码仓库,Q 是给求解器的自然语言请求,S = {s₁, …, sₘ} 是 Q 中嵌入的规格集合,E 是带验证器 V 的执行环境。求解器产出补丁 Δ,当 sᵢ(Δ) = 1 对所有 i 成立时 Δ ∈ F(T);实践中验证器 V 通过执行测试套件检查 Δ 是否属于 F(T)。
关键在下一步。设 d = (d₁, …, d_k) 是规格集 S 允许的工程决策变量,F_d 是可行空间。如果任务可分解,那么 F_d = ∏ⱼ F_j——每个决策可以在自己的子空间里贪心求解,任务退化为清单。而相互依赖规格打破了这个因子分解:F_d ⊊ ∏ⱼ F_j,满足某一条规格所做的选择会严格收缩另一条的可行集。局部编辑无法解耦,求解器被迫跨所有需求做联合推理。这就是"交互性"的数学定义,也是整个方法的原点:论文坦言,早期只堆规格数量的合成尝试里,语言模型仅靠逐条孤立满足就能拿到高分,任务毫无难度可言——“朴素堆规格"和"刻意造耦合"之间隔着一道本质鸿沟。
举一个论文附录 D 的完整任务示例来体感这种耦合:Skycoin 交易构建器的新 hour 分配功能。它要求对多收款人按币量比例分配 coin hour(确定性整数取整、平局按请求顺序、不得有收款人拿到零),有找零输出时先按既有 50/50 政策拆分(奇数 hour 给找零),无找零时不得丢弃 hour,输出顺序保持请求序、找零最后;同时不得回归单收款人的既有行为(原有的 hour 上限与输出值必须原样保留)。比例规则适用于多收款人、旧上限只适用于单收款人——把两条规则不加区分地应用到所有请求就会违反新分配政策。分配、取整、输出构造被同一个任务的五条需求联合约束,这就是 F_d ⊊ ∏ⱼ F_j 的工程肉身。
再用论文图 1 底部那个 13 条规格的消息认领任务把交互性说透。这个任务要求实现一套消息处理前的"认领”(claim)机制,规格包括:S1 并发预留——处理前必须预留,阻塞并发重复;S4 重试——失败后释放认领,同一 key 可重试;S8 保留——成功后认领保留至正常过期;S3 生命周期与并发约束;S6 兼容——保留旧 API 与急切认领行为;S5/S7 取消——消息取消后清理仍须工作;另有输出与错误保留规格。关键在于:这些规格共享同一份状态(认领记录)与同一个生命周期(预留→处理→释放/过期),S1 的"阻塞并发"与 S4 的"释放重试"作用于同一份状态的不同转移——实现"阻塞"时加宽锁粒度就会杀死"重试"的可行性,实现"保留至过期"时忘记清理路径就违反 S5/S7。单独抽任何一条出来都是一个平庸的实现题;织在一起,每条规格都成了其他规格的约束条件。
解法:合成 + 审计的双 agent 管线
CodeSpecWeave 的管线分两个阶段,对应开篇提出的两个挑战——如何让规格真正耦合,以及如何验证这种耦合。整条管线的漏斗形态大致是:104,182 个规格种子 → 14,905 个初始任务 → 3,275 个过难度过滤 → 766 个过对齐审查(单批),最终全管线累计产出 4,670 个训练任务。
第一阶段:任务合成。 首先从开源仓库的 commit 历史、issue 讨论和 pull request 中挖掘真实开发者规格,过滤掉对话噪声和原始代码片段后,经归一化去重得到 104,182 个候选规格单元(覆盖六种自然语言),以此构成一份包含示例、定义与边界指引的规格参考。合成 agent(MiMo-V2.5-Pro,Claude Code harness)在给定仓库内探索代码库,把互补的需求锚定到相同的状态转移或核心组件上——例如把输入校验、事务回滚、既有读者的向后兼容耦合进同一个任务,使得孤立地满足任何一条都会违反整体契约。合成 agent 迭代起草任务请求 Q、细粒度规格 S 与对应测试 A,测试与规格是多对多的灵活映射(多个测试验证一条规格、一个集成测试覆盖多条义务),并且直接在仓库里执行生成的测试、根据运行时反馈迭代修正。
第二阶段:验证与修复。 论文给出了一组发人深省的数字:在一批 14,905 个初始任务中,难度过滤(筛掉太简单与太困难的)保留 3,275 个候选,而审查 agent 对其中 3,067 个候选的审计发现 73.9%(2,267 个)存在测试对齐缺陷——50.5% 只有假阳性(接受不完整实现)、13.9% 只有假阴性(拒绝有效解)、9.6% 两者皆有,仅 26.1% 未观察到问题。这个数字本身就是对"让 LLM 自动生成可靠测试有多难"的一次实证回答:需求之间交互越密切,测试越容易漏掉只在交互时才暴露的缺陷,也越容易把某一种实现方式错当成需求本身。
修补方式同样务实:这些缺陷只在代码真正跑起来面对需求时才显形,静态检查代码或测试都看不出来。于是收集多个独立编码模型(MiMo-V2.5-Pro 与 MiMo-V2.5-Flash,多次尝试)的求解补丁 Δ 与执行轨迹 τ,只保留"部分模型成功"的混合结果任务(太难太易都被过滤);review agent 检查完整四元组 (Q, A, Δ, τ)——违反多条规格却通过的运行暴露缺失的检查(假阳性),满足规格却失败的运行暴露测试夹带了未声明的实现假设(假阴性);对确认有缺陷的候选,修复 agent 依据审查发现与执行轨迹修订任务请求或验证器,修完后重跑所有执行检查、新鲜求解试验与对齐审查。最终一批从 14,905 个任务里筛出 766 个验证通过的任务。管线全程还设有基线检查:未修改仓库跑生成的测试必须按预期失败,防止测试空转。
实验证据:更少但更难的数据赢得 RL
训练设置。 用 GRPO 对两个 MoE 模型做 RL:MiMo-V2.5 与 MiMo-V2.6-Flash-SFT(均为 310B 总参/15B 激活)。训练超参:batch size 128、每任务 16 个样本、温度 1.0、top-p 0.97、prompt 上限 8,192 token、响应上限 516,096 token。训练数据对比三套 RL 数据集:CodeSpecWeave(4,670 任务/2,865 仓库)、SWE-PI(Prime Intellect 发布的 30,128 任务混合集,含 Scale-SWE、SWE-Lego、SWE-rebench V2、Multi-SWE-RL)、MiMo Coding(小米内部多管线策划集:issue 驱动开发、日常开发工作流、功能实现、长程工程)。评测覆盖四个基准:CodeSpecWeave-Bench(100 任务/1,044 规格,经作者人工逐任务审查任务描述、验证器、补丁与轨迹)、DeepSWE-v1.1(113 个长程任务)、SWE-bench Verified(500 题人工验证)、SWE-bench Pro(731 题多语言)。评测设置:每任务 3 个样本、512K 上下文预算、温度 1.0、top-p 0.95。
值得一提的是查询长度分布(附录 C.2):CodeSpecWeave 任务的中位查询长度 2,131 字符(P10-P90 为 1,414-2,856),而其他训练数据集为 731-1,361 字符——更长的任务描述本身也是任务更丰富的一个旁证。
主结果。 在 MiMo-V2.6-Flash-SFT 上,CodeSpecWeave 训练拿到全场均分 67.60%,其中 DeepSWE-v1.1 从 Vanilla 的 54.42% 提升到 62.98%,显著超过 SWE-PI 的 56.64% 与 MiMo Coding 的 50.74%——用不到 SWE-PI 十六分之一的数据量,在长程基准上反超 6.34 个百分点。更值得注意的是 SWE-PI 在 MiMo-V2.5 上出现负迁移(DeepSWE 12.39% → 6.78%),而 CodeSpecWeave 依然稳定提升(12.39% → 25.30%)。在基准自身上,Flash-SFT 从 59.00% 提到 70.67%(SWE-PI 66.33%、MiMo Coding 69.00%)。同时 SWE-bench Verified/Pro 保持了有竞争力的成绩(77.40%/59.37%,均为第一或第二),说明提升并非以牺牲常规能力为代价。学习曲线(图 5)显示 CodeSpecWeave 在两个骨干上的 CodeSpecWeave-Bench 与 DeepSWE 双双稳步上行,无震荡或过拟合迹象。
分规格数与类别的增益。 按任务规格数分桶(3-8 条/36 任务、9-11 条/32 任务、12-31 条/32 任务),Flash-SFT 训练后增益分别为 +10.2、+12.5、+12.5 个百分点——规格越多的任务增益越大,恰好验证"交互规格训练出联合推理能力"的机制假设。按七个规格类别分解,增益均衡分布在 9.5-14.9 个百分点之间,功能语义与接口契约、执行顺序、状态、错误处理等约束类别均受益。基准的规格分类学(附录 C.1)本身也值得参考:1,044 条规格分为功能语义(470,45.0%,再分为解析与表示 182、计算与算法 145、领域与协议规则 143)、状态与副作用(181)、错误与恢复(187)、接口与 I/O 契约(108)、控制流与顺序(98)——非功能约束合计过半,这正是现有数据集缺失的那部分。
行为变化。 训练后的模型呈现出清晰的行为迁移:thinking tokens 在两个模型上分别放大 4.8×/3.0×(29.7k→141.6k、22.8k→69.5k),修改文件数从 4.47→9.79 与 4.09→6.17,修改行数 451→3,632 与 350→667——从局部补丁转向跨文件重构。最关键的是这种行为有验证闭环兜底:编辑-测试循环(一次或多次代码编辑后跟一次可执行测试反馈)从 3.48→4.34 与 2.96→4.90,≥2 次循环的轨迹比例从 63.0%/69.0% 升至 72.7%/78.3%,测试失败后再编辑再测试的比率从 77.1%/77.7% 升至 86.0%/87.1%。训练动力学上,策略熵全程稳定在 0.29-0.40,确认是持续的策略改进而非熵坍缩;两个模型还展现出不同的适应策略——MiMo-V2.5 靠拉长单轮输出(响应长度翻倍以上),Flash-SFT 靠增加多轮交互(agent turns 近乎翻倍),殊途同归地加大单位任务的探索投入。
基准区分度。 CodeSpecWeave-Bench 上,GPT-6 Astra 74.0% 最高,往下依次是 Claude Opus 5 71.1%、GPT-5.6 Sol 69.0%、GPT-5.5 67.0%、GPT-5.4 66.0%、Qwen3.8-Max 65.0%、MiMo-V2.6-Flash-SFT 59.0%、Kimi K3 55.0%、MiMo-V2.5-Pro 47.0%、MiMo-V2.5 44.0%——最强模型仍有 26% 失败,headroom 充足。评测跨越三种 harness:OpenAI Codex(四个 GPT 模型)、Claude Code(Claude Opus 5、Kimi K3、Qwen3.8-Max)、MimoAgent(三个 MiMo 模型),说明区分度不是某一框架的伪影。一个有趣的观察是:更高通过率不需要更多输出 token,GPT-6 Astra 以最短的 17.2k 输出拿到最高分,Codex 内四个 GPT 模型通过率随平均输出长度单调下降(74.0%@17.2k → 66.0%@31.8k),Claude Opus 5 比 Qwen3.8-Max 高 6.1 个百分点却少用约 47% token——多出来的长度主要是解纠缠规格时的无效试错,而非有效推理。
失败模式。 论文附录 F 用前沿 agent 解剖失败样本,给出两类典型失败。其一,规格被部分执行(incomplete enforcement)——SimpleX Markdown 解析任务(11 条需求)里,补丁实现了标点边界处理与链接识别,agent 在 GHCi 里的探针也能识别括号内 URL,但文本前缀后跟 URL 的场景(See(URL))最终评测仍是纯文本:需求只在部分输入设定下成立,agent 的自检探针恰好落在成立的那个子域里。其二,满足一条违反另一条(interacting requirements)——Hyperledger Iroha 多签交易任务(9 条需求)里,agent 同时处理签名合并与状态隔离,插入时克隆了交易(copyTx),但整体状态拷贝后两个状态共享同一交易对象,向副本添加签名(addSignature 原地更新)的同时也改了原件:验证器测得原件签名数期望 1、实测 2。而 agent 的 39 个自写测试(含它自己写的隔离用例)三连跑全过——自测覆盖不到耦合路径。这两类失败,正是"交互规格"难度的具象化:错误不在单个功能的实现里,而在功能之间的缝隙里。
数据与实验细节一图流。 为方便复查,把关键数字集中列出:规格种子 104,182 单元(六种语言);单批合成 14,905 → 难度过滤 3,275 → 审查通过 766;训练任务 4,670/2,865 仓库;基准 100 任务/1,044 规格/均值 10.44(中位 9,范围 3-31);查询中位长 2,131 字符;RL 超参 batch 128、16 样本/任务、响应上限 516,096 token;评测每任务 3 样本、512K 上下文。
根源解释:为什么交互规格的数据更有效
回到因子分解 F_d ⊊ ∏ⱼ F_j。当任务可分解时,局部编辑即可通过测试,梯度信号奖励的是"逐项打勾"的浅层策略;而当规格耦合时,任何单点修改都会波及其他需求的可行域,唯一通过路径是全局推理。RL 在这类任务上的奖励因此塑形出了三种可观察的行为:跨文件重构(修改面扩大)、主动验证(编辑-测试循环增多)、失败后重试(重测率上升)。换句话说,数据不是在教模型更多知识,而是在教它一种"先联合推演、再动手、再验证"的工作方式。73.9% 的测试缺陷率则从反面说明:合成交互规格的测试极易夹带实现假设或漏检交互缺陷,多模型轨迹审计不是锦上添花,而是这类数据可用的前提。
论文识别出的两类失败模式也佐证了这一点:无论"部分执行"还是"满足一条违反另一条",失败都发生在需求之间的缝隙里,而这类缝隙恰恰是单需求数据永远覆盖不到的。
局限与成本
作者在 Limitations 一节坦承三点:其一,用合成任务做 RL 需要可观的计算资源;其二,每个任务配一个容器镜像、跑在 Kubernetes pod 上,训练与评测都要求能并发管理大量容器的基础设施;其三,高质量任务依赖强模型与多轮过滤,会丢弃大量生成候选。这最后一点意味着管线的"任务转化率"天然偏低,规模化路径不完全靠堆算力就能铺平。
知识反推:从这篇论文可以提炼出的领域事实
- 现有 SWE 训练集的规格密度平均只有 1.3-4.4 条/任务且彼此独立,与真实工程任务的需求密度相差一个数量级,这是长程能力欠拟合的直接数据学解释。CodeSpecWeave 训练集的 8.36 条/4.08 类与基准的 10.44 条/任务给出了"下一个数量级"的参考坐标。
- LLM 自动生成的测试在复杂规格下不可信是常态而非例外——3,067 个候选中 73.9% 有对齐缺陷,其中约六成问题(50.5% 假阳性)是"测试放水",约四分之一(13.9% 假阴性 + 部分双向)是"测试过严"。做任务合成或自验证相关工作时,这是必须正视的基线事实。
- 混合求解成功率是任务质量的有效信号:全部模型都能解或都不能解的任务对 RL 几乎无信息量,“部分成功"的任务才是可学习任务。
- RL 数据的质与量可以解耦:4,670 个高交互任务全面胜过 30,128 个常规任务,且在非分布基准(SWE-bench 系列)上无退化;反过来,量大方桶也可能出现负迁移(SWE-PI 在 MiMo-V2.5 上)。
- 强模型在难任务上的效率优势:GPT-6 Astra 以最短输出拿最高分,且通过率与输出长度在 Codex 内单调负相关——“反复试错拉长输出"是能力不足的信号而非勤奋的标志。
- RL 训练改变的是工作方式而非知识:修改面扩大、验证循环增多、失败重测率上升、策略熵保持稳定——四个指标联合刻画了"从局部贪心到全局推演"的策略迁移。
通用灵感:超越编码任务的启示
- 把"不可分解性"作为数据合成的筛选标准,可以推广到任何多约束域:多目标工具调用、长程规划、多轮对话一致性——只要构造出"单点最优 ≠ 全局最优"的训练信号,就能逼出联合推理行为。
- 验证器质量决定数据上限。用多模型的执行轨迹交叉审计测试的假阳/假阴,这一流程可平移到任何"自动生成评测"的场景——数学题的自生成答案校验、工具调用轨迹的自生成评分,都面临同构的假阳/假阴风险。
- 行为指标(循环次数、重试率、修改面)比通过率更能刻画训练带来的策略变化,做 RL 训练分析时值得作为标配。CodeSpecWeave 展示的"输出更长 ≠ 表现更好”(GPT-6 Astra 用最短输出拿最高分)也提醒:token 预算与质量的换算关系并不稳定,评测时报告 token 开销应成为惯例。
- 规格密度是可以设计的任务属性。如果要构造评测集,“每任务多少条规格、覆盖几个类别、彼此是否耦合"这三个参数比任务数量更能决定基准的区分力。
- 难度过滤的"混合成功率"原则可以直接复用:一个候选任务只有在部分求解器成功时才有教学价值,全自动通过或全军覆没的任务都应剔除。
第二篇:Skeleton Coding——程序结构本身就是规格
论文标题:Skeleton Coding: Program Structure as a Specification for Agents
团队:AWS Agentic AI + USC/UCLA 等学界作者(Golatkar、Achille、Soatto 等)
链接:📄 原文链接
背景与定位:“只说 what、不说 how"的信条正在失效
规格驱动开发的主流叙事承袭 Dijkstra 的关注点分离(separation of concerns):开发者负责声明"任何可接受结果必须有什么行为”(what),通过 prompt、示例、测试或形式化契约表达;至于"怎么实现”(how),交给 Agent。这套分离承诺把开发者从写代码的劳役中解放出来,也是 Kiro 这类规格驱动 IDE 产品的理念底座。但本文一上来就拆这个台:这种分离实际上可能让所需努力指数级增长。
论证的支点是一个此前被忽视的观察:需要多少测试、需要哪些测试,不是被实现函数的属性,而是被实现结构(implementation structure)的属性。作者举的例子是 NumPy 的索引规则:穷举其全部边界行为需要大量测试与示例,但其中大多数都从单一结构选择自然导出——把数组实现为内存的跨步视图(strided view of memory)。没有哪个端到端测试能表达这个结构;而结构选择权恰恰握在 Agent 手里。为一种结构准备的充分测试集,对另一种结构可能严重欠定,需要完全不同的边界用例乃至指数级更多的示例。开发者无法在没看到 Agent 选了哪个结构之前确定自己的规格是否完备——除非反向工程数千行生成代码,这恰恰是规格驱动开发想要免除的劳动。
形式化地,Agent 面对的是一个识别问题(identification problem):H 是它能产出的程序全集,G ⊆ H 是开发者可接受的目标程序集。Agent 先做出结构承诺(数据类型/模块/函数的分解),把搜索空间限制到某个假设类 H_S;测试再从 H_S 内部选出具体程序。测试在两个层面同时起作用——在每个骨架内选程序,以及按存活程序的先验质量重新加权骨架本身(p₀(G|D) = Σ_S p₀(S|D)·p_S(G|D))。开发者即便供出骨架之外什么都不做,只要所选骨架的成功率高于 Agent 自选的平均水平,就已经在提升成功概率。
第二个理论框架转换同样重要:把 AI 辅助编码从"生成问题"重述为控制问题。开发者的角色不是"需求方"而是控制器:给定输入-输出观测 D,希望 prompt 之后 Agent 以高概率产出 G 内程序(p₀(G|D) ≥ 1−δ),关心最小测试数 N_δ。问题的麻烦在于最优 D 依赖于 H_S,而开发者看不到 H_S。Skeleton Coding 的解法干脆利落:让开发者直接供出 H_S——不再用一个测试一个测试地雕刻目标集,而是先收缩假设类,再为这个小类提供最优测试。
骨架的具体形态是高保真、代码式的部分抽象:数据类型、模块边界、允许的调用与数据流、带签名的函数声明,外加局部契约与全局不变量,省略实现体。论文图 1 右侧给了一个精炼的示例——为跨步视图(strided view)写的切片函数契约:
class View:
buffer: list[float]; offset: int; stride: int; size: int
def slice_view(v: View, lo: int, hi: int) -> View:
"""Return a slice that shares the original data buffer.
Requires:
THE CALLER SHALL ensure 0 <= lo <= hi <= v.size.
Ensures:
THE CALLABLE SHALL return r with:
r.buffer is v.buffer; r.stride == v.stride,
r.offset == v.offset + lo * v.stride,
r.size == hi - lo.
THE CALLABLE SHALL NOT modify v or its buffer.
"""
...
寥寥几行就把"切片共享底层缓冲、跨步不变、偏移线性映射、禁止原地修改"这套结构性决策钉死了——这些恰恰是任何端到端测试都无法表达的实现级约定。注意这个契约的写法:类型签名承载结构,EARS 句式(THE CALLER/THE CALLABLE SHALL …)承载行为义务,前置条件划分调用方责任——三种信息各就各位。
论文附录 A 给出了十种规格形态的完整模板(以一个虚构的图书借阅模块 booklend 为例):(i) Task only(README 式任务描述);(ii) Concrete Behaviors(EARS 格式的单例输入-输出目录);(iii) Generalized Behaviors(量化输入类的 EARS 规则);(iv) Behavioral Tests(对公共 API 的可执行 pytest);(v) Design(prose 设计文档 + EARS 验收标准);(vi) Signature Specifications(.pyi 式 stub 树,首个固定内部表示的层级);(vii) Local Contracts(stub 加 docstring 内的 EARS 后置条件);(viii) Global Invariants(局部契约加跨函数的 INVARIANTS.md);(ix) Architecture Specifications(五级递进的 prose 架构文档);(x) Native Skeleton(ProgramBench 用的源语言骨架,如 Rust 的 unimplemented!() stub + 模块级 EARS 契约文件)。这个模板目录本身就是一份实用的"规格设计词汇表”。
问题定义与理论结果:三条指数定理
先把四条理论结果的主线摆出来:定理 2.1 说"同样大小的假设类,结构不同则测试数指数不同";定理 2.2 说"暴露中间接口可把端到端的指数测试降为局部的线性测试";命题 2.3 说"有些需求测试永远表达不了";定理 2.4 把总成本拆成可优化的三项。四条合起来,构成"骨架为什么有效"的完整理论账本。
定理 2.1(骨架间的指数分离)。 对任意 d ≥ 1,存在目标函数与两个骨架 S_A、S_B,各含 2^d 个行为互异的程序(均匀先验),使得对每个 0 ≤ δ < 1/2:N_δ(S_A) = 2^d − 1 而 N_δ(S_B) = d。构造基于奇偶函数 f*(x) = x₁ ⊕ … ⊕ x_d:S_A 允许"联合异常分支"(每个错误程序只在单一输入 a 上偏离目标),每条测试至多排除一个程序;S_B 把偏差组合为 XOR 累积(h_a(x) = f*(x) ⊕ ⟨a,x⟩),每条测试(秩 r 的输入)砍掉一半候选,d 条标准基测试即够。直观图景(论文图 4):两个骨架都从 16 个候选程序出发(d=4),弱骨架每加一条测试只淘汰 1 个,4 条后还剩 12 个;强骨架每条测试对半砍,4 条后只剩 1 个。定理第二部分更扎心:为 S_B 设计的 d 条最优测试在 S_A 下成功率只有 1/(2^d − d)。而且按公式 p₀(G|D) = Σ_S p₀(S|D)·p_S(G|D),条件化于 D 反而会把 Agent 的概率质量推向测试最不具信息量的那个结构——因为那个结构损失的程序最少。附录 E.1 还给了一个信息论视角:同一条带标样本在 S_A 下只提供 Θ(2^(-d)) 比特信息,在 S_B 下提供整整 1 比特。这解释了为什么"给足测试"在实证中救不了行为规格。
定理 2.2(局部测试与端到端测试的指数分离)。 考虑读 n 个输入位、携带一位状态的链式程序 zᵢ = hᵢ(xᵢ, zᵢ₋₁),z₀ = 0,F_h(x₁, …, xₙ) = zₙ,每个 hᵢ : {0,1}² → {0,1}。目标是实现恒零函数(G ∩ H_S = {h ∈ H_S : F_h ≡ 0})。存在先验(参考实现占 1/2 质量)使得端到端测试需要 N_δ(S) ≥ 2ⁿ·(1−2δ)/(1−δ)、精确识别 N₀(S) = 2ⁿ 条;而任意给正确解正质量的先验下,4n 条局部测试即可识别整个程序。构造的直觉:把先验质量 2^-(n+1) 放在每个"单点指示器"实现上,每次测试恰好排除一个实现,全零的观察记录让所有未测输入对应的错误实现存活。原因有二:程序只有 4n 个未知真值表位(每个 hᵢ 的真值表 4 位),但输出会掩盖分歧发生的位置——状态记录了"至今输入是否都匹配 a",一旦失配后续阶段保持零,端点测试既看不出哪个阶段拒绝也不知其他阶段会怎么做;局部测试在错误被后续计算掩盖之前直接观测组件。这正是软件可测试性理论中"故障执行-感染-传播"(fault execution, infection, propagation)三环节的形式化回声:端到端测试必须等到感染传播到输出,局部接口则同时提供了可控性与可观测性。附录 E.2 还补充了无先验的最坏情形:即使允许自适应选择输入,精确识别仍需 2ⁿ 次端到端查询。
命题 2.3(行为测试无法区分实现质量)。 若目标集 G ⊂ [h₀](与参考实现输入-输出等价的程序类 [h₀] 的真子集,例如排除资源浪费、可维护性差的实现),则对任意测试集 D 有 p_S(G|D) ≤ p_S(G)/p_S([h₀])——后验被先验比率封顶,1−δ 超过该比率时 N_δ(S) = ∞。证明很直白:[h₀] 里每个成员都通过所有测试,条件化不改变类内相对权重。代码质量、资源消耗这类需求对输出测试根本不可见,唯一的控制手段是写进骨架。
定理 2.4 进一步把骨架成本分解为"描述 + 局部测试 + 兼容性测试":N₀(S) = min_{G₁,…,G_k} [Σᵢ Nᵢ(Gᵢ) + J_S(G₁, …, G_k)],且 J_S = 0 当且仅当 H_S ∩ ∏ᵢ Gᵢ ⊆ G——即"组件各自合格则整体必然合格"。完整的 Hoare 风格前后置条件恰好达到 J_S = 0,此时组件相互独立,可交给多个(甚至更小的)Agent 并行实现而互不冲突,每个 agent 面对的任务也更简单。
第 3 节处理闭环问题:开环的初始条件至多是"条件化"而非"控制",而且 LLM 的 prompting 并非贝叶斯条件化——加规格不保证单调改进(实证中过细契约反而降分)。两条出路:其一,规格可形式化检查时,用拒绝采样(rejection sampling)兜底,保证随规格增加最终收敛;命题 3.1 证明逐组件重采样的期望代价是 Σ 1/αᵢ 而整程序重采样是 ∏ 1/αᵢ——又一处乘法变加法。其二,非正式契约(写在 docstring 里、由 agent 自查或 judge 模型检查)下,命题 3.2 刻画假接受率 εᵢ = βᵢ + (1−βᵢ)eᵢ:βᵢ 是契约措辞本身允许的违规比例(任何 judge 都删不掉的地板,只能靠把契约写得更精确压到零),eᵢ 是 judge 自身的误判率;judge 只有在 εᵢ ≪ αᵢ 时才真正有用。这组结果合起来给出一条工程定律:验收层必须机械可查,且检查粒度必须对齐组件粒度。
实验证据:三个基准、四种模型的一致图景
实验覆盖 GPT-5.6 Sol、GPT-5.6 Luna、Qwen3.8-27B、GLM 5.2 四个模型,三类基准:SCBench(35 个问题的长程迭代 greenfield,评测重建最终仓库态)、自建 SDDBench(13 个从真实 Python 库匿名化派生的库:Babel→LocaleFoundry、marshmallow→serializor、statsmodels→StatWeaver、xarray→AxisAtlas 等,重命名包名、改写项目描述以降低直接识别)、ProgramBench(20 个提供 oracle 二进制的任务:brotli、fzf、ninja、typst、xz 等)。
实验协议值得细看,它是所有结论的方法学基础。每个实验从真值代码库 h* ∈ G 出发,按实验条件 c 从 h* 生成规格 S_c;参考代码随后被隐藏,实现 agent 只凭任务描述 T 与规格 S_c 采样重建程序 h ~ q_θ(·|T, S_c);结构条件下的规格是骨架,行为条件下的规格是从参考导出的观测,task-only 基线不提供任何规格。功能正确性用对应评测套件的通过率计分(评测套件与实现过程隔离执行)。这个"同一真值、多种规格、同一 agent"的受控设计把变量干净地隔离在"规格携带什么信息"上。所有实验跑在开源 AI Functions 框架上,指标含测试通过率、代码侵蚀(cyclomatic complexity > 10 的函数所占复杂度质量份额,质量为圈复杂度乘以源行数平方根)、冗长度(重复/模式化代码行占比)与按 token 计价的实现成本(含输入、输出与缓存读取)。
行为规格的天花板。 ProgramBench 上即便提供 oracle 二进制(完整行为规格),模型也只过 61.5% 的隐藏测试。更系统的实验:把约 25% 的参考通过测试留作评测,其余作为可用池,按 0/33.3/66.7/100% 四档嵌套子集喂给 agent(固定种子抽取、所有条件在同一留出集上评分),结果是通过率随测试数上升,但平均而言任何数量的测试都不足以让 agent 识别出正确程序——定理 2.1 预言的实证版。Figure 10 的补充实验进一步显示:在同样保留 oracle 访问的条件下,Task only 64.0% → 签名规格 71.7% → 局部契约 70.9% → 全局不变量 73.7%,prose EARS(73.6%)与原始注释(63.3%)作对照——结构信息稳定兑现。
结构规格碾压行为规格。 SCBench 平均通过率 71.7% → 89.2%,SDDBench 29% → 74.2%;相比之下最好的纯行为规格(含 EARS 具体化/泛化、可执行行为测试)最多提升 9.4 个百分点。跨三基准四模型,最佳骨架规格相对最佳端到端行为规格平均测试错误相对降 48.4%(40.7% → 21.0%)。仅加函数 stub 就把 SDDBench 从 53% 提到 66.4%。骨架覆盖率实验(附录 D)显示收益随覆盖度单调上升:按复杂度排序保留 25/50/75% 的契约子集,通过率逐级爬升,SCBench 最佳骨架均值达 94.62%、SDDBench 达 92.09%;目录草图加逐文件夹规格也能再提升 ProgramBench 通过率。
有 oracle 也照样有用。 ProgramBench 上 agent 可任意查询 oracle 的条件下,加带局部契约的骨架仍把平均通过率相对提高 10.9%(64.0% → 70.9%);最佳结构条件(全局不变量骨架)把四模型平均测试错误相对降 27.0%(36.0% → 26.3%)。更严苛的对照:把 curated 观测从 20 加到 160 条(或允许无限查询),任何数量下都严格劣于"骨架 + 20 条查询"——观察数量弥补不了结构信息。
代码级优于文档级。 prose 架构文档逐级加细节(组件边界→数据模型→协作→仓库布局→文件草图,五级嵌套,输入膨胀 4-7 倍),SCBench 61%→71%、SDDBench 40.1%→52.8%,但每一级都仍低于同仓库上的最佳代码式骨架规格。这说明差距不在信息量而在表示形式:类型签名与契约是模型可直接对齐的结构化锚点,prose 里的同等内容要先被"翻译"才能起作用。
缩小模型差距、降低成本。 GPT-5.6 Luna(小模型)配详细全局不变量:SCBench 67% → 90%、SDDBench 21.1% → 79.5%,距最强 GPT-5.6 Sol 的成绩仅差 5.0-8.2 个百分点,而实现成本低约 15× 与 26×。大小模型平均差距缩小约 52.4%。成本-性能 Pareto 前沿几乎全部由"小模型 + 结构规格"组合构成——规格是比参数量便宜得多的算力杠杆。
代码质量。 结构规格相对 task-only 把代码侵蚀从 0.66→0.56(SCBench)与 0.41→0.24(SDDBench),行为规格反而把侵蚀推高到 0.73/0.43——平均降低 24.7% 侵蚀,命题 2.3 的直接验证。冗长度各条件间变化较小,但 SDDBench 上结构规格同样最低。迭代修复场景(8 轮、每轮披露新失败测试、代码与骨架带入新会话)下,骨架工作流以 32% 更少的 oracle 查询(2,341 → 1,587 次调用)达到相近错误率,累计成本 $823.19 → $661.71,且最终代码侵蚀更低(0.890 → 0.840)、可维护性更高(3.12 → 4.22)。
一个重要的反直觉发现:过细契约伤小模型。 在最佳骨架上继续叠加正确但过于详尽的局部/全局契约,性能不升反降,小模型受损最明显。作者称之为非贝叶斯行为(prompting ≠ conditioning)导致的"模型疲劳"(model fatigue)——理论上贝叶斯后验下加规格不应变差,实践上规格越多、真实条件化越难近似。这为"规格越多越好"的朴素直觉画了红线。
根源解释:为什么骨架如此有效
三条机制共同作用。其一,假设类收缩:骨架直接砍掉 H 中大部分程序,测试从小类里挑程序的难度自然骤降——且定理 2.1 说明这不只是维度效应,同等大小的类,结构好的类比结构差的类需要指数级少的测试。其二,中间状态可观测:骨架的接口给每个组件起了名字,组件错误无需传播到输出即可暴露,把端到端的搜索式排错变成局部直查。其三,不可观测需求可声明:质量、资源、安全这类输出不可见的要求只能写进结构,测试永远表达不了。三者叠加,识别难度从指数级降到多项式级。而"骨架像代码"这一形式选择也非偶然:可版本化、可 diff、可 review、可与实现共同演化,还记录了哪些决策是需求——新增功能时 Agent 可以干净重写而非层叠补丁,直指长寿命代码库上"AI code slop"的病灶。
在相关工作谱系里给自己定位:程序草图(program sketching)是骨架的直接先声——程序员写部分程序固定解的结构、合成器填补细节;Synchromesh 把解码约束在语言与语义约束内;AlphaVerus/AutoVerus 用验证器反馈生成可验证代码与证明;SMART 从模块化设计文档再生 ML 性能库;SpecFirst 把行为规格抽取作为程序合成的第一等步骤。论文的关键区分是:这些工作解决的都是"给定规格之后的下游问题"(找到代码/证明),Skeleton Coding 问的是上游问题——实现目标里该装什么信息、由谁来写、能消除多少实现不确定性。实验里用可执行验收检查而非机器检查证明,也正是为了把"规格内容"与"验证机制"两个变量解耦。
局限与成本
论文自承的边界主要有三处。其一,实验协议是"从参考实现反推规格再重建",真实开发者手写骨架的成本、完整度与质量如何随项目规模变化,论文没有量化——骨架经济学的"开发者侧成本曲线"仍属空白。其二,SDDBench 源自公开 Python 库(虽经匿名化),作者明言不能完全排除训练数据污染。其三,第 3 节讨论的形式化机器检查契约(Dafny/Verus/Lean 一路)在实验里用的是可执行验收检查替代,机器可查证明版的骨架工作流留作未来工作。此外,实验主要覆盖 greenfield 重建与 ProgramBench 场景,brownfield(从既有代码先恢复行为再修改)的负担只在 related work 里点到。
知识反推:从这篇论文可以提炼出的领域事实
- 行为规格存在结构性天花板:即便 oracle 全开 + 160 条 curated 观测,仍不及"骨架 + 20 条查询"——这不是模型不够强,而是信息论意义上的欠定。
- 结构信息的信息效率远超行为信息:同一任务,代码级骨架比同等长度的 prose 架构文档传达更多可被模型利用的控制信息(五级架构文档膨胀 4-7 倍输入仍追不上代码式骨架);且收益随骨架覆盖度单调上升(25%→50%→75%→100% 契约覆盖逐级提升通过率)。
- “更多规格"不单调更好:过细契约伤小模型是 prompt 非贝叶斯条件化的直接证据,规格设计存在最优粒度;这是对"把项目约束文件写成百科全书"式实践的一记警告。
- 小模型 + 好骨架 ≈ 大模型 + 无骨架(差距 5-8 个百分点,成本降 15-26 倍):规格是比参数量更便宜的算力杠杆,Pareto 前沿几乎全由"小模型 + 结构规格"构成。
- 行为规格主动伤害代码质量:测试驱动的重建比无规格基线侵蚀更高(0.66→0.73),只有结构规格降侵蚀(→0.56)——“过测试的代码更烂"第一次有了受控实验支持。
- 输出可观测性是可测试性的本质:链式程序 4n 个未知位需要 2ⁿ 次端到端查询、只需 4n 次局部查询——这条定理对所有"只看最终产物的验收流程"都成立,不限代码。
通用灵感:超越编码任务的启示
- “结构先行"适用于一切生成式 Agent 场景:写长文档先给章节大纲与每节要点契约、做数据分析先给 pipeline DAG 与各步输入输出 schema、做多 agent 协作先给角色接口与消息协议——本质都是供出假设类、让局部错误可观测、让组件可并行。
- 控制论视角(识别/控制/可观测性)是分析 Agent-人类交互的锐利工具:把"人给 Agent 提供什么"翻译成"控制输入对后验分布的收缩效应”,很多模糊的工程直觉立刻变得可比较。教学维度(teaching dimension)这个来自学习理论的旧概念,在 Agent 时代焕发新生。
- 形式化契约 + 拒绝采样是收敛保证的来源:非正式 prompt 没有单调性,任何指望"多改几轮 prompt 总能收敛"的流程都缺一个机械可查的验收层。命题 3.2 的"βᵢ 地板"还提醒:验收标准的措辞精度本身就是上限,措辞允许的违规任何 judge 都拦不住。
- 可维护性需求必须写进规格,任何测试驱动流程都无法从输出侧强制它——这为"AI 生成的代码为什么越堆越烂"提供了一个机制解释:行为规格(测试)不但护不住质量,还会主动推高侵蚀(0.66→0.73)。
- 规格存在最优粒度,过犹不及:给小模型的规格应当"刚好够收缩假设类”,详尽到接近实现的契约反而触发模型疲劳。规格写作的目标读者能力越弱,越要做减法。
- 成本杠杆的重估:15-26× 的实现成本差距意味着,在团队层面推广"骨架 + 小模型"的组合,可能比追逐旗舰模型 API 更划算——尤其结合骨架的并行化收益(J_S = 0 时组件可独立实现)。
双篇对比评:数据合成与规格表示的互补闭环
把两篇并排看,会发现它们回答的是同一个问题的两个半边。先用一张表对齐关键差异:
| 对比维度 | CodeSpecWeave | Skeleton Coding |
|---|---|---|
| 改造对象 | 模型的训练信号(先验) | 开发者的输入信息结构(似然收缩) |
| 是否重训 | 是(GRPO RL,4,670 任务) | 否(纯推理时规格设计) |
| 规格耦合的处理 | 刻意制造耦合造难题(F ⊊ ∏Fⱼ) | 刻意拆解耦合降难度(J_S = 0 理想) |
| 理论贡献 | 因子分解破坏的形式化 | 三条定理 + 两条命题(教学维度框架) |
| 验证器哲学 | 用多模型轨迹审计修测试 | 用契约/拒绝采样保证收敛 |
| 受益者 | 训练出的模型(能力内化) | 任何模型(即插即用,小模型受益最大) |
| 交付基准 | CodeSpecWeave-Bench(100 任务/1,044 规格) | SDDBench(13 个匿名化 Python 库) |
攻击面不同。 CodeSpecWeave 站在数据/训练端:它不改变开发者的工作方式,而是改变模型的学习信号——通过合成规格相互耦合的任务,让 RL 把"联合推理 + 主动验证"训练进策略里。Skeleton Coding 站在推理/交互端:它不重训任何模型,而是改变开发者表达意图的载体——从行为描述换成代码级骨架,直接收缩 Agent 的假设类。前者改造模型的先验,后者改造输入的信息结构。
对"规格"的用法相反却同源。 有趣的是两者对规格耦合性的处理看似相反:CodeSpecWeave 刻意制造规格间的深度耦合来制造任务难度(F_d ⊊ ∏F_j,迫使联合推理);Skeleton Coding 则通过好的骨架把组件解耦(定理 2.4 中 J_S = 0 的理想,组件可独立并行实现)来降低实现难度。但底层是同一条原理的两面:任务难度由结构决定。合成端用它造难题训练能力,表示端用它拆难题摊薄成本——一个是抵抗者视角,一个是利用者视角,合起来恰好证明"结构/规格形态"是编码任务复杂度的主控制变量。
也可以用教学维度(teaching dimension)的语言统一两者:CodeSpecWeave 的贡献是造出了"教学维度高"的任务——需要大量联合观察才能定位目标行为;Skeleton Coding 的贡献是证明了"假设类选得好,教学维度断崖式下降”。前者把模型推向高教学维度任务的胜任区,后者把人类表达意图的成本从教学维度中解放出来。
理论-实证互证。 CodeSpecWeave 的 73.9% 测试缺陷率是 Skeleton Coding 定理 2.2/2.3 的绝佳实证注脚:测试难以覆盖交互缺陷(假阳性 50.5%)与测试夹带实现假设(假阴性),正是"端到端测试对内部结构不可观测/过拟合单一结构"的运行时表现。反过来,Skeleton Coding 的"任何数量的测试都不够"(ProgramBench 实证)为 CodeSpecWeave 图 1 里现有数据集规格稀薄的危害提供了理论下界:独立规格堆再多也只是清单,交互规格才是难度的来源。两边甚至在行为层面互相印证:CodeSpecWeave 训练出的"更多编辑-测试循环"(3.48→4.90),恰是 Skeleton Coding 定理 2.2 预言的"用局部检查代替端到端搜索"的行为体现——学会把大程序问题拆成一串小程序验证。
互补而非替代。 一个自然的组合是:开发者用 Skeleton Coding 式的骨架表达意图(表示端保证规格可识别、可验证),CodeSpecWeave 式的合成-审计管线在仓库上生成骨架填充任务与可靠测试(数据端训练填充能力),RL 训出的模型再在骨架约束下实现——此时局部契约恰好提供了定理 2.4 承诺的"组件独立、可并行、无需兼容性测试"的结构。拆开来看这条闭环的四个环节:
- 意图表达(人→规格):开发者写出 stub + 契约 + 不变量,Skeleton Coding 证明这一步的信息效率远超行为描述与 prose 文档。
- 任务合成(规格→训练数据):以骨架的每个可填空位为锚点,围绕共享状态与生命周期编织耦合需求,CodeSpecWeave 的合成 agent 已示范如何做到。
- 验证审计(数据→可信奖励):多模型轨迹交叉检查假阳/假阴,修复后重验——73.9% 的缺陷率说明这一步不可省略。
- 训练与执行(数据→能力→行为):RL 内化联合推理,推理时骨架再把假设类收窄、组件解耦——训练给能力,规格给通道。
两篇工作拼在一起,构成"规格表示 → 数据合成 → 训练 → 交互"的完整闭环雏形。
局限各表。 CodeSpecWeave 的成本不小:每个任务配容器镜像、跑在 Kubernetes pod 上,高质量任务依赖强模型与多轮过滤(14,905 → 766 的筛选率),RL 训练本身耗资源。Skeleton Coding 的实验依赖从参考实现反向生成规格(实验设定是"重建"),真实开发者手写骨架的成本与质量、以及骨架在 brownfield 场景(先从既有代码恢复行为)下的表现,仍待更多证据;形式化机器检查契约的评估也留作未来工作。另外,Skeleton Coding 的基准(SDDBench 源自公开库匿名化)无法完全排除训练数据污染。
一点批判性视角。 两篇论文各自的强证据背后也各有值得追问之处。CodeSpecWeave 的基准(CodeSpecWeave-Bench)与训练数据同分布,70.67% 的自基准成绩难免有"主场优势"之嫌——好在 DeepSWE 与 SWE-bench 系列的外部验证足够扎实,主结论站得住;但"交互规格"的难度是否可以脱离具体构造被独立度量(例如像 Skeleton Coding 那样给出教学维度式的刻画),论文没有回答。Skeleton Coding 的"重建"协议则默认存在一个足够好的参考实现与可从中反推的骨架——这在前瞻性项目(没有参考实现)里不成立,开发者手写骨架时如何避免把骨架本身写错(错误骨架会不会反而锁死错误结构),实验里也未触及。两者共同的隐含假设是:规格本身是清晰、自洽、可验证的——而 CodeSpecWeave 的 73.9% 缺陷率恰恰说明这个假设在自动生成侧何等脆弱。
对规格驱动开发生态的含义。 如果把两篇的结论外推到工程实践,规格驱动开发(spec-driven development)的工具链应当长出三个新组件:一是规格质量审计器(CodeSpecWeave 的 review agent 已是雏形),在规格进入开发流程前检出其对齐缺陷;二是骨架即版本化工件(Skeleton Coding 的核心主张),让 .pyi 式 stub + 契约与代码同库演进、同 PR 评审;三是耦合度分析器,能像圈复杂度度量代码一样度量"这套规格有多不可分解",为任务分派(交给大模型还是小模型、单人还是并行)提供依据。三者分别对应两篇论文铺开的三块石头。
结语
这两篇论文放在一起读,最大的收获不是某个具体数字,而是一个正在成形的判断:编码 Agent 技术栈的重心,正从"让模型更会写代码"转向"让规格更会被写"。CodeSpecWeave 用 4,670 个交互规格任务撬动 DeepSWE 上 8.56 个百分点的提升,证明了规格密度与耦合度是训练数据中被忽视的关键维度;Skeleton Coding 用三条定理加 48.4% 的相对错误下降,证明了开发者的最优控制动作是供出结构而非堆测试。前者告诉我们 Agent 该学什么,后者告诉我们人该说什么。
更准确地说,两篇论文合起来重新划定了编码 Agent 时代"开发者技能"的内涵。当实现被外包给模型,开发者剩余的核心价值恰是两篇论文分别定价的两种活动:一是设计耦合——识别哪些需求必须相互约束、把真实世界的工程权衡翻译成不可分解的任务定义(CodeSpecWeave 的规格种子正是从这种活动中挖掘的);二是设计结构——选定数据类型、模块边界与契约,把庞大的程序空间切分成可独立识别的小块(Skeleton Coding 证明这一步的价值是指数级的)。写代码的技艺没有消失,而是向上沉淀成了写规格的技艺。
对从业者,两篇论文各自给出了可直接落地的动作:做编码 Agent 训练的,把"规格交互性"与"多模型轨迹审计"纳入数据管线,优先做任务的耦合结构而非数量;用编码 Agent 干活的,把需求文档换成带类型签名与 EARS 契约的骨架 stub 文件,并警惕规格过载对小模型的反效果;做评测的,报告规格数量与类别覆盖,把 token 开销与通过率并列呈现。
对研究者,两篇合起来指向一串开放问题:交互规格的难度是否可以像 Skeleton Coding 那样被形式化刻画(比如交互规格下的教学维度)?开发者手写骨架与模型反推骨架的成本收益如何权衡?错误骨架的灾难性后果如何防范?当 RL 训练出的联合推理能力遇到骨架约束的假设类,会冲突还是叠加?最后一个问题尤其值得期待——两篇工作的直接组合(骨架规格做输入、交互规格任务做训练、局部契约做验收)几乎构成一个完整技术路线图的草图。
规格怎么表达、怎么交互——这个软件工程的老问题,正在成为编码 Agent 时代的新前沿。
参考链接
- When Requirements Interact: Scaling Long-Horizon Coding via Interdependent Specifications:https://arxiv.org/abs/2610.40256
- Skeleton Coding: Program Structure as a Specification for Agents:https://arxiv.org/abs/2610.38214
- SlopCodeBench (SCBench):https://arxiv.org/abs/2603.24755
- ProgramBench: Can Language Models Rebuild Programs From Scratch?:https://arxiv.org/abs/2605.03546
两篇论文关键数字速查
| 论文 | 指标 | 数值 |
|---|---|---|
| CodeSpecWeave | 训练任务/仓库 | 4,670 / 2,865 |
| CodeSpecWeave | 基准规模 | 100 任务 / 1,044 规格 / 均值 10.44 |
| CodeSpecWeave | 测试缺陷审计检出率 | 73.9%(2,267/3,067) |
| CodeSpecWeave | DeepSWE-v1.1(Flash-SFT) | 54.42% → 62.98%(SWE-PI 56.64%) |
| CodeSpecWeave | 四基准均分(Flash-SFT) | 67.60%(Vanilla 60.54%) |
| CodeSpecWeave | 编辑-测试循环(Flash-SFT) | 2.96 → 4.90;≥2 循环 69.0% → 78.3% |
| CodeSpecWeave | 最强模型基准通过率 | GPT-6 Astra 74.0%(输出 17.2k 最短) |
| Skeleton Coding | 平均测试错误相对降幅 | 48.4%(40.7% → 21.0%) |
| Skeleton Coding | SDDBench 通过率 | 29% → 74.2%(SCBench 71.7% → 89.2%) |
| Skeleton Coding | 局部 vs 端到端测试 | 4n vs ≥2ⁿ(Thm 2.2) |
| Skeleton Coding | oracle 下加骨架 | 通过率 +10.9%(64.0%→70.9%);错误 −27.0% |
| Skeleton Coding | 大小模型差距 | 缩小约 52.4%;成本降 15-26× |
| Skeleton Coding | 代码侵蚀 | 结构规格 −24.7%,行为规格反增 |