第十節 智慧程式設計工具

下列工具預設在工作區目錄範圍內可用,互相協同支撐助手在你的程式碼儲存庫裡"幹活"。

10.1 讀文件

支持按行或按位元組讀取,自動處理大文件分段。讀取時會附帶內容指紋,確保後續編輯基於"剛剛讀過"的版本,防止並行覆寫。

10.2 寫文件 / 編輯

  • 覆蓋寫:完整重寫整個文件,會校驗"讀過"前提。
  • 片段編輯:基於內容指紋做精確取代,AI 必須先讀、再改,杜絕幻覺式覆蓋。

10.3 目錄列表 / 文件尋找

  • 列目錄支持過濾、按時間排序。
  • 支持通配符匹配檔名,自動跳過 .git / node_modules 等無關目錄。

10.4 內容搜尋

  • 支持正則表達式、檔名通配過濾。
  • 自動跳過二進制文件,啟發式判斷編碼。

10.5 終端機執行

  • 同步執行:單次命令執行後等待完成,輸出回到對話流。
  • 背景執行:長任務(構建、壓測)轉後台,期間可拉取實時輸出、隨時停止。

每一次終端機呼叫預設都受工具權限管控:可放行、可詢問、可停用。

10.6 版本控制

提供基礎 Git 操作:倉庫狀態查詢、新增 / 切換分支、新增倉庫,以及暫存 / 提交 / 合併 / 變基等分支寫操作;推送仍由助手通過終端機執行類工具完成。這些操作預設與其他工具一致為「啟用」(不額外彈詢問);對合併、推送等高風險操作,可在智慧體管理器 →「配置工具」裡按工作模式把對應工具設為「詢問」或「停用」(見 §13.1)。

10.7 網路檢索(可選)

  • web.bing:Bing RSS 端點搜尋,傳回標題 / 摘要 / URL。
  • web.fetch:抓取指定 URL 並自動清洗為 Markdown / 文字 / HTML。

檢索來源與內容均會作為引用卡片展示在訊息流。

10.8 時間與上下文

  • time.now:獲取當前時間(含時區),方便助手為記錄檔、TODO、檔名打標。
  • TodoWrite:寫入 / 更新待辦列表,單次最多 50 條;詳見第十六節。

10.9 上下文截斷

任何讀取或檢索類工具的單次傳回都有"軟上限 + 硬上限",超出會自動截斷並標註,方便助手分批續讀,避免一次性灌爆模型上下文。

工具結果瘦身,更省額度:工作區工具的傳回結果做了精簡 —— 檔案路徑改為相對工作區根顯示、錯誤訊息剝除冗長的根路徑前綴、去除重復的行雜湊、分頁記賬僅在結果被截斷時才輸出。整體減少無謂的 token 佔用,長任務更省額度(也不再把絕對根路徑洩露到結果裡)。

10.10 程式碼智慧工具組(code.*,基於語言伺服器)

新增一組讓 AI 像 IDE 一樣理解程式碼的工具:基於業界標準的 LSP(Language Server Protocol),把語言伺服器的"找定義 / 找引用 / 重命名 / 編譯診斷"等能力直接交給 AI 使用 — 做事更準、更省來回、不再靠正則猜。

工具 用途
code.definition 跳轉到定義:找到某符號在哪個文件第幾行真正定義
code.references 尋找引用:列出某函數 / 類型 / 變數被哪裡呼叫
code.hover 看簽章 / 類型 / 文件:等同 IDE 滑鼠停留
code.symbols 文件大綱:列出文件裡的函數 / 類型 / 方法
code.workspace_symbols 全倉按名搜尋符號
code.diagnostics 編譯錯誤 / 警告:拿到編譯器級別的報錯,不是靠記錄檔猜
code.call_hierarchy 呼叫圖:某函數被誰呼叫 / 呼叫了誰
code.repo_map 專案骨架:文件樹 + 各文件頂層符號,token 友好的全倉概覽
code.rename 跨文件安全重命名 — 真正改名而不是文字取代
code.code_action 快速修正:列出 / 應用語言伺服器給出的 quick fix;配合 code.diagnostics 形成"看錯 → 修錯"自愈閉環
code.lsp_status 看本工作區 LSP server 池的實時狀態
code.implementation 找實現:從接口 / 抽象方法跳到它的各個實現
code.type_definition 跳類型定義:從變數或表達式跳到它的類型宣告處
code.document_highlight 本文件內高亮:某符號在當前文件裡的全部讀寫與引用點,比全倉找引用輕量
code.completion 補全候選:給出某個游標位置的程式碼補全建議
code.signature_help 函式簽章提示:呼叫函式時給出形參列表並標出當前參數
code.formatting 格式化整篇:按語言伺服器規則格式化並寫回文件(無改動則不寫)

