iT邦幫忙

2026 iThome 鐵人賽

DAY 3
0

準備這篇的時候,我做了一個受控測試:拿同一份會命中規則的測試稿,用兩種方式呼叫我的內容機檢。第一種把檔案路徑直接當參數傳進去,機檢回報「通過」;第二種照 Hook 契約從 JSON stdin 傳入,才回報「不通過」,還附上被擋的原因。寫這篇的當天我又重跑了一次,結果一樣。

(給工程背景的讀者一句對照:機檢回報用的是程式慣例的 exit code,0 是通過、2 是不通過,原因印在 stderr。後面全篇直接寫「通過/不通過」。)

規則沒有變。差別是,它有沒有真的接進控制流。寫了一支檢查腳本,不等於 AI 已經擁有驗證能力。事件、輸入格式、回傳結果和下一步動作,四件事都要接對。

同一份測試稿的兩種呼叫方式:位置參數回報通過其實沒有掃,JSON stdin 才回報不通過並附上原因

從 Day 2 接過來

Day 2 我把幾條內容工作流攤開,反覆出現的是同一件事:人的判斷做久了,有些標準已經可以說清楚。我也留了一句話:同一個判斷做久了、標準說得清楚了,就能沉澱成規則、測試或機檢。今天就來做這件事,只做一個最小切片。

案例我挑了發文草稿線。三個候選比較過:深度專欄線的證據其實最完整,有測試演習、驗證器和逐層讀回紀錄,但拿它當主案例會提早吃掉後面的篇章,先當旁證;鐵人賽工作台跟我此刻的寫作情境最接近,可是它的文章路徑不在現行機檢的掃描範圍,拿來示範「機檢已接好」會變成說謊。發文草稿線贏在四件事都齊:固定的寫入範圍、可重跑的機檢、看得懂的回報結果,以及最後有明確的人工批准。

這條線長什麼樣

流程圖

這張圖的終點只停在「交給我判斷」,不畫到「發布成功」。目前也沒有一條同時串起 Skill 啟動、正式草稿、Hook 回饋與最終發布的單次完整紀錄,所以這篇說的都是「現有配置與受控實驗」,不是「整條線每次都完整跑過」。

先給 Harness 一個工作定義

這個場景就是 Day 1 說的 Harness Engineering 的一個最小切片。不過要先講清楚:Harness 不是一個叫做 Harness 的單一工具,各家的用法範圍也不完全一樣。OpenAI 的工程文章把人的新工作描述成設計環境、說清楚意圖、建立回饋迴圈;他們介紹 Codex 架構的另一篇,則把 agent 迴圈、設定、沙箱裡的工具執行和 Skill 都算進 harness。Anthropic 在評估文件裡又分成兩個詞:讓模型能行動的 agent harness,和負責跑任務、記錄、評分的 evaluation harness。

所以我在這個系列裡用的是工作用的定義:Harness 是模型外面那套讓規則真正發生作用的執行與控制環境。拆開來是六種責任:指示(告訴 AI 怎麼做)、能力(讓它動手)、觀測(讓它看見結果)、判分(對照條件給出通過或失敗)、阻擋(限制能力與範圍),以及人工批准。這是我的整理,方便這三十天說話,不是哪一家的官方分層。

Harness 的六種責任:指示、能力、觀測、判分、阻擋、人工批准,一組可接線的工程層

放回這條寫稿線,每個元件的責任都不一樣,也都有不能誇大的地方:

元件 在這條線裡的角色 不能誇大成
Skill 提供程序、知識與資源 AI 一定會遵守的硬規則
Tool 讓 AI 讀寫檔案或執行命令 有工具就會用對
Hook 在固定事件介入 每種 Hook 都能撤銷動作
機檢與測試 對照已知條件,回傳結果 能理解所有語意與未知問題
回報結果與原因 把結果送回控制流 「通過」代表內容正確
權限與沙箱 限制能力與越界範圍 能判斷文章品質
認領經驗、判斷證據、批准公開 所有機檢都靠人重做

七個元件的責任卡:Skill、Tool、Hook、機檢、回報結果、權限沙箱、人,各自負責一件事

Skill 是指示,不是訊號

Skill 在官方定義裡是按需載入的知識、指示或工作流程,一個資料夾放著說明檔,可以帶腳本、參考資料和素材。我的發文 Skill 就是這樣:把選題、寫稿、語氣、發前診斷和我的批准點整理成可重用的程序,省掉每次從頭交代。

但它仍然是交給模型讀的指示。就像一本操作手冊:寫得再完整,翻不翻、照不照做,還是看讀的人。只把紅線寫在 Skill 裡,模型漏讀的那一次,不會有任何失敗訊號出現。這就是「寫在提示詞裡」和「接進控制流」的差別:前者靠模型記得,後者漏不掉。

規則的兩種命運:寫在 Skill 裡,模型漏讀就沒有訊號;接進機檢,每次寫入都會檢查,失敗會變成訊號

Hook 決定時機,時機決定能不能擋

Hook 解決的是「什麼事件發生時要執行檢查」。我的設定很短,示意起來就這樣:

{
  "PostToolUse": [{
    "matcher": "Write|Edit",
    "hooks": [{ "type": "command", "command": "bash content-gate.sh" }]
  }]
}

但 Hook 不是同質的機制,介入時機決定它能做什麼。官方文件寫得很清楚:PreToolUse 發生在工具執行前,回報「不通過」可以真的擋下那次動作,甚至回傳允許、拒絕或升級詢問;PostToolUse 發生時工具已經執行完,「不通過」只會把原因顯示給 AI,不能撤銷剛才那次寫入。另外還有一個接線陷阱:PreToolUse 的 Hook 逾時的話,工具會照常走一般流程,不會自動變成一道可靠的閘。

名字叫 Hook,不代表它一定能阻止動作。要看三件事:事件發生在動作前還是動作後、能不能拿到這次呼叫的參數、失敗會不會改變下一步。

Hook 的時機軸:PreToolUse 在工具執行前可以擋下,PostToolUse 在動作發生後只能回饋、不能撤銷

打開機檢

我的內容機檢掛在 Write/Edit 之後,它不會掃整台電腦。內部只做幾件事:

收到事件 JSON
  ↓
讀取 tool_input.file_path
  ↓
確認副檔名與掃描範圍
  ↓
排除引用、程式碼與註解
  ↓
比對已知規則
  ├─ 命中:不通過+原因
  └─ 未命中:通過

第四步要多說兩句。掃描前會先排除 code fence、引用區塊和 HTML 註解,因為教學文章常常需要「示範一句錯的」。沒有這一步,這篇文章自己就會被機檢擋下,因為等一下我就要貼一句違規句。誤擋跟漏擋一樣,都會讓人不再信任檢查。

內容機檢的內部五步:收事件、讀路徑、確認範圍、排除引用、比對規則,命中回報原因、未命中放行

它擋的是幾類已知、可重複比對的問題:疑似虛構事件的句型、教學文的假驚訝開場、不能公開的敏感資訊與金鑰樣式,還有明確的 AI 套話。完整的比對式和詞表不公開,公開了等於教人繞過。它管不到整篇文章的事實與觀點,這條邊界後面再談。

一次從不通過走回通過

先回答一個大家可能會有的疑問:這個回饋迴圈是誰在跑?不是我叫 AI「寫完去驗證一下」,也不是 AI 自己想到要檢查。機檢是底層自動跑的:AI 每次寫入草稿,工具環境就會呼叫它,「不通過」的原因會直接出現在 AI 眼前,它下一步自然就是照著修。AI 平常也會自己說「我檢查過了」,但那是自述,可能說錯也可能偷懶;這條訊號是環境給的,不用 AI 記得,也由不得它跳過。

這一步的目的很單純,像消防演習:不是真的失火,是確認警鈴會響、逃生門推得開。我放一句一定會命中、而且是我最怕 AI 寫出來的句子進草稿路徑:

有讀者私訊我說,這套流程幫他省了一半時間。

這種句子就是 AI 幫忙寫社群內容時最危險的地方:流暢、好看、很能收尾。但如果根本沒有那則私訊,它就是編造。照 Hook 契約送入 JSON 後,機檢回報「不通過」,錯誤訊息指出「疑似編造事件句型」。

修法要看仔細。機檢只知道這是一種高風險句型,不知道那則私訊到底存不存在。存不存在,要人去查:真的有,附上出處留著;查不到,整句拿掉。測試裡我把它改成「這套流程有沒有幫到別人,我還沒有證據」,同一條路徑再跑一次,「通過」。判斷是人的,訊號是機器的。

同一天我也重跑了機檢自己的測試套件:10 個測試稿對應 13 項回報結果檢查,結果 13 PASS、0 FAIL。這能證明目前寫進套件的行為都成立,不能證明機檢沒有漏網的未知規則。

受控測試走一圈:一句編造的讀者互動被擋下並回報原因,人查證後修正,同一條路徑放行

這道機檢的兩個誠實邊界

第一個邊界:它掛在 PostToolUse,檢查發生時,檔案已經寫下去了。它的價值不是「錯誤內容寫不進來」,而是「錯誤稿不會安靜地被當成完成」。AI 收到具體位置和原因,可以只修命中的地方再重跑。真正難以回收的動作,像發布、寄信、刪除,應該在 PreToolUse、權限規則、沙箱或交付出口前就擋,不能靠事後回饋。OpenAI 的 agent 框架有個對照:輸出護欄可以拒絕最後的候選輸出,但過程中已經執行的工具呼叫都留在紀錄裡了。拒絕輸出和撤銷動作,從來是兩個問題。

第二個邊界:「通過」只代表沒有命中目前寫進去的規則。哪些問題判定得了、哪些判定不了,其實畫得出一條線:禁用詞、句型樣式、金鑰樣式、格式與範圍,這些說得清楚,交給機器;事實真偽、來源是否支持主張、值不值得認領公開,這些說不清楚成規則,留給人。說得清楚的才接得進去,這也是 Day 2 那句「人工判斷沉澱成驗證」的實際門檻。

可判定光譜:說得清楚的規則交給機器,說不清楚的判斷留給人

這套機檢實際替我省掉的,是兩種重複工作。一是發文前的敏感資訊掃雷:金鑰樣式、不該公開的資訊,不用再靠記憶提心吊膽。二是不用每次寫作都把同一批規則重新提醒 AI 一遍,就算漏講也有底。省下多少時間我沒有量測,所以不寫數字。

官方和研究都往同一個方向走

這不只是我的土做法。OpenAI 那篇 Harness Engineering 文章有一句我很認同的主張:文件不足以維持一致性時,就把規則提升成程式與工具。Anthropic 的評估指南也給了三條很實用的原則:能用固定規則評的就先用固定規則,再考慮用模型當評審;模型評審要跟專家校準,還要留「不知道」的出口;以及,agent 自己說任務完成不算數,要看環境裡的最終狀態。換到內容產線,AI 說「已查證」不算證據,來源台帳和連結才算。

近半年的研究也在收斂到同一個工程方向:能形式化的規則,搬進程式碼、資料格式或外部驗證器;無法形式化又要承擔風險的決定,交給人。三個例子,各自帶著邊界:

  • 〈From Prompts to Contracts〉把來源邊界、輸出格式與紀錄規則搬進程式碼層的檢查。270 次邊界測試全數通過程式碼層檢查,但完整合約只有 198 次通過,失敗集中在交給模型自己組的檢查。可判定的條件搬出提示詞有效;模型自己的判斷仍會失敗。
  • 〈Solver-Aided Verification〉先把政策編成形式化約束,在執行前攔下違規的工具呼叫。加了檢查器之後,無效的寫入呼叫仍有 29%。能事前硬擋,不代表規則已經寫完整。
  • 〈The Verifier Tax〉在 2,970 條 agent 軌跡裡,最多攔下 94.1% 的不合規提案,但多數設定下安全又成功完成任務的比率低於 5%;被擋之後能自己修回來的比率,依模型和領域從兩成掉到接近零。擋下來會改變控制流,不會自動讓 AI 知道怎麼修。

