Cedars Digital · 2024-05 → Present

MR pipeline 上的 AI Code Review

GitLab main pipeline 上的每一個 MR,都用它所屬服務自己的審查標準審過一遍;背後的模型可以換

0
新服務接入所需程式碼變更
2
內部問卷輪數
11+
架構模式復用年數

問題

Review 的產出速度跟不上工程師產原始碼的速度。真正讓我在意的不是隊伍排多長,而是資深工程師的注意力花在哪裡:命名、漏寫的測試、上次發版後就默默飄掉的設定。那些只有他們能回答的架構問題,全排在這些東西後面等。

架構

flowchart LR
  MR[GitLab MR trigger] --> Loader["Profile Loader<br/>Service Registry"]
  Loader --> Standards["shared + system-specific<br/>review standards"]
  Standards --> Retrieval["檢索層<br/>混合檢索+token 預算<br/>(fail-open)"]
  Retrieval --> Composer[Prompt Composer]
  Composer --> AI["LLM Provider<br/>(可切換)"]
  AI --> Reflect["Self-reflection 驗證<br/>(可選)"]
  Reflect --> Comment[MR 評論發佈]

一個服務要接進來,只要註冊一份 profile;服務自己的 repo 裡不必放任何東西。所以團隊接入的成本是零行程式碼變更,審查標準也集中在一個地方,不會被複製貼上散進每一條 pipeline。

檢索,而不是更大的 prompt(2026)

第一版的做法是把審查可能用得到的東西整包餵給它。這招能撐一陣子,撐到審查標準、API 契約、累積一年的審查歷史都想在同一個 context window 裡佔位置——然後就不行了。所以 2026 年我把 context 組裝換成檢索,而且向量庫是自己寫的、沒有外掛現成的:SQLite 存放、768 維 embedding、純 JS 的 L2 暴力搜尋。在這個語料規模下,多養一套外部向量資料庫是白扛的維運成本。

檢索走混合路線。BM25 與 embedding 兩路結果用 RRF 融合,再經過兩層結構化路由,每個來源各有自己的 token 預算,所以任何單一語料都擠不掉其他語料在 prompt 裡的位置。索引由每週一次的離線工作建置,以原子方式發佈並附上 sha256 校驗碼,消費端驗過才切換。每一層都 fail-open:混合檢索壞了就退成詞彙檢索,詞彙檢索壞了就退成全量載入。索引壞掉只會讓一次審查變慢,永遠不會擋住合併。

benchmark 撐得起的說法到哪裡:以 recall 來看,混合檢索在三個語料上都贏純詞彙檢索。排序就沒那麼好看。以 MRR 衡量只有契約語料明顯進步,另外兩個語料跟詞彙檢索互有勝負,看查詢而定。我現在敢辯護的是「該找的找得到」,還不是「排得更好」。這一層上線的時間以週計、不是以季計,請當成早期結果看。

我的角色

從 v1.0 設計到 v2.0 擴張,包含 profile module、self-reflection 那一關,以及推廣到各個微服務。

成果

學到什麼——同一副骨架,用了三次

2015 年在 iPanSec 做 A4P:一個 Python subprocess 驅動 MobSF、一支爬蟲抓報表,最後輸出結構化結果。

2024 年在 Cedars,AI Code Review 把 MobSF 換成 LLM API,其餘骨架幾乎沒動。

2026 年補上檢索層,骨架還是幾乎沒動。真正變的只有一件事:模型現在拿到的是選過的東西,不是整堆。

資深工程師的長期價值,不在於他能講出哪個最新的框架,而在於他看得出哪個老問題現在有更好的解法。