位置參數對外 1-based(與讀文件一致 / 同 cat -n),不必心算偏移。

按語言伺服器實際支持情況自動降級:並非每門語言的伺服器都實現了全部能力。是否支持以實際呼叫結果為準,而不是聽伺服器自報,避免它其實能做卻被誤判拒絕;判定出"不支持"後會記住,同一台伺服器在後續工作階段裡不再重複試探。

10.10.1 內置 22 門語言 + 按需自動下載

內置覆蓋主流語言:Go、TypeScript / JavaScript、Python、C / C++、Rust、Java、Lua、Bash、YAML、PHP、Ruby、Vue、Zig、Dart、Kotlin、Clojure、Elixir、Haskell、F# / C#、Gleam、Astro 等 22 門。

  • 缺哪門語言的伺服器會按需自動下載(安全託管、帶緊急開關),下載進度有 toast 提示。
  • 設置 → 程式碼智慧 / LSP 面板能看到執行中的伺服器與安裝狀態。

10.10.2 用 lsp.json / lsp.yaml 覆蓋預設

工作區根目錄或 ~/.avlcode/ 放一個 lsp.yaml(推薦,相容舊 lsp.json)就能覆蓋預設設置 — 改啟動命令、改 root marker、停用某門語言、增加自定義 server 都行。改完熱重載、不用重新啟動工作區;伺服器程序崩了 / SSH 掉線自動重新啟動

10.10.3 遠端工作區同樣可用

LSP 在 SSH 遠端啟動:遠端缺什麼語言的伺服器按需自動下載到遠端,跨系統的路徑與讀寫都已正確處理,遠端工作區的程式碼智慧與本機等同。

10.10.4 Python 虛擬環境(venv)自動遵循

AI 在工作區裡跑 Python 相關命令時自動探測並使用工作區的虛擬環境,不必每次手動 activate

  • 覆蓋venv / .venvconda(含 Windows 上 Scripts/python.exe 版面)、poetry(含專案目錄之外的環境)、pipenv
  • 機制:把首命令改寫成 venv 裡的絕對路徑,並注入 VIRTUAL_ENV / PATH,保持工具鏈一致;探測不到 venv 時零行為變化(命令原樣執行)。
  • 快取:專案外的發現(poetry / pipenv)有 5 分鐘快取 + 15 秒探測超時,避免每輪都 fork。
  • 逃生口:環境變數 AVLCODE_DISABLE_VENV_AUTODETECT 非空即全域關閉自動感知。
  • pyright 語言服務也接入 venv 感知,本機和 SSH 遠端都生效,程式碼智慧裡的類型推導走的就是你真實的 venv。

