谷歌公開自家「AI+軟件工程」框架DIDACT:數(shù)千名開發(fā)者內(nèi)部測試,用了都說生產(chǎn)力高
任何一個大型軟件都不是一開始就構(gòu)思完善的,而是通過開發(fā)人員的一次次改進、編輯、單元測試、修復構(gòu)建錯誤、解決代碼審查,再循環(huán)解決問題,直到滿足上線需求后才能把代碼合并到倉庫中。
控制整個過程的學問就叫做軟件工程。
軟件工程并非一個獨立的過程,而是由開發(fā)人員、代碼審查員、錯誤報告員、軟件架構(gòu)師和各種開發(fā)工具(如編譯器、單元測試、連接器、靜態(tài)分析器)之間的交流組成。
最近,Google公布了自家的DIDACT(Dynamic Integrated Developer ACTivity,動態(tài)集成開發(fā)人員活動)框架,用AI技術(shù)增強軟件工程,將軟件開發(fā)的中間狀態(tài)作為訓練數(shù)據(jù),輔助開發(fā)人員編寫、修改代碼,并實時了解軟件開發(fā)的動態(tài)。
DIDACT是一個多任務模型,在編輯、調(diào)試、修復和代碼審查在內(nèi)的開發(fā)活動上進行訓練
研究人員在內(nèi)部構(gòu)建并部署了三個DIDACT工具,注釋解析、構(gòu)建修復和提示預測,每個工具都集成在開發(fā)工作流程的不同階段。
軟件工程=交互日志
幾十年以來,Google的軟件工程工具鏈都是將與代碼相關(guān)的每個操作都存儲為工具和開發(fā)人員之間的交互日志。
原則上,用戶可以使用這些記錄來詳細重放軟件開發(fā)過程中的關(guān)鍵變更過程,即Google的代碼庫是如何形成的,包括每一次的代碼編輯、編譯、注釋、變量重命名等。
Google的開發(fā)團隊會將代碼存放于monorepo(單倉庫,mono repository)中,即包含所有工具和系統(tǒng)的代碼存儲庫。
軟件開發(fā)人員通常在云中客戶端(Clients in the Cloud, CitC)系統(tǒng)管理的本地寫時復制(copy-on-write)工作空間中對代碼修改進行實驗。
當開發(fā)者準備好將一組代碼變更打包在一起實現(xiàn)某個任務時(比如修復某個bug),需要在Google的代碼審查系統(tǒng)Critique中創(chuàng)建了一個變更列表(changelist, CL)。
與常用的代碼評審系統(tǒng)一樣,開發(fā)人員與同行評審者會就功能和風格進行交流,然后編輯CL以解決評審注釋時提出的問題。
最后,評審員宣布代碼「LGTM!(looks good to me)」,并把CL合并到代碼存儲庫中。
當然,除了與代碼評審員的對話之外,開發(fā)人員還需要維護大量與其他軟件工程工具的「對話」,包括編譯器、測試框架、鏈接器、靜態(tài)分析器、模糊測試工具等。
軟件開發(fā)中涉及的復雜活動網(wǎng)絡(luò)的說明:開發(fā)人員的活動、與代碼評審員的交互以及對編譯器等工具的調(diào)用。
軟件工程中的多任務模型
DIDACT利用工程師和工具之間的交互對機器學習模型賦能,通過建議或優(yōu)化開發(fā)人員在執(zhí)行軟件工程任務時的行動,來輔助Google開發(fā)人員參與軟件工程過程。
為此,研究人員定義了一些關(guān)于單個開發(fā)人員活動的任務:修復損壞的構(gòu)建、預測代碼審查注釋、處理代碼審查注釋、重命名變量、編輯文件等。
然后為每個活動定義一個通用的形式:獲取某個State(代碼文件)、某個Intent(特定于某個活動的注釋,例如代碼評審注釋或編譯器錯誤),并生成一個Action(用于處理任務的操作)。
其中Action就像一個迷你編程語言,可以擴展為新添加的活動,涵蓋了編輯、添加注釋、重命名變量、標記代碼錯誤等內(nèi)容,也可以稱這種語言為DevScript。
DIDACT模型的輸入提示為任務、代碼片段和與該任務相關(guān)的注釋,輸出為開發(fā)動作,如編輯或評論
狀態(tài)-意圖-行動(State-Intent-Action)的定義形式能夠以通用的方式捕捉不同的任務,更重要的是,DevScript可以簡潔地表達復雜動作,不需要像動作發(fā)生后那樣輸出整個狀態(tài)(原始代碼),使得模型更有效且更可解釋。
比如重命名可能會修改代碼文件中的多處地方,但模型只需要預測一個重命名操作即可。
給AI模型配個程序員
DIDACT在個人輔助任務上運行得非常好,比如下面的例子中演示了DIDACT在功能完成后的代碼清理工作,先輸入代碼審查員的最終注釋(圖片中標記為human),然后預測解決注釋中提出問題所需要的操作(用diff展現(xiàn))。
給定代碼的初始片段和代碼審查員附加到代碼片段的注釋,DIDACT的Pre-Submit Cleanup任務生成處理這些注釋的編輯操作(文本的插入和刪除)
DIDACT的多模態(tài)性質(zhì)也產(chǎn)生了一些隨規(guī)模增大而涌現(xiàn)出的全新行為,其中一種能力是歷史增強(history augmentation),可以經(jīng)由提示來啟用這種能力,了解開發(fā)人員最近做了什么可以讓模型更好地預測開發(fā)人員下一步應該做什么。
歷史增強代碼補全的演示
歷史增強代碼補全任務可以展現(xiàn)這種能力,上圖的例子中,開發(fā)人員添加了一個新的函數(shù)參數(shù)(1),并將光標移動到文檔中(2)。以開發(fā)人員編輯的歷史和光標位置為條件,模型通過正確預測新參數(shù)的文檔字符串條目來完成行(3)。
在難度更大的歷史增強編輯預測任務中,模型能夠以歷史一致的方式選擇下一步編輯的位置。
在多個鏈式迭代上的編輯預測的演示
如果開發(fā)人員刪除了函數(shù)參數(shù)(1),則模型可以根據(jù)歷史正確地預測對刪除參數(shù)的文檔字符串(2)的更新(而無需人類開發(fā)人員手動地將光標放置在那里),并且在語法上(也可以說是語義上)正確地更新函數(shù)(3)中的語句。
有了歷史后,模型可以明確地決定如何正確地繼續(xù)「編輯代碼過程」,而如果沒有歷史記錄,模型就無法知道丟失的函數(shù)參數(shù)是故意的(因為開發(fā)人員正在進行更長的編輯操作以刪除參數(shù))還是意外情況(模型應該重新添加參數(shù)以修復問題)。
除此之外,模型還可以完成更多的任務,比如從一個空白文件開始,要求模型連續(xù)預測接下來的編輯操作,直到編寫出一個完整的代碼文件。
最重要的是,該模型能夠以一種對開發(fā)人員來說很自然的、循序漸進的方式輔助編寫代碼:
首先創(chuàng)建了一個具有導入、標志和基本main函數(shù)的完整工作框架;然后再逐步添加新功能,例如從文件中閱讀和寫入結(jié)果,并添加基于用戶提供的正則表達式來過濾某些行的功能。
結(jié)論
DIDACT將Google的軟件開發(fā)過程轉(zhuǎn)變?yōu)闄C器學習開發(fā)人員助理的訓練演示,并使用這些演示數(shù)據(jù)來訓練模型,以循序漸進的方式構(gòu)建代碼,與工具和代碼審查人員交互。
DIDACT方法補充了Google和其他公司的大型語言模型所取得的巨大成就,可以減少工作量,提高生產(chǎn)力,并提高軟件工程師的工作質(zhì)量。