「human-in-the-loop」(人在迴路裡)這個詞這兩年很紅,但它常被講得很空——好像只要「人有在看」就算數了。今天我想用兩個真實案例,講清楚它到底是什麼:它是一套具體的分工,而且這套分工能不能運作,取決於一件很少人提的事——人跟 AI 之間的「接口」有沒有對齊。
前六天其實一直在鋪這件事。今天把它收攏成一個完整的樣貌。
我做過一個稽核軌跡的需求:系統原本記錄操作的方式不足以應付資安稽核,得補上「誰、在什麼時候、做了什麼」的完整軌跡。這件事我是這樣分工的——
第一步,在 claude.ai 上做分析與決策。 我跟它一起釐清:現有記錄缺了哪些欄位、稽核到底要求什麼、哪些操作要記、記在哪一層(應用層還是資料庫層)。這一步是「想清楚要做什麼」,是發散、討論、權衡的過程。claude.ai 的對話介面適合這種思考。
第二步,把結論固化成規則。 討論收斂後,我不是直接叫它動手。這一步其實是 AI 自己在討論到一個段落時主動提議的——我問它要怎麼讓後續的工作階段延續今天的共識,它的回答是:「最有效的方式是在專案根目錄放一份 CLAUDE.md——Claude Code 每次啟動會自動讀取,不需要每次對話重新說明。」
於是我們把哪些表要掛稽核 hook、記錄哪些欄位、為什麼這樣設計,都寫進了 CLAUDE.md。這裡有個細節我覺得特別值得記下來:它還提醒我要區分「長期規範」和「一次性任務」——像欄位驗證這種背景知識該寫進 CLAUDE.md,但「這次要實作某個 hook」這種一次性的工作不該寫進去,否則「會讓它每次啟動都以為有工作要做」。這一步很關鍵,它把「一場對話裡的共識」變成「一份每次都生效的規格」。
第三步,交給 Claude Code 實作。 有了固化的規格,Claude Code 就能照著把稽核 hook 實作出來,而且因為規則寫在 CLAUDE.md 裡,它每次都遵守同一套設計,不會這次這樣、下次那樣。
這個分工還有一個漂亮的收尾。當那次對話變長、我問它該不該另開一個新的工作階段時,它說:「建議另開,而且時機正好——CLAUDE.md 剛更新完,等於這一段的成果已經固化成文件,不需要靠對話歷史來保存。」——這句話正好說明了「記」這一步的意義:共識一旦固化成文件,就不再依賴脆弱的對話記憶。
你看這個分工:claude.ai 負責「想」(分析、決策),CLAUDE.md 負責「記」(固化共識),Claude Code 負責「做」(實作)。而人站在每一個交接點上——決定討論何時收斂、決定哪些結論值得固化、決定實作出來的東西對不對。 這就是 human-in-the-loop 具體的樣子:不是「人在旁邊看」,是人握著每一段的方向盤。
但分工設計得再漂亮,還有一個前提:人跟 AI 交換的資訊要對得上。 少了關鍵的一項,分工就會空轉。這件事我最近踩了一次,值得完整講。
事情是這樣:我要把一個舊專案的容器底層,從一個舊版的 Debian 升到新版(trixie,也就是 Debian 13)。我把 Dockerfile 和套件清單丟給 AI,它很快分析出升級後會壞掉的幾個系統套件(pdftk、p7zip、ImageMagick 的路徑…),一個一個給我對應的修法。這部分它做得很好。
但接下來就開始鬼打牆了。我照著改、實際去 build,一直失敗,而且錯誤訊息極度誤導——最後卡在一個地方:安裝一個只有 53KB 的極小套件,竟然報「記憶體不足(Cannot allocate memory)」。而那台機器有 16GB RAM、12GB 可用。
我們就繞著這個假象追。AI 一開始也被套件相容性帶著走,分析了七八輪各種套件版本、policy 檔格式、執行檔改名……方向都對,但都不是真凶。
真相是什麼? 當 AI 看到「53KB 的檔案卻報記憶體不足」這個矛盾時,它其實反應很快,立刻說這「跟套件本身完全無關」,並推導出真正的原因:那台 build 機器的 Docker 版本太舊。 舊版 Docker 的安全過濾機制(seccomp)會把新版系統用到的一個系統呼叫(clone3)擋掉,導致解壓縮時無法建立執行緒,於是被誤報成「記憶體不足」。它甚至精準地區分了「這是 Docker 版本的問題,不是作業系統核心的問題」。
問題是——這個真相,我其實一開始就能讓它少繞很多路。
追到後面,AI 問我那台機器的實際版本。我回:「這台測試機很久了,Docker 版本是 18,Ubuntu 版本是 16。」
它一看就說:「這解釋完了……我們花了好幾輪在追一台老測試機的幽靈。」
關鍵就在這句「好幾輪」。那台機器的 Docker 18、Ubuntu 16——這兩個數字,是整件事的核心線索。如果我一開始就連同 Dockerfile 一起,把這台機器的環境版本攤給它,它極可能第一時間就往「build 環境太舊」的方向查,而不是陪我在套件相容性裡繞七八輪。
我犯的錯,跟很多人跟 AI 協作時一樣:我預設「問題在我改的那份設定裡」,就只給了它設定檔,卻沒給它「這份設定要跑在什麼環境上」。而環境,往往才是真凶藏身的地方。
這件事之所以值得寫,是因為它跟前面那個順利的稽核軌跡案例,剛好是一體兩面:分工要能運作,接口必須對齊。 稽核軌跡那次,人和 AI 在每個交接點的資訊都對得上,所以 1+1 順利大於 2;trixie 這次,AI 的分析能力其實在線上(它一看到矛盾就破案了),卡住的是我漏交了一項它需要的脈絡,害那個「1」在錯的方向上空轉了好幾輪。
把兩個案例擺在一起,human-in-the-loop 的完整樣貌就清楚了。
它首先是分工——像稽核軌跡那樣,人負責想清楚方向與決策、固化共識、驗收成果,AI 負責在既定方向上分析與實作。各司其職,這是 1+1>2 的基礎。
但分工要能運作,接口必須對齊——像 trixie 那樣,如果人握著關鍵脈絡(機器的環境版本)卻沒交出來,AI 再會分析,也只能在錯誤的方向上使力。它不是不夠聰明,是你沒給它破案需要的那塊拼圖。
所以 human-in-the-loop 真正的意思是:人不只是「在迴路裡」被動把關,而是主動維護那個讓分工能運作的接口。 你給的脈絡有多完整,直接決定了 AI 那個「1」能不能真的加成到「大於 2」。尤其是環境資訊——作業系統、版本、這台機器跟別台有什麼不同——這些「背景」在順利時你不會想到要講,但問題一旦跟底層有關,它就是破案的鑰匙。這是人在協作裡,另一個無法外包的責任。
trixie 那次,是「人漏給了脈絡,害 AI 繞路」。但還有另一種更麻煩的情況:你把脈絡都給了,工具也全部回報「沒問題」,但東西就是不動。 明天這個案例,我跟 AI 繞了整整兩天——所有檢查都是綠燈,git push 成功、自我檢測 26 項全過、檔案權限完全正確,但它就是不觸發。最後逼出來的真凶,藏在一個所有人都信任、卻正在說謊的系統指令裡。