10.10.5 全函式庫程式碼檢索與問答(code.search / code.ask

在「找定義 / 找引用」這種精確點查之外,新增兩個全函式庫語義檢索工具,回答「登入邏輯在哪、怎麼走的」這類問題:

工具 用途
code.search 用自然語言 / 關鍵詞在整個專案裡檢索符號(函數 / 類型 / 方法),傳回排好序、文件:行 的命中
code.ask code.search 基礎上,直接基於檢索到的片段合成「人話答案 + 文件:行 引用」,找不到會直說、不編造

特點:

  • 純本機、零向量 / 零 embedding,可離線(air-gap):用 BM25 + 識別碼切分(駝峰 / 底線 / 連字元自動拆詞)+ 中日韓二元切分(中文註釋、中文提問同樣能命中),不相依任何模型或連網。
  • 命中可解釋:每條結果都給出 文件:行命中的關鍵詞,看得清為什麼是這條。
  • 索引自動跟上:首次呼叫自動建索引;之後按文件 mtime 增量重新整理(改 / 增 / 刪自動更新)。本機索引落在工作區 .avlcode/rag/。建索引與啟動語言服務的進度以單條原地更新的進度列顯示(不再刷一屏 toast)。
  • 超大倉庫如實告知:索引最多覆蓋 4000 個文件。超過時會明確告訴你有多少文件沒被索引,而不是悄悄少搜一部分 —— 「沒搜到」到底是真不存在,還是沒覆蓋到,一看便知。
  • 結構感知重排:結合中心度呼叫關係把「被呼叫更多 = 更核心」的符號排前(code.searchexpand=true 顯式啟用;code.ask 現在預設就做這道智慧重排,回答程式碼問題更聚焦相關內容)。增量重新整理的作用域也已修正,文件變更後更準,不多刷、不漏刷。
  • 遠端也可用:SSH 遠端工作區同樣支持(遠端枚舉 / 讀取,索引在記憶體);code.ask 復用當前工作階段的模型

這兩個工具與上表的 code.*(LSP 精確查詢)互補:精確定位用 code.definition / code.references,「這事在哪、怎麼實現的」用 code.search / code.ask

10.11 測試執行工具 test.run

AI 現在能自己跑測試、讀懂失敗、再回去修,形成「跑測試 → 看失敗 → 改程式碼 → 再跑驗證」的閉環。

  • 自動識別測試框架:按專案文件判斷 — go.mod → Go / pyproject.toml·pytest.ini → pytest / Cargo.toml → cargo / package.json → Node(vitest、jest);也可手動指定 frameworkcommand 完全覆蓋。
  • 結構化失敗:跑完把輸出解析成 failures[](每條含 test 名 / 文件 / 第幾行 / 錯誤訊息),最多回灌 50 條 + 一小段原始 tail,不把整篇測試記錄檔灌進對話 — 省 token
  • 未知框架兜底:解析失敗時退回到結束碼 + 末尾輸出,保證至少能告訴你失敗了什麼。
  • 範圍限定:可傳 path 限定(Go 包模式如 ./pkg/...、pytest 目錄或文件、cargo 包名)。
  • 遠端也能用:本機 + SSH 遠端工作區一視同仁。
  • plan(籌劃)模式停用:跑測試 = 執行專案程式碼,會產生寫副作用,與"只想不做"的定位衝突。assess(評估)模式可用 — 驗收階段本就需要實際跑一遍。

10.11.1 自檢門禁(opt-in,四類檢查器)

自檢門禁」是測試門禁的泛化:啟用後 AI 每輪幹完活後自動跑一組檢查;如果有失敗,把結構化失敗訊息回灌給它並強制接着修,直到全綠 — 不用你手動催「再跑下測試」。

六類檢查器(可單選 / 組合):

檢查器 用途 後端 / 工具
test 跑測試 test.run(Go / pytest / cargo / Node)
diagnostics 編譯 / 類型錯誤 code.diagnostics(LSP,無需額外工具)
lint 程式碼風格 / 潛在 bug lint.run(golangci-lint / eslint / ruff)
sast 安全靜態分析 sast.run(semgrep)
testgen 改動的原始檔缺測試 → 自動補(opt-in) fs.glob 經 zMCP 閘道查慣例路徑(Go / Python / JS / TS)
judge LLM 收尾自審(opt-in,預設 report 獨立 fresh-context 模型呼叫,只看「目標 + 本輪 diff」,挑機檢抓不到的邏輯 / 語義 / 安全意圖錯

每個檢查器都可調

  • modeblock(預設,注入失敗強制修) / report(只通報不攔)
  • submode
    • testchanged(預設,只測改動的)/ full(全跑)
    • lintstrict(警告也算紅)/ lenient
    • sastquick(限大文件加速)/ deep(完整)
  • scopechanged(預設,本輪改動文件)/ workspace(全函式庫)
  • path / linters / config:精細化覆蓋

testgen / judge 不在預設集:要顯式把 testgen / judge 加進 checks 才生效;前者只判 Go / Python / JS / TS 這些有明確測試慣例的語言,跳過測試文件本身與生成物(如 .pb.go),共用門禁的 3 次注入硬上限。

judge 永不誤攔:模型亂報 / JSON 髒 / 超時一律視為「非權威」放行;門禁裡 judge 安排在所有便宜檢查器之後、且僅當 block 檢查器全綠時才跑(省一次模型呼叫,也不在客觀失敗上堆主觀意見)。few-shot 範例 + 當輪診斷背景注入到 judge prompt,判斷更準。

為什麼是獨立模型呼叫:judge 在全新上下文裡評審,不帶 agent 自己的對話歷史,消除「自己查自己」的自我合理化偏見 — 這正是 LLM-as-judge 區別於「讓 agent 自我反思」的核心。

省開銷:僅在本輪真正改過文件後才跑;沒有編輯的輪次整組跳過。 結構化展示:失敗在前端用結構化面板展示,不是一坨裸 JSON。 不會死循環:同工作階段連續注入硬上限(預設 3 次)— 撞到即停門禁、交回常規流程,避免 flaky / 不可修正的檢查把 AI 困死;真正的使用者介入立即清零。

10.11.2 「繼承 + 覆蓋」三級開關

來源 作用
全域預設 設置 → 程式碼測試與自檢 tab(落到 ~/.config/avlcode/checkgate-default.yaml 沒配工作區時的預設檢查集
工作區預設 工作區 .avlcode/testgate.yaml(側邊欄 / Header 工作區選單一鍵開關 + Strip 全參數編輯器) 新工作階段預設值;按當前工作模式(plan / prepare / execute / assess)還可單獨覆蓋
工作階段覆蓋 工作階段選單的檢查項勾選清單 單個工作階段可逐條勾選哪些檢查器啟用,工作區開了仍能把某條單獨關掉,反之亦然

工作階段選單和工作區選單顯示的都是實際生效狀態,所見即所得。

10.11.3 CheckGateStrip — 輸入框上方的全參數編輯器

工作區啟用自檢門禁後,輸入框上方會出現一條 CheckGateStrip

  • 一行 chip 顯示每個檢查器的當前生效態(mode / submode / scope)。
  • 點 chip 展開全參數編輯器,可改 mode / submode / scope / path / linters / config / timeout,所改即時寫入工作區配置。
  • 關掉門禁後 Strip 隱藏,不擋視線。

10.11.4 工具安裝狀態

設置 → 程式碼測試與自檢 頁底部展示外部工具的安裝狀態(主程序 PATH 可見性):

類別 工具 缺失時的安裝指引
test go / pytest / npm / cargo 裝相應工具鏈
lint golangci-lint / eslint / ruff go install … / npm i … / pip install ruff
sast semgrep pip install semgrepbrew install semgrep

macOS GUI 程序的 PATH 可能不含 shell(.zshrc)裡 pip / npm 裝的路徑,這裡是主程序可見性的盡力探測;真正執行仍由工作區 interpreter 在工作區上下文跑,可能成功 — 不必拘泥於此處的 ✗。

10.11.5 lint.run 與 sast.run — 也可單獨被 AI 呼叫

lint.runsast.run 不只是自檢門禁的後端,AI 也能在 plan / assess 等只讀模式下直接呼叫做靜態稽核 — 它們是只讀分析(不改源、不執行專案程式碼),不在 read-only 拒絕列表裡。

lint.run

  • 自動識別 lintergo.mod → golangci-lint / .eslintrc·eslint.config → eslint / pyproject.toml·ruff.toml → ruff;也可 linter / command 手動覆蓋。
  • 結構化發現findings[](每條 {file, line, rule, severity, message}),與 test.run 同形。
  • submodestrict(如 eslint 警告也算失敗)/ lenient

sast.run

  • 後端:semgrep(--config auto 預設,需連網拉規則;離線請用 config 指定本機 .semgrep.yml)。
  • 結構化發現findings[] 同形。
  • submodequick(限大文件加速)/ deep(完整)。

10.12 工具自省 tools.list / tools.describe / tools.load

AI 可以枚舉自己當前可用的工具及其用法,減少「不知道有沒有某個能力」的猜測:

工具 用途
tools.list 列本工作階段可呼叫的工具(名 + 描述);prefix 可按命名空間過濾(如 fs / code / test
tools.describe 傳回指定工具的完整 schema(描述 + 參數定義)
tools.load 按分類載入工具;不帶參數時傳回分類目錄,每類附一句話能力說明與工具名清單

列出的結果會按本工作階段實際可用的範圍裁剪(受工具三態與分類延遲載入影響),並提示"當前表裡看不見並不代表不存在,可以先載入對應分類"。