最後這點對內容產線特別重要:機檢回報失敗只是起點,AI 拿到原因之後會不會修、修得對不對,是另一段工程。這個方向和我的做法相鄰,但要說清楚,它們不能反過來證明我這套機檢有效。

擋下來之後:提案被擋、AI 不一定會修、需要設計恢復路徑,擋住不等於任務完成

人留在哪裡

我不需要自己重看每一個禁用詞,但文章裡的經驗是不是真的發生、來源能不能支持主張、這篇內容值不值得公開,不能交給比對規則的程式。機器負責一致地檢查已知問題;我保留事實、觀點與公開批准。

要我說一條分界的話:說得清標準的,交給機器;說不清的,留給我。禁用詞、樣式、格式這些寫得成規則的,交出去之後機器比我穩;事實真偽、來源支持、值不值得認領,每一篇長得都不一樣,寫不成規則,就留在我手上。

機檢負責已知句型、敏感樣式與 AI 套話,人負責經驗真偽、來源支持與認領批准,通過不是正確證明

想自己接第一條規則的話

把這篇濃縮成五步:

  1. 挑一條說得清楚的規則。判不了的先別接,光譜右邊的留給人。
  2. 決定時機。動作前要硬擋用 PreToolUse,寫完給回饋用 PostToolUse
  3. 寫檢查。限定掃描範圍、排除引用和程式碼,命中就回報「不通過」和原因。
  4. 照事件契約接線。從 JSON stdin 拿參數,別當位置參數傳,那是我踩過的坑。
  5. 驗證整條迴路。放一句必中的測試句,確認從「不通過」到「通過」真的走得完。

今天能證明到哪裡

主張 證據 邊界
Skill 定義選題、產稿、品質鏈與批准點 現有 Skill 檔 是流程契約,不是單次執行紀錄
寫入草稿後會呼叫內容機檢 現役 Hook 設定 只在目前的工具環境成立
機檢從 JSON stdin 取得目標檔案並限定範圍 機檢程式與接線測試 不在掃描範圍的檔案會放行
受控演習得到「不通過 → 通過」 2026-08-26 實跑 只證明當次輸入、規則與環境
機檢套件 13 項檢查全數通過 2026-08-26 重跑套件 只證明已寫進套件的行為
位置參數呼叫會靜默放行 2026-08-26 實跑 不能外推成歷史草稿全部漏檢

今天先證明一件小事:能明確判定的問題,可以從提示詞裡的提醒,變成每次寫入都會回傳的外部檢查結果。但只要檢查器是程式,它也可能寫錯。這次甚至已經看到,接線方式錯了,同一份違規稿就會從「不通過」變成「通過」。它可能漏判,也可能把正常內容擋掉;AI 被擋之後,還可能不知道怎麼回到正確的路。下一篇就來拆:誰來檢查檢查器?


參考資料:

我平常在這些地方輸出,有興趣歡迎交流:

  • Threads:@ci.fullstack — 我平常在這裡輸出 AI 驅動開發的心得
  • Discord:邀請連結 — 一起聊 AI 驅動開發,不限主題

上一篇
Day 2|先把地圖攤開:我手上的 AI 內容工作流
下一篇
Day 4|AI 工作流的紅綠燈,也要先測過
系列文
情報進來,內容發出去:30 天拆一條每天真的在跑的 AI 內容產線12
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言