国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

構(gòu)建你自己的 AI 輔助編碼助手:從 IDE 插件、代碼數(shù)據(jù)生成和模型微調(diào)(萬(wàn)字長(zhǎng)文)...

這篇具有很好參考價(jià)值的文章主要介紹了構(gòu)建你自己的 AI 輔助編碼助手:從 IDE 插件、代碼數(shù)據(jù)生成和模型微調(diào)(萬(wàn)字長(zhǎng)文)...。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

treesitter和 intellij psi lsp,人工智能,ide

我們會(huì)在 GitHub 上持續(xù)更新這個(gè)教程: https://github.com/phodal/build-ai-coding-assistant,歡迎在 GitHub 上討論。

2023 年,生成式 AI 的火爆,讓越來(lái)越多的組織開(kāi)始引入 AI 輔助編碼。與在 2021 年發(fā)布的 GitHub Copilot 稍有差異的是,代碼補(bǔ)全只是重多場(chǎng)景中的一個(gè)。大量的企業(yè)內(nèi)部在探索結(jié)合需求生成完整代碼、代碼審查等場(chǎng)景,也引入生成式 AI,來(lái)提升開(kāi)發(fā)效率。

在這個(gè)背景下,我們(Thoughtworks)也開(kāi)發(fā)了一系列的開(kāi)源工具,以幫助更多的組織構(gòu)建自己的 AI 輔助編碼助手:

  • AutoDev,基于 JetBrains 平臺(tái)的全流程 AI 輔助編碼工具。

  • Unit Eval,代碼補(bǔ)全場(chǎng)景下的高質(zhì)量數(shù)據(jù)集構(gòu)建與生成工具。

  • Unit Minions,在需求生成、測(cè)試生成等測(cè)試場(chǎng)景下,基于數(shù)據(jù)蒸餾的數(shù)據(jù)集構(gòu)建工具。

由于,我們?cè)O(shè)計(jì) AutoDev 時(shí),各類開(kāi)源模型也在不斷演進(jìn)。在這個(gè)背景下,它的步驟是:

  • 構(gòu)建 IDE 插件與度量體系設(shè)計(jì)。基于公開(kāi)模型 API,編寫和豐富 IDE 插件功能。

  • 模型評(píng)估體系與微調(diào)試驗(yàn)。

  • 圍繞意圖的數(shù)據(jù)工程與模型演進(jìn)。

也因此,這個(gè)教程也是圍繞于這三個(gè)步驟展開(kāi)的。除此,基于我們的經(jīng)驗(yàn),本教程的示例技術(shù)棧:

  • 插件:Intellij IDEA。AutoDev 是基于 Intellij IDEA 構(gòu)建的,并且自帶靜態(tài)代碼分析能力,所以基于它作為示例。我們也提供了 VSCode 插件的參考架構(gòu),你可以在這個(gè)基礎(chǔ)上進(jìn)行開(kāi)發(fā)。

  • 模型:DeepSeek Coder 6.7b。基于 Llama 2 架構(gòu),與 Llama 生態(tài)兼容

  • 微調(diào):Deepspeed + 官方腳本 + Unit Eval。

  • GPU:RTX 4090x2 +?OpenBayes。(PS: 用我的專用邀請(qǐng)鏈接,注冊(cè) OpenBayes,雙方各獲得 60 分鐘 RTX 4090 使用時(shí)長(zhǎng),支持累積,永久有效:https://openbayes.com/console/signup?r=phodal_uVxU )

由于,我們?cè)?AI 方面的經(jīng)驗(yàn)相對(duì)比較有限,難免會(huì)有一些錯(cuò)誤,所以,我們也希望能夠與更多的開(kāi)發(fā)者一起,來(lái)構(gòu)建這個(gè)開(kāi)源項(xiàng)目。

功能設(shè)計(jì):定義你的 AI 助手

結(jié)合 JetBrains 2023《開(kāi)發(fā)者生態(tài)系統(tǒng)》報(bào)告的人工智能部分?,我們可以總結(jié)出一些通用的場(chǎng)景,這些場(chǎng)景反映了在開(kāi)發(fā)過(guò)程中生成式 AI 可以發(fā)揮作用的領(lǐng)域。以下是一些主要的場(chǎng)景:

  • 代碼自動(dòng)補(bǔ)全:在日常編碼中,生成式 AI 可以通過(guò)分析上下文和學(xué)習(xí)代碼模式,提供智能的代碼自動(dòng)補(bǔ)全建議,從而提高開(kāi)發(fā)效率。

  • 解釋代碼:生成式 AI 能夠解釋代碼,幫助開(kāi)發(fā)者理解特定代碼片段的功能和實(shí)現(xiàn)方式,提供更深層次的代碼理解支持。

  • 生成代碼:通過(guò)學(xué)習(xí)大量的代碼庫(kù)和模式,生成式 AI 可以生成符合需求的代碼片段,加速開(kāi)發(fā)過(guò)程,尤其在重復(fù)性工作中發(fā)揮重要作用。

  • 代碼審查:生成式 AI 能夠進(jìn)行代碼審查,提供高質(zhì)量的建議和反饋,幫助開(kāi)發(fā)者改進(jìn)代碼質(zhì)量、遵循最佳實(shí)踐。

  • 自然語(yǔ)言查詢:開(kāi)發(fā)者可以使用自然語(yǔ)言查詢與生成式 AI 進(jìn)行交互,提出問(wèn)題或請(qǐng)求,以獲取相關(guān)代碼片段、文檔或解釋,使得開(kāi)發(fā)者更輕松地獲取需要的信息。

  • 其它。諸如于重構(gòu)、提交信息生成、建模、提交總結(jié)等。

而在我們構(gòu)建 AutoDev 時(shí),也發(fā)現(xiàn)了諸如于創(chuàng)建 SQL DDL、生成需求、TDD 等場(chǎng)景。所以。我們提供了自定義場(chǎng)景的能力,以讓開(kāi)發(fā)者可以自定義自己的 AI 能力,詳細(xì)見(jiàn):https://ide.unitmesh.cc/customize。

場(chǎng)景驅(qū)動(dòng)架構(gòu)設(shè)計(jì):平衡模型速度與能力

在日常編碼時(shí),會(huì)存在幾類不同場(chǎng)景,對(duì)于 AI 響應(yīng)速度的要求也是不同的(僅作為示例):

treesitter和 intellij psi lsp,人工智能,ide

PS:這里的 32B 僅作為一個(gè)量級(jí)表示,因?yàn)樵诟蟮哪P拖?,效果?huì)更好。

因此,我們將其總結(jié)為:一大一中一微三模型,提供全面 AI 輔助編碼:

  • 高質(zhì)量大模型:32B~。用于代碼重構(gòu)、需求生成、自然語(yǔ)言代碼搜索與解釋等場(chǎng)景。

  • 高響應(yīng)速度中模型:6B~。用于代碼補(bǔ)全、單元測(cè)試生成、文檔生成、代碼審查等場(chǎng)景。

  • 向量化微模型:~100M。用于在 IDE 中進(jìn)行向量化,諸如:代碼相似度、代碼相關(guān)度等。

重點(diǎn)場(chǎng)景介紹:補(bǔ)全模式

AI 代碼補(bǔ)全能結(jié)合 IDE 工具分析代碼上下文和程序語(yǔ)言的規(guī)則,由 AI 自動(dòng)生成或建議代碼片段。在類似于 GitHub Copilot 的代碼補(bǔ)全工具中, 通常會(huì)分為三種細(xì)分模式:

行內(nèi)補(bǔ)全(Inline)

類似于 FIM(fill in the middle)的模式,補(bǔ)全的內(nèi)容在當(dāng)前行中。諸如于:?BlotPost?blogpost?=?new,補(bǔ)全為:?BlogPost();, 以實(shí)現(xiàn):?BlogPost?blogpost?=?new?BlogPost();

我們可以?Deepseek Coder?作為例子,看在這個(gè)場(chǎng)景下的效果:

<|fim▁begin|>def quick_sort(arr):
if len(arr) <= 1:
return arr
    pivot = arr[0]
    left = []
    right = []
<|fim▁hole|>
if arr[i] < pivot:
            left.append(arr[i])
else:
            right.append(arr[i])
return quick_sort(left) + [pivot] + quick_sort(right)<|fim▁end|>

在這里,我們就需要結(jié)合光標(biāo)前和光標(biāo)后的代碼。

塊內(nèi)補(bǔ)全(InBlock)

通過(guò)上下文學(xué)習(xí)(In-Context Learning)來(lái)實(shí)現(xiàn),補(bǔ)全的內(nèi)容在當(dāng)前函數(shù)塊中。諸如于,原始的代碼是:

fun createBlog(blogDto: CreateBlogDto): BlogPost{
}

補(bǔ)全的代碼為:

val blogPost = BlogPost(
    title = blogDto.title,
    content = blogDto.content,
    author = blogDto.author
)
return blogRepository.save(blogPost)

塊間補(bǔ)全(AfterBlock)

通過(guò)上下文學(xué)習(xí)(In-Context Learning)來(lái)實(shí)現(xiàn),在當(dāng)前函數(shù)塊之后補(bǔ)全,如:在當(dāng)前函數(shù)塊之后補(bǔ)全一個(gè)新的函數(shù)。諸如于,原始的代碼是:

fun createBlog(blogDto: CreateBlogDto): BlogPost{
//...
}

補(bǔ)全的代碼為:

fun updateBlog(id: Long, blogDto: CreateBlogDto): BlogPost{
//...
}
fun deleteBlog(id: Long) {
//...
}

在我們構(gòu)建對(duì)應(yīng)的 AI 補(bǔ)全功能時(shí),也需要考慮應(yīng)用到對(duì)應(yīng)的模式數(shù)據(jù)集,以提升補(bǔ)全的質(zhì)量,提供更好的用戶體驗(yàn)。

編寫本文里的一些相關(guān)資源:

  • Why your AI Code Completion tool needs to Fill in the Middle

  • Exploring Custom LLM-Based Coding Assistance Functions

重點(diǎn)場(chǎng)景介紹:代碼解釋

代碼解釋旨在幫助開(kāi)發(fā)者更有效地管理和理解大型代碼庫(kù)。這些助手能夠回答關(guān)于代碼庫(kù)的問(wèn)題、 提供文檔、搜索代碼、識(shí)別錯(cuò)誤源頭、減少代碼重復(fù)等, 從而提高開(kāi)發(fā)效率、降低錯(cuò)誤率,并減輕開(kāi)發(fā)者的工作負(fù)擔(dān)。

在這個(gè)場(chǎng)景下,取決于我們預(yù)期的生成質(zhì)量,通常會(huì)由一大一微或一中一微兩個(gè)模型組成,更大的模型在生成的質(zhì)量上結(jié)果更好。結(jié)合,我們?cè)?Chocolate Factory?工具中的設(shè)計(jì)經(jīng)驗(yàn),通常這樣的功能可以分為幾步:

  • 理解用戶意圖:借助大模型理解用戶意圖,將其轉(zhuǎn)換為對(duì)應(yīng)的 AI Agent 能力調(diào)用或者 function calling 。

  • 轉(zhuǎn)換意圖搜索:借助模型將用戶意圖轉(zhuǎn)換為對(duì)應(yīng)的代碼片段、文檔或解釋,結(jié)合傳統(tǒng)搜索、路徑搜索和向量化搜索等技術(shù),進(jìn)行搜索及排序。

  • 輸出結(jié)果:交由大模型對(duì)最后的結(jié)果進(jìn)行總結(jié),輸出給用戶。

作為一個(gè) RAG 應(yīng)用,其分為 indexing 和 query 兩個(gè)部分。

在 indexing 階段,我們需要將代碼庫(kù)進(jìn)行索引,并涉及到文本分割、向量化、數(shù)據(jù)庫(kù)索引等技術(shù)。其中最有挑戰(zhàn)的一個(gè)內(nèi)容是拆分,我們參考的折分規(guī)則是:https://docs.sweep.dev/blogs/chunking-2m-files 。即:

  • 代碼的平均 Token 到字符比例約為1:5(300 個(gè) Token),而嵌入模型的 Token 上限為 512 個(gè)。

  • 1500 個(gè)字符大約對(duì)應(yīng)于 40 行,大致相當(dāng)于一個(gè)小到中等大小的函數(shù)或類。

  • 挑戰(zhàn)在于盡可能接近 1500 個(gè)字符,同時(shí)確保分塊在語(yǔ)義上相似且相關(guān)上下文連接在一起。

在不同的場(chǎng)景下,我們也可以通過(guò)不同的方式進(jìn)行折分,如在?Chocolate Factory?是通過(guò) AST 進(jìn)行折分,以保證生成上下文的質(zhì)量。

在 querying 階段,需要結(jié)合我們一些傳統(tǒng)的搜索技術(shù),如:向量化搜索、路徑搜索等,以保證搜索的質(zhì)量。同時(shí),在中文場(chǎng)景下,我們也需要考慮到轉(zhuǎn)換為中文 的問(wèn)題,如:將英文轉(zhuǎn)換為中文,以保證搜索的質(zhì)量。

  • 相關(guān)工具:https://github.com/BloopAI/bloop

  • 相關(guān)資源:

    • Prompt 策略:代碼庫(kù) AI 助手的語(yǔ)義化搜索設(shè)計(jì)

其它:日常輔助

對(duì)于日常輔助來(lái)說(shuō),我們也可以通過(guò)生成式 AI 來(lái)實(shí)現(xiàn),如:自動(dòng)創(chuàng)建 SQL DDL、自動(dòng)創(chuàng)建測(cè)試用例、自動(dòng)創(chuàng)建需求等。這些只需要通過(guò)自定義提示詞, 結(jié)合特定的領(lǐng)域知識(shí),便可以實(shí)現(xiàn),這里不再贅述。

架構(gòu)設(shè)計(jì):上下文工程

除了模型之外,上下文也是影響 AI 輔助能力的重要因素。在我們構(gòu)建 AutoDev 時(shí),我們也發(fā)現(xiàn)了兩種不同的上下文模式:

  • 相關(guān)上下文:基于靜態(tài)代碼分析的上下文生成,可以構(gòu)建更好質(zhì)量的上下文,以生成更高質(zhì)量的代碼和測(cè)試等,依賴于 IDE 的靜態(tài)代碼分析能力。

  • 相似上下文:基于相似式搜索的上下文,可以構(gòu)建更多的上下文,以生成更多的代碼和測(cè)試等,與平臺(tái)能力無(wú)關(guān)。

簡(jiǎn)單對(duì)比如下:

treesitter和 intellij psi lsp,人工智能,ide

在支持 IDE 有限時(shí),相關(guān)上下文的才會(huì)帶來(lái)更高的性價(jià)高

相似上下文架構(gòu):GitHub Copilot 案例

GitHub Copilot 采用了相似上下文的架構(gòu)模式,其精略的架構(gòu)分層如下:

  • 監(jiān)聽(tīng)用戶操作(IDE API )。監(jiān)聽(tīng)用戶的 Run Action、快捷鍵、UI 操作、輸入等,以及最近的文檔操作歷史(20 個(gè)文件)。

  • IDE 膠水層(Plugin)。作為 IDE 與底層 Agent 的膠水層,處理輸入和輸出。

  • 上下文構(gòu)建(Agent)。JSON RPC Server,處理 IDE 的各種變化,對(duì)源碼進(jìn)行分析,封裝為 “prompt” (疑似) 并發(fā)送給服務(wù)器。

  • 服務(wù)端(Server)。處理 prompt 請(qǐng)求,并交給 LLM 服務(wù)端處理。

在 “公開(kāi)” 的?Copilot-Explorer?項(xiàng)目的研究資料里,可以看到 Prompt 是如何構(gòu)建出來(lái)的。如下是發(fā)送到的 prompt 請(qǐng)求:

