【文献笔记】Automated Repair of Ambiguous Problem Descriptions for LLM-Based Code Generation
Automated Repair of Ambiguous Problem Descriptions for LLM-Based Code Generation
https://github.com/msv-lab/SpecFix.
歧义性自然语言需求的自动化修复
信息:
- 作者:Haoxiang Jia, Robbie Morris, He Ye, Federica Sarro and Sergey Mechtaev
- 单位:北京大学,UCL
- 日期:2025.09
1. 介绍
1.1. 研究背景
随着大语言模型越来越多地用于代码生成,自然语言描述实际上变成了“软需求规格”。但如果问题描述本身存在歧义,LLM 生成的代码就可能偏离真实意图。已有研究发现歧义任务描述会显著降低模型表现;而现有方法多是让模型提出澄清问题,但这些澄清问题往往冗余、无关,甚至会增加用户理解负担。因此,本文提出一个新的任务:自动修复有歧义的自然语言问题描述,使其更适合 LLM 代码生成。
论文的核心判断是:很多歧义并不一定需要人类额外介入才能解决。因为代码生成任务的 prompt 往往包含自然语言描述和输入输出样例,而这些样例其实隐含了作者意图。例如,描述中说“删除重复边”,既可以理解为“只删除第二次及之后出现的重复边”,也可以理解为“所有出现超过一次的边都删除”。如果样例明确支持其中一种解释,那么系统就可以通过样例反推出更清晰的文字描述。

这个例子见图1,展示了原始描述如何导致 DeepSeek-V3 生成错误解释,而 SPECFIX 如何把描述修复为“只保留恰好出现一次的连接”。
本文不是简单提升模型推理能力,而是把“自然语言规格本身”作为可修复对象。也就是说,错误不完全来自模型不会写代码,而可能来自问题描述没有把意图约束清楚。
1.2. 贡献
-
本文提出了首个面向 LLM 代码生成的自然语言问题描述自动修复方法。这里的“修复”不是修代码,而是修 prompt/specification,使模型更稳定地产生符合意图的程序。
-
论文提出了一个新的质量指标 example consistency,简称 EC,用来衡量模型生成程序与问题描述中输入输出样例的一致程度。传统方法更多关注 semantic entropy,即生成程序的语义分布是否分散;本文认为仅看分散程度不够,因为有时所有程序都集中到同一个错误解释上,此时 semantic entropy 很低,但代码仍然错。因此必须引入 EC 来检查模型解释是否与样例一致。
-
论文提出了 SPECFIX 框架。它不是直接让 LLM“修改这段有歧义的描述”,而是先分析该描述诱导出的程序分布,再修复程序分布,最后通过 contrastive specification inference 把程序分布的差异反向映射回自然语言描述。
-
论文在 HumanEval+、MBPP+ 和 LiveCodeBench 三个代码生成基准上,使用 GPT-4o、GPT-4o-mini、DeepSeek-V3 和 Qwen2.5-Coder-32B-Instruct 四个模型进行实验。结果显示,SPECFIX 修改了 43.58% 的描述,在被修改子集上 Pass@1 平均提升 30.9%,在完整 benchmark 上带来 4.09% 的绝对提升,并且一个模型修复出的描述还能迁移提升其他模型,平均跨模型提升 10.48%。
2. 研究方法
2.1. 前序研究
论文首先把代码生成中的自然语言描述看作 specification,即对自动生成程序应满足行为、属性或结果的权威性描述。本文只讨论功能性规格,也就是程序输入输出行为,不讨论性能、资源占用、代码风格等非功能需求。
设问题描述空间为 D,程序空间为 P。给定一个问题描述 D,LLM 可以被形式化为一个条件概率分布:
m ( ⋅ ∣ D ) : P → [ 0 , 1 ] m(\cdot \mid D): P \rightarrow [0,1] m(⋅∣D):P→[0,1]
也就是说,同一个描述可能诱导出多个程序,每个程序有一定生成概率。由于真实分布不可见,实际做法是从模型中采样 N 个程序,用样本频率近似模型分布。论文默认采样数 (N=20),因为实验发现 N 从 5 增加到 20 时语义熵变化较明显,之后继续增加收益不大。
接着,论文引入 semantic cluster:两个程序如果在所有有效输入上产生相同输出,就认为它们语义等价。于是,采样得到的程序集合可以按输入输出行为划分为若干语义簇。语义簇的意义是:它不是看代码长得像不像,而是看代码表达了哪一种“问题解释”。
Observation 1: Subtle ambiguities in natural language requirements may lead to the generation of incorrect code by LLMs, even in the presence of clarifying IO examples. Such requirements can be disambiguated automatically by aligning natural language with the examples. (观察1:自然语言需求中的微妙歧义可能导致LLMs生成错误的代码,即使存在明确的输入输出示例也难以避免。此类需求可通过将自然语言与示例对齐的方式来自动去歧义化。)

