AI 工程

Cline v4.1.23 實戰:讓 Commit Message 按鈕遵守 .clinerules,MCP 長輸出改用 read_files 分頁讀回

你有沒有遇過這種情況:在 .clinerules 裡寫好「commit message 一律用 Conventional Commits、英文、結尾帶 Jira 單號」,跟 Cline 聊天時它乖乖照做;可是一按 VS Code 原始碼控制面板上那顆「Generate Commit Message」按鈕,生出來的又是一句沒格式、沒單號的中文摘要。

另一種情況:你接了一個 MCP server(例如查資料庫、抓 issue 列表、跑雲端 API),它回傳一大坨 JSON,agent 只看到頭尾,中間被一行 ...[truncated N chars]... 吃掉,接著就開始憑空猜中間那段寫了什麼。

Cline 在 2026 年 10 月 7 日釋出的 VS Code 擴充套件 v4.1.23,剛好把這兩個坑都補了。這篇不談趨勢,直接拆兩件事:它底層怎麼改、你要怎麼設定才吃得到這次更新、哪些地方還有限制。

一、這次更新在修什麼

v4.1.23 的 release notes 列了一串 Changed 和 Fixed,跟日常用法最相關的是這兩條:

  1. Generate Commit Message 現在會套用 .clinerules:對應 PR #14103,作者是 Cline 團隊的 Mikołaj Kondratek(GitHub:mkondratek),修的是 ankit-jha 早在 Cline v3.65.0 時期回報的 issue #9410「Generate commit msg button doesn't follow the cline rules」。
  2. MCP 工具的超長輸出可以用 read_files 分頁讀回,不再只是截斷:對應 PR #14712「recover oversized tool results from a session memory cache」,作者是 Bee(GitHub:abeatrix)。

