AI News HubLIVE
站內改寫4 分鐘閱讀

對比AI代碼審查中的上下文檢索方法

Compare The Market公司比較了兩種上下文檢索方法(GKG和RAG)用於AI代碼審查。通過嚴格的評估,發現基於知識圖譜的GKG方法在代碼審查質量指標上優於RAG,能夠更準確地理解代碼結構和關係,減少誤報。

來源Hacker News AI作者: adzicg

在Compare The Market公司,我們有一個內部AI工具,用於自動審查合併請求(MR),目標是加快開發人員接收代碼反饋的速度,並提高整個組織的MR吞吐量。該工具在MR打開後的幾分鐘內提供智能的初輪審查,效果良好,但我們希望它更好。早期的審查者傾向於保守,由於孤立地審查代碼更改,常常出現誤報。我們希望讓審查者瞭解更改在更廣泛系統中的位置,例如,刪除的函數可能看起來是死代碼,除非知道它被另一個服務動態調用。

為此,我們面臨一個基本架構決策:代理應如何檢索代碼庫的上下文?我們有兩個主要選項:

  1. GitLab知識圖譜(GKG):一種代碼分析引擎,使用Tree-sitter AST解析構建結構化的代碼實體和關係知識圖譜,存儲在Kuzu圖數據庫中。支持精確查詢,如“查找此函數的所有調用者”或“顯示類層次結構”。
  1. 檢索增強生成(RAG):一種向量相似性搜索方法,將代碼分塊,創建嵌入,並檢索語義相似的代碼片段。

我們基於直覺選擇了GKG——我們的假設是,代碼審查需要代碼關係的結構理解,而不僅僅是語義相似性。審查函數更改時,需要知道什麼調用它、它調用什麼,以及它如何融入整體架構。RAG擅長查找“相似”代碼,但相似性不等於代碼審查的相關性。

本文驗證了這一直覺。通過使用Databricks上的MLflow進行嚴格評估,我們比較了四種方法,發現GKG在代碼審查質量最重要的指標上優於RAG。數據證實我們的架構決策是正確的。

四種方法

我們評估了四種配置:僅基線、GKG、RAG、GKG+RAG。

GKG集成

去年,GitLab推出了GitLab知識圖譜(GKG)的測試版,這是一個模型上下文協議(MCP)服務器。API索引倉庫並構建代碼庫的結構化可查詢表示,將依賴關係映射到圖中的節點,理解函數定義及其用法,跟蹤繼承層次結構,並捕獲模塊之間的交叉引用。結果形成代碼的語義映射——不僅是一列文件,而是一個關係網絡。通過MCP服務器提供的工具,AI代理可以實時查詢此圖,例如:“這個函數在哪裏被調用?”或“如果我改變此方法簽名,會有什麼影響?”

由於GKG仍處於測試階段且未作為原生GitLab CI/CD功能提供,我們構建了一個單獨的側車服務——一個輕量級Docker容器,包裝官方GKG二進制文件,在CI管道中與審查者一起運行。工作流程包括:當MR管道啓動時,側車容器掛載項目源代碼並索引整個代碼庫,從頭構建知識圖譜;索引完成後,它在本地端口啓動GKG MCP服務器,暴露一組工具調用;我們的AI審查者連接到MCP服務器並在審查工作流中使用這些工具。

GKG構建一個符號圖,其中節點表示代碼實體(類、函數、變量),邊表示關係(調用、繼承、導入)。當GKG索引倉庫時,它創建交互式圖可視化,顯示整個代碼庫結構。每個節點類型代表不同的代碼實體:橙色(目錄)、綠色(文件)、紫色(定義,即代碼中定義的類、函數和方法)、藍色(導入符號,即外部依賴和導入)。邊顯示關係:哪些文件包含哪些定義,哪些函數調用其他函數,哪些模塊導入哪些符號。