{
"prefix": "# Path: codeviz\\app.py\n#....",
"suffix": "if __name__ == '__main__':\r\n    app.run(debug=True)",
"isFimEnabled": true,
"promptElementRanges": [
{
"kind": "PathMarker",
"start": 0,
"end": 23
},
{
"kind": "SimilarFile",
"start": 23,
"end": 2219
},
{
"kind": "BeforeCursor",
"start": 2219,
"end": 3142
}
]
}

其中:

  • 用于構(gòu)建 prompt 的?prefix?部分,是由 promptElements 構(gòu)建了,其中包含了:?BeforeCursor,?AfterCursor,?SimilarFile,?ImportedFile,?LanguageMarker,?PathMarker,?RetrievalSnippet?等類型。從幾種?PromptElementKind?的名稱,我們也可以看出其真正的含義。

  • 用于構(gòu)建 prompt 的?suffix?部分,則是由光標(biāo)所在的部分決定的,根據(jù) tokens 的上限(2048 )去計(jì)算還有多少位置放下。而這里的 Token 計(jì)算則是真正的 LLM 的 token 計(jì)算,在 Copilot 里是通過(guò) Cushman002 計(jì)算的,諸如于中文的字符的 token 長(zhǎng)度是不一樣的,如:?{?context:?"console.log('你好,世界')",?lineCount:?1,?tokenLength:?30?}?,其中 context 中的內(nèi)容的 length 為 20,但是 tokenLength 是 30,中文字符共 5 個(gè)(包含?,?)的長(zhǎng)度,單個(gè)字符占的 token 就是 3。

如下是一個(gè)更詳細(xì)的 Java 應(yīng)用的上下文示例:

