Rethinking Repetition Problems of LLMs in Code Generation¶
会议: ACL 2025
arXiv: 2505.10402
代码: 无
领域: 文本生成/代码生成
关键词: 代码生成, 重复问题, 结构性重复, 语法规则, 解码策略
一句话总结¶
本文重新定义了代码生成中的重复问题,区分出比内容重复更普遍且更难处理的"结构性重复",并提出基于语法规则的重复惩罚解码方法RPG(Repetition Penalization based on Grammar),在新构建的CodeRepetEval和标准基准上大幅缓解重复问题。
研究背景与动机¶
领域现状:LLM在代码生成任务中取得了显著进展,但生成过程中的重复问题一直是困扰研究者的顽疾。当前对重复问题的研究主要集中在"内容重复"——即模型逐字逐句地重复已生成的代码片段。常见的缓解手段包括重复惩罚(repetition penalty)、n-gram blocking等。
现有痛点:内容重复(逐字重复)只是代码生成重复问题的冰山一角。更普遍且更难检测的是"结构性重复"——代码中反复出现具有相同结构/模式但表面文本不同的代码块。例如,模型可能连续生成几十个格式相同但变量名不同的if-else语句,或重复类似的函数定义。这种重复在文本层面不容易用n-gram匹配检测,但在语法结构上高度冗余。
核心矛盾:现有的重复惩罚方法基于token或n-gram级别的匹配,无法识别结构性重复。因为结构性重复的每次出现可能使用不同的变量名和参数,表面文本差异很大,但语法树结构完全一致。这是代码与自然语言的关键区别——代码具有严格的语法结构,重复可以发生在语法结构层面而非文本层面。
本文目标:(1) 形式化定义"结构性重复"的概念和检测标准;(2) 提出能够同时处理内容重复和结构性重复的解码方法;(3) 构建专门评估代码生成重复问题的综合基准。
切入角度:利用编程语言的形式语法(formal grammar)来检测重复——如果生成的代码在语法规则(production rule)使用序列上呈现出重复模式,则判定为结构性重复。这比文本层面的匹配更精确、更全面。
核心 idea:基于语法规则的重复检测与惩罚——将解码过程中每个token对应到语法规则,在语法规则序列上检测重复模式,并衰减导致重复的关键token的生成概率。
方法详解¶
整体框架¶
RPG的工作流程为:在LLM生成代码的每一步,(1) 将当前生成的partial code对应到语法规则序列;(2) 在语法规则序列上检测是否存在重复模式(包括严格重复和结构性重复);(3) 如果检测到重复趋势,衰减那些会"延续"重复模式的关键token的logit值;(4) 基于修改后的logit分布采样/选择下一个token。整个过程作为解码策略嵌入到推理pipeline中,不需要修改模型参数。
关键设计¶
-
结构性重复的形式化定义:
- 功能:为代码生成中的结构性重复提供严格的数学定义和检测标准
- 核心思路:定义代码的语法规则应用序列 \(R = [r_1, r_2, \ldots, r_n]\),其中 \(r_i\) 表示在生成第 \(i\) 个token时所应用的语法产生式规则。结构性重复定义为:存在一个子序列 \(R[i:j]\) 在 \(R\) 中出现超过 \(k\) 次(\(k\) 为可配置的阈值),即 \(|{m : R[m:m+j-i] = R[i:j]}| > k\)。关键在于这里比较的是语法规则序列而非原始token序列——两段文本不同但语法规则序列相同的代码就是结构性重复。
- 设计动机:利用编程语言天然具有形式语法的特点,将重复检测从文本层面提升到结构层面,覆盖了传统n-gram方法无法捕捉的重复类型
-
基于语法的重复检测模块:
- 功能:在解码过程中实时检测当前生成的代码是否正在进入重复模式
- 核心思路:维护一个语法规则应用的滑动窗口,使用改进的后缀数组或字符串匹配算法在语法规则序列上检测重复子串。具体地,对于当前位置 \(t\) 的语法规则序列 \(R[1:t]\),检查最近生成的长度为 \(l\) 的子序列 \(R[t-l+1:t]\) 是否在之前的序列中已经出现过。如果匹配到重复模式,进一步判断当前正在生成的token是否属于重复模式中的"关键触发token"——即如果该token被替换,重复模式将被打破。
- 设计动机:解码时需要实时检测,算法效率是关键。利用语法规则序列(比原始token序列短得多)进行匹配,降低了计算复杂度
-
重复惩罚衰减策略(Repetition Penalization Decay):
- 功能:一旦检测到重复趋势,降低延续重复的token的生成概率
- 核心思路:识别出当前重复模式中的"关键token"——那些如果被改变就能打破重复循环的token。对这些token的logit值施加衰减惩罚:\(\text{logit}'(t) = \text{logit}(t) \times \alpha^{c}\),其中 \(\alpha < 1\) 是衰减因子,\(c\) 是当前重复次数。重复次数越多,惩罚越重(指数衰减)。同时,为了避免过度惩罚导致的质量下降,设置了最低logit阈值——当惩罚后的logit低于阈值时停止进一步衰减。
- 设计动机:指数衰减确保轻微重复不被过度惩罚(代码中有些重复是合理的),但持续重复会被强力抑制。阈值机制防止惩罚过重导致模型选择语义不合理的替代token
损失函数 / 训练策略¶
RPG是纯解码阶段的方法,不涉及任何训练或损失函数。核心超参数包括:重复检测的最小子序列长度 \(l\)、重复次数阈值 \(k\)、衰减因子 \(\alpha\)、最低logit阈值。这些参数可以根据具体编程语言和生成任务进行调整。方法实现为一个即插即用的解码wrapper,兼容任何基于autoregressive解码的代码生成模型。
实验关键数据¶
主实验¶
在CodeRepetEval数据集上的重复率和功能正确性对比:
| 方法 | 重复率 ↓ | Pass@1 ↑ | 生成效率 | 适用范围 |
|---|---|---|---|---|
| Greedy Decoding | 42.3% | 38.1 | 最快 | 基线 |
| Repetition Penalty | 28.7% | 39.5 | 快 | 仅内容重复 |
| N-gram Blocking | 25.4% | 36.8 | 快 | 仅内容重复 |
| Nucleus Sampling | 31.2% | 40.2 | 快 | 随机性缓解 |
| RPG | 12.5% | 44.8 | 中等 | 内容+结构重复 |
在标准基准HumanEval和MBPP上的结果(CodeLlama-7B):
| 方法 | HumanEval Pass@1 | MBPP Pass@1 | 重复问题率 |
|---|---|---|---|
| Greedy Decoding | 33.5 | 47.2 | 18.3% |
| Repetition Penalty | 34.2 | 47.8 | 12.1% |
| RPG | 36.8 | 50.3 | 5.7% |
消融实验¶
RPG各组件的贡献分析:
| 配置 | CodeRepetEval重复率 | Pass@1 | 说明 |
|---|---|---|---|
| 完整RPG | 12.5% | 44.8 | 最佳 |
| 仅token级重复检测 | 25.8% | 40.1 | 退化为标准重复惩罚 |
| 仅语法规则检测(无衰减) | 18.3% | 42.1 | 检测到但惩罚策略缺失 |
| 固定惩罚(非指数衰减) | 15.1% | 41.5 | 过轻或过重 |
| 去掉最低logit阈值 | 13.8% | 40.3 | 重复率低但质量下降 |
关键发现¶
- 结构性重复远比内容重复普遍:在CodeRepetEval中,约70%的重复问题属于结构性重复,仅30%是传统的内容重复。这解释了为何基于n-gram的方法效果有限。
- RPG在降低重复率的同时提升了功能正确性:这看似矛盾,但原因在于——消除无意义的重复代码后,模型有更多的"token预算"来生成真正需要的逻辑代码,而非在重复循环中浪费输出长度。
- 指数衰减是平衡重复抑制和生成质量的关键:固定惩罚容易要么惩罚不够(小值),要么过度干预正常的代码结构(大值)。指数衰减根据重复严重程度自动调节力度。
- RPG对不同大小的模型(7B到33B)和不同编程语言(Python、Java、C++)都有一致的改善效果。
亮点与洞察¶
- 重新定义代码生成的重复问题:将重复从"内容重复"扩展到"结构性重复",这是一个重要的概念贡献。利用代码的形式语法特性来检测结构性重复是自然且有效的切入点,这个思路可以扩展到其他具有形式结构的生成任务(如SQL生成、数学证明生成)。
- 解码策略的即插即用性:RPG不需要修改模型、不需要额外训练,作为一个解码wrapper可以直接应用于任何代码生成模型。这种低侵入性的设计使得方法在工程上极易被采用。
- CodeRepetEval基准的构建:填补了代码生成重复问题评估的空白,此前没有专门针对重复问题的综合基准。
局限与展望¶
- 语法规则匹配增加了解码的计算开销,对于实时代码补全等低延迟场景可能不够高效
- 目前仅支持有明确形式语法的编程语言,对于配置文件、DSL等非标准语言适用性有限
- 重复检测的最小子序列长度阈值需要针对不同任务调优
- CodeRepetEval数据集的规模和多样性有待扩展
- 改进方向:可以利用增量解析(incremental parsing)技术来降低语法分析的计算开销;也可以将语法规则重复检测集成到模型内部(作为辅助训练目标),从根本上减少模型生成重复代码的倾向
相关工作与启发¶
- vs Standard Repetition Penalty: 标准重复惩罚仅在token级别检测和惩罚重复,无法捕捉结构性重复;RPG将检测提升到语法规则级别,覆盖面更广
- vs Nucleus Sampling/Top-k: 采样策略通过引入随机性间接缓解重复,但这种方法不具有针对性,可能在缓解重复的同时引入不合理的代码
- vs ReflectionCoder (2405.17057): ReflectionCoder从训练数据角度提升代码质量,RPG从解码策略角度缓解重复——两者互补,可以联合使用
- 本文的核心启发在于——代码生成不应该只关注"生成什么",还要关注"怎么生成",解码策略的设计空间值得更多关注
评分¶
- 新颖性: ⭐⭐⭐⭐ 结构性重复的概念定义和语法规则级别的解码策略有显著创新
- 实验充分度: ⭐⭐⭐⭐ 新基准+标准基准,多模型多语言,消融完整
- 写作质量: ⭐⭐⭐⭐ 形式化定义清晰,示例直观
- 价值: ⭐⭐⭐⭐ 代码生成重复问题的首次系统化研究,即插即用的实用解决方案
相关论文¶
- [ACL 2025] TeXpert: A Multi-Level Benchmark for Evaluating LaTeX Code Generation by LLMs
- [NeurIPS 2025] Learning to Solve Complex Problems via Dataset Decomposition
- [ICML 2025] Function-to-Style Guidance of LLMs for Code Translation
- [ACL 2025] GiFT: Gibbs Fine-Tuning for Code Generation
- [ACL 2025] Tree-of-Code: A Tree-Structured Exploring Framework for End-to-End Code Generation