例如,考慮一個簡單的UserService類。GKG將其映射為一個圖,顯示類、其方法以及調用這些方法的所有文件。當AI審查者需要了解更改的影響時,它會查詢GKG。例如,如果有人修改validate_input(),代理會問:“誰調用這個函數?”這種精確信息使審查者能夠評估對validate_input()的更改是否會破壞任何調用者——僅憑差異本身無法做到這一點。

RAG集成

我們的RAG實現使用LlamaIndex進行智能代碼分塊,並使用OpenAI嵌入進行向量相似性搜索。索引管道掃描倉庫中的代碼文件,使用LlamaIndex的CodeSplitter(基於AST感知的分塊)將代碼分割成語義單元(函數、類),然後通過OpenAI text-embedding-3-small生成嵌入,並存儲在FAISS向量存儲中。檢索管道根據查詢嵌入檢索最相似的代碼塊。

CodeSplitter採用圖優先方法:首先構建代碼的AST圖,然後利用結構理解創建語義上有意義的分塊。與樸素文本分塊不同,它識別語義邊界:函數邊界(每個函數成為一個塊)、類邊界(類定義及其方法)、邏輯分組(相關代碼保持在一起)。

然而,RAG在代碼審查中可能遇到根本限制:它依賴向量空間中的語義相似性,這對於自然語言效果良好,但對於代碼有以下固有侷限:

  • 無法進行符號解析:無法區分同名的函數定義和函數調用。
  • 無法跟蹤引用:審查函數更改時,無法可靠地找到所有調用者。
  • 分塊邊界問題:即使有AST感知分塊,重要上下文可能被分割到不同塊中。
  • 精確度與召回率的權衡:語義相似性優化可能返回“相關”但不相關的代碼,給LLM帶來噪音。

評估設置

評估生成式AI審查者不同於評估分類器或搜索引擎。代碼審查沒有規範的正確答案——兩位專家工程師審查同一MR會寫出不同但同樣有效的反饋。因此,標準準確率指標不適用。質量是多維度的:審查可能識別正確的風險但誇大嚴重性,可能完美校準但錯過關鍵問題,或發現正確問題但指向錯誤代碼。

我們構建了一個包含79個真實MR的金標準數據集,每個條目由專家註釋了多維度地面真相:預期摘要點、預期問題、預期內聯評論(與特定文件和代碼行綁定)、預期分數範圍。這些MR代表真實的生產複雜性,涵蓋不同代碼庫、更改大小和類型。

所有四種方法在同一79個條目上進行評估,每個生成的審查在五個核心質量維度上評分:

  • 覆蓋率:輸出中包含多少預期摘要點、問題和內聯評論?
  • 精確度:審查者發現的內容中有多少是真正必要的?這懲罰過度生成。
  • 內聯評論位置準確性:代碼審查本質上是空間性的;問題需要附加到正確的文件和相關的代碼更改。
  • 分數校準:審查者分配的嚴重性分數(0-10)是否在人類認為合理的範圍內?
  • 結構有效性:模式檢查確保必需字段存在且格式良好。所有方法在此維度上均通過。

對於細微標準,如摘要是否“覆蓋相同點”,文本匹配失敗。我們使用LLM作為自動法官,根據參考期望和生成輸出計數預期點的命中數。

評估在MLflow和Databricks上運行,包括數據準備、比較和迭代優化。

結果與結論

GKG在覆蓋率和精確度上明顯優於RAG。GKG集成使審查者能夠查詢知識圖譜,驗證初步關注點,產生更準確、一致的反饋,並顯著減少誤報。RAG在語義相似性任務上表現良好,但不足以滿足代碼審查的結構化需求。結合GKG和RAG並未顯著優於單獨使用GKG,表明GKG提供了審查所需的核心上下文。

這一架構決策使我們的AI代碼審查工具從依賴表面語義轉變為理解代碼庫的真實結構,從而為開發人員提供更可靠、更值得信賴的審查反饋。