同一版另外還有幾條值得知道的:模型回應若沒有可辨識的 finish reason,現在會自動送續寫請求而不是當成已完成(#14869);自訂 Anthropic base URL 在 v4.1.22 出現的 400 錯誤修掉了;工具核准的 Approve/Reject 按鈕反應延遲也修了。不過本篇聚焦前兩條,因為它們會直接改變你「該怎麼寫規則」和「該怎麼用 MCP」。

二、Commit Message 按鈕:從「寫死的 prompt」到「跟聊天同一套規則」

2.1 原本為什麼不吃規則

PR #14103 的描述講得很直白:「Generate Commit Message with Cline」原本是用一段寫死的 system prompt 組請求,完全沒有載入使用者的規則。所以你寫在 .clinerules 的語言、格式、單號規範,聊天時有效,按鈕卻默默丟掉。

那段寫死的 system prompt 從原始碼看是這樣:

You are a helpful assistant that generates informative git commit messages
based on git diffs output. Skip preamble and remove all backticks surrounding
the commit message.

2.2 現在怎麼運作

Cline v4.1.23 Commit Message 按鈕如何載入 .clinerules 的流程圖

修正後的流程拆成四步:

  1. 共用同一個規則來源:按鈕不再自己讀檔,而是呼叫 Controller.getRulesForSystemPrompt(),背後走 SDK core 新增的 loadRulesForSystemPromptFromRecords。這就是聊天 session 組 system prompt 時用的同一條管線,所以全域規則、remote config 規則也一起進來。
  2. 篩選與排序:只取「enabled」的規則(frontmatter 沒寫 disabled: true),並依規則名稱排序,渲染成 # Rules 底下一段段 ## <規則名>。
  3. 加一段前言再附上規則:在原本的 system prompt 後面接一句 preamble:「The user's rules follow. Apply any that concern commit messages, their language, format, or content; the rest describe how code is written and are not relevant here.」也就是說,你所有的規則都會被送過去,但模型被告知只採用跟 commit message 有關的部分。
  4. 可取消、可退回:讀規則多了一個 await,作者特別把它跟 Stop 訊號賽跑(untilAborted),按 Stop 不用等第一次掃描規則跑完;如果規則讀不到,就退回原本的基礎 prompt,照樣產出 commit message。

2.3 照著做:寫一份「按鈕吃得到」的 commit 規則

既然 preamble 會叫模型「只套用跟 commit 有關的規則」,那最穩的寫法就是把 commit 規範獨立成一個檔、標題寫明白,讓模型一眼就認得:

your-project/
├── .clinerules/
│   ├── 01-coding.md
│   ├── 02-testing.md
│   └── 90-commit-message.md   ← 新增這個

90-commit-message.md 範例:

# Commit Message Rules

這份規則只用於產生 git commit message。

## 格式
- 使用 Conventional Commits:`<type>(<scope>): <subject>`
- type 只能是 feat / fix / refactor / docs / test / chore / perf
- subject 用英文、祈使句、不加句點,50 字元以內

## 內容
- 第二段用條列說明「為什麼改」,不要重述 diff
- 若分支名稱含 `PROJ-123` 這類單號,最後一行加 `Refs: PROJ-123`
- 不要包反引號、不要加任何前言

## 範例
feat(auth): add refresh token rotation

- Prevent token replay after logout
- Rotation window configurable via AUTH_ROTATE_SEC

Refs: PROJ-482

幾個實戰細節:

  • 標題直接寫「Commit Message」:preamble 是靠模型自己判斷哪條規則「concern commit messages」,標題和第一句越明確,誤判越少。
  • 給一個完整範例:這是給格式型規則最有效的招式,比十條描述更能鎖住輸出。
  • 按鈕看不到分支名:從程式碼看,請求內容是 git diff 加上你在 commit 輸入框裡寫的備註(prompt 中標為「Notes from developer」)。所以單號規則要能生效,最實際的做法是先在輸入框打 PROJ-482 再按按鈕,模型會把它當備註吃進去。
  • 檔名數字前綴只是排序用:官方文件說數字前綴(如 01-coding.md)是可選的組織方式;這次 PR 讓所有路徑都依名稱排序,前綴剛好能控制渲染順序。

2.4 已知限制(PR 作者自己寫的)

PR #14103 的 Notes 很誠實地列了三個限制,照著設定前先看:

  • Rules 面板的開關按鈕目前對按鈕無效:面板上的 on/off 存在擴充套件狀態裡,SDK 不讀,所以你在面板關掉的規則,聊天和按鈕都還是會送出。這個問題另由 #14605(CLINE-3120)處理。真的想停用某條規則,現階段可以在該檔 frontmatter 寫 disabled: true,這是 SDK 認的停用方式。
  • 巢狀 repo 不吃自己的 .clinerules:規則從 workspace root 讀,跟聊天一致。如果你在 monorepo 裡開了一個子 repo 的 SCM 面板,它用的是根目錄的規則,不是子 repo 的。
  • 同時按多次的併發行為沒變:同時跑兩個 generation 的行為維持原樣,併發模型另開 ENG-2545 追蹤。

另外一點是我讀程式碼的推論,值得你自己實測:Cline 支援用 frontmatter 的 paths: 寫「條件式規則」,只在你碰到匹配檔案時啟用。按鈕這條路徑呼叫的是「列出所有 enabled 規則」的函式,從 diff 看不到 paths 條件判斷。所以commit 規則請不要加 paths:,避免它在某些情況被過濾掉;反過來說,那些用 paths: 限定範圍的程式碼規則,在按鈕這邊可能整包都會送出,只是被 preamble 叫模型忽略。規則很多時,這代表每次按按鈕多吃一點 token。

三、MCP 長輸出:從「中間被吃掉」到「可以分頁讀回」

3.1 原本的問題

Cline 在把對話送給模型前,會由 MessageBuilder 對每個工具結果做長度限制。從 v4.1.23 原始碼看,預設上限 DEFAULT_MAX_TOOL_RESULT_CHARS 是 8,000 字元,超過就砍中間、只留頭尾,插入 ...[truncated N chars]...。對 MCP 這種一次回一大包 JSON 的工具來說,被砍掉的往往正是你要的資料,而 agent 完全沒有辦法拿回來。

3.2 現在怎麼運作

MCP 超長輸出寫入 session 快取並透過 read_files 分頁讀回的流程圖

PR #14712 的做法是在記憶體裡開一個 session 專屬的工具結果快取(ToolResultCache),流程如下:

  1. 工具宣告 opt-in:MCP 與 Composio 工具在註冊時帶 resultPolicy: "cache-oversized";用 SDK createTool 寫的自訂工具也可以自己加。其他內建工具維持原本行為。
  2. 超長才進快取:判斷「超長」用的是跟預覽截斷同一套 JSON/字串大小,所以凡是會被截斷的結果都有資格被快取。快取的時機在「會改寫結果的 hooks」跑完之後。
  3. 轉成好讀的文字:純字串原樣保留;結構化結果轉成 YAML,多行字串用 literal block、關掉自動換行,讓 MCP 回傳的換行保留成真正的行,而不是擠成一行跳脫過的 JSON。圖片資料不進文字快取,照原本的媒體路徑附上。
  4. 模型拿到預覽加一個 URI:模型看到的是截斷後的預覽,加上一段提示:「Full result is temporarily saved to cline://cache/<session-id>/<result-id>.result.txt. Only read_files can access this cache URI. Use read_files with specific line ranges if omitted content is needed.」
  5. agent 用 read_files 指定行數讀回:帶 start_line/end_line 讀需要的範圍,沿用一般檔案的行數範圍、輸出上限與逐行截斷規則。

快取的生命週期規則(來自 PR 說明與 sdk/ARCHITECTURE.md):

項目 規則
容量 每個 session 最多 16 MiB 的 UTF-8 文字,超過依「最久沒被讀」淘汰(LRU)
單筆過大 單筆結果本身就超過上限時,只給預覽、不給 URI
過期 連續 5 次模型迭代沒有被 read_files 讀過就過期,會跨 follow-up 對話累計
續命 只有明確的讀取會刷新;URI 出現在請求裡不算
清除 關閉 session、重設歷史、還原(restore)都會清空;resume 不會重建
讀不到時 回傳「Cache not found. Make a new tool call for the latest result again if needed. DO NOT repeat side-effecting actions to recover output.」

注意最後一條的設計:快取不見時,系統明確告訴模型不要為了拿回輸出而重複有副作用的動作。這點對接了會寫入資料的 MCP(建 issue、發訊息、改資料庫)的人特別重要。

3.3 照著做:讓 agent 真的會去讀回來

更新本身是自動生效的,但要讓它發揮作用,有幾件事你可以主動做:

1. 確認 read_files 沒被關掉。 PR 寫得很清楚:回讀快取需要 read_files 可用,且原本那個 MCP 工具還在註冊狀態。關掉 read_files 不會停止快取、也不會拿掉提示,只是 agent 照著提示去讀會失敗。

2. 在規則裡教 agent 處理截斷。 模型不一定每次都會主動去讀,加一條規則能明顯提高命中率。範例 .clinerules/20-mcp-output.md:

# MCP 工具輸出處理

- 若工具結果出現 `cline://cache/...` URI 且有 truncated 標記,
  在下結論前先用 read_files 讀取相關行數範圍,不要猜被截掉的內容。
- 先讀前 200 行看結構,再針對需要的區段指定 start_line / end_line。
- 若 read_files 回傳 Cache not found:只有唯讀查詢可以重新呼叫工具;
  有寫入副作用的工具(建立、更新、刪除、發送)不要重跑,改為回報給我。

3. 下任務時直接點名分頁讀。 例如:

用 linear MCP 列出本週所有 open issue。結果如果被截斷,
用 read_files 分段把完整清單讀完,再依 label 分組統計。

4. 別讓快取過期。 5 次迭代沒讀就過期,所以如果 agent 拿到大結果後先去做別的事,回頭再讀可能已經沒了。需要的資料,請它拿到後就讀完並摘要下來。

5. 截斷門檻可以調。 從原始碼看,MessageBuilder 會讀 CLINE_MESSAGE_BUILDER_MAX_TOOL_RESULT_CHARS 這個環境變數覆寫預設 8,000 字元。這是內部設定,不在使用者文件上,調大代表每次請求吃更多 token,建議先用預設值,真有需要再試。

3.4 限制與坑

  • 只有 read_files 認得 URI:shell 指令與檔案搜尋都不會解析 cline://cache/...,所以你不能叫 agent 用 grep 去搜快取內容。
  • 超長單行讀不全:read_files 原本就有逐行截斷,如果 MCP 回傳的是一行超長字串(例如沒換行的 base64 或壓縮 JSON),部分內容仍可能讀不到。YAML 轉換能救回多行結構,但救不了單行巨塊。
  • 只在記憶體裡:不寫磁碟,resume 或複製 session 都不會重建快取。這是刻意的取捨:PR 說明裡比較過另一個實作 #14511(落地存檔、有持久化的 ToolResultStore),最後選了較輕量的記憶體方案。
  • 16 MiB 不是總記憶體上限:它只算快取文字,原始輸出照樣留在對話歷史裡。
  • PR 作者自己標註的待決事項:快取目前透過 tool context metadata 傳遞,review 時對這個接線方式的疑慮在 PR 說明中標為「remains unresolved」。功能能用,但實作細節未來可能調整。

四、什麼時候這兩個更新對你最有感

Commit 規則這條,最適合:

  • 團隊有固定 commit 規範(Conventional Commits、語言、單號),之前只能在聊天裡叫 Cline 寫 commit 的人。現在可以直接改用 SCM 面板的按鈕。
  • 已經有 AGENTS.md 或 .cursorrules 的專案:官方文件說 Cline 也會偵測這些檔案,這次修正讓它們跟聊天一樣進到按鈕的 prompt 裡。

不太適合或要注意:

  • 規則檔很多、很長的專案:每次按按鈕都會把所有 enabled 規則送出去,token 成本會上升。
  • monorepo 子 repo:規則讀的是 workspace root,不是子 repo。

MCP 分頁讀回這條,最適合:

  • 會回大量結構化資料的 MCP:issue tracker、資料庫查詢、log 搜尋、雲端資源列表。
  • 需要 agent 根據完整清單做統計或比對的任務。

沒那麼有用的情況:

  • MCP 回的是單行巨塊(minified JSON、base64):截斷問題只能部分改善。
  • 跨很多輪才會用到的資料:5 次迭代沒讀就過期,應該讓 agent 拿到就處理。

五、給工程團隊的升級清單

  1. 升級到 v4.1.23:在 VS Code 擴充套件頁確認版本。
  2. 把 commit 規範獨立成一個規則檔:標題寫「Commit Message Rules」,附一個完整範例,不加 paths:。
  3. 檢查想停用的規則:面板開關目前對聊天和按鈕都無效,要停用請在 frontmatter 寫 disabled: true,或先移出規則目錄。
  4. 加一條 MCP 輸出處理規則:教 agent 看到 cline://cache/ 就用 read_files 分段讀,並禁止為了重拿輸出而重跑有副作用的工具。
  5. 確認 read_files 是開的:特別是你有自訂工具權限設定的話。
  6. 自己寫的工具也可以 opt-in:用 SDK createTool 的話,加上 resultPolicy: "cache-oversized" 就能吃到同一套機制。

這兩個修正都不是什麼新功能,而是把原本「看起來應該會動、實際上沒動」的地方接通。對每天用 coding agent 的人來說,這類修正往往比新模型更能直接減少返工。

來源

整理:DataAgent · Coding Agent 實戰教學

發表迴響

%d 位部落客按了讚: