编辑:Panda W
本文带你全面洞悉用LLM写代码的各式方法。
随着 BERT 和 GPT 等预训练 Transformer 的出现,语言建模近些年来取得了显著进步。随着大型语言模型(LLM)的规模扩展至数以千万计的参数数量,LLM 开始展现出通用人工智能的迹象,它们的应用也已经不局限于文本处理。Codex 首次展现出了 LLM 在代码处理方面的出色能力,之后更是出现了 Github Copilot 这样的商业产品以及 StarCoder 和 Code LLaMA 等开源代码模型。
但是,预训练 Transformer 在代码处理方面的应用可以追溯到仅解码器(decoder-only)自回归模型成为主流技术之前的时期,而这一领域还尚没有一篇完整的综述。
上海交通大学和蚂蚁集团的一个研究团队填补了这一空白。他们对用于代码的语言模型进行了全景式的总结,覆盖了 50 多个模型、30 多个下游任务和 500 多个相关研究成果。他们对代码语言模型进行了分类,从在一般域上训练的巨型模型到专门针对代码理解或生成任务训练的微型模型。
他们关注的重点是这些模型之间的关系和差异,并格外强调了在语言模型中集成特定于代码的功能(例如抽象语法树或数据流)以及从 NLP 领域借用过来的最新技术。
下面机器之心将介绍这一篇综述论文。如果你想更全面地了解代码语言模型的发展历程,请一定不要错过原论文。此外,该团队还在 GitHub 上建了一个开放的相关文献索引库,以跟踪和分享代码 LLM 的最近成果。
背景
这一节,作者总结了基于 Transformer 的语言建模的基本知识,包括单向和双向模型的共同目标,以及 NLP 中的一些流行模型和设计。
单向语言模型(也被称为因果语言模型)是将句子的概率分解为每个 token 的条件概率与链式法则的乘积。
不同于因果语言模型,双向语言模型的训练目标是为文本获得更好的上下文表征,而不是以自回归的方式生成文本。
GPT 式的因果语言模型和 BERT 式的双向语言模型各有其优点和缺点。GPT 虽可用于自回归生成,但却缺乏对输入文本的双向表征,因此不适用于翻译和摘要等序列到序列任务(seq2seq)。另一方面,BERT 虽可产生双向表征,但其预训练的目标是掩码填充,而非生成。
最基本的 Transformer 编码器 - 解码器架构将 GPT 和 BERT 各自的优点结合到了一起。T5 便是这样一个模型,其预训练过程使用了 span corruption,可被看作是掩码式语言建模(MLM)的一种变体。
因果语言建模(CLM)和 MLM 等语言建模目标主要是训练模型捕获 token 层面的信息,而无法高效地建模文档结构。因此,为了帮助模型学习全局信息,通常还会添加辅助目标,比如 BERT 的预训练在使用 MLM 的同时还使用了下一句子预测(NSP)目标。
另外值得一提的是,尽管大多数预训练语言模型研究都集中于设计训练目标,但 Transformer 架构本身的低层实现也在不断进步,获得了更好的稳定性、性能和效率。
评估用于代码的语言模型
过去十年中,软件工程社区已经提出了多种不同的用于评估代码模型的评估任务。CodeXGLUE 将大多数此类整合成了单一基准,其中涵盖克隆检测、缺陷检测等代码理解任务以及代码修复、代码转译、程序合成和代码总结等序列到序列生成任务。但是,自 Chen et al. (2021) 引入了 HumanEval 和 Codex 之后,文本到代码合成就被带到了 NLP 社区的聚光灯下,并从此成为评估 LLM 的标准任务(图 2)。
代码处理的下游任务
在这篇综述中,作者按照软件工程的惯例,基于输入 / 输出的模态对代码评估任务进行了分类,而这些类别又可归总为 5 个大类:文本到代码、代码到代码、代码到文本、代码到模式、文本到文本。下面将简单列出这些任务,至于对这些任务的解释,请参阅原论文。
文本到代码任务以文本为输入,输出代码。其中包括:代码检索、代码合成、文本到 SQL、数学编程。
代码到代码任务以代码为输入,输出代码。其中包括:代码搜索、代码补全、代码转译、代码修复、填空测验、代码填充、代码混淆、单元测试生成、断言生成、模糊测试(Fuzzing)、类型预测。
代码到文本任务以代码为输入,输出文本。其中包括:代码摘要、代码审查、标识符预测。
代码到模式任务是对代码执行分类。其中包括:缺陷检测、克隆检测、代码分类、代码推理。
文本到文本任务以文本为输入,输出文本。其中包括:文档翻译、日志解析。
评估指标
代码理解任务在形式上与自然语言理解任务相似,所使用的评估指标也类似,比如准确度、F1 和 MRR(Mean Reciprocal Rank),而标识符预测等短生成任务则可使用精准匹配的准确度进行评估。代码到文本任务可使用文本生成任务的常用评估指标,比如 BLEU。
而涉及代码生成的评估任务则更复杂。大多数早期研究都是评估句法正确度,即可成功解析的生成结果百分比。Chen et al. (2018) 反对此类指标,并提出了参照匹配(reference match)指标,即生成结果与参考结果完全一致的比例。Ren et al. (2020) 则提出了 CodeBLUE,这是 BLEU 的一种变体,其评估的是抽象语法树(AST)和数据流的重叠范围,可兼顾代码的句法和语义。
但是,随着这些年来代码生成模型能力的提升,人们发现这些基于内容重叠度的指标已经不够用了,因为执行同样功能的代码段可能在词汇形式上大不相同。
因此,研究者将关注重点转向了功能正确性。pass@k 就是其中的代表。该指标由 Kulal et al. (2019) 提出,并被 Chen et al. (2021) 加以优化,能够无偏差地估计模型使用任意 k 个生成样本通过程序的所有单元测试的几率。该指标还可以泛化成 passn@k (Li et al., 2022),其将模型提交的数量限制到了 n,但允许根据输入中给定的单元测试对 k 个样本进行过滤。
程序合成
随着这些年来代码模型的进步,研究者的关注重点逐渐转向了实践中的程序合成任务。
2018 年的 CONCODE 是该领域的一个早期数据集,其中包含超过 10 万条 JAVA 方法,并已经被整合到了 CodeXGLUE 基准中。
2021 年以来,相关数据集迅速增多,其中大部分都专注于 Python/ target=_blank class=infotextkey>Python 语言,比如 AppS、HumanEval、MBPP;而近期也有一些工作将 HumanEval 扩展到了其它编程语言。DS-1000 是一个更现实的 Python 数据集,专注于 NumPy 和 SciPy 等数据科学软件库,同时一些数学推理基准也已被转换为编程任务,包括 MathQA-Python 和 GSM8K-Python。
代码库层面的评估
前面谈到的大多数评估任务都仅限于单个文件甚至单个函数。
近期一些研究探索了利用代码库层面的上下文来进行代码补全,而 Liu et al. (2023) 提出了用于评估这些系统的 RepoBench。最近,Bairi et al. (2023) 研究了难度更大的代码库层面的 API 迁移和时间编辑任务,Jimenez et al. (2023) 则引入了一个相应的基准 SWE-bench。
用于代码的通用语言模型
自从语言模型的参数数量扩展到数以千亿计,它们中的许多就已经展现出了非凡的编程能力,即便它们并不是专门针对代码而设计或训练的。Codex 之后,研究者发现只需继续在代码上进行预训练,就能显著提升语言模型的代码性能。
现成可用的语言模型
大型语言模型的预训练通常会使用数以万亿计的 token,遵循缩放律(scaling laws),而这巨量的文本数据中往往包含少量但不可忽视的多样化代码。比如 Pile 数据集包含 95GB 代码(爬取自 GitHub 的 800GB 原始数据集);1.6 TB 的多语言预训练数据集 ROOTS 也包含 163GB 代码,涵盖 13 种编程语言。这是两个最大型的开源预训练数据集,让许多语言模型具备了编程能力。比如 GPT-J、GPT-NeoX 和 BLOOM 在 HumanEval 上都有不错的表现。
LLaMA(其预训练数据集包含 328GB 来自 GitHub 的代码)在 HumanEval 指标上取得了 23.7 的 pass@1 表现,其后继模型 LLaMA 2 得到了更高的 29.9。
另一方面,闭源模型的表现一般更好。比如 LaMDA 和 PaLM 在 HumanEval 上的 pass@1 性能分别为 14.0 和 26.2,而 GPT-4 的则达到了惊人的 67.0,这一成绩直到最近都高于任何专门针对代码预训练或指令微调的模型。
最近的一大趋势是使用更大的数据集训练更小的模型,遵循修订版的缩放律。
举两个例子:Baichuan 2 是使用 2.6T token 训练出的 13B 模型,而 Qwen 则是用 3T token 训练的 14B 模型。它们在 HumanEval 上的 pass@1 性能分别为 17.1 和 32.3。Li et al. (2023) 则表明 1.3B 的小模型也能获得与更大型模型相当的编程能力,同时还能维持合理的一般文本处理能力,甚至也能显现出一些涌现能力,比如思维链推理。他们的模型 Phi-1.5 的训练使用了 ChatGPT 生成的 21B token 的教材数据以及取自 Stack Overflow 和 Refined Web 的 100B token 的已过滤网络数据;其在 HumanEval 上的 pass@1 性能为 41.4。
表 1 给出了这些模型的性能表现。
在代码上进行过额外预训练的语言模型
伴随着开创性的基准 HumanEval,Chen et al. (2021) 还开启了将 LLM 用于代码的时代。他们的贡献是 Codex,这是一个 GPT-3 检查点模型,但额外使用了 100B 的代码 token 进行预训练。这是最早的超十亿参数规模的代码模型之一。
之后出现的还有接连成为 HumanEval 和 MBPP 当前最佳的 PaLM-Coder 和 PaLM 2-S*。类似地,Lewkowycz et al. (2022) 用 38.5B token 的 arXiv 论文和数学内容训练了 PaLM;Rozière et al. (2023) 则使用超过 500B 代码 token 训练 LLaMA 2 而得到了 Code LLaMA,其在 HumanEval 上的表现超过除 GPT-4 外的之前所有语言模型。
Liu et al. (2023) 又使用多任务微调(MFT)进一步训练了 Code LLaMA,得到了 CodeFuse-CodeLLaMA,其在 HumanEval 上的 pass@1 性能为 74.4,超过了 OpenAI 报告的 GPT-4 的性能。
尽管这些模型基本都是使用 CLM 预训练的 Transformer 解码器,但研究者也在不断改进这种架构,引入了并行注意力、MQA、RoPE 等新方法。
专用于代码的语言模型
随着 GPT 和 BERT 等预训练 Transformer 在自然语言处理方面取得巨大成功,此类模型架构、学习范式和训练目标很快被软件工程社区采用,打造出了用于代码理解和生成的专用模型。表 3 给出了这些预训练模型的概况。
代码训练数据集
现在已经有许多大规模的代码预训练数据集,包括 CodeSearc.NET、CodeParrot、Stack;它们分别包含 20GB、50GB 和 3TB 代码文档(见表 2)。
编码器
Kanade et al. (2020) 在代码语料库上重复了 BERT 的训练过程,得到了 CuBERT。而 Feng et al. (2020) 则在 CodeSearchNet 上使用 MLM 和 ELECTRA 的 RTD 训练得到了 CodeBERT。他们还利用了 CodeSearchNet 中的显式「文本 - 代码」对,并将它们分别用作 BERT 输入的第一和第二段。
除了这些标准的训练目标之外,研究者还引入了许多专为代码任务设计的辅助目标。GraphCodeBERT 和 SynCoBERT 会从源代码中提取图(graph),各自对应于数据流图和抽象语法树,然后它们借此训练模型来预测节点之间的类型关系;另外 SynCoBERT 和 Code-MVP 还在预训练阶段以标记的形式添加了类型推理。
另一个常用目标是对比学习:SynCoBERT 和 Code-MVP 会对比输入的不同角度(比如代码、注释、AST 和经过转换的代码);而 DISCO 则会通过混淆等保留语义的变换来构建正例样本对,通过注入人工错误来构建负例样本对。
编码器 - 解码器
相比于仅编码器模型,编码器 - 解码器自然更强大,因为它们可以用于条件文本生成,而它们的编码器部分始终可以单独用于执行需要仅编码器架构的任务,例如回归。
受编码器 - 解码器架构进步的激励,研究社区已经提出了许多用于代码处理的此类模型。
PyMT5 (Clement et al., 2020) 和 Mastropaolo et al. (2021) 在代码语料库上重复了 T5 的预训练和多任务微调过程,而 Ahmad et al. (2021) 则提出了 PLBART,这是在 655GB 的 Java、Python 和自然语言组合数据上预训练的 BART 模型。Lachaux et al. (2021) 认为 MLM 对于编程语言来说可能是一项过于简单的任务,因为标识符名称经常在单个上下文窗口中出现多次;他们提出了一种去混淆预训练目标,即模型的训练目标是将经过混淆的代码转换成原有形式。
基于这些之前的研究成果,Wang et al. (2021) 提出了 CodeT5,其预训练使用了 T5 原有的 span corruption、标识符标记、掩码式标识符预测、文本到代码和代码到文本生成。其后继模型 CodeT5+ 则从 UL2 获得了灵感,将因果语言建模(CLM)引入了预训练过程,此外还有基于文本 - 代码匹配的对比目标。
Li et al. (2022) 的 AlphaCode 也使用了多个训练目标:其编码器用 MLM 训练,解码器用 CLM 训练,此外还有浅编码器和深解码器、多查询注意力等架构上的调整;其模型规模也比 CodeT5 大很多,多达 410 亿参数。
Chakraborty et al. (2022) 的 NatGen 的预训练则使用了一个类似于去混淆的「自然化(naturalization)」目标:通过循环变换、死代码注入和变量重命名等预定义操作生成语义上等效但不自然的代码,然后训练模型将这些不自然的代码转译回其原始形式。
除了这些一般性预训练目标之外,一些研究工作训练 Transformer 编码器 - 解码器时的重点是代码转译,这是 Transformer 模型在代码方面的一个自然应用,毕竟 Transformer 架构最早就是 Vaswani et al. (2017) 为机器翻译任务提出的。但是,不同于自然语言,代码的并行数据很少。
为了解决这个问题,Rozière et al. (2020) 提出了 Transcoder,其首先使用 XLM 预训练一个编码器,然后使用这个编码器初始化一个基本的 Transformer,再继续使用去噪自动编码(DAE)对其进行预训练并转译回去;之后的 Szafraniec et al. (2023) 还使用了与语言无关的中间表征来增强这一过程。
除了训练数据和目标之外,这些模型大多保留了 NLP 社区提出的原始架构,如表 3 所示。
解码器
GPT-3 历史的发布以及上下文学习方法出现之后,仅解码器 Transformer 模型已经成为语言建模的主导技术。在代码处理领域,也出现了许多类似使用 CLM 预训练的模型,比如 GPT-C、CodeGPT、PolyCoder、CodeGen、PyCodeGPT、Pangu-Coder、CodeGeeX、Phi-1、CodeFuse、CodeShell、DeepSeek Coder。这些模型中有一些实验了其它的训练目标,比如 Pangu-Coder 用了 MLM 和 Masked CLM,但这样的表现并不及仅使用 CLM 训练的方法。Zan et al. (2022) 还提出了在草案(sketch)上进行持续训练,也就是让模型学习先生成程序的草案,然后再实际写代码。
尽管 Christopoulou et al. (2022) 报告说去噪目标的表现不及仅解码器模型,但也有一些研究工作将去噪或多任务预训练与解码器架构结合到了一起。Incoder、SantaCoder 和 StarCoder 的训练都使用了中间填入(FIM/fill-in-the-middle)目标(也被称为因果掩码),其本质上就是仅解码器架构采用的 span corruption。这些填入目标有一个明显优势:它们可以让模型有能力在推理时间填补输入代码中间的空白部分,而 CLM 只允许自回归生成。但是,如表 4 所示,相比于 CodeGen 等仅 CLM 模型,这些目标也会提升模型在下游任务上的性能表现。
UniLM
一些研究者也将 UniLM 这另一种 Transformer 模型用在了代码处理上。CugLM 通过交替的注意力掩码使用了 CLM 和 MLM + NSP,而 UniXcoder 的训练则使用了 CLM、MLM、Span Corruption 以及对比学习和文本 - 代码双向生成等辅助目标。但是,这两个模型的规模都相对较小,因此这种架构究竟是否适合代码处理还有待探索。
扩散模型
虽然目前主导文本生成领域的是 Transformer 架构,但也有一些研究者探索了使用计算机视觉领域的扩散模型(Diffusion Model)来生成文本。
近期的 CodeFusion 将扩散模型引入了代码建模领域,并且研究表明:一个 7500 万参数的扩散模型在三个代码合成数据集上取得了优于 StarCoder、CodeT5+ 和 GPT-3 的表现。
用于代码的指令微调和强化学习
跟随自然语言领域的研究成果,代码社区的研究者也已经在使用指令微调技术。Wang et al. (2023) 使用 InstructGPT 生成的 2 万个指令数据对 CodeT5+ 进行了微调,得到了 InstructCodeT5+。WizardCoder 按照 WizardLM 的方法,将 2 万代码的 Alpaca 样本演进成了一个 78K 的数据集,并使用其来微调 StarCoder。Pangu-Coder 2 也使用 WizardLM 的 Evol-Instruct 从 2 万代码的 Alpaca 生成了 6.8 万个指令样本,其还通过排名响应(Rank Responses)引入了强化学习来对齐测试与教师反馈(RRTF)。
OctoCoder 则采用了另一条路径,其是使用 Git 提交历史作为指令数据来微调 StarCoder 和 CodeGeeX2。更近期的 CodeFuse 还使用了多任务微调,显式地将多个下游任务引入到了指令数据中。表 4 也给出了这些经过指令微调的代码模型的性能。
在 NLP 领域,另一个与指令微调紧密关联的技术是根据人类反馈的强化学习(RLHF),其在对齐 LLM 与人类价值方面发挥了重要作用。将强化学习用于代码有一个很自然的优势,因为编译器可以自动为语言模型生成的代码样本生成反馈。
CodeRL 就是一个这样的模型,其会为每个生成的程序定义四个层级的奖励(即编译错误、运行时错误、单元测试失败、通过)以及由一个 critic 模型估计的细粒度的 token 层面的奖励。其 actor 模型扩展自 CodeT5,然后再使用 REINFORCE 算法训练。类似地,CompCoder 和 PPOCoder 使用近端策略优化(PPO)分别训练了 CodeGPT 和 CodeT5,而 RLTF 则提出基于编译器提供的报错信息和位置给出细粒度反馈,并使用考虑了已通过测试案例比例的适应性反馈。
语言模型所用的代码特征
编程语言和自然语言的一大主要差异是:前者是人工定义的,力求精确无歧义,并且需要在执行之前无错误地编译(或解释)。这样一来,除了 CLM、MLM 和 Span Corruption 等词汇操作之外,在设计代码的预训练目标方面会有更大的灵活性。
编程语言在句法特征等方面有很大的优势。C、Python 和 Java 等每个主流编程语言都有现成可用的编译器工具包,可以轻松且准确地提取出程序的语义信息,比如抽象语法树(AST)、与语言无关的中间表征(IR)以及每个 token 的类型和控制 / 数据流图(CFG/DFG)等辅助信息。因此,对于用于代码的 Transformer 式语言建模,很多研究工作将这些特征整合进了他们的训练流程。
抽象语法树和中间表征
Jiang et al. (2021) 提出的 TreeBERT 是最早尝试把 AST 用于基于 Transformer 的预训练 - 微调框架的模型之一。这是一个 Transformer 编码器 - 解码器模型,其预训练使用了 Tree MLM 和 Node Order Prediction。
之后还出现了 SynCoBER、SPT-Code 和 UniXcoder 等研究成果,详见原论文。
在编译流程中,AST 后面通常跟着与语言无关的中间表征,比如 LLVM IR。这种独立于特定编程语言的特征让它们非常适合作为转译中枢。
控制流和数据流
尽管研究已经证明 AST 和 IR 对特定任务(如代码转译)来说很有用,但它们本质上是静态的,就像源代码一样,并且可能无法捕获仅在运行时揭示的代码的语义属性。而控制流和数据流等动态特征中包含这样的语义。
类似于 AST,在预训练 Transformer 兴起之前,要使用专门的网络来处理这样的信息,比如 ProGraML 使用的消息传递神经网络。但是不同于 AST,即使在预训练 Transformer 变得主流之后,也少有研究探索这个方向。
GraphCodeBERT 就是这样一项研究,其会为流图中的变量创建特殊的 token 和位置嵌入,并将这个变量序列连接到文本和源代码后面来构建模型输入,其还使用了针对代码和变量段定制的注意力掩码。
类型
除了 AST、IR 和数据流,类型信息也会被用于辅助语言模型处理代码。举个例子,CugLM 在微调阶段使用了类型信息来辅助单向 MLM (即有单向注意力掩码的 MLM)的 token 预测:首先是根据最终 Transformer 层的表征预测掩码 token 的类型,然后基于隐藏表征和预测的类型预测 token 本身。相比之下,CodeT5 和 SynCoBERT 的预训练目标中都包含标识符标记,这可以被视为粗粒度的类型预测。
值得一提的是,Wang et al. (2022) 将上述的许多特征整合进了 Code-MVP:源代码、文档字符串、AST、CFG 以及通过标识符重命名、循环交换和死代码插入等方式转换过的源代码。该模型是从 GraphCodeBERT 初始化,然后使用 MLM、细粒度的类型预测和不同角度的对比学习(比如文本与代码、代码与 AST、代码与 CFG)来进行训练。
软件开发中的 LLM
随着语言模型在软件工程基准上创造新记录,软件工程技术也正反过来扩展语言模型的边界,并将其带入现实世界的开发周期。
使用编程工具扩展 LLM
NLP 社区的研究已经表明 LLM 可以学习使用外部工具,比如计算器、机器翻译系统和搜索引擎。因此可以使用解释器来增强 LLM 处理复杂推理任务的能力。PAL 和 PoT 都使用了 Python 解释器来扩展 Codex,使其具备数值计算能力,而 ViperGPT 则是通过调用视觉 API 进行了进一步扩展,使其可以提取视觉输入的信息并回答相关问题。
除了减轻抽象的推理任务中数值计算的负担,解释器也可对代码生成过程本身提供反馈以及进行单元测试。CodeT 和 TiCoder 使用 Codex 来生成单元测试,这些测试运行在生成的代码样本上,可以提升模型在代码合成上的性能。类似地,TransCoder-ST 通过执行代码转译的外部单元测试增强了 TransCoder 和 DOBF。另外,单元测试的执行结果可作为代码强化学习的自然监督信号。
值得一提的是,OpenAI 在 2023 年 3 月为 ChatGPT 发布了一个解释器插件,该插件可以接受用户的文件输入,根据用户指令生成代码,并通过实时执行提供反馈。Zhou et al. (2023) 的研究表明这一功能让 GPT-4 可以自我调试。
在 LLM 研究中,一个与使用工具紧密关联的主题是作为智能体进行规划,理论和实验研究均表明这可以提升 LLM 的能力。Ruan et al. (2023) 发现 LLM 可以使用外部 SQL 生成器和 Python 生成器进行规划来解决复杂任务,而 CodePlan 可通过自适应规划执行代码库层面的编程。
另一类工作是使用 LLM 来创建用于代码生成的多智能体系统,比如 self-collaboration、ChatDev 和 MetaGPT。在这些框架中,多个 LLM 各自扮演着不同的角色,比如编程者、审查者和管理者。这些角色相互交互,将代码生成任务分为不同的阶段(比如设计、写代码、测试和做文档),并通过协作来完成复杂任务。
将 LLM 整合进软件开发
随着 LLM 的交互式编程能力的提升,研究者已经开始将其整合进软件开发的整个过程中。
自动代码补全是语言模型在软件开发领域的最早期应用之一,因为这一任务只需要预测下一 token 的能力。即使是在语言模型的规模达到数十亿参数之前,就已经有人将 Pythia 和 IntelliCode 等代码补全系统整合进常用的 IDE 了。
不过近段时间,代码语言模型的应用已经超越了简单的代码补全。GitHub Copilot 可以说是最流行的 AI 编程助理之一,其具备非常多功能,包括代码生成、漏洞检测和证书管理,而 CodeFuse 也将代码生成、代码转译、代码注释和测试用例生成整合成了单一的 IDE 插件,但是,随着代码语言模型越来越大,它们的客户端部署和实时性能也遭遇了新的挑战。
随着 LLM 持续发展,基于它们构建应用本身也正在变成一项具有重要价值的任务。目前已经出现了许多针对此类应用的开源框架,包括 LangChain、AutoGPT 和 WorkGPT。
总结和挑战
这份综述系统性地回顾了使用预训练 Transformer 语言模型处理代码的历史,并强调了它们与一般领域预训练模型的关系,还进行了比较。
代码建模的进步通常紧随 NLP 的历史进程:从 SMT 模型发展到 NMT 模型,然后到微调的预训练 Transformer,最后到 LLM 的少样本应用甚至现实世界产品中的自主智能体。
不用于自然语言,代码的本质让我们可以轻易从不同角度提取辅助信息,并利用解释器和单元测试来获取自动反馈。
在此基础上,作者最后指出了当前代码建模领域所面临的一些挑战: