本篇出自 2026年9月13日 晨報
八月下旬,一則中文轉述在社群裡流傳:agent 工具廠商 Pi 的開發筆記說,新一代 Claude 接上非 Claude Code 的工具層時,會自己生出 `requireUnique`、`matchCase`、`oldText2` 這種對方根本沒有的參數;同一天,兩位評測者對同一個匿名模型跑同一套題,得到 58.4% 與約 63%,兩人都把差距歸給「工具層不同」。本站昨夜把這兩件事合成一條判斷:模型與工具層分不開,不只是量不準,是換過去真的會退步,機制是模型的後訓練對自家工具定義過度貼合。
本篇把這條判斷拆開重驗,結論分三層。第一層,出處排錯了。 那三個參數名不是八月二十二日的新消息,是 Pi 作者之一 Armin Ronacher 七月四日一篇部落格裡的原句,本站七月就收過,昨夜的判斷沒有引用;那組「19 個 session、prefill 降 72% 到 88%」的數字,則來自一位外部貢獻者八月十五日開的 PR,被機器人以「非核准貢獻者」自動關閉,從未合併。第二層,機制比昨夜寫的更具體,也更可修。 模型生出來的欄位,用的是對方工具自己的命名風格,加上 Claude Code 那套工具的規則;提出觀察的作者本人給的解釋不是「記住了自家欄位名」,而是「自家工具層太寬容,多寫的欄位會被靜默丟掉,所以訓練時從來沒有被扣過分」。這個讀法的直接後果是:修法在工具層那一端,一個嚴格模式的開關,或一行過濾未知欄位的程式。第三層,那個 4.6 個百分點不能用,但同一份紀錄裡有一個更大的數字可以用。 113 題的抽樣誤差本身就是 4.6 個百分點,兩份跑分的差距剛好落在誤差裡;可是 58.4% 那份的公開紀錄自己寫著,113 次嘗試裡有 11 次是因為模型連續三次沒有回傳工具呼叫而中止。那才是工具層與模型合不合的讀數,而且它比兩位評測者之間的差距大一倍。
本篇路線分六步:
① 先把出處排對:兩條線指回同一篇七月的部落格和一個沒合併的 PR。
② 解釋「發明參數」到底發生了什麼:工具定義是什麼、兩家的編輯工具長什麼樣、為什麼多出來的欄位長那個樣子。
③ 廠商自己怎麼說:一家把「模型受訓於這個工具」寫進文件並給了數字,另一家的文件裡沒有那句話。
④ 把那個 4.6 個百分點拿掉,換上同一份紀錄裡的 11 次。
⑤ 正面攻擊最強的反駁:既然一個開關就修得掉,憑什麼拿它談採購?答案是撐住一半,撐不住的那一半是時間差。
⑥ 所以「模型乘以工具層」這個採購單位到底長什麼樣,以及該向誰要什麼。
這條沒上過日報,因為它是昨夜才收進來的判斷。這篇比那條判斷多給了什麼?三件,都指得出來。第一,我們攻了「同一天兩個互不相干的來源撞到同一件事」,它沒撐住:不是同一天,也不是兩個來源,是一篇七月的部落格被轉述了一次、一個八月的外部 PR 被當成廠商筆記。第二,我們拆開了那個 4.6 個百分點的分母:它是 113 題,抽樣誤差正好 4.6 個百分點,所以這個差距對「工具層有沒有影響」零資訊;換上去的是同一份紀錄裡的 11 次格式中止。第三,我們寫死了推翻條件:只要有人在 Pi 的原始工具定義上開嚴格模式後,仍量到編輯成功率明顯落後,本篇「修得掉」的收窄就錯,昨夜那個更強的版本就回來。
進行中 ?
上圖是本站追蹤 coding agent 這條線的地圖。本篇處理的是分岔右邊那條路線,也就是「工具層與模型分不開」的主張,第一次拿到一個有名字、有出處、有修法的機制。
如果你只讀到這裡:向工具層廠商要的那一題已經有標準寫法,就是「你對每一個模型用哪一套工具定義、嚴格模式預設開不開、新模型上線後多久補上那一列」。
昨夜那條判斷的骨架是「同一天、兩個互不相干的來源」。這個骨架要成立,兩個來源必須各自獨立、各自新鮮。實際查下去,兩個條件都不成立。
| 昨夜以為的來源 | 實際的出處 | 日期 |
|---|---|---|
| Pi 開發筆記:Claude 會生出 `requireUnique`、`matchCase`、`oldText2` | Armin Ronacher 部落格〈Better Models: Worse Tools〉,那三個名字在他列的十六個發明欄位裡;同一天 Simon Willison 轉載 | 2026-07-04 |
| Pi 開發筆記:19 個 session,context 降 26% 到 35%,未快取 prefill 降 72% 到 88% | 外部貢獻者 adamteale 在 Pi 的 GitHub 開的 PR #8172,標題是「example: tool-result pruner + spill extension」,被 github-actions 機器人以「只有經 lgtm 核准的貢獻者可以開 PR」自動關閉 | 2026-08-15 開,未合併 |
| 兩位評測者的 58.4% 與約 63% | 58.4% 那份有公開的逐題紀錄;另一份自陳在 Cursor 裡跑 | 2026-08-22 |
排對之後,三件事變了。第一,機制那半的出處從「二手中文轉述」升為一手部落格加一個 GitHub issue,而且那個 issue #6278 是七月三日開的,比部落格還早一天。第二,數字那半的出處從「廠商自報」降為「一位外部貢獻者的範例擴充,廠商沒有接受」,它不能再拿來當 Pi 的主張,更不能當任何廠商的量測。第三,八月二十三日一位台灣作者在整理這條線時已經寫下「我在已合併的 Pi 文件裡沒核到這三個欄位名」,他找不到是對的,因為那三個名字不在 Pi 的文件裡,在 Ronacher 的部落格裡。
這一節的教訓不是誰轉述錯了。是「同一天撞到」這種形狀的證據,第一件要查的永遠是日期。
先把三個詞講清楚。
工具定義:你讓模型呼叫一個工具之前,要先用一份 JSON 格式的說明告訴它這個工具叫什麼、收哪些參數、每個參數是什麼型別。模型回傳的工具呼叫必須符合這份說明,不然工具層要嘛拒收、要嘛猜。
Claude Code 的編輯工具:依 Anthropic 的官方工具參考,它叫 Edit,收四個參數:`file_path`、`old_string`、`new_string`,以及選填的 `replace_all`。規則是 `old_string` 必須在檔案裡剛好出現一次,出現多次就要給更長的上下文,或者把 `replace_all` 設成真。
Pi 的編輯工具:依 Pi 三月底的版本說明,它收 `path` 和一個 `edits` 陣列,陣列裡每一項是 `oldText` 與 `newText`。命名用駝峰式,一次可以送多筆。
現在看模型多寫了什麼。Ronacher 列出的欄位是:`type, id, kind, unique, requireUnique, matchCase, in_file, forceMatchCount, children, notes, cost, oldText2, newText2, oldText_2, newText_2`,還有一個 `event.0.additionalProperties`。把這串對著上面兩份定義看,形狀很清楚:
換句話說,模型帶過去的不是自家工具的字面,是自家工具的習慣:它習慣一次多筆、習慣表達「這段要唯一」,於是用對方的命名風格把這些習慣寫了出來。這比昨夜寫的「對自家工具定義過度貼合」更窄,也更好驗。
Ronacher 自己給的解釋還再往下一層。他的原話是:Claude Code 的編輯工具「silently filters out unexpected keys and it does not use `strict` mode either」,多出來的欄位會被靜默丟掉,也沒有開嚴格模式。接著:「If reinforcement learning happens in a harness like that, or a simulation of one, then slightly malformed tool calls can still complete the task and receive reward」,如果強化學習是在這樣的工具層裡跑的,稍微不合格式的呼叫照樣能完成任務、照樣拿到獎勵。結論一句:「The harness fully absorbs the error and there is little gradient against inventing an alias, adding a stray field or using a nearby parameter name」,工具層把錯誤全吸收了,訓練時幾乎沒有力量去阻止模型發明別名、多加欄位、或用一個相近的參數名。
這個解釋有三個可以查的推論,三個都對上了。第一,它預測舊模型沒有這個毛病、新模型有,因為這是後訓練越來越貼近自家工具層的副作用。Ronacher 的觀察是「both Opus 4.8 and Sonnet 5 show it but none of the older models」,同一家的最新兩款有、舊款沒有。第二,它預測一旦強制格式,毛病就消失。他寫「Obviously one could turn on `strict` sampling in Anthropic and the problem should go away」。第三,它預測在自家工具層裡完全看不到,因為那裡本來就會丟掉多餘欄位。這一點沒有人量過,但它解釋了為什麼這件事是被第三方工具層的作者發現,而不是被 Claude Code 的用戶發現。
至於發生率,issue 裡的量測是一位用戶的 session 中「about 20% of a particular edit call responses were malformed this way」,某一種編輯呼叫約兩成不合格式。這是單一 session、單一用戶、單一模型的讀數,不是母體讀數;本篇後面不會用它做任何倍數。
昨夜的判斷把「模型受訓於自家工具定義」寫成 Pi 的猜測。實際上有一家廠商自己寫在文件裡。
OpenAI 在 GPT-5.1 的提示指南裡的原句是:「GPT-5.1 has been post-trained on specific tools that are commonly used in coding use cases」,GPT-5.1 針對幾個常用於寫程式的工具做過後訓練,點名的是 `apply_patch` 與 `shell`。同一份文件還給了一個數字:「In testing, the named function decreased apply_patch failure rates by 35%」,用他們定義好的那個工具型別,而不是自己寫一個同功能的函式,`apply_patch` 的失敗率在測試裡降了 35%。官方 API 文件列出這個工具支援 GPT-5.1 到 GPT-5.5。
這句話的重要性在於它把昨夜的「猜測」變成一個廠商的自述,而且附了受訓工具形狀對非受訓工具形狀的差距。它同時解釋了 Ronacher 的另一個觀察:「So far, the Codex models I tested did not show this type of regression」,他測過的 Codex 模型沒有出現同樣的退步。合理的讀法是:OpenAI 把受訓的工具形狀做成 API 上人人可用的型別,第三方工具層接上去就是模型受訓的那個形狀;Anthropic 受訓的編輯形狀住在 Claude Code 裡,第三方工具層預設不會用它。
Anthropic 這一側,本篇查到的是兩份文件,各說了一半。文字編輯工具的文件提供一個 Anthropic 定義的 `str_replace_based_edit_tool`,版本從 2025 年 1 月到 7 月共三版,其中最早那版的說明寫著「optimized for Claude Sonnet 3.7」,為那款模型最佳化;本篇在這份文件裡沒有找到「模型受訓於此工具」這樣的句子,這一點必須如實記下。另一份是嚴格工具使用的文件:把工具定義標上 `strict: true`,模型的輸出會用文法約束取樣,保證符合定義;支援的模型包括 Opus 4.8、Sonnet 5、Opus 5、Fable 5 與 5.1,代價是定義必須把 `additionalProperties` 設為假、不能用遞迴與數值範圍等幾類語法,而且第一次用某個定義時要多等文法編譯,之後快取 24 小時。
也就是說,Ronacher 說的那個「開了就應該消失」的開關,在 Anthropic 的 API 上是有的,而且他報告有問題的那兩款模型都在支援名單上。Pi 的 issue 裡也指向這條路:「Anthropic API offers strict schema validation that ensures this」。
昨夜判斷的數字那半是:同一個模型、同一套題,兩位評測者得 58.4% 與約 63%,兩人都把差距歸給工具層。這個歸因的問題不在動機,在算術。
那套題有 113 題。58.4% 是 66 題通過。在這個通過率下,單一次跑分的抽樣誤差是 113 題開根號的那個式子,算出來約 4.6 個百分點;兩次獨立跑分的差距,誤差約 6.6 個百分點。兩人差 4.6 個百分點,等於零點七個誤差單位。這個差距對任何原因都是零資訊,無論是工具層、溫度、還是運氣。兩位評測者自己指向工具層,是誠實的猜測,不是量測。
但同一份紀錄裡有一個可以用的數字。58.4% 那份跑分附了公開的逐題紀錄,它寫明工具層是 `pier` 0.3.1 加 `mini-swe-agent`,並自陳:113 次嘗試裡有 11 次,也就是 9.7%,是因為模型連續三次回傳的內容裡沒有任何工具呼叫而被中止,紀錄的用語是這些失敗來自「tool-call format errors rather than reasoning deficits」,是工具呼叫的格式錯誤,不是推理不夠。
這 11 次才是「模型與工具層合不合」的讀數,而且它的形狀跟第二節的發明欄位是同一族:模型該產出工具層看得懂的東西時,產出了工具層看不懂的東西。它的量級是兩位評測者之間差距的兩倍,它落在同一次跑分裡,不需要跨評測者比較。
把這個讀數放回更大的母體看,形狀一致。北京大學與啟元科技的 Harness-Bench 用六個可組態的工具層乘以八個模型後端,跑了 5,194 條執行軌跡,最好與最差的工具層在同一批任務、同一池模型上差 23.8 分;而它對失敗的分類裡,最大的一類是「contract / format」,也就是格式與輸出契約違規,佔它定義的執行對齊失敗的 36.4%,其次是工具錯誤後沒有有效恢復的 24.6%。這是單篇自報、還沒有人在別的地方重做出來,但它給了本篇要的那個形狀:工具層造成的差距裡,最大的一塊是格式,不是能力。
再加一個本站八月已收的樣本:同一個 DeepSeek V4-Flash 在 TerminalBench 2.1 上被三家不同工具層量出 82.7、79、67,落差 15.7 個百分點,這組數字經同一位轉述者彙整,三家原始發布本站沒有逐一核對。
現在攻擊本篇自己。最強的反駁是這樣:
第二節你自己說了,修法是 `strict: true`,或者在工具層加一行過濾未知欄位。Claude Code 就是這樣做的。一個一行就修好的 bug,跟「採購單位從模型變成模型乘以工具層」有什麼關係?
這個反駁撐住一半,必須認。對第二節那個失敗形狀,也就是多寫欄位,答案就是這麼便宜:開嚴格模式,或學 Claude Code 把未知欄位丟掉。Ronacher 也說編輯內容本身「usually correct」,內容是對的,只是包裝不合格。所以昨夜那句「換過去真的會退步」要收窄成:換過去會撞上一種可以用一個開關修掉的格式退步。
撐不住的那一半有兩塊。
第一塊是時間差。 這個開關不是模型廠替你開的,是工具層廠商替每一個模型決定的。Ronacher 的 issue 七月三日開,指向一個做嚴格驗證的 PR;社群同時長出了兩個擴充:一個是 pi-anthropic-text-editor,在 Pi 裡替 Claude 註冊 Anthropic 原生的 `str_replace_based_edit_tool`;另一個是 pi-apply-patch,當 GPT 模型在用時,把 Pi 的寫入與編輯工具換成 Codex 風格的 `apply_patch`,說明裡寫這是為了用「Codex models were trained on」的那套格式。兩個擴充都是從同一個分支專案抽出來的,一個零顆星,一個 16 顆星。規模是零,形狀是全部:工具層裡開始出現一張「每個模型用哪套工具形狀」的表,而這張表由第三方維護,新模型上線到表補上那一列之間的幾週,就是「換過去會退步」真實發生的窗口。這不是 bug,是一種會反覆發生的維護債。
第二塊是本篇量不到的那一層。 開關解決的是「多寫欄位」,解決不了「習慣不同」。第二節指出模型帶過去的是規則與習慣:一次多筆、要求唯一。嚴格模式會強迫它不寫那些欄位,但不會讓它放棄那些習慣;它可能改成分多次呼叫、或在 `oldText` 裡塞更長的上下文。這一層有沒有成功率的代價,目前沒有任何人量過。這是本篇最誠實的邊界,也是第七節第一條推翻條件的來源。
還有一個反方向的樣本要放進來,它不利於「用原廠工具層就沒事」這種簡化。Sebastian Raschka 六月底自測,Qwen3.6 在 OpenAI 的 Codex 工具層裡表現「to my surprise」竟然比在自家的 Qwen-Code 裡好;他自己打折說是小樣本。這說明「綁定」不等於「原生最好」。模型學到的是它訓練場的寬容度與習慣,不是某個品牌名;一個工具層只要跟訓練場一樣寬容、習慣相容,就算不是原廠也能接得好。所以那張表要填的不是「用誰家的」,是「對這個模型,用哪套工具形狀、開不開嚴格」。
把前五節整理起來,昨夜那句「採購單位從模型變成模型乘以工具層」需要換單位。乘號右邊不是一個品牌,是一張表:
| 這張表的一列 | 內容 | 誰維護 |
|---|---|---|
| 模型 | 例如 Opus 4.8 | 模型廠 |
| 工具形狀 | 用工具層自家的定義,還是模型廠受訓的那套原生定義 | 工具層廠商 |
| 嚴格模式 | 預設開或關;開了之後定義要改寫成合規語法 | 工具層廠商 |
| 更新時差 | 新模型世代上線到這一列補好的天數 | 工具層廠商 |
從這張表推出三件該做的事。
該量的數字換了。 跨工具層的模型排名不可移植,這一點本站七月已寫過;本篇加的是:該量的是同一模型在你自己工具層裡的工具呼叫格式失敗率,就像 58.4% 那份紀錄裡的 11 次那樣,一個跑分裡就能拿到,不需要別人的榜。Terminal-Bench 3.0 的每一列本來就是模型加工具層一起計分,榜首那列是 Opus 5 配 mini-SWE-agent 的 42.7%;它能告訴你的是那個組合,不是模型。
該向工具層廠商要的東西有了標準寫法。 就是上面那張表。一家宣稱多模型的工具層廠商,拿不出「對每個模型用哪套工具形狀、嚴格模式預設如何、新模型多久補列」的答案,它的多模型是介面上的,不是行為上的。
協定開放與模型可移植是兩件事,這次看得更清楚。 Vercel 八月二十三日宣告自家 agent 工具 fx 只走 MCP、Skills、Plugins 三個開放協定,隔日版本說明把「修好 Codex 與 Grok 的登入」列為賣點。協定層的開放是真的,而它跟本篇講的那張表互不干涉:協定決定你能接上哪些工具,那張表決定接上之後模型會不會多寫欄位。一家平台商可以兩者都做,但做了前者不等於做了後者。
模型換得動,但不是換一行設定,是換一張表:每一個模型在這個工具層裡用哪套工具形狀、嚴格模式開不開、新模型上線後多久補上這一列。多寫欄位這個毛病本身一個開關就修得掉,所以它不是「換過去會退步」的證明;它證明的是工具層必須替每個模型維護這張表,而表跟不上新模型世代的那幾週,就是退步真實發生的窗口。之後每一筆「模型與工具層分不分得開」的主張,本站都先問它講的是這張表的哪一列,而不是問它站在分岔的哪一邊。
「換模型只要改一行設定」與「換模型等於重新驗收一輪」都是全稱口號,本篇把它們換成一個問句:你的工具層對你考慮中的那個模型那一列填好了沒?填好了,換模型接近改設定;沒填,你會在第一週看到成功率掉,而掉的那一塊多半是格式,不是能力。談判桌上的替代威脅是否可信,取決於你的工具層廠商補列的速度,不取決於模型廠。
Claude Code 靜默丟掉未知欄位這件事,現在有了一個你必須知道的含義:它是那家模型的訓練場,你的產品跟它的寬容度差多少,模型接上你之後就會差多少。兩個最便宜的動作:對支援嚴格模式的模型預設開嚴格;對有原生工具型別的模型,用原生型別而不是自己重寫一個同功能的函式,OpenAI 那份 35% 的失敗率差距就是這條的價格。然後把你的「每模型工具形狀表」公開,那會是你多模型宣稱唯一能被驗證的部分。
本篇為第一與第二條自設觀察窗,因為那是這組問題下一次最可能被回答的地方:Pi 的 issue 串與 Ronacher 的後續。本站將於本篇判斷的對答案日,2026 年 11 月 12 日,覆核三件事:Pi 是否對 Claude 預設開了嚴格模式或原生工具;有沒有人公布 Opus 5 或 Fable 5 的發明欄位讀數;有沒有任何工具層廠商公開每模型的格式失敗率。
只留 email,隨時退訂。這是我們唯一想請你做的事。
但決定權可能不在訓練,而在執行。 這個機制假設「模型會不會用你的軟體」是在訓練的時候決定的。目前檯面上唯一真的把這件事量出來的兩篇論文說,它是在執行的時候決定的,而那把整個處方換掉…
九月三日,OpenAI 宣布「Daybreak for Frontline Defenders」:10 億美元的補貼式存取,給自來水廠、電網、州與地方政府、社區銀行、非營利與開源維…
九月一日,OpenAI 放行 GPT-6 Astra,這是它史上第一個被自家評為「Critical」資安等級的模型:給它工具與權限,它能自己找出沒人知道的漏洞並寫出攻擊鏈。官方的放…
九月二日 Google 發表 Gemini 3.8 Flash Cyber:一款只做資安的模型,官方稿從頭到尾沒有價錢,只寫著「透過我們新的 Fairwind Program 提供…