~/blog/ai-tic-check-that-never-ran

AI Workflow · part 17

[Dev Workflow] 清單上寫著「人工掃」的那一條,從來沒被執行過

cat --toc

TL;DR

一篇技術文過完所有實際會執行的閘——事實查核、中英各一輪外部語感閘、本地模型測可讀性——全部放行。唯一的人類讀者只回一句:那個句型很怪。被點的是「我不會假裝沒有」,一種先宣告自己誠實、再講不利事實的句型。我改去搜「同一個動作」而不是同一組字:中英文各 5 次。語感閘沒抓到,因為它們查的是翻譯腔;根因是我清單上那一條標著**「人工掃」,所以從來沒變成一個動作。解法是把可數的凍成腳本,門檻拿五篇已發布的舊文校準**——會讓舊作不及格的門檻是噪音。

封面:一份稿子通過一排發光的檢查閘門,每一道都亮著綠燈放行,最後一道閘門的牌子上寫著「人工掃」而且是暗的、沒有通電;閘門盡頭站著一個人,手裡拿著紅筆停在一行字上。

白話版:AI 幫你寫的稿子,為什麼會長出口頭禪

先講給沒在碰這行的朋友聽。你身邊大概有這種人:每次要承認自己搞砸什麼,開口前一定先補一句「我這人不騙你」。講一次很誠懇,同一場飯局講五次,你注意的就變成他的口頭禪,而他講了什麼反而記不得。

AI 幫我寫稿,長出了同一個口頭禪。每次要寫一件對我不利的事——量測條件不對等、我判斷錯了、這段是推論不是實測——它都會先寫一句「我不會假裝沒有」再講。承認的部分句句是真的,拿掉哪一句都會讓文章變得比較不老實。多出來的只有宣告本身那一句話。

更麻煩的是,我為了防這種事跑了四發外部審稿(兩個模型、各審兩種語言),全部說沒問題。因為我叫他們查的是「這段讀起來像不像翻譯的」,不是「這段讀起來像不像 AI 寫的」。這是兩種病,而我只裝了其中一種的閘。

最後把它揪出來的是唯一的人類讀者,回饋只有一句:那個句型我一直覺得很怪。這篇就是我從那一句話,一路追到自己寫作清單上一條標著「人工掃」、因此從來沒有人掃過的檢查。怎麼解很無聊,無聊到我一直沒動手:把數得出來的部分寫成一支腳本,讓它在我按下發布的時候直接擋人。


前言

工地驗收有一種很經典的失敗:牆上貼著十條檢查項目,九條有人簽名蓋章,第十條寫著「目視確認」。它不是被跳過的,它從一開始就不是一個動作。

Part 15 我把 193 個 skill 砍到剩 7 個,Part 16 在追一個 agent 把自己的錯答案存進長期記憶。這篇是同一個病灶的第三面:一條寫在文件裡、但沒有任何東西強制執行的規則,跟根本沒有這條規則,差別到底有多大。

答案是差不多一樣大。而這件事是我自己的稿子教會我的。

五道閘全放行,擋下這篇稿子的是唯一的人類讀者

如果你也讓模型幫你寫東西,你大概也裝了一排閘。我的排法是這樣:一篇技術文寫完,先讓 Codex 逐條查事實,再讓 Codex 跟 agy 各跑一輪語感審(中英文各一輪),最後丟給本地的模型當中線讀者,測一般人讀不讀得動。

那篇是洋垃圾跑大模型系列的第三篇。事實查核那關抓到三個錯,修掉之後,四道有實際執行的閘全部放行——第五道根本沒通電。閘不是擺著好看的,有跑的那四道在自己負責的事情上都有出力。

稿子回到我手上。我讀到中段某一節,停住了。停住的地方是這句:

所以頻寬在這裡確實有在做事,我不會假裝沒有。

我當下的回饋只有一句話:那個句型我一直覺得很怪。

這條管線是我搭的,閘是我裝的,稿子是我跟模型一起寫出來的。模型在其他四道閘的表現都對——事實沒錯、英文道地、可讀性沒問題。真正壞掉的是我根本沒裝的那一道。

搜「同一個動作」而不是同一組字:中英文各 5 次

第一直覺當然是把那句改掉,然後收工。

我沒有。我改去搜「同一個動作」而不是同一組字——不搜「我不會假裝」這幾個字,搜「先宣告自己誠實、再講不利事實」這個形狀。搜出來中文版 5 次、英文版 5 次。

被點名的那句之外,中文版還有四句:

「這點我寧可攤開講也不想偷偷改掉」 「這裡我要把話說準」 「不過這裡我得把自己的證物也一起攤開」

英文版的四句長這樣:

"I'm not going to pretend otherwise" "I'd rather flag that than quietly fix it" "Full disclosure:" "I should be exact about what I did here"

一句是口誤,五句是節奏。而且它們專挑同一種位置長:每次都緊貼在一個對自己不利的事實前面。

病徵是表演式坦誠:先宣告自己誠實,再講那個不利的事實

我給它取的名字是表演式坦誠(performative candour)。定義很短:每次要承認一件對自己不利的事,先宣告自己要誠實,再講。

五個位置有一個共通點,而且是這個病最狡猾的地方:後面接的都是真的不利事實。量測條件不對等、我判斷錯了、這段是推論不是實測——五件事全是真的,寫出來也對讀者有用。多出來的是前面那句宣告。

它跟兩個鄰居長得像但不一樣。清嗓子(throat-clearing)是任何論點前面的暖場,不管講什麼都先鋪一句。諂媚是捧讀者。表演式坦誠捧的是作者。

高風險文體很明確:第一人稱的除錯文、偵探文。因為這種文章每一節都有東西要承認,一節長一次,整篇就從技術紀錄變成人格表演。而這正好是我最常寫的那種文體。

解法只有六個字:留事實,砍宣告。修訂版把那五個承認一字不刪,只把前面的宣告刪掉。稿子沒有變得比較不誠實,只是不再一直提醒你它很誠實。

順帶一提,我這份清單的起點是 Wikipedia 編者整理的 AI 寫作特徵表——很值得整份讀過。表演式坦誠還不在上面。

語感閘為什麼放行:它們查的是翻譯腔,不是 AI 味

為什麼四發外部審稿全部沒抓到?

去看它們的提問就懂了。那兩輪語感閘問的是同一個問題:這讀起來像不像從中文翻過去的?

答案是不像。那五句英文全部道地,其中一家的評語是整篇讀起來無可挑剔。它們給的是正確答案,只是我問錯了問題。

草稿由左往右穿過四道閘,每一道都蓋上「過」——事實(是真的嗎)、語感(像翻譯嗎)兩道、讀者(看得懂嗎);走到第五個位置時,那裡只有一個虛線空框,標題寫著「人工掃」。那裡沒有閘,所以同一個修辭動作直接從缺口走了出去五次。

翻譯腔和 AI 味是兩種病。我裝了前者的閘,然後預設它會順便涵蓋後者。它不涵蓋。更麻煩的是這兩件事成反比:模型越流暢,越乾淨地通過流暢度檢查,剩下的破綻就越是結構性的——出在同一個動作重複幾次,不在用字上。你不可能用查用字的閘,抓一個查不到單字的病。

根因:那條檢查的標題寫著「人工掃」,所以它從來沒被執行過

追到這裡我才去翻自己的寫作 skill。翻到之後有點想笑。

那份 skill 裡本來就有一節在講這個。清單上列著句長節奏、段末金句密度、翻轉句濫用、破折號濫用——正好涵蓋草稿裡那些病。內容是對的,而且是我自己寫的。

那一節的標題長這樣:

節奏 + AI 結構痕跡(人工掃,grep 抓不到)

所以它沒有指令、沒有 exit code(程式跑完回給系統的成功或失敗代號)、沒有任何東西會擋住我的 commit。

實際跑過的是這些:機械關鍵詞掃描跑過了、本地讀者席可讀性跑過了、四發外部語感閘跑過了。只有這一條沒跑。而且不是我某一次趕時間決定跳過——是它從來沒有變成一個可以被執行的動作。

一句話:只活在「記得看一下」裡的規則,其實只是一張提醒你有這條規則的便條。

更好笑的是,我前一天才自己寫下一條原則:成熟、重複、而且機器判得出來的判斷,要寫死成腳本,因為 skill 檔每次都會被模型重新詮釋,標準會漂。而這次沒照做的就是我自己。

難的不是 regex,是門檻:拿五篇已發布的舊文當規格

解法的第一半很無聊:把那一節拆兩半。可數的東西寫成腳本;不可數的(這段有沒有資訊量、這是真反對還是稻草人)留給人讀。

腳本本身很快就寫完了,regex(字串比對規則)不是難的部分。難的是門檻要訂在哪。

訂太嚴會發生一件很具體的事:什麼都報 → 你每次都 override → 你養成 override 的習慣 → 這個閘等於不存在。所以門檻不能訂在「好文章應該長怎樣」,得訂在「我實際上都寫成怎樣」。

做法是拿五篇自己已經發布、而且回頭看還算滿意的文章跑一遍,把跑出來的分佈當成規格。

這張表只要看最上面那一列的 0/5,下面三列是拿來對照的:

病徵五篇已發布的實際分佈訂的門檻擋不擋
表演式坦誠0/5 篇有1
翻轉句1 篇到 55只警告
破折號5 篇在 2.7–7.2/千字7.5/千字只警告
的的不休5 篇在 1–6 句6只警告

兩條數線。上面那條是表演式坦誠:我五篇已發布文章的點全部疊在 0,門檻線畫在 1,右邊一整片越線區,而新草稿的叉深深落在裡面。下面那條是破折號每千字:五個點散在 2.7 到 7.0 之間,門檻畫在 7.5,越線區只剩最右邊一條窄縫,五個點一個都沒碰到。

零那一列是整個設計的重點。五篇舊文一次都沒出現,新草稿出現五次——這代表它不是我現在才想加的風格偏好,是漂移。漂移才值得硬擋。其他三列在我的舊文裡本來就有,那是聲音的一部分,擋它們只會擋到我自己。

破折號那列我先錯過一次。第一版我訂 3.0/千字,還覺得這樣叫自律。跑完五篇,四篇不及格。那不是閘,是廚房裡那個一煎東西就叫的煙霧警報器。我把它放寬到 6.5,略高於當時量到的上限 6.4。

然後我又錯了第二次,這次的原因值得單獨記著。做到一半我改了腳本「什麼算正文」(下面會講為什麼),引用被剝掉、分母變小,所有密度整體往上跑。破折號的實測上限從 6.4 移到 7.2,我剛剛才畫的那條 6.5 當場就有一篇舊文越線。門檻只要是按「每單位文字」算的,你一改變什麼算文字,它就得重新校準。 我又放寬一次,再把五篇跑過。

校準完的形狀是:五篇舊文全過,連警告都沒有,新草稿照樣被抓。要的就是這個形狀——對自己的歷史安靜,對新東西大聲

兩次真實攔截:先擋住我的稿,再擋住這篇文章本身

腳本寫完不算數。會擋人的那一刻才算數,而它擋了兩次,兩次都有東西可學。

第一次,它擋住我自己。 我把腳本接進發文閘之後試著發布,終端機吐回 gate-pass BLOCKED。當下的狀態是:中文版修完了,英文版還剩兩處沒改,而工作紀錄上已經寫著「修好了」,流程正準備往下走。擋下來的是腳本。

順著這次攔截還多撿到一個 bug:英文那組 regex 漏了忽略大小寫,所以 Full disclosure 這種大寫開頭的完全沒被比對到。我是被擋下來、去看它抓出來的那份清單,才發現漏抓的。沒擋過你的閘,是你還沒測過的閘。

第二次,它擋住這篇文章,而這次錯的是腳本。 10 個命中,全部是本文為了診斷而引用的那些病句。腳本把引用讀成了自白。

一支分不清引用和自白的檢查器,沒辦法拿來寫一篇討論句型的文章。所以我改成忽略引用區塊和引號裡的文字,只算作者自述。

