大模型寫代碼能力突飛猛進(jìn),北大團(tuán)隊(duì)提出結(jié)構(gòu)化思維鏈SCoT
大型語言模型(下文稱為:大模型)在代碼生成上表現(xiàn)出了強(qiáng)大的能力。大模型依賴于 prompt 作為輸入,思維鏈?zhǔn)悄壳坝糜谠O(shè)計(jì) prompt 的主流方法,在代碼生成上取得了目前最好的準(zhǔn)確率。但大模型的準(zhǔn)確率依舊較低,無法用于實(shí)際生產(chǎn)環(huán)境。
北京大學(xué)李戈、金芝教授團(tuán)隊(duì)提出了一種結(jié)構(gòu)化的思維鏈,顯著地提升了大模型在代碼生成上的準(zhǔn)確率。結(jié)構(gòu)化的思維鏈約束大模型使用程序結(jié)構(gòu)(例如:順序、分支和循環(huán)結(jié)構(gòu))去組織思維過程,引導(dǎo)大模型從程序語言的角度去思考如何解決需求。實(shí)驗(yàn)結(jié)果表明:結(jié)構(gòu)化的思維鏈穩(wěn)定地超越了之前的工作(例如:標(biāo)準(zhǔn)的思維鏈),進(jìn)一步提升了大模型在代碼生成上的性能。
論文鏈接:https://arxiv.org/pdf/2305.06599.pdf
論文概述
大型語言模型(下文稱為:大模型)在代碼生成上表現(xiàn)出了強(qiáng)大的能力。用戶的輸入是一條 prompt,其中包括若干個(gè)演示樣例(需求 - 代碼)和一個(gè)新的需求。大模型基于 prompt 自動(dòng)地為新需求生成源代碼。
現(xiàn)有研究發(fā)現(xiàn):prompt 的設(shè)計(jì)對(duì)于大模型的性能影響較大。因此,如何設(shè)計(jì)有效的 prompt 來提升大模型在代碼生成上的準(zhǔn)確率是軟件工程和人工智能領(lǐng)域的一個(gè)研究熱點(diǎn)。
Chain-of-Thought Prompting (下文稱:CoT prompting)是一種用于設(shè)計(jì) prompt 的新興方法,在代碼生成上取得了目前最好的準(zhǔn)確率。針對(duì)一個(gè)需求,CoT prompting 先引導(dǎo)大模型思考如何解決需求,生成一段思維鏈(下文稱:CoT)。CoT 指的是一連串的中間推理步驟,描述了如何一步一步地撰寫代碼。圖 1 展示了在代碼生成上 CoT 的示例。盡管 CoT prompting 在代碼生成上取得了一定程度的提升,但它的準(zhǔn)確率依舊較低,無法用于實(shí)際生產(chǎn)環(huán)境。
今年 7 月,北京大學(xué)李戈、金芝教授團(tuán)隊(duì)(下文稱為:研究者們)針對(duì)代碼生成,提出一種結(jié)構(gòu)化的思維鏈(Structured Chain-of-Thought,下文稱為:SCoT)。
研究者們的動(dòng)機(jī)是:源代碼具有較強(qiáng)的結(jié)構(gòu)性,例如:獨(dú)特的程序結(jié)構(gòu) - 順序結(jié)構(gòu)、分支結(jié)構(gòu)和循環(huán)結(jié)構(gòu)。直覺上來說,一種結(jié)構(gòu)化的思維鏈(即中間推理步驟)有利于推導(dǎo)出結(jié)構(gòu)化的源代碼。
想象一名人類程序員 Allen 在解決一個(gè)需求(例如:求取一個(gè)列表中的最大值)時(shí)的思維過程:
1. 初始化一個(gè)變量 Result;
2. 使用循環(huán)結(jié)構(gòu)遍歷列表中的值;
a. 使用分支結(jié)構(gòu)對(duì)每個(gè)值進(jìn)行判斷,
i. 如果它大于 Result,則更新 Result
ii....
顯然,這種基于程序結(jié)構(gòu)的思維過程更貼近程序語言的解題邏輯,因此有利于引導(dǎo)后續(xù)的編碼實(shí)現(xiàn)。
受到上述分析的啟發(fā),研究者們提出:使用程序結(jié)構(gòu)來組織思維過程,得到結(jié)構(gòu)化的思維鏈 - SCoT。
圖 1(b)展示了一個(gè) SCoT 的示例。相較于標(biāo)準(zhǔn)的 CoT,SCoT 具有兩點(diǎn)不同:
(1)它使用三種基礎(chǔ)程序結(jié)構(gòu)來組織中間推理步驟。
Bohm 和 Jacopini 在 1966 年指出:任何簡單或復(fù)雜的算法都可以由順序結(jié)構(gòu)、分支結(jié)構(gòu)和循環(huán)結(jié)構(gòu)這三種基本結(jié)構(gòu)組合而成[1]。因此,研究者們引入三種基礎(chǔ)結(jié)構(gòu),并約束大模型使用這三種基礎(chǔ)結(jié)構(gòu)去生成思維鏈。這要求大模型從程序語言的角度去思考如何解決需求,并使用三種基礎(chǔ)結(jié)構(gòu)準(zhǔn)確地表達(dá)思維過程。
例如在圖 1(b)中,SCoT 清晰地展示了一個(gè)大致的解題流程。其中,它使用一個(gè)循環(huán)結(jié)構(gòu)準(zhǔn)確地描述了第二行的遍歷操作(例如:作用域、循環(huán)起止點(diǎn)),并使用一個(gè)分支結(jié)構(gòu)去描述不同情況下的處理方法。而在標(biāo)準(zhǔn)的 CoT 中,第二行和第四行的遍歷操作存在歧義,例如:作用域模糊。這會(huì)誤導(dǎo)后續(xù)的生成過程,導(dǎo)致生成錯(cuò)誤的代碼。
(2)它包含輸入輸出結(jié)構(gòu)。
每一個(gè)程序都包含輸入輸出結(jié)構(gòu),它指明了程序的輸入輸出參數(shù)及其類型。例如:圖 1(b)中的:Input: array: list [list]; Output: result。
研究者們認(rèn)為,引入輸入輸出結(jié)構(gòu)有助于大模型去分析需求和明確程序的出入口。同時(shí),一個(gè)明確的輸入輸出結(jié)構(gòu)也有利于引導(dǎo)出后續(xù)解題的思維過程。
基于上述的 SCoT,研究者們提出一種新的代碼生成方法,叫做:SCoT prompting。針對(duì)一個(gè)需求,它利用大模型先生成一段 SCoT,然后基于需求和 SCoT 生成相應(yīng)的源代碼。相比于 CoT prompting,SCoT prompting 顯式地在思維鏈中引入程序結(jié)構(gòu),以此來引導(dǎo)大模型從程序語言的角度來思考如何解決需求。這進(jìn)一步釋放了大模型在代碼生成上的推理能力,從而提升大模型的準(zhǔn)確率。
研究者們將 SCoT prompting 應(yīng)用至兩個(gè)大模型(Codex 和 ChatGPT),并在三個(gè)代碼生成數(shù)據(jù)集上進(jìn)行了驗(yàn)證。研究者使用單元測試用例來評(píng)估生成的代碼的正確性,并計(jì)算 Pass@K。實(shí)驗(yàn)結(jié)果表明:
- 在三個(gè)數(shù)據(jù)集上,SCoT prompting 穩(wěn)定地超越了目前最好的方法 - CoT prompting。例如,在 Pass@1 上,SCoT prompting 在三個(gè)數(shù)據(jù)集上分別獲得了 13.79%、12.31% 和 6.63% 的相對(duì)提升;
- 人工評(píng)估表明:人類程序員更偏愛基于 SCoT prompting 生成的代碼;
- SCoT prompting 在不同的大模型和編程語言上都具有穩(wěn)定的效果;
- SCoT prompting 具有較強(qiáng)的魯棒性,不依賴于具體的演示樣例和寫作風(fēng)格。
總的來說,本文的貢獻(xiàn)可總結(jié)為以下幾點(diǎn):
- 一種結(jié)構(gòu)化的思維鏈 - SCoT,它使用程序結(jié)構(gòu)去組織中間推理步驟;
- 一種新的基于大模型的代碼生成方法 - SCoT prompting,它利用大模型先生成結(jié)構(gòu)化的思維鏈,再生成源代碼;
- 進(jìn)行了大量的定性和定量實(shí)驗(yàn),展示了結(jié)構(gòu)化思維鏈的有效性。
結(jié)構(gòu)化的思維鏈 - SCoT
標(biāo)準(zhǔn)的思維鏈(CoT)初始是為自然語言生成任務(wù)而設(shè)計(jì),使用自然語言順序地描述如何逐步地解決問題。在代碼生成上,CoT 帶來的提升有限,大模型的準(zhǔn)確率仍舊較低。
在本文中,研究者們提出一種結(jié)構(gòu)化的思維鏈(Structured CoT,SCoT)。SCoT 顯式地引入程序結(jié)構(gòu)去撰寫思維鏈,引導(dǎo)大模型使用程序語言的邏輯去思考如何解決需求。圖 2 展示了 SCoT 的一些樣例。
現(xiàn)有研究表明:任何簡單或復(fù)雜的算法都可以由順序結(jié)構(gòu)、分支結(jié)構(gòu)和循環(huán)結(jié)構(gòu)這三種基本結(jié)構(gòu)組合而成。因此,研究者們使用這三種基本結(jié)構(gòu)撰寫思維鏈。三種基本結(jié)構(gòu)的詳情如下所示:
- 順序結(jié)構(gòu):中間步驟被順序地組織,所有的步驟位于相同的層級(jí)。
- 分支結(jié)構(gòu):它以一個(gè)條件(condition)作為起始,并基于條件的不同結(jié)果放置不同的中間步驟。在本文中,分支結(jié)構(gòu)包含三種形式:if ..., if ... else, if ... elif ... else。
- 循環(huán)結(jié)構(gòu):重復(fù)地執(zhí)行一系列中間步驟,直到某項(xiàng)條件不被滿足。在本文中,循環(huán)結(jié)構(gòu)包括兩種形式:for 循環(huán)和 while 循環(huán)結(jié)構(gòu)。
不同的程序結(jié)構(gòu)可以被嵌套使用,這允許大模型自主地設(shè)計(jì)更復(fù)雜的 SCoT 去解決困難的需求。如圖 2 所示,SCoT 靈活地使用各種程序結(jié)構(gòu)去構(gòu)建一個(gè)解題流程。
除了三種基本結(jié)構(gòu),研究者們還引入了輸入輸出結(jié)構(gòu),它包括輸入輸出參數(shù)及其類型。研究者們認(rèn)為輸入輸出結(jié)構(gòu)反映了程序的入口和出口。生成輸入輸出結(jié)構(gòu)有助于澄清需求并引導(dǎo)后續(xù)的推理過程。
SCoT prompting
基于結(jié)構(gòu)化的思維鏈(SCoT),研究者們面向代碼生成提出一種新的 prompt 設(shè)計(jì)方法 - SCoT prompting。它引導(dǎo)大模型先生成一段 SCoT,然后再生成相應(yīng)的源代碼。
為了實(shí)現(xiàn) SCoT prompting,研究者們設(shè)計(jì)了兩種特殊的 prompts。第一個(gè) prompt 用于引導(dǎo)大模型基于需求生成一段 SCoT,圖 3 展示了該 prompt 的一個(gè)示例。這個(gè) prompt 包含若干個(gè)人工撰寫的演示樣例(即:需求 - SCoT)和一個(gè)新的需求。這些演示樣例覆蓋了三種基本程序結(jié)構(gòu)和輸入輸出結(jié)構(gòu)。斜體字是面向大模型的自然語言指令,描述任務(wù)的定義。大模型從演示樣例中學(xué)習(xí),并為新需求生成相應(yīng)的 SCoT。
生成一段 SCoT 之后,研究者們設(shè)計(jì)第二種 prompt 來利用大模型生成最終的代碼。圖 4 展示了第二種 prompt 示例。這個(gè) prompt 包含若干個(gè)人工撰寫的演示樣例(即:需求 - SCoT - 代碼),以及新的需求和 SCoT。斜體字是面向大模型的自然語言指令,描述任務(wù)的定義。大模型從演示樣例中學(xué)習(xí),并基于新需求和 SCoT 生成相應(yīng)的源代碼。
現(xiàn)有研究發(fā)現(xiàn):多階段的生成方法容易受到錯(cuò)誤積累的影響。類似地,在 SCoT prompting 中,第一步生成的 SCoT 中可能包含噪聲(例如:錯(cuò)誤步驟)。這些噪聲會(huì)誤導(dǎo)后續(xù)的編碼實(shí)現(xiàn),導(dǎo)致生成錯(cuò)誤的代碼。針對(duì)這一點(diǎn),研究者們采用了兩種方法來緩解錯(cuò)誤積累問題。
- 如圖 4 所示,研究者們要求大模型去檢查 SCoT,并修復(fù)其中可能的錯(cuò)誤。這允許大模型選擇性地參考 SCoT 并忽略其中的噪聲。
- 此外,SCoT prompting 采用了一種兩階段的生成流程,這提供了一個(gè)與人交互的窗口。在實(shí)際場景中,用戶可以先檢查 SCoT 的正確性并修復(fù)其中問題,然后再使用 SCoT 生成代碼。
實(shí)驗(yàn)設(shè)計(jì)
研究者設(shè)計(jì)了一個(gè)大規(guī)模的評(píng)估來回答四個(gè)研究問題:
- 問題 1:相較于現(xiàn)有方法,SCoT prompting 在代碼生成上的準(zhǔn)確率如何?
- 問題 2:人類程序員是否更偏愛 SCoT prompting 生成的代碼?
- 問題 3:SCoT prompting 對(duì)于不同的演示樣例是否是魯棒的?
- 問題 4:SCoT prompting 中不同程序結(jié)構(gòu)的貢獻(xiàn)是怎么樣的?
數(shù)據(jù)集 & 評(píng)估指標(biāo)
研究者在三個(gè)流行的代碼生成數(shù)據(jù)集上進(jìn)行評(píng)估,包括:HumanEval、MBPP 和 MBCPP。三個(gè)數(shù)據(jù)集的統(tǒng)計(jì)結(jié)果如表 1 所示。
研究者們采用單元測試來衡量生成的代碼的正確性,并計(jì)算 Pass@k。
Baselines
研究者挑選了代碼生成上已有的三種 prompting 方法作為 baselines。
- Zero-shot prompting:利用大模型基于需求直接生成源代碼,不需要演示樣例;
- Few-shot prompting:隨機(jī)地挑選一些需求 - 代碼對(duì)作為演示樣例,利用大模型為一個(gè)新的需求直接生成源代碼;
- Chain-of-Thought prompting:few-shot prompting 的一個(gè)變體,采用需求 - 思維鏈 - 代碼作為演示樣例,引導(dǎo)大模型先生成一段思維鏈,再生成源代碼。
實(shí)驗(yàn)結(jié)果及分析
問題 1:相較于現(xiàn)有方法,SCoT prompting 在代碼生成上的準(zhǔn)確率如何?
研究者將 baselines 和 SCoT prompting 應(yīng)用至兩個(gè)大模型(Codex 和 ChatGPT)上,并衡量它們在三個(gè)數(shù)據(jù)集上的 Pass@k。實(shí)驗(yàn)結(jié)果如表 2 所示。SCoT prompting 在三個(gè)數(shù)據(jù)集上顯著地超越了所有的 baselines。相較于 CoT prompting,在 Pass@1 上,SCoT prompting 在三個(gè)數(shù)據(jù)集上分別取得了 13.79%、12.31% 和 6.63% 的相對(duì)提升。這些提升顯示了 SCoT prompting 在代碼生成上的有效性。
問題 2:人類程序員是否更偏愛 SCoT prompting 生成的代碼?
代碼生成的目的是輔助人類程序員撰寫代碼。因此,研究者們雇傭了 10 名人類開發(fā)者作為評(píng)估員,來評(píng)估不同方法生成的代碼。評(píng)估指標(biāo)如下所示:
- 正確性:代碼是否正確地實(shí)現(xiàn)了需求;
- 代碼異味:代碼是否包含代碼異味;
- 可維護(hù)性:代碼的實(shí)現(xiàn)是否標(biāo)準(zhǔn),是否具有較好的可讀性。
每項(xiàng)指標(biāo)的細(xì)節(jié)請(qǐng)見論文原文。每個(gè)指標(biāo)的分?jǐn)?shù)是一個(gè)從 0 到 2 的整數(shù),分?jǐn)?shù)越大則表明在該方面表現(xiàn)越好。人工評(píng)估的結(jié)果如表 2 所示。SCoT prompting 在三個(gè)指標(biāo)上的得分都穩(wěn)定地優(yōu)于 baselines。
圖 5 展示了 few-shot prompting 和 SCoT prompting 在同一個(gè)需求上的輸出。兩個(gè)方法生成的代碼都通過了所有的測試用例。但 few-shot prompting 生成的代碼中包含一條很晦澀難懂的條件語句。在實(shí)際場景中,程序員需要花費(fèi)額外的精力去理解和維護(hù)這樣的程序。相較之下,SCoT prompting 生成的代碼具有較好的可讀性,更易于維護(hù)。此外,SCoT 清晰地解釋了代碼的整體行為,可以當(dāng)做代碼的注釋,便于后續(xù)的維護(hù)。
問題 3:SCoT prompting 對(duì)于不同的演示樣例是否是魯棒的?
如圖 3 和圖 4 所示,SCoT prompting 需要一些人工撰寫的演示樣例來制作 prompt。在真實(shí)世界中,不同的用戶會(huì)寫出不同的樣例,這可能會(huì)導(dǎo)致 SCoT prompting 的性能有一些波動(dòng)。因此,研究者們探究 SCoT prompting 對(duì)于演示樣例的魯棒性。
研究者們從兩個(gè)方面探究 SCoT prompting 的魯棒性:
- 樣例的選擇。研究者們隨機(jī)地選擇多組需求 - 代碼對(duì)作為種子,然后要求一名標(biāo)注人員基于不同的種子撰寫演示樣例。之后,研究者們衡量 SCoT prompting 在不同演示樣例上的性能;
- 寫作風(fēng)格。不同的標(biāo)注人員有不同的寫作風(fēng)格。研究者挑選一組需求 - 代碼作為種子,雇傭多名標(biāo)注人員基于相同的種子撰寫演示樣例。之后,研究者們衡量 SCoT prompting 在不同演示樣例上的性能。
為了比較,研究者們同樣衡量了 CoT prompting 在上述場景下的魯棒性。
實(shí)驗(yàn)結(jié)果如表 5 和表 6 所示。SCoT prompting 對(duì)于演示樣例具有較強(qiáng)的魯棒性。它并不依賴于特定的樣例或者寫作風(fēng)格,在不同的設(shè)置下都優(yōu)于 CoT prompting。
問題 4:SCoT prompting 中不同程序結(jié)構(gòu)的貢獻(xiàn)是怎么樣的?
SCoT 中包括三種基本結(jié)構(gòu)和輸入輸出結(jié)構(gòu)。研究者們進(jìn)一步探究了不同的程序結(jié)構(gòu)對(duì)最終性能的貢獻(xiàn)。具體來說,研究者們分別將基本結(jié)構(gòu)和輸入輸出結(jié)構(gòu)移除,然后衡量 SCoT prompting 在三個(gè)數(shù)據(jù)集上的性能。
實(shí)驗(yàn)結(jié)果如表 4 所示。從中可以看出,基本結(jié)構(gòu)和輸入輸出結(jié)構(gòu)都是必要的。研究者們進(jìn)一步觀察了具體的樣例,并定性地分析了不同程序結(jié)構(gòu)的作用。詳情可見論文原文。
討論
SCoT 和偽代碼的比較
本文的 SCoT 與偽代碼具有一些相似之處。二者都包含輸入輸出結(jié)構(gòu)和一個(gè)大致的解題流程。研究者們隨機(jī)挑選了 100 條生成的 SCoTs。經(jīng)過人工檢查,研究者們發(fā)現(xiàn),26% 的 SCoTs 與偽代碼很相近。其余大部分(74%)的 SCoTs 與偽代碼不同,因?yàn)?SCoT 更加的抽象,不包含具體的實(shí)現(xiàn)細(xì)節(jié)。研究者們認(rèn)為這種一定程度的相似性也增強(qiáng)了 SCoT prompting 的可用性。在實(shí)際場景中,程序員可以通過 SCoT 快速地了解代碼的整體行為,也可以使用 SCoT 作為代碼注釋,便于后續(xù)的維護(hù)。
為了進(jìn)一步驗(yàn)證 SCoT 的優(yōu)越性,研究者們設(shè)計(jì)了一個(gè)變體 - SCoT-P prompting。它與 SCoT prompting 有相同的流程,但采用偽代碼作為思維鏈。表 7 展示了 SCoT prompting 和 SCoT-P prompting 的比較結(jié)果。從中可以看出,SCoT prompting 穩(wěn)定地優(yōu)于 SCoT-P prompting。這展示了本文 SCoT 在代碼生成上的優(yōu)越性。
SCoT prompting 和排序技術(shù)的比較
最近,一些研究人員提出各種排序技術(shù)(例如:CodeT)來提升大模型在代碼生成上的準(zhǔn)確率。針對(duì)一個(gè)需求,他們先利用大模型生成大量的候選代碼,然后利用測試用例或者神經(jīng)網(wǎng)絡(luò)對(duì)候選代碼進(jìn)行排序,選出其中的 Top-n 個(gè)代碼作為最終輸出。
研究者們并沒有將 SCoT prompting 與這類排序技術(shù)直接對(duì)比,主要原因是:SCoT prompting 和排序技術(shù)的應(yīng)用場景不同,且二者是互補(bǔ)的。SCoT prompting 旨在設(shè)計(jì)更有效的 prompt 來提升大模型的準(zhǔn)確率。排序技術(shù)并不關(guān)心大模型,而是聚焦于從大模型的輸出中挑選出更好的代碼。在實(shí)際場景中,程序員可以先使用 SCoT prompting 生成大量的候選代碼,再使用排序技術(shù)挑選最終輸出。
為了驗(yàn)證兩種方法的互補(bǔ)性,研究者們挑選了一個(gè)經(jīng)典的排序技術(shù) - CodeT。研究者們將 ChatGPT 作為基礎(chǔ)模型,逐漸地引入 CodeT 和 SCoT prompting。實(shí)驗(yàn)結(jié)果如圖 8 所示。可以看出,引入兩種方法不斷地提升 ChatGPT 的準(zhǔn)確率。
總結(jié)和未來工作
本文提出了一種結(jié)構(gòu)化的思維鏈(SCoT),用于提升大模型在代碼生成上的準(zhǔn)確率。它約束大模型使用程序結(jié)構(gòu)去組織思維過程,引導(dǎo)大模型從程序語言的角度去思考如何解決需求。在三個(gè) benchmarks 上的實(shí)驗(yàn)結(jié)果表明了 SCoT 的有效性。
未來,研究者們會(huì)進(jìn)一步探索如何提升大模型在代碼生成上的可用性,包括:基于上下文的代碼生成、長代碼生成等等。