训练代码生成模型实现自我调试

本文介绍通过监督微调和强化学习训练大语言模型进行代码自我调试的方法,使用合成训练数据提升代码生成成功率39%,涵盖数据合成、模型更新和评估实验的全流程技术方案。

训练代码生成模型实现自我调试

代码生成——将自然语言规范自动转换为计算机代码——是大语言模型(LLM)最具前景的应用之一。但编程任务越复杂,LLM出错的可能性就越高。当然,任务越复杂,人类编码者同样更容易出错,这正是调试成为软件开发流程关键环节的原因。

在2024年神经信息处理系统大会(NeurIPS)上发表的研究中,提出了一种训练LLM成为更优秀调试器的新方法,同时提升代码生成能力。此前利用LLM调试代码的尝试主要采用少样本学习,即提供少量成功调试示例由LLM推断其余部分。相比之下,该研究同时使用监督微调(SFT)和强化学习(RL)来专门训练LLM进行调试。由于调试训练数据稀缺,研究团队利用LLM生成高质量合成训练数据。

数据合成方法

现有多个广泛使用的代码生成模型公共数据集,包含自然语言提示、代码规范实现以及单元测试。但调试模型的训练数据相对匮乏。

构建调试数据集时,首先从现有代码生成数据集中提取自然语言提示,将其反复输入代码生成模型,获得同一提示的多个生成结果(例如20个)。随后对生成代码运行单元测试,仅保留未通过测试的错误代码。

接着将错误代码与单元测试生成的错误信息一起输入LLM,要求模型解释错误发生的位置和原因。最后将LLM的诊断结果、错误代码和错误信息再次输入LLM,并指示其修复错误。这是思维链推理的一种应用:已有研究表明,要求LLM在行动前先解释其意图可有效提升性能。

修订后的代码再次运行单元测试,仅保留通过全部测试的版本。最终获得包含自然语言提示、错误实现、错误诊断、调试后代码和单元测试的新数据集。

模型更新策略

获得数据集后,通过SFT和RL两种方式更新调试模型。两种方法均尝试了两种训练方案:要求模型在代码修订前进行思维链解释,或直接要求修订。

SFT方法中,模型输入包括自然语言指令、错误代码和单元测试错误信息。模型输出根据单元测试性能进行评估。

RL方法中,模型与训练数据进行迭代交互,尝试学习最大化奖励函数的策略。经典RL算法需要连续奖励函数以探索优化空间,而单元测试反馈是离散的二进制结果。为解决此限制,除了单元测试成功率,RL奖励函数还包含修订代码的CodeBLEU分数(衡量与规范代码示例的差异),提供连续奖励信号。

由于单元测试耗时且资源密集,基于CodeBLEU分数的训练开辟了直接使用规范示例进行训练的可能性,这种过程计算效率更高。实验表明该方法确实能提升调试性能——尽管效果不如结合单元测试结果的训练。

实验评估

研究使用三类模型:完全依赖提示工程的原始LLM、仅使用SFT更新数据集的LLM,以及同时使用SFT和RL更新数据集的LLM。每类模型采用三种不同LLM架构实现,对每类模型测量三组输出:初始生成代码、直接修订版本和包含思维链推理的修订版本。此外还研究两种生成范式:单次生成正确代码的机会和10次生成机会,共形成24组对比。

实验结果表明,更新后的模型全面超越提示工程基线。在几乎所有案例中,同时使用SFT和RL更新的模型表现优于仅使用SFT的版本。总体而言,该研究展示了利用执行反馈和规范示例来优化代码模型调试并提升生成性能的可扩展方法。

通过标准基准数据集(如MBPP)测试,该方法在StarCoder-15B、CodeLlama-7B和CodeLlama-13B等代码LLM上将pass@k分数最高提升39%。pass@k指标要求模型生成k个自然语言规范实现,只要至少一个实现通过预设测试即视为成功。

关键词:大语言模型、代码生成、强化学习、监督微调、单元测试、CodeBLEU评分

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计