但這裡有個更重要的動作:回歸測試比解法本身重要。我把同樣那五句去掉引號再餵一次,腳本照樣擋。排除引用不等於排除證據。沒驗這一下的話,我會出貨一個「東西一放進引號就閉嘴」的檢查器,而且短期內完全看不出來。

機械閘抓不到的變體:沒有任何自我宣告,只是太滿意自己

這支腳本抓得到的病是有限的,而且邊界比我以為的近。

那篇文章上線之後,我寫社群貼文推它,英文再過一次語感閘,被攔下一句:

"Clean, reproducible, and answering a question nobody had asked."

那句在講我自己配置錯的一組 benchmark。審稿的判讀是:這是把錯誤包裝成漂亮的洞察,讓錯誤變得很有魅力,而不只是一個錯誤。

它跟剛擋掉的病是兄弟,但腳本抓不到——它一個自我宣告的關鍵詞都沒有。它沒說自己誠實,它只是把一次失敗打磨到發亮。改完是這樣:

"Total user error."

然後同一組審稿讀了這篇文章,而這才是真正值得留下來看的部分。

它在這篇、在這篇整個主題就是這個病的文章裡,又抓到三處。中文的「誠實的收尾在這裡」「講清楚功過:」「這裡是我最該早點想到、卻拖最久的一步:」,英文的 "Here is the embarrassing part" 和 "The honest limit"。它還點出我把自己訂錯的門檻寫成「還覺得這樣叫自律」——把一個錯誤包裝成某種美德的證據,跟社群貼文那句是同一個動作,而且就發生在我解釋完為什麼不能這樣寫的幾段之後。

我的腳本這幾處全給零分。 每一處都符合我自己在前面幾節下的定義,但沒有一處長成我 regex 認得的字串。

真正的極限在這裡,而且比「regex 讀不懂文章」更尖銳:這個病是一個形狀,而 regex 比對的是字串。 我從一份草稿裡抽出五種措辭,就把它們當成了那個病本身。我做出來的閘,抓得到我已經看過的句子。沒看過的,一個都沒抓到。

所以我把那四種新形狀補進表裡、重跑五篇舊文確認沒誤傷、然後改寫了這一節——這就是迴圈在正常運作,只是跟我以為自己在蓋的那個迴圈不一樣。這支腳本不是「表演式坦誠偵測器」,它是一份記錄,記著我們到目前為止抓到過的每一個案例,而且它需要有人一直餵。

分工因此跟我原本想的剛好相反。我以為腳本負責抓、人負責判斷。實際發生的是:人負責抓,腳本負責確保同一件事不會過第二次。

收穫

最花時間的地方:校準,而且是先錯一次的那種校準。 寫檢查器一個下午就好。真正吃掉時間的是門檻,而且我是先訂錯、跑完五篇舊文才發現的。我對「合理門檻長怎樣」的直覺,對照自己已經發布的作品差了大約一倍,方向還是偏嚴的那一邊。信直覺就會出一個狼來了的工具,而狼來了的工具跟沒有工具是同一件事。

可以直接拿去用的作法:翻自己的清單,找出所有寫著「人工判斷」「靠經驗看」的項目,一條一條查它有沒有真的被執行過。 我那條的紀錄是從來沒有,而且查完發現不只那一條。活下來的項目對半拆:可數的變成腳本加 exit code,不可數的留在散文裡。訂數字的時候拿自己已經出貨、而且回頭看還滿意的作品跑一遍——你的檔案庫比你的品味更適合當規格,因為你的品味正是產出那些檔案的東西

通用原則:只寫在文件裡的品質標準,充其量是個人偏好。 能讓某個東西拒絕往下走的那一刻,它才變成標準。中間那片灰色地帶是你以為有,其實沒有。

給用模型寫東西的人:六條

  1. 流暢度的閘跟 AI 味的閘不是同一個閘。流暢的輸出按定義就會過第一個。
  2. 搜「重複的動作」,不要搜「重複的字」。指紋是同一個形狀差不多一節出現一次。
  3. 留承認,砍宣告。一句話如果在告訴讀者你很誠實,那下一句本來就在做這件事了。
  4. 每條寫著「請人工檢查」的規則,把可數的那一半凍成有 exit code 的東西。
  5. 拿自己已經發布的作品校準。會讓你的舊作不及格的門檻是噪音。
  6. 沒擋過你的閘不要信。