图2展示了一条模棱两可的需求:尽管提供了一个澄清的示例,但其中短语“具有相同的字符”可能被解释为(1)由相同的字符集合组成,或(2)由相同的多重字符集组成,即考虑字符出现的频率。
2.1.1. semantic entropy(语义熵,SE)
在 semantic cluster 的基础上,论文使用 semantic entropy(语义熵,SE) 衡量模型解释的不确定性。若模型生成的程序分布落在多个语义簇上,说明同一描述诱发了多种语义解释,描述可能存在歧义。公式为:
S E ( m ≡ ( ⋅ ∣ x ) ) = − ∑ y m ≡ ( y ∣ x ) log m ≡ ( y ∣ x ) SE(m_{\equiv}(\cdot \mid x)) = - \sum_y m_{\equiv}(y \mid x)\log m_{\equiv}(y \mid x) SE(m≡(⋅∣x))=−y∑m≡(y∣x)logm≡(y∣x)
m ≡ m_{\equiv} m≡ 表示语义簇层面的分布,y 是某个语义簇。直观地说,如果模型 90% 生成解释 A,10% 生成解释 B,那么 semantic entropy 大于 0,说明描述仍然有多种解释;如果所有程序都属于一个语义簇,则 semantic entropy 为 0。
但本文很重要的一个洞察是:semantic entropy 不足以判断描述是否“好”。因为模型可能非常稳定地生成同一个错误解释,此时 semantic entropy 很低,却仍然与样例不一致。(图1就是这种情况:DeepSeek-V3 采样的 20 个程序都属于同一个错误语义簇,概率 (P=1),但这些程序全部不满足样例(下文的EC=0)。)
2.1.2. example consistency(样例一致性,EC)
因此论文提出 example consistency(样例一致性,EC)。对于一个程序 P,若问题描述中有 m 个输入输出样例 ( x i , y i ) (x_i,y_i) (xi,yi),则:
E C ( P , { ( x i , y i ) } i = 1 m ) = 1 m ∑ i = 1 m I ( P ( x i ) = y i ) EC(P,\{(x_i,y_i)\}_{i=1}^{m}) =\frac{1}{m}\sum_{i=1}^{m} I(P(x_i)=y_i) EC(P,{(xi,yi)}i=1m)=m1i=1∑mI(P(xi)=yi)
其中 I ( ⋅ ) I(\cdot) I(⋅) 是指示函数,程序在样例上输出正确则为 1,否则为 0。对于整个语义簇分布,则按语义簇概率加权求和:
E C ( m ≡ ( ⋅ ∣ D ) , E X ) = ∑ [ P ] ∈ m ≡ ( ⋅ ∣ D ) m ≡ ( [ P ] ∣ D ) E C ( P , E X ) EC(m_{\equiv}(\cdot \mid D), EX)=\sum_{[P]\in m_{\equiv}(\cdot \mid D)}m_{\equiv}([P]\mid D) EC(P,EX) EC(m≡(⋅∣D),EX)=[P]∈m≡(⋅∣D)∑m≡([P]∣D)EC(P,EX)
这个指标的作用是判断模型生成程序是否尊重描述中的样例。若某个语义簇的 EC=1,说明该解释完全符合样例;若 EC=0,说明该解释与样例完全冲突。
2.2. 问题定义
基于 SE 和 EC,论文将问题描述修复定义为:给定原始描述 D、样例 EX 和模型 m,寻找一个修改后描述 D’,使得修复后语义熵SE降低、样例一致性EC提高,同时 D 与 D’ 的差异尽可能小。即:
S E ( m ≡ ( ⋅ ∣ D ′ ) ) < S E ( m ≡ ( ⋅ ∣ D ) ) SE(m_{\equiv}(\cdot \mid D')) < SE(m_{\equiv}(\cdot \mid D)) SE(m≡(⋅∣D′))<SE(m≡(⋅∣D))
且:
E C ( m ≡ ( ⋅ ∣ D ′ ) , E X ) > E C ( m ≡ ( ⋅ ∣ D ) , E X ) EC(m_{\equiv}(\cdot \mid D'), EX) > EC(m_{\equiv}(\cdot \mid D), EX) EC(m≡(⋅∣D′),EX)>EC(m≡(⋅∣D),EX)
同时要求 d i f f ( D , D ′ ) < τ diff(D,D')<\tau diff(D,D′)<τ,避免把描述完全重写成很长的新 prompt。
2.3. SPECFIX
SPECFIX 的核心思想不是直接问 LLM:“请帮我消除这段描述的歧义。”论文认为这种直接提示很容易失败,因为 LLM 很难准确预测“自然语言改动会如何改变自己生成程序的分布”。所以 SPECFIX 把任务拆成两步:先修复程序分布,再把程序分布的变化反推回自然语言描述。

整个流程见 Algorithm 1:
2.3.1. 从描述中抽取输入输出样例
SPECFIX 使用同一个 LLM 从原始问题描述中提取 embedded examples。这里的样例不是 hidden tests,也不是人工新加信息,而是原 prompt 中已有的 assert、输入输出说明或示例。
2.3.2. 解释原始描述诱导出的程序分布
系统从模型 m ( ⋅ ∣ D ) m(\cdot|D) m(⋅∣D) 中采样 N 个程序,然后让 LLM 生成一批测试输入,用这些测试输入运行所有采样程序,并根据输出结果对程序进行分组。输出行为一致的程序被放入同一个 semantic cluster。这个步骤等价于把“模型对自然语言的不同理解”显式化。
2.3.3. 计算两个质量指标
计算semantic entropy 和 example consistency。SE 用于判断解释是否分散,EC 用于判断解释是否符合样例。两者共同决定是否需要修复。
如果 SE=0 且 EC=1,说明所有采样程序都属于同一语义解释,并且都满足样例,那么描述暂时被视为不需要修复。否则进入修复过程。
2.3.4. 修复程序分布(distribution repair)。
这一步有两种策略:
- probability-guided repair:若存在至少一个语义簇完全通过样例,即 EC=1,那么 SPECFIX 选择其中概率最大的语义簇作为 selected cluster,把其他语义簇视为 rejected clusters。图2就是典型例子:虽然正确解释只占 10%,错误解释占 90%,但正确解释 EC=1,错误解释 EC=0,所以 SPECFIX 选择低概率但样例一致的语义簇,再通过修改描述提高它的生成概率。
- program-repair-based description repair:若没有任何语义簇能完全通过样例,说明模型采样出的所有解释都与样例冲突。此时 SPECFIX 选择概率最大的错误簇中的程序,用自动程序修复方法将其修到通过样例。具体采用 self-refine 思路,利用错误程序、运行反馈、期望输出和实际输出,让模型生成一个修复后的程序。之后,原错误程序成为 rejected program,修复后的程序成为 selected program。

图3展示了这个程序修复描述机制:原始描述没有说明金字塔输入高度到底是垂直高度还是斜高,模型全部按错误解释生成程序;SPECFIX 先把程序修到符合样例,再从“修复前程序”和“修复后程序”的差异中推断应该把描述改成“slant height”。
2.3.5. 对比规范推理 contrastive specification inference
这是 SPECFIX 最关键也最有启发性的部分。它不是让 LLM 单独解释 selected program,而是同时给出 selected program 和 rejected program,让 LLM 对比二者行为差异,并诊断原始描述中哪个词、短语或结构导致了错误解释。然后要求 LLM 对自然语言描述做最小修改,使其支持 selected program 的行为,同时排除 rejected program 的行为。换句话说,SPECFIX 不是“从样例直接写解释”,而是“通过正确程序和错误程序的行为对比,反推出描述中应该补充哪一句话”。
这个设计的好处在于,LLM 不需要抽象地判断“哪里有歧义”,而是面对非常具体的对比:为什么程序 A 符合样例,程序 B 不符合?描述怎样改,才能让模型更倾向于生成 A 而不是 B?这比直接让 LLM 写澄清问题更稳健。
2.3.6. 迭代验证
SPECFIX 生成修复后描述 D’ 后,会重新采样程序、重新聚类、重新计算 SE 和 EC。只有当 EC 提升且 SE 降低时,修复才被接受。否则不接受该修改。这个机制使 SPECFIX 不是一次性 prompt rewriting,而是带有反馈验证的 specification repair。
3. 实验
3.1. 实验设置
论文围绕三个研究问题展开实验:
- RQ1 检验 SPECFIX 修复后的描述是否提升代码生成性能;
- RQ2 检验修复是否能跨模型迁移;
- RQ3 检验修复后描述长度是否显著增加;
- RQ4 建议这种方法是否有跨模型的泛化性。
基准数据集:
- HumanEval+ 有 164 个 Python 编程问题
- MBPP+ 有 378 个手工验证的 Python 编程问题,二者均来自 EvalPlus 增强版本;
- LiveCodeBench,包含 2025 年 1 月至 5 月发布的 175 个较新竞赛编程题,以降低数据泄漏风险。
LLM设置:
- 在生成最终代码时,模型温度设为 0,保证确定性;但在估计程序分布、采样多个候选程序时,使用非零温度,以获得多样化程序。
- 实验使用四个 LLM:GPT-4o、GPT-4o-mini、DeepSeek-V3 和 Qwen2.5-Coder-32B-Instruct。
每个实验重复三次并报告平均结果。采样数 N 默认设为 20,这是论文通过不同采样规模比较后得到的折中配置。
评价指标:
- Pass@1 衡量生成程序完全通过测试的概率;
- AvgPassRate 衡量平均通过测试比例;
- %Pass@1>0 衡量至少能生成一个完全正确程序的问题比例;
- Majority@20 衡量 20 个采样程序中多数投票结果是否正确;
- Semantic Entropy 衡量程序语义解释的分散程度。
3.2. Baseline
论文设置了三个主要 baseline:
- Original,即不修复原始描述,直接进行代码生成。这是判断 SPECFIX 是否真正有用的基本参照。
- Vanilla Repair:它让 LLM 判断描述是否有歧义,如果有,则提示模型按照最可能解释消除歧义。这是最直接的“让 LLM 自己改 prompt”方法。
- ClarifyGPT-auto。ClarifyGPT 原本通过语义簇发现歧义,并让模型提出澄清问题;本文将其改造成自动修复版本,即用问题描述中的样例来模拟用户回答澄清问题,然后把澄清内容拼接到原描述中。
- µFix:µFix 不是描述修复方法,而是代码生成推理增强方法。它通过分析程序为何未通过样例来修正模型推理。论文将其作为强 reasoning baseline,用于说明“修复描述”和“增强推理”是不同路线。(图3说明,在自然语言歧义较强时,µFix 可能错误地解释样例,例如把公式不一致归因于 rounding,而不是发现 height/slant height 的概念歧义。)
3.3. 主要结果

主要结果见表 I。整体来看,在所有模型和所有 benchmark 组合中,SPECFIX 都取得最高 Pass@1。以 DeepSeek 在 HumanEval+ 上为例,原始描述 Pass@1 为 87.8%,ClarifyGPT-auto 为 89.0%,SPECFIX 达到 92.0%。在 MBPP+ 和 LiveCodeBench 上也有类似提升。
论文强调,SPECFIX 不仅提升 Pass@1,也降低 semantic entropy,说明修复后的描述让模型生成程序的语义分布更集中。此外,SPECFIX 是唯一稳定提升 Majority@20 的方法,这意味着它不仅让模型偶尔生成正确代码,而且让模型在重复采样时更稳定地收敛到正确解释。
在被 SPECFIX 修改的子集上,效果更明显。论文报告 SPECFIX 平均修改 43.58% 的描述,并在这些被修改描述上带来 30.9% 的 Pass@1 提升;如果放到完整 benchmark 上,相当于 4.09% 的绝对提升。这个结果说明,歧义并不是少数边缘问题,而是足以影响大量代码生成 benchmark 的系统性因素。

表 II 进一步做了公平比较:由于不同修复方法会修改不同的描述,论文只比较 SPECFIX 和 baseline 都修改过的交集子集。结果显示,除了一个很小样本的例外,SPECFIX 在这些交集子集上几乎都优于原始描述和 baseline。排除了“方法只是挑了更容易修的问题”的可能性。

跨模型结果见表 III。实验方式是:用一个模型修复问题描述,再用另一个模型评估代码生成性能。如果修复只是在迎合某个模型的特定偏差,那么换模型后效果应该消失;但结果显示,跨模型平均仍提升 10.48%。这说明 SPECFIX 修复的不只是模型局部误解,而可能是问题描述本身存在的真实歧义。

描述长度结果见表 IV。ClarifyGPT-auto 和 µFix 往往大幅增加描述长度。例如 GPT-4o 在 MBPP+ 上,ClarifyGPT-auto 使描述长度增加 576.6%,µFix 增加 426.6%。相比之下,SPECFIX 的增长更温和,虽然在某些数据集上也会增加不少,但总体明显少于 reasoning chain 或大量澄清问题拼接。论文认为,过长解释可能干扰模型理解原问题,也可能导致模型过拟合样例或澄清文本。
4. 总结
4.1. 结论
这篇论文的核心结论是:LLM 代码生成失败并不总是因为模型不会写代码,也可能是因为自然语言问题描述本身存在隐性歧义;而这种歧义可以通过分析模型生成程序的语义分布、结合输入输出样例进行自动修复。SPECFIX 的价值在于,它把“修 prompt”从经验性人工改写变成了一个可度量、可验证、可迭代的过程。
SPECFIX 先让 LLM 生成多个程序,用这些程序暴露模型对描述的不同理解;再通过样例一致性判断哪些理解是可接受的;最后用正确程序和错误程序的对比来反推自然语言中需要补充或修改的地方。这个路线比简单 prompt rewriting 更严谨,因为它把自然语言歧义转化成了可执行程序行为之间的差异。
4.2. 限制
-
它假设问题描述中的输入输出样例是正确的。如果样例本身与参考解冲突,SPECFIX 会被错误样例误导。论文也承认,在 HumanEval+ 和 MBPP+ 中发现了 5 个样例与参考解冲突的实例,虽然比例低于 1%,但足以说明该假设并不总是成立。
-
SPECFIX 假设生成代码可以独立执行,并且模型至少能生成一些正确或接近正确的候选程序。如果代码必须嵌入大型系统才能运行,或者任务复杂到模型无法产生有意义候选程序,那么基于采样、执行和聚类的语义分析会变得困难。
-
semantic cluster 的划分依赖生成测试输入和程序输出行为。若测试输入覆盖不足,两个实际不同的程序可能被错误地归为同一簇;反过来,若程序因异常、边界条件或随机性产生不同输出,也可能造成聚类噪声。因此,SPECFIX 的“语义理解”本质上是测试近似,而不是严格形式验证。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)