// Path: src/main/cc/unitmesh/demo/infrastructure/repositories/ProductRepository.java
// Compare this snippet from src/main/cc/unitmesh/demo/domain/product/Product.java:
// ....
// Compare this snippet from src/main/cc/unitmesh/demo/application/ProductService.java:
// ...
// @Component
// public class ProductService {
//     //...
// }
//
package cc.unitmesh.demo.repositories;
// ...
@Component
publicclassProductRepository{
//...

在計(jì)算上下文里,GitHub Copilot 采用的是?Jaccard 系數(shù)?(Jaccard Similarity) ,這部分的實(shí)現(xiàn)是在 Agent 實(shí)現(xiàn),更詳細(xì)的邏輯可以參考:?花了大半個(gè)月,我終于逆向分析了Github Copilot。

相關(guān)資源:

  • 上下文工程:基于 Github Copilot 的實(shí)時(shí)能力分析與思考

相關(guān)上下文架構(gòu):AutoDev 與 JetBrains AI Assistant 案例

如上所述,相關(guān)代碼依賴于靜態(tài)代碼分析,主要借助于代碼的結(jié)構(gòu)信息,如:AST、CFG、DDG 等。在不同的場(chǎng)景和平臺(tái)之下,我們可以結(jié)合不同的靜態(tài)代碼分析工具, 如下是常見(jiàn)的一些靜態(tài)代碼分析工具:

  • TreeSitter,由 GitHub 開(kāi)發(fā)的用于生成高效的自定義語(yǔ)法分析器的框架。

  • Intellij PSI?(Program Structure Interface),由 JetBrains 開(kāi)發(fā)的用于其 IDE 的靜態(tài)代碼分析接口。

  • LSP(Language Server Protocol),由微軟開(kāi)發(fā)的用于 IDE 的通用語(yǔ)言服務(wù)器協(xié)議。

  • Chapi?(common hierarchical abstract parser implementation) ,由筆者(@phodal)開(kāi)發(fā)的用于通用的靜態(tài)代碼分析工具。

在補(bǔ)全場(chǎng)景下,通過(guò)靜態(tài)代碼分析,我們可以得到當(dāng)前的上下文,如:當(dāng)前的函數(shù)、當(dāng)前的類、當(dāng)前的文件等。如下是一個(gè) AutoDev 的生成單元測(cè)試的上下文示例:

// here are related classes:
// 'filePath: /Users/phodal/IdeaProjects/untitled/src/main/java/cc/unitmesh/untitled/demo/service/BlogService.java
// class BlogService {
//   blogRepository
//   + public BlogPost createBlog(BlogPost blogDto)
//   + public BlogPost getBlogById(Long id)
//   + public BlogPost updateBlog(Long id, BlogPost blogDto)
//   + public void deleteBlog(Long id)
// }
// 'filePath: /Users/phodal/IdeaProjects/untitled/src/main/java/cc/unitmesh/untitled/demo/dto/CreateBlogRequest.java
// class CreateBlogRequest ...
// 'filePath: /Users/phodal/IdeaProjects/untitled/src/main/java/cc/unitmesh/untitled/demo/entity/BlogPost.java
// class BlogPost {...
@ApiOperation(value = "Create a new blog")
@PostMapping("/")
publicBlogPost createBlog(@RequestBodyCreateBlogRequest request) {

在這個(gè)示例中,會(huì)分析?createBlog?函數(shù)的上下文,獲取函數(shù)的輸入和輸出類:?CreateBlogRequest、?BlogPost?信息,以及 BlogService 類信息,作為上下文(在注釋中提供)提供給模型。在這時(shí),模型會(huì)生成更準(zhǔn)確的構(gòu)造函數(shù),以及更準(zhǔn)確的測(cè)試用例。

由于相關(guān)上下文依賴于對(duì)不同語(yǔ)言的靜態(tài)代碼分析、不同 IDE 的 API,所以,我們也需要針對(duì)不同的語(yǔ)言、不同的 IDE 進(jìn)行適配。在構(gòu)建成本上,相對(duì)于相似上下文成本更高。

步驟 1:構(gòu)建 IDE 插件與度量體系設(shè)計(jì)

IDE、編輯器作為開(kāi)發(fā)者的主要工具,其設(shè)計(jì)和學(xué)習(xí)成本也相對(duì)比較高。首先,我們可以用官方提供的模板生成:

  • IDEA 插件模板

  • VSCode 插件生成

然后,再往上添加功能(是不是很簡(jiǎn)單),當(dāng)然不是。以下是一些可以參考的 IDEA 插件資源:

  • Intellij Community 版本源碼

  • IntelliJ SDK Docs Code Samples

  • Intellij Rust

當(dāng)然了,更合適的是參考AutoDev 插件。

JetBrains 插件

可以直接使用官方的模板來(lái)生成對(duì)應(yīng)的插件:https://github.com/JetBrains/intellij-platform-plugin-template

treesitter和 intellij psi lsp,人工智能,ide

對(duì)于 IDEA 插件實(shí)現(xiàn)來(lái)說(shuō),主要是通過(guò) Action 和 Listener 來(lái)實(shí)現(xiàn)的,只需要在?plugin.xml?中注冊(cè)即可。詳細(xì)可以參考官方文檔:IntelliJ Platform Plugin SDK

版本兼容與兼容架構(gòu)

由于我們前期未 AutoDev 考慮到對(duì) IDE 版本的兼容問(wèn)題,后期為了兼容舊版本的 IDE,我們需要對(duì)插件進(jìn)行兼容性處理。所以,如官方文檔:Build Number Ranges?中所描述,我們可以看到不同版本,對(duì)于 JDK 的要求是不一樣的,如下是不同版本的要求:

treesitter和 intellij psi lsp,人工智能,ide

并配置到?gradle.properties?中:

pluginSinceBuild = 223
pluginUntilBuild = 233.*

后續(xù)配置兼容性比較麻煩,可以參考 AutoDev 的設(shè)計(jì)。

補(bǔ)全模式:Inlay

在自動(dòng)代碼補(bǔ)全上,國(guó)內(nèi)的廠商主要參考的是 GitHub Copilot 的實(shí)現(xiàn),邏輯也不復(fù)雜。

采用快捷鍵方式觸發(fā)

其主要是在 Action 里監(jiān)聽(tīng)用戶的輸入,然后:

treesitter和 intellij psi lsp,人工智能,ide

采用自動(dòng)觸發(fā)方式

其主要通過(guò)?EditorFactoryListener?監(jiān)聽(tīng)用戶的輸入,然后:根據(jù)不同的輸入,觸發(fā)不同的補(bǔ)全結(jié)果。核心代碼如下:

classAutoDevEditorListener: EditorFactoryListener{
override fun editorCreated(event: EditorFactoryEvent) {
//...
        editor.document.addDocumentListener(AutoDevDocumentListener(editor), editorDisposable)
        editor.caretModel.addCaretListener(AutoDevCaretListener(editor), editorDisposable)
//...
}
classAutoDevCaretListener(val editor: Editor) : CaretListener{
override fun caretPositionChanged(event: CaretEvent) {
//...
            val wasTypeOver = TypeOverHandler.getPendingTypeOverAndReset(editor)
//...
            llmInlayManager.disposeInlays(editor, InlayDisposeContext.CaretChange)
}
}
classAutoDevDocumentListener(val editor: Editor) : BulkAwareDocumentListener{
override fun documentChangedNonBulk(event: DocumentEvent) {
//...
            val llmInlayManager = LLMInlayManager.getInstance()
            llmInlayManager
.editorModified(editor, changeOffset)
}
}
}

再根據(jù)不同的輸入,觸發(fā)不同的補(bǔ)全結(jié)果,并對(duì)結(jié)構(gòu)進(jìn)行處理。

渲染補(bǔ)全代碼

隨后,我們需要實(shí)現(xiàn)一個(gè) Inlay Render,它繼承自?EditorCustomElementRenderer。

日常輔助功能開(kāi)發(fā)

結(jié)合 IDE 的接口能力,我們需要添加對(duì)應(yīng)的 Action,以及對(duì)應(yīng)的 Group,以及對(duì)應(yīng)的 Icon。如下是一個(gè) Action 的示例:

<add-to-group?group-id="ShowIntentionsGroup"?relative-to-action="ShowIntentionActions"?anchor="after"/>

如下是 AutoDev 的一些 ActionGroup:

treesitter和 intellij psi lsp,人工智能,ide

在編寫 ShowIntentionsGroup 時(shí),我們可以參考 AutoDev 的實(shí)現(xiàn)來(lái)構(gòu)建對(duì)應(yīng)的 Group:

<groupid="AutoDevIntentionsActionGroup"class="cc.unitmesh.devti.intentions.IntentionsActionGroup"
icon="cc.unitmesh.devti.AutoDevIcons.AI_COPILOT"searchable="false">
<add-to-groupgroup-id="ShowIntentionsGroup"relative-to-action="ShowIntentionActions"anchor="after"/>
</group>
多語(yǔ)言上下文架構(gòu)

由于 Intellij 的平臺(tái)策略,使得運(yùn)行于 Java IDE(Intellij IDEA)與在其它 IDE 如 Python IDE(Pycharm)之間的差異性變得更大。我們需要提供基于多平臺(tái)產(chǎn)品的兼容性,詳細(xì)介紹可以參考:Plugin Compatibility with IntelliJ Platform Products

首先,將插件的架構(gòu)進(jìn)一步模塊化,即針對(duì)于不同的語(yǔ)言,提供不同的模塊。如下是 AutoDev 的模塊化架構(gòu):

java/   # Java 語(yǔ)言插件
  src/main/java/cc/unitmesh/autodev/ # Java 語(yǔ)言入口
  src/main/resources/META-INF/plugin.xml
plugin/ # 多平臺(tái)入口
  src/main/resources/META-INF/plugin.xml
src/    # 即核心模塊
  main/resource/META-INF/core.plugin.xml

在?plugin/plugin.xml?中,我們需要添加對(duì)應(yīng)的?depends,以及?extensions,如下是一個(gè)示例:

<idea-pluginpackage="cc.unitmesh"xmlns:xi="http://www.w3.org/2001/XInclude"allow-bundled-update="true">
<xi:includehref="/META-INF/core.xml"xpointer="xpointer(/idea-plugin/*)"/>
<content>
<modulename="cc.unitmesh.java"/>
<!--  其它模塊 -->
</content>
</idea-plugin>

而在?java/plugin.xml?中,我們需要添加對(duì)應(yīng)的?depends,以及?extensions,如下是一個(gè)示例:

<idea-pluginpackage="cc.unitmesh.java">
<!--suppress PluginXmlValidity -->
<dependencies>
<pluginid="com.intellij.modules.java"/>
<pluginid="org.jetbrains.plugins.gradle"/>
</dependencies>
</idea-plugin>

隨后,Intellij 會(huì)自動(dòng)加載對(duì)應(yīng)的模塊,以實(shí)現(xiàn)多語(yǔ)言的支持。根據(jù)我們預(yù)期支持的不同語(yǔ)言,便需要對(duì)應(yīng)的?plugin.xml,諸如于:

cc.unitmesh.javascript.xml
cc.unitmesh.rust.xml
cc.unitmesh.python.xml
cc.unitmesh.kotlin.xml
cc.unitmesh.java.xml
cc.unitmesh.go.xml
cc.unitmesh.cpp.xml

最后,在不同的語(yǔ)言模塊里,實(shí)現(xiàn)對(duì)應(yīng)的功能即可。

上下文構(gòu)建

為了簡(jiǎn)化這個(gè)過(guò)程,我們使用 Unit Eval 來(lái)展示如何構(gòu)建兩種類似的上下文。

靜態(tài)代碼分析

通過(guò)靜態(tài)代碼分析,我們可以得到當(dāng)前的函數(shù)、當(dāng)前的類、當(dāng)前的文件等。再結(jié)合路徑相似性,尋找最貼進(jìn)的上下文。

private fun findRelatedCode(container: CodeContainer): List<CodeDataStruct> {
// 1. collects all similar data structure by imports if exists in a file tree
    val byImports = container.Imports
.mapNotNull {
            context.fileTree[it.Source]?.container?.DataStructures
}
.flatten()
// 2. collects by inheritance tree for some node in the same package
    val byInheritance = container.DataStructures
.map {
(it.Implements+ it.Extend).mapNotNull { i ->
                context.fileTree[i]?.container?.DataStructures
}.flatten()
}
.flatten()
    val related = (byImports + byInheritance).distinctBy { it.NodeName}
// 3. convert all similar data structure to uml
return related
}
classRelatedCodeStrategyBuilder(private val context: JobContext) : CodeStrategyBuilder{
override fun build(): List<TypedIns> {
// ...
        val findRelatedCodeDs = findRelatedCode(container)
        val relatedCodePath = findRelatedCodeDs.map { it.FilePath}
        val jaccardSimilarity = SimilarChunker.pathLevelJaccardSimilarity(relatedCodePath, currentPath)
        val relatedCode = jaccardSimilarity.mapIndexed { index, d ->
            findRelatedCodeDs[index] to d
}.sortedByDescending {
            it.second
}.take(3).map {
            it.first
}
//...
}
}

上述的代碼,我們可以通過(guò)代碼的 Imports 信息作為相關(guān)代碼的一部分。再通過(guò)代碼的繼承關(guān)系,來(lái)尋找相關(guān)的代碼。最后,通過(guò)再路徑相似性,來(lái)尋找最貼近的上下文。

相關(guān)代碼分析

先尋找,再通過(guò)代碼相似性,來(lái)尋找相關(guān)的代碼。核心邏輯所示:

fun pathLevelJaccardSimilarity(chunks: List<String>, text: String): List<Double> {
//...
}
fun tokenize(chunk: String): List<String> {
return chunk.split(Regex("[^a-zA-Z0-9]")).filter { it.isNotBlank() }
}
fun similarityScore(set1: Set<String>, set2: Set<String>): Double{
//...
}

詳細(xì)見(jiàn):SimilarChunker

VSCode 插件

TODO

TreeSitter

TreeSitter 是一個(gè)用于生成高效的自定義語(yǔ)法分析器的框架,由 GitHub 開(kāi)發(fā)。它使用 LR(1)解析器,這意味著它可以在 O(n)時(shí)間內(nèi)解析任何語(yǔ)言,而不是 O(n2)時(shí)間。它還使用了一種稱為“語(yǔ)法樹(shù)的重用”的技術(shù),該技術(shù)使其能夠在不重新解析整個(gè)文件的情況下更新語(yǔ)法樹(shù)。

由于 TreeSitter 已經(jīng)提供了多語(yǔ)言的支持,你可以使用 Node.js、Rust 等語(yǔ)言來(lái)構(gòu)建對(duì)應(yīng)的插件。詳細(xì)見(jiàn):TreeSitter。

根據(jù)我們的意圖不同,使用 TreeSitter 也有不同的方式:

解析 Symbol

在代碼自然語(yǔ)言搜索引擎?Bloop?中,我們使用 TreeSitter 來(lái)解析 Symbol,以實(shí)現(xiàn)更好的搜索質(zhì)量。

;; methods
(method_declaration
  name: (identifier) @hoist.definition.method)

隨后,根據(jù)不同的類型來(lái)決定如何顯示:

pub static JAVA: TSLanguageConfig= TSLanguageConfig{
    language_ids: &["Java"],
    file_extensions: &["java"],
    grammar: tree_sitter_java::language,
    scope_query: MemoizedQuery::new(include_str!("./scopes.scm")),
    hoverable_query: MemoizedQuery::new(
        r#"
[(identifier)
(type_identifier)] @hoverable
"#,
    ),
    namespaces: &[&[
        // variables
        "local",
        // functions
        "method",
        // namespacing, modules
        "package",
        "module",
        // types
        "class",
        "enum",
        "enumConstant",
        "record",
        "interface",
        "typedef",
        // misc.
        "label",
    ]],
};

Chunk 代碼

如下是?Improving LlamaIndex’s Code Chunker by Cleaning Tree-Sitter CSTs?中的 TreeSitter 的使用方式:

from tree_sitter importTree
def chunker(
    tree: Tree,
    source_code: bytes,
    MAX_CHARS=512* 3,
    coalesce=50# Any chunk less than 50 characters long gets coalesced with the next chunk
) -> list[Span]:
# 1. Recursively form chunks based on the last post (https://docs.sweep.dev/blogs/chunking-2m-files)
def chunk_node(node: Node) -> list[Span]:
        chunks: list[Span] = []
        current_chunk: Span= Span(node.start_byte, node.start_byte)
        node_children = node.children
for child in node_children:
if child.end_byte - child.start_byte > MAX_CHARS:
                chunks.append(current_chunk)
                current_chunk = Span(child.end_byte, child.end_byte)
                chunks.extend(chunk_node(child))
elif child.end_byte - child.start_byte + len(current_chunk) > MAX_CHARS:
                chunks.append(current_chunk)
                current_chunk = Span(child.start_byte, child.end_byte)
else:
                current_chunk += Span(child.start_byte, child.end_byte)
        chunks.append(current_chunk)
return chunks
    chunks = chunk_node(tree.root_node)
# 2. Filling in the gaps
for prev, curr in zip(chunks[:-1], chunks[1:]):
        prev.end = curr.start
    curr.start = tree.root_node.end_byte
# 3. Combining small chunks with bigger ones
    new_chunks = []
    current_chunk = Span(0, 0)
for chunk in chunks:
        current_chunk += chunk
if non_whitespace_len(current_chunk.extract(source_code)) > coalesce \
and"\n"in current_chunk.extract(source_code):
            new_chunks.append(current_chunk)
            current_chunk = Span(chunk.end, chunk.end)
if len(current_chunk) > 0:
        new_chunks.append(current_chunk)
# 4. Changing line numbers
    line_chunks = [Span(get_line_number(chunk.start, source_code),
                    get_line_number(chunk.end, source_code)) for chunk in new_chunks]
# 5. Eliminating empty chunks
    line_chunks = [chunk for chunk in line_chunks if len(chunk) > 0]
return line_chunks

度量體系設(shè)計(jì)

常用指標(biāo)

代碼接受率

AI 生成的代碼被開(kāi)發(fā)者接受的比例。

入庫(kù)率

AI 生成的代碼被開(kāi)發(fā)者入庫(kù)的比例。

開(kāi)發(fā)者體驗(yàn)驅(qū)動(dòng)

如微軟和 GitHub 所構(gòu)建的:DevEx: What Actually Drives Productivity: The developer-centric approach to measuring and improving productivity

treesitter和 intellij psi lsp,人工智能,ide

步驟 2:模型評(píng)估體系與微調(diào)試驗(yàn)

評(píng)估數(shù)據(jù)集:HumanEval

模型選擇與測(cè)試

在結(jié)合公開(kāi) API 的大語(yǔ)言模型之后,我們就可以構(gòu)建基本的 IDE 功能。隨后,應(yīng)該進(jìn)一步探索適合于內(nèi)部的模型,以適合于組織內(nèi)部的效果。

模型選擇

現(xiàn)有的開(kāi)源模型里采用 LLaMA 架構(gòu)相對(duì)比較多,并且由于其模型的質(zhì)量比較高,其生態(tài)也相對(duì)比較完善。因此,我們也采用 LLaMA 架構(gòu)來(lái)構(gòu)建,即:DeepSeek Coder。

OpenBayes 平臺(tái)部署與測(cè)試

隨后,我們需要部署模型,并提供一個(gè)對(duì)應(yīng)的 API,這個(gè) API 需要與我們的 IDE 接口保持一致。這里我們采用了 OpenBayes 平臺(tái)來(lái)部署模型。詳細(xì)見(jiàn):?code/server?目錄下的相關(guān)代碼。

pip install -r requirements.txt
python server-python38.py

如下是適用于 OpenBayes 的代碼,以在后臺(tái)提供公網(wǎng) API:

if __name__ == "__main__":
try:
        meta = requests.get('http://localhost:21999/gear-status', timeout=5).json()
        url = meta['links'].get('auxiliary')
if url:
print("打開(kāi)該鏈接訪問(wèn):", url)
exceptException:
pass
    uvicorn.run(app, host="0.0.0.0", port=8080)

隨后,在 IDE 插件中,我們就可以結(jié)合他們來(lái)測(cè)試功能。

大規(guī)模模型部署

結(jié)合模型量化技術(shù),如 INT4,可以實(shí)現(xiàn) 6B 模型在消費(fèi)級(jí)的顯卡上進(jìn)行本地部署。

(TODO)

模型微調(diào)

有監(jiān)督微調(diào)(SFT)是指采用預(yù)先訓(xùn)練好的神經(jīng)網(wǎng)絡(luò)模型,并針對(duì)你自己的專門任務(wù)在少量的監(jiān)督數(shù)據(jù)上對(duì)其進(jìn)行重新訓(xùn)練的技術(shù)。

數(shù)據(jù)驅(qū)動(dòng)的微調(diào)方法

結(jié)合 【SFT最佳實(shí)踐?】中提供的權(quán)衡考慮:

  • 樣本數(shù)量少于 1000 且需注重基座模型的通用能力:優(yōu)先考慮 LoRA。

  • 如果特定任務(wù)數(shù)據(jù)樣本較多且主要注重這些任務(wù)效果:使用 SFT。

  • 如果希望結(jié)合兩者優(yōu)勢(shì):將特定任務(wù)的數(shù)據(jù)與通用任務(wù)數(shù)據(jù)進(jìn)行混合配比后,再使用這些訓(xùn)練方法能得到更好的效果。

這就意味著:

任務(wù)類型 樣本數(shù)量 通用編碼數(shù)據(jù)集
IDE AI 功能支持 少于 1000 需要
內(nèi)部代碼補(bǔ)全 大于 10,000 不需要
IDE + 代碼補(bǔ)全 大于 10,000 需要

通常來(lái)說(shuō),我們測(cè)試是結(jié)合 IDE 的功能,以及代碼補(bǔ)全的功能,因此,我們需要合并兩個(gè)數(shù)據(jù)集。

數(shù)據(jù)集構(gòu)建

根據(jù)不同的模型,其所需要的指令也是不同的。如下是一個(gè)基于 DeepSeek + DeepSpeed 的數(shù)據(jù)集示例:

{
"instruction": "Write unit test for following code.\n<SomeCode>",
"output": "<TestCode>"
}

下面是 LLaMA 模型的數(shù)據(jù)集示例:

{
"instruction": "Write unit test for following code.",
"input": "<SomeCode>",
"output": "<TestCode>"
}
數(shù)據(jù)集構(gòu)建

我們構(gòu)建?Unit Eval?項(xiàng)目,以生成更適合于 AutoDev 的數(shù)據(jù)集。

  • 代碼補(bǔ)全。行內(nèi)(Inline)、塊內(nèi)(InBlock)、塊間(AfterBlock)三種場(chǎng)景。

  • 單元測(cè)試生成。生成符合上下文的單元測(cè)試。

而為了提供 IDE 中的其他功能支持,我們結(jié)合了開(kāi)源數(shù)據(jù)集,以及數(shù)據(jù)蒸餾的方式來(lái)構(gòu)建數(shù)據(jù)集。

開(kāi)源數(shù)據(jù)集

在 GitHub、HuggingFace 等平臺(tái)上,有一些開(kāi)源的數(shù)據(jù)集。

Magicoder: Source Code Is All You Need?中開(kāi)源的兩個(gè)數(shù)據(jù)集:

  • https://huggingface.co/datasets/ise-uiuc/Magicoder-OSS-Instruct-75K

  • https://huggingface.co/datasets/ise-uiuc/Magicoder-Evol-Instruct-110K

在 License 合適的情況下,我們可以直接使用這些數(shù)據(jù)集;在不合適的情況下,我們可以拿來(lái)做一些實(shí)驗(yàn)。

數(shù)據(jù)蒸餾

數(shù)據(jù)蒸餾。過(guò)去的定義是,即將大型真實(shí)數(shù)據(jù)集(訓(xùn)練集)作為輸入,并輸出一個(gè)小的合成蒸餾數(shù)據(jù)集。但是,我們要做的是直接用 OpenAI 這一類公開(kāi) API 的模型:

  • 生成符合預(yù)期的數(shù)據(jù)集。

  • 對(duì)數(shù)據(jù)集進(jìn)行篩選,以保證數(shù)據(jù)集的質(zhì)量。

  • 對(duì)數(shù)據(jù)集進(jìn)行擴(kuò)充,以保證數(shù)據(jù)集的多樣性。

  • 對(duì)數(shù)據(jù)集進(jìn)行標(biāo)注,以保證數(shù)據(jù)集的可用性。

微調(diào)示例:OpenBayes + DeepSeek

在這里我們使用的是,以及 DeepSeek 官方提供的腳本來(lái)進(jìn)行微調(diào)。

  • 云 GPU:?OpenBayes

  • GPU 算力:4090x2 (目測(cè)和微調(diào)參數(shù)有關(guān),但是我試了幾次 4090 還是不行)

  • 微調(diào)腳本:https://github.com/deepseek-ai/DeepSeek-Coder

  • 數(shù)據(jù)集:6000

我在 OpenBayes 上傳了的 DeepSeek 模型:OpenBayes deepseek-coder-6.7b-instruct,你可以在創(chuàng)建時(shí)直接使用這個(gè)模型。

treesitter和 intellij psi lsp,人工智能,ide

數(shù)據(jù)集信息

由 Unit Eval + OSS Instruct 數(shù)據(jù)集構(gòu)建而來(lái):

  • 150 條補(bǔ)全(Inline,InBlock,AfterBlock)數(shù)據(jù)集。

  • 150 條單元測(cè)試數(shù)據(jù)集。

  • 3700 條 OSS Instruct 數(shù)據(jù)集。

而從結(jié)果來(lái)看,如何保持高質(zhì)量的數(shù)據(jù)是最大的挑戰(zhàn)。

測(cè)試視頻:開(kāi)源 AI 輔助編程方案:Unit Mesh 端到端打通 v0.0.1 版本

參數(shù)示例:
DATA_PATH="/openbayes/home/summary.jsonl"
OUTPUT_PATH="/openbayes/home/output"
MODEL_PATH="/openbayes/input/input0/"
!cd DeepSeek-Coder/finetune && deepspeed finetune_deepseekcoder.py \
--model_name_or_path $MODEL_PATH \
--data_path $DATA_PATH \
--output_dir $OUTPUT_PATH \
--num_train_epochs 1 \
--model_max_length 1024 \
--per_device_train_batch_size 8 \
--per_device_eval_batch_size 1 \
--gradient_accumulation_steps 1 \
--evaluation_strategy "no" \
--save_strategy "steps" \
--save_steps 375 \
--save_total_limit 10 \
--learning_rate 1e-4 \
--warmup_steps 10 \
--logging_steps 1 \
--lr_scheduler_type "cosine" \
--gradient_checkpointing True \
--report_to "tensorboard" \
--deepspeed configs/ds_config_zero3.json \
--bf16 True

運(yùn)行日志:

`use_cache=True` is incompatible with gradient checkpointing. Setting`use_cache=False`...
0%|                                                   | 0/375[00:00<?, ?it/s]`use_cache=True` is incompatible with gradient checkpointing. Setting`use_cache=False`...
{'loss': 0.6934, 'learning_rate': 0.0, 'epoch': 0.0}                            
{'loss': 0.3086, 'learning_rate': 3.0102999566398115e-05, 'epoch': 0.01}        
{'loss': 0.3693, 'learning_rate': 4.771212547196624e-05, 'epoch': 0.01}         
{'loss': 0.3374, 'learning_rate': 6.020599913279623e-05, 'epoch': 0.01}         
{'loss': 0.4744, 'learning_rate': 6.989700043360187e-05, 'epoch': 0.01}         
{'loss': 0.3465, 'learning_rate': 7.781512503836436e-05, 'epoch': 0.02}         
{'loss': 0.4258, 'learning_rate': 8.450980400142567e-05, 'epoch': 0.02}         
{'loss': 0.4027, 'learning_rate': 9.030899869919434e-05, 'epoch': 0.02}         
{'loss': 0.2844, 'learning_rate': 9.542425094393248e-05, 'epoch': 0.02}         
{'loss': 0.3783, 'learning_rate': 9.999999999999999e-05, 'epoch': 0.03}

其它:

  • 詳細(xì)的 Notebook 見(jiàn):code/finetune/finetune.ipynb

  • 微調(diào)參數(shù),詳細(xì)見(jiàn):Trainer

步驟 3:圍繞意圖的數(shù)據(jù)工程與模型演進(jìn)

treesitter和 intellij psi lsp,人工智能,ide
Unit Tools Workflow

Unit Eval 是一個(gè)針對(duì)于構(gòu)建高質(zhì)量代碼微調(diào)的開(kāi)源工具箱。其三個(gè)核心設(shè)計(jì)原則:

  • 統(tǒng)一提示詞(Prompt)。統(tǒng)一工具-微調(diào)-評(píng)估底層的提示詞。

  • 代碼質(zhì)量管道。諸如于代碼復(fù)雜性、代碼壞味道、測(cè)試壞味道、API 設(shè)計(jì)味道等。

  • 可擴(kuò)展的質(zhì)量閾。自定義規(guī)則、自定義閾值、自定義質(zhì)量類型等。

即要解決易于測(cè)試的數(shù)據(jù)集生成,以及易于評(píng)估的模型評(píng)估問(wèn)題。

IDE 指令設(shè)計(jì)與演化

AutoDev 早期采用的是 OpenAI API,其模型能力較強(qiáng),因此在指令設(shè)計(jì)上比較強(qiáng)大。而當(dāng)我們需要微調(diào)里,我們需要更簡(jiǎn)單、易于區(qū)分的指令來(lái)構(gòu)建。

模板指令

如下是在 AutoDev 中精簡(jiǎn)化后的 Prompt 示例:

Write unit test for following code.
${context.testFramework}
${context.coreFramework}
${context.testSpec}
```${context.language}
${context.related_model}
${context.selection}
```

其中包含了:

  • 技術(shù)棧上下文

  • 測(cè)試技術(shù)棧上下文

  • 代碼塊(類、函數(shù))的輸入和輸出信息

而這個(gè)模板指令,也是我們?cè)?Unit Eval 中所采用的指令。

統(tǒng)一指令模板

為了實(shí)現(xiàn)統(tǒng)一的指令模板,我們引入了 Apache Velocity 模板引擎來(lái)實(shí)現(xiàn),并通過(guò) Chocolate Factory 實(shí)現(xiàn)底層的通用邏輯:

  • 工具側(cè)。在 IDE 插件中,直接通過(guò) Velocity 模板引擎、基于 Chocolate Factory 來(lái)實(shí)現(xiàn)指令的生成。

  • 數(shù)據(jù)集成。在 Unit Eval 中,生成適用于模板的數(shù)據(jù)集。

  • 結(jié)果評(píng)估?;?Chocolate Factory 的實(shí)現(xiàn),對(duì)模板的結(jié)果進(jìn)行評(píng)估。

高質(zhì)量數(shù)據(jù)集生成

年初(2023 年 4 月),我們做了一系列的代碼微調(diào)探索, 在那篇 《AI 研發(fā)提效的正確姿勢(shì):開(kāi)源 LLM + LoRA?》里,企業(yè)應(yīng)該開(kāi)始著力于:

  • 規(guī)范與流程標(biāo)準(zhǔn)化

  • 工程化的數(shù)據(jù)準(zhǔn)備

  • 高質(zhì)量的脫敏數(shù)據(jù)

只有微調(diào)是不夠的,模型需要與工具緊密相結(jié)合。

質(zhì)量流水線設(shè)計(jì)示例
treesitter和 intellij psi lsp,人工智能,ide
Code Quality Workflow

基于 Thoughtworks 在軟件工程的豐富經(jīng)驗(yàn),以及 Thoughtworks 的架構(gòu)治理開(kāi)源工具?ArchGuard?作為基礎(chǔ)設(shè)施。在 UnitEval 中,我們也將代碼質(zhì)量的篩選構(gòu)建成 pipeline 的方式:

  • 代碼復(fù)雜度。在當(dāng)前的版本設(shè)計(jì)里,可以直接通過(guò)代碼復(fù)雜度來(lái)決定是否放代碼文件進(jìn)入數(shù)據(jù)庫(kù)。

  • 不同的壞味道檢查類型。諸如于代碼壞味道、測(cè)試壞味道等。

  • 特定的規(guī)則檢查。Controller 的 API 設(shè)計(jì)、Repository 的 SQL 設(shè)計(jì) 等。

而基于 ArchGuard 中所提供的豐富代碼質(zhì)量和架構(gòu)質(zhì)量分析能力,諸如 OpenAPI、 SCA(軟件依賴分析)能力,我們也在思考未來(lái)是否也加入相關(guān)的設(shè)計(jì)。

實(shí)現(xiàn)高質(zhì)量數(shù)據(jù)集生成

如下是 Unit Eval 0.3.0 的主要代碼邏輯:

val codeDir = GitUtil
.checkoutCode(config.url, config.branch, tempGitDir, config.gitDepth)
.toFile().canonicalFile
logger.info("start walk $codeDir")
val languageWorker = LanguageWorker()
val workerManager = WorkerManager(
WorkerContext(
        config.codeContextStrategies,
        config.codeQualityTypes,
        config.insOutputConfig,
        pureDataFileName = config.pureDataFileName(),
        config.completionTypes,
        config.maxCompletionEachFile,
        config.completionTypeSize,
        qualityThreshold = InsQualityThreshold(
            complexity = InsQualityThreshold.MAX_COMPLEXITY,
            fileSize = InsQualityThreshold.MAX_FILE_SIZE,
            maxLineInCode = config.maxLineInCode,
            maxCharInCode = config.maxCharInCode,
            maxTokenLength = config.maxTokenLength,
)
)
)
workerManager.init(codeDir, config.language)

隨后是根據(jù)不同的質(zhì)量門禁,來(lái)進(jìn)行不同的質(zhì)量檢查:

fun filterByThreshold(job: InstructionFileJob) {
    val summary = job.fileSummary
if(!supportedExtensions.contains(summary.extension)) {
return
}
// limit by complexity
if(summary.complexity > context.qualityThreshold.complexity) {
        logger.info("skip file ${summary.location} for complexity ${summary.complexity}")
return
}
// like js minified file
if(summary.binary || summary.generated || summary.minified) {
return
}
// if the file size is too large, we just try 64k
if(summary.bytes > context.qualityThreshold.fileSize) {
        logger.info("skip file ${summary.location} for size ${summary.bytes}")
return
}
// limit by token length
    val encoded = enc.encode(job.code)
    val length = encoded.size
if(length > context.qualityThreshold.maxTokenLength) {
        logger.info("skip file ${summary.location} for over ${context.qualityThreshold.maxTokenLength} tokens")
        println("| filename: ${summary.filename} |  tokens: $length | complexity: ${summary.complexity} | code: ${summary.lines} | size: ${summary.bytes} | location: ${summary.location} |")
return
}
    val language = SupportedLang.from(summary.language)
    val worker = workers[language] ?: return
    worker.addJob(job)
}

在過(guò)慮之后,我們就可以由不同語(yǔ)言的 Worker 來(lái)進(jìn)行處理,諸如 JavaWorker、PythonWorker 等。

val lists = jobs.map { job ->
    val jobContext = JobContext(
        job,
        context.qualityTypes,
        fileTree,
        context.insOutputConfig,
        context.completionTypes,
        context.maxCompletionInOneFile,
        project = ProjectContext(
            compositionDependency = context.compositionDependency,
),
        context.qualityThreshold
)
    context.codeContextStrategies.map { type ->
        val codeStrategyBuilder = type.builder(jobContext)
        codeStrategyBuilder.build()
}.flatten()
}.flatten()

根據(jù)用戶選擇的上下文策略,我們就可以構(gòu)建出不同的上下文,如:相關(guān)上下文、相似上下文等

在上下文策略中檢查代碼質(zhì)量

SimilarChunksStrategyBuilder 主要邏輯如下

  1. 使用配置中指定的規(guī)則檢查以識(shí)別存在問(wèn)題的數(shù)據(jù)結(jié)構(gòu)。

  2. 收集所有具有相似數(shù)據(jù)結(jié)構(gòu)的數(shù)據(jù)結(jié)構(gòu)。

  3. 為每個(gè)被識(shí)別的數(shù)據(jù)結(jié)構(gòu)中的函數(shù)構(gòu)建完成生成器。

  4. 過(guò)濾掉具有空的前置和后置光標(biāo)的完成生成器。

  5. 使用JavaSimilarChunker計(jì)算塊補(bǔ)全的相似塊。

  6. 為每個(gè)完成生成器創(chuàng)建SimilarChunkIns對(duì)象,包括語(yǔ)言、前置光標(biāo)、相似塊、后置光標(biāo)、輸出和類型的相關(guān)信息。

  7. 返回生成的SimilarChunkIns對(duì)象的列表。

在規(guī)則檢查里,我們可以通過(guò)不同的規(guī)則來(lái)檢查不同的代碼質(zhì)量問(wèn)題,如:代碼壞味道、測(cè)試壞味道、API 設(shè)計(jì)味道等。

fun create(types: List<CodeQualityType>, thresholds: Map<String, Int> = mapOf()): List<QualityAnalyser> {
return types.map { type ->
when(type) {
CodeQualityType.BadSmell-> BadsmellAnalyser(thresholds)
CodeQualityType.TestBadSmell-> TestBadsmellAnalyser(thresholds)
CodeQualityType.JavaController-> JavaControllerAnalyser(thresholds)
CodeQualityType.JavaRepository-> JavaRepositoryAnalyser(thresholds)
CodeQualityType.JavaService-> JavaServiceAnalyser(thresholds)
}
}
}

其它

我們會(huì)在 GitHub 上持續(xù)更新這個(gè)教程: https://github.com/phodal/build-ai-coding-assistant,歡迎在 GitHub 上討論。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-809404.html

到了這里,關(guān)于構(gòu)建你自己的 AI 輔助編碼助手:從 IDE 插件、代碼數(shù)據(jù)生成和模型微調(diào)(萬(wàn)字長(zhǎng)文)...的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 會(huì)自動(dòng)寫代碼的AI大模型來(lái)了!阿里云推出智能編碼助手通義靈碼

    會(huì)自動(dòng)寫代碼的AI大模型來(lái)了!阿里云推出智能編碼助手通義靈碼

    用大模型寫代碼是什么樣的體驗(yàn) ?10月31日,杭州云棲大會(huì)上,阿里云對(duì)外展示了一款可自動(dòng)編寫代碼的 AI 助手,在編碼軟件的對(duì)話窗口輸入“幫我用 python 寫一個(gè)飛機(jī)游戲”,短短幾秒,這款名為“通義靈碼”的 AI 助手就自動(dòng)生成了100多行代碼,點(diǎn)擊運(yùn)行后一個(gè)充滿兒時(shí)回

    2024年02月06日
    瀏覽(22)
  • 【LangChain】如何本地部署基于chatGPT的實(shí)時(shí)文檔和表格數(shù)據(jù)的助手,在自己的數(shù)據(jù)上構(gòu)建chatGPT?

    【LangChain】如何本地部署基于chatGPT的實(shí)時(shí)文檔和表格數(shù)據(jù)的助手,在自己的數(shù)據(jù)上構(gòu)建chatGPT?

    (1) LangChain 是一個(gè)用于自然語(yǔ)言處理的 Python 庫(kù),它的目標(biāo)是嘗試簡(jiǎn)化自然語(yǔ)言處理任務(wù),提高處理效率和準(zhǔn)確性。 該庫(kù)提供了一組易于使用的函數(shù)和工具,可以幫助你實(shí)現(xiàn)各種自然語(yǔ)言處理任務(wù),例如語(yǔ)句分割、分詞、詞性標(biāo)注、命名實(shí)體識(shí)別、情感分析等。與其它自然

    2024年02月08日
    瀏覽(24)
  • AI代碼補(bǔ)全 案例 - 阿里云智能編碼插件Cosy

    阿里云智能編碼插件(Alibaba Cloud AI Coding Assistant)是一款 AI編程助手 ,提供

    2024年02月12日
    瀏覽(16)
  • 【人工智能AI代碼:AIXCodeCompletionHelper】一個(gè)集成了 Open AI 人工智能寫代碼的 Jetbrains IDE 插件(支持 Golang,IDEA等)

    目錄 AIXCodeCompletionHelper 簡(jiǎn)介? 支持平臺(tái) 項(xiàng)目源代碼 GitHub - to-be-architect/AIXCodeCompletionHelper 核心實(shí)現(xiàn)代碼

    2023年04月08日
    瀏覽(23)
  • AI輔助編碼體驗(yàn)

    自從自己架設(shè)了ai玩了一個(gè)月以后,感覺(jué)好哇塞 在線的文心一言很棒棒 前幾天Llama3出來(lái)了,因?yàn)椴环瓑λ缘冗@兩天大家搬家我就把Llama3-8B-Chinese-Chat模型給用上了,簡(jiǎn)單一試感覺(jué)比microsoft_phi-2(好像是7B,大了我這也跑不起來(lái)亞) 好那么一點(diǎn)點(diǎn)。 今天,就在今天,我被震撼

    2024年04月26日
    瀏覽(27)
  • JetBrains編程IDE將具備Ai助手功能,或?qū)⑻岣唛_(kāi)發(fā)速度

    JetBrains編程IDE將具備Ai助手功能,或?qū)⑻岣唛_(kāi)發(fā)速度

    近日J(rèn)etBrains發(fā)布博客文章宣布,本周所有基于IntelliJ的IDE和.NET工具的EAP版本都將具備AI助手功能。而這些操作或許將提高開(kāi)發(fā)效率,并且這些AI助手也是使用自家的**ERP**模型和OpenAI服務(wù)。 JetBrains表示,當(dāng)下AI助手功能主要體現(xiàn)在IDE的兩個(gè)方面:將AI助手融入核心IDE用戶工作流程

    2024年02月11日
    瀏覽(26)
  • 基于聞達(dá)(wenda+chatGLM-6B),構(gòu)建自己的知識(shí)庫(kù)小助手

    基于聞達(dá)(wenda+chatGLM-6B),構(gòu)建自己的知識(shí)庫(kù)小助手

    目錄 安裝miniconda 拉取倉(cāng)庫(kù) 使用內(nèi)置python 安裝依賴 上傳模型 克隆及下載 text2vec-large-chinese 修改配置 上傳知識(shí)庫(kù)(txt文件) 處理txt數(shù)據(jù) 啟動(dòng)服務(wù) 測(cè)試 ChatGLM-6B是清華團(tuán)隊(duì)+智譜AI開(kāi)發(fā)的,一個(gè)開(kāi)源的、支持中英雙語(yǔ)的對(duì)話語(yǔ)言模型,具有 62 億參數(shù)。被很多人視為ChatGPT的平替

    2024年02月06日
    瀏覽(22)
  • AI神器之微軟的編碼助手Copilot

    AI神器之微軟的編碼助手Copilot

    更多內(nèi)容請(qǐng)關(guān)注wx公眾號(hào): AI高工 歡迎進(jìn)社群參與分享討論請(qǐng)加WX號(hào): peter_gao ChatGPT 之后微軟又推出了一個(gè)王炸產(chǎn)品,Microsoft 365 Copilot。這次是將GPT4的能力應(yīng)用到了Office領(lǐng)域當(dāng)中。 眾所周知,微軟Office系列的功能深不可測(cè),絕大多數(shù)的用戶甚至連其中10%的功能都使用不到。

    2024年03月25日
    瀏覽(23)
  • 大語(yǔ)言模型 AI 輔助編碼使用過(guò)程體驗(yàn)報(bào)告(Github Copilot、Cursor)

    大語(yǔ)言模型 AI 輔助編碼使用過(guò)程體驗(yàn)報(bào)告(Github Copilot、Cursor)

    在過(guò)去一周多的時(shí)間里,我在?ChatGPT?的協(xié)助下,生成了做一個(gè)簡(jiǎn)單編輯器的產(chǎn)品文檔、技術(shù)方案文檔,然后在這個(gè)基礎(chǔ)上,進(jìn)行程序的編碼。 為了更全面地感受?AI?IDE?對(duì)研發(fā)過(guò)程的影響,我特意選擇了一個(gè)我不太了解的項(xiàng)目,并且以整體形式做下來(lái),從中深度感受?AI?I

    2024年02月14日
    瀏覽(33)
  • 通義靈碼 - 免費(fèi)的阿里云 VS code Jetbrains AI 編碼輔助工具

    通義靈碼 - 免費(fèi)的阿里云 VS code Jetbrains AI 編碼輔助工具

    ? 通義靈碼,是阿里云出品的一款基于通義大模型的智能編碼輔助工具,提供行級(jí)/函數(shù)級(jí)實(shí)時(shí)續(xù)寫、自然語(yǔ)言生成代碼、單元測(cè)試生成、代碼注釋生成、代碼解釋、研發(fā)智能問(wèn)答、異常報(bào)錯(cuò)排查等能力,并針對(duì)阿里云 SDK/OpenAPI 的使用場(chǎng)景調(diào)優(yōu),助力開(kāi)發(fā)者高效、流暢的編碼

    2024年01月17日
    瀏覽(32)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包