這篇是 [AI Workflow] 系列的一部分,同樣在講「規則跟執行之間的落差」的還有這兩篇:

常見問題

什麼是「表演式坦誠」?
每次要承認一件對自己不利的事,先宣告一次自己要誠實,再講那個事實。像「我不會假裝沒有」「這點我寧可攤開講」。承認的部分通常是真的,多出來的是那句宣告。它跟清嗓子(任何論點前的暖場)、諂媚(捧讀者)是鄰居,差別在這個句型捧的是作者自己。第一人稱的除錯文最容易長出來,因為每一節都有東西要承認。
為什麼外部語感閘抓得到翻譯腔、抓不到 AI 味?
因為兩輪閘問的問題都是「這讀起來像不像從另一個語言翻過去的」。那五句全是道地英文,其中一家還評整篇讀起來無可挑剔。翻譯腔和 AI 味是兩種病,流暢度的閘按定義就會放行流暢的輸出。模型越流暢,剩下的破綻越是結構性的,不在用字上。
寫作檢查的門檻該怎麼訂才不會變成噪音?
別訂在「好文章應該長怎樣」,那會什麼都報,然後訓練你養成 override 的習慣,等於沒有閘。做法是拿五篇自己已經發布而且滿意的文章跑一遍,把實測分佈當成規格。會讓你的舊作不及格的門檻是噪音;會讓舊作全過、只對新東西出聲的門檻才是漂移偵測。

接著讀

  • 2026-07-17
    [Dev Workflow] 幫 AI agent 的 skill 減肥:193 個塞爆 2% 預算,砍到剩 7 個

    AI Workflow 系列第 15 篇。某天早上我讀 codex 紀錄,滑到一行:skill 描述被剪短,才塞得進 2% 的 context 預算。我共用的 root 累到 193 個 skill,全載進去撐爆上限,每條描述都被截斷——我天天在用的,被剪掉是為了替我從不碰的一百多個騰位子。這篇講怎麼用 per-agent allowlist(不是刪)砍到 7 個、薄殼配深引擎壓低每個 skill 的載入成本,再用一個閘門加稽核加可逆退場區守住,不讓它肥回去。

  • 2026-07-16
    [Dev Workflow] 一群 AI 交接工作卻不用重講:原來是同一套系統的兩條軸

    這是 AI Workflow 系列裡『兩軸合流』這一段的收尾。回頭看整段路,前面六篇其實在蓋同一套系統的兩條軸:持久知識(我知道什麼,長效、要用再查)和即時狀態(我現在做到哪,易逝、隨時寫)。這篇講清楚兩條軸為什麼互不代替、怎麼匯流到『多 AI 交接』、又受同一套哲學管——以及那條讓一群不完全信任的模型還能安全協作的中心律:沒有收據就不信。

  • 2026-07-15
    [Dev Workflow] 搜尋找得到,卻要每個 session 重推一遍:幫 AI 記憶加一層蒸餾層

    我拿一批 markdown 檔當 AI 的長期記憶,在檢索(搜尋加知識圖譜)之上再疊一層蒸餾層。檢索撈回的是原始材料,每個 session、每個 agent 都得重讀重推一遍;蒸餾層把定案結論冶煉一次、存成一檔一個 claim,之後直接取用。這篇講清楚這層是什麼、為什麼它的目的是『少解釋一次』而不是『逼大家講一樣』、以及我怎麼學會真的去信它。

  • 2026-07-14
    [Dev Workflow] 搜尋找得到筆記、卻連不起來:幫 AI 記憶加一張知識圖譜

    我拿大約 600 篇 markdown 檔當 AI 的長期記憶,分成三層:檔案本身是唯一的真相源、一個搜尋引擎讓它們找得到、一張知識圖譜用概念把它們連起來。這篇先講清楚這個設計、每一層為什麼存在、換來什麼好處,最後才講我建它時走錯的那幾條路。

不想錯過新文章?

訂閱我確保不漏接!

隨時一鍵退訂。