我把自己那條情報流程的程式打開,數了一下:裡面有四個 agent()。
三個負責掃不同來源,包在一個 parallel() 裡同時跑;第四個接手把結果整理成日報。
然後我看外層。外層完全不是那回事:掃描的退出碼是多少、Markdown 檔在不在、轉檔成不成功、HTML 在不在、交付回傳什麼,五個條件一路往下判,該停就停。沒有任何一個地方需要誰「決定」。
一邊是四個 agent(),一邊是一串固定的 if。這個反差就是今天的題目。
因為四個 agent() 只能證明一件事:我用了四次那個包裝。 它證明不了那四份工作都需要 Agent。
所以今天這篇不教你怎麼多加一個 Agent。方向剛好相反,是先把包裝拆掉,看裡面到底是什麼。
函式名稱不算。角色數量不算。提示詞長度也不算。
parallel() 也不算。它只是「這幾件事可以同時做」的形狀,跟「誰決定下一步」是兩回事。
這幾件事都很容易拿來自我說服,因為它們看得見、數得出來。但它們都不是證據。
不是「用 AI」或「不用 AI」的二選一,也不是「Agent」或「土法煉鋼」。實際上有四格:
| 做法 | 什麼時候先用它 |
|---|---|
| 固定程式 | 條件、分支與輸出都能事前列出來 |
| 單次模型處理 | 需要語意理解或改寫,但拿到答案後不會再換工具或查詢 |
| 有限 Agent | 新的觀察會改變下一個查詢或動作,而且這份工作能被驗收 |
| 人工決定 | 涉及作者偏好、認領、批准、對外副作用,或機器沒辦法安全判斷 |
這張表最有用的地方不是分類本身,而是它提醒了一件事:同一個函式裡面,常常同時裝著這四類工作。
所以正確的動作通常不是替整個函式貼一個標籤,而是把它拆開。
第一道門問控制流: 執行之前,能不能把合理的步驟跟分支列完?
能列完,就先寫固定程式。如果只是需要理解一段文字,但拿到答案之後不會再換工具、也不會再查一次,那先試單次模型處理。
第二道門問證據。工具回傳的新觀察,是不是真的改變了下一個動作?而且這份工作能不能被驗收?Day 18 那套驗收是分開看兩件事:最後產物對不對,以及中間過程走得對不對。這份工作套得上去嗎?
兩道門都過,最多也只能標成「Agent 候選」。 這還不是採用。
因為「這份工作的形狀適合 Agent」跟「模型做這件事真的比強基線好」是兩回事,而後者要另外跑。
我把那四個 agent() 各自過了一次門:
| 工作單元 | 暫定裁決 | 最簡單的下一個基線 |
|---|---|---|
| 腳本來源掃描 | 拆開 | 固定命令與 JSON 解析交給程式,相關性判斷先試單次模型 |
| Threads 來源補查 | Agent 候選 | 固定第一手查詢,有缺口才交給有限候選 |
| X 與新聞來源補查 | Agent 候選 | 同上 |
| 日報整理與發文建議 | 未證明 | 先試單次模型處理,加上確定性的寫檔 |
有兩件事要講清楚,不然這張表很容易被讀反。
第一,四個呼叫的 Agent 成效全部都是「沒跑過」。我沒有做過任何比較。
第二,「拆開」不是 Agent 成功,「Agent 候選」也不是 Agent 必要。這張表是設計紀錄,記的是下一輪該測什麼,不是成績單。
我把外層那些關卡改寫成純函式的時候,發現除了上面那五個條件,前面還有一道我原本沒算進去的:第一手採集成功了嗎?如果失敗,准不准用備援?加起來六道關卡、八條出口。
八組狀態就這樣重播一次:全部成功、掃描失敗、Markdown 缺席、轉檔失敗、HTML 缺席、交付失敗、第一手採集失敗且不准用備援、第一手採集失敗但備援完成。
八組都走到事先寫下的出口。其中 2 組完成,6 組停下來交回檢查。
那個 2 比 6 不是什麼抽樣比例。八組是刻意設計的:每一個失敗分支各配一個案例,再加兩條成功路徑(一般成功,以及第一手採集失敗但備援補上)。目的是把每個分支各走一次,所以比例是設計的結果,不是統計出來的。
這組的結論很直接。這些固定條件已經能決定下一站,沒有理由再讓模型判一次。
參考模組沒有接模型,也沒有接外部工具。稽核裡的模型 Agent 呼叫、外部呼叫與寫入都是 0。
這三個 0 我要講得更精確一點:產生它們的那個函式根本沒有計數邏輯,它就是直接回傳 0。 稽核檔自己也標了 telemetry_status: not_collected。所以正確的說法是「宣告為 0」,不是「量到 0」。程式裡壓根沒有一條路會呼叫模型或外部服務,於是它宣告 0。
而且八組全是離線的固定合成狀態,不是正式排程,更不是發布紀錄。
第二組用一份固定、離線、唯讀的合成來源目錄,跑三個案例:
| 案例 | 拿掉補查角色 | 固定參考控制器 |
|---|---|---|
| 第一筆就有支持資料 | 完成 | 完成 |
| 第一筆同名但語意模糊,第二筆才支持 | 需要決定 | 看完第一筆後改查第二筆,最後完成 |
| 允許的資料都不支持 | 需要決定 | 看完第二筆後回「查無」 |
每一步都分開保存兩個欄位,一個記「看到了什麼」,另一個記「因此決定做什麼」。
這個分欄不是我發明的。ReAct 那篇論文的做法就是把推理、動作跟外部觀察交錯在同一條軌跡裡,讓新的觀察回到後續推理。從那裡可以抽出一個能檢查的訊號:不是「有沒有呼叫工具」,而是能不能從紀錄裡指出「因為看到了這個結果,所以換了那個下一步」。
還有一件事:「需要決定」是安全出口,不是測試失敗。查不到就說查不到,這是對的行為。
那第二組實驗到底說明了什麼?它說明第一筆資料的狀態不同,下一步就不同。
它沒有證明這個決定一定要交給模型。
事實上,那三組保存下來的分支,全都能由一個固定規則的參考控制器處理完。那個控制器不是模型,它就是規則。
所以「會看回饋再轉彎」只是必要線索,不是充分條件。W3C 的狀態機規格早就定義了這件事:狀態收到事件之後,可以依事件名稱跟條件選擇要轉去哪裡。普通狀態機本來就會讀回饋、本來就會改走另一條路。
那什麼時候才真的需要?要同時滿足兩件事:真實來源缺口的合理查詢難以事前列完,而且有限 Agent 在相同輸入與相同限制下,確實贏過固定程式或單次模型。
第二件事這次沒跑。
把裁決寫成一張矩陣,會清楚很多:
| 最強的非 Agent 基線 | 有限 Agent 候選 | 裁決 |
|---|---|---|
| 通過 | 通過 | 仍然選固定的,或較簡單的那個版本 |
| 通過 | 失敗 | 選固定的,把 Agent 失敗原因存下來 |
| 合規地回「需要決定」 | 通過硬規則,而且證明有難以列完的回饋依賴 | 保留為 Agent 候選 |
| 失敗 | 失敗 | 改規格、把工作縮小,或交回人工 |
第一列是重點:打平的時候選固定的。 不是因為固定比較高級,是因為它比較好懂、好修、好驗。
這條在稽核裡不是一句口號,它是一個欄位:決勝規則寫著 simpler_baseline。同一份快照裡還鎖著四步決策順序:先拆可分離的機械步驟、再看回饋依賴、回饋沒被證明就先試單次模型、能列完的轉移就用固定程式。順序被 schema 鎖死,不能臨場調換。
還有兩條線不能踩。不可以故意把固定基線做弱,也不可以把基線那個合規的安全停手算成失敗,只為了替 Agent 製造一場勝利。
如果哪天真的要比,至少要四層基線:固定程式、單次模型、固定的兩段模型流程、有限 Agent。
四組要站在同一條起跑線上:同一個題目、同一個模型版本、同一份來源快照、同一批工具、同樣的輸出形狀。時間、工具呼叫次數、重試與成本的上限也要可比,不能讓某一組偷跑。
而且一次只拿掉一個角色,其他介面用既有產物或原樣傳遞補齊。
為什麼要這麼囉唆?因為資源差會冒充角色價值。
Anthropic 在自家多 Agent 研究系統的分析裡提到,在那個評估上,光是 token 用量就解釋了 80% 的表現變異;同一頁也報告 Agent 大約用掉一般聊天 4 倍的 token,多 Agent 大約 15 倍。那些數字是他們的研究評估,不是內容產線,也不是等預算比較,我不會拿來預測我這裡會有多少增益。
但它把一個混淆因素講得很白。如果 Agent 那組拿到更多上下文、更多工具呼叫、更多運算量,它贏了也不代表角色設計本身有效。
他們另一篇談長時間開發 Harness 的文章裡,早期那組完整 Harness 與單一 Agent 的對照,一邊跑了 6 小時、花 200 美元,一邊跑了 20 分鐘、花 9 美元。這種對照同時改變了時間、成本、範圍跟流程,改太多東西,就看不出是哪一個造成差異。那是原文的案例,不是我的成本。
題組也要挑。Anthropic 的 Agent 評估指南建議同時放「應該搜尋」和「不該搜尋」的案例——如果題目全都是必須補查的情況,Agent 很容易被測成贏家。我那三組案例裡,第一組就是「第一筆證據就夠了,不用再查」,放進去就是為了這件事。
至於方法本身有沒有前例:有一份研究把軟體修補拆成問題定位、修補產生、修補驗證三個固定階段,不讓模型決定未來動作,在當時那個基準上回報 300 題解出 96 題。那個數字只屬於論文當時的基準、模型與成本設定,我不會借來當自己的成績。能借的是方法:先把「拿掉 Agent 的強版本」做好,再談 Agent 多帶來什麼。 弱基線只會替複雜架構製造假勝利。
昨天那篇我寫過一個問題:標準答案跟判定規則如果出自同一手筆,全部通過就只能證明可重現,不能證明判斷正確。
今天這份稽核有同樣的洞。 八組關卡加三組補查,十一個案例的斷言全部通過。但那些「預期結果」是我照著自己寫的判定函式手寫出來的,跟判定邏輯互相依賴。所以十一分之十一不是外部驗證,它是「我確保期望值跟實作一致」的必然結果。
第二個洞是分支覆蓋。判定規則樹有四條分支,實際被走到的只有前三條;最後那條(不含可分離的機械步驟、觀察也不改變下一步、連單次模型基線都不支持)沒有任何案例或測試走到過。外層那個判定也一樣,它的「非確定性」分支同樣沒被走到,因為唯一那組外層控制永遠是可列舉、不需要模型判斷。
兩條規則寫了,但沒被驗過。「有這條規則」跟「這條規則被驗過」是兩件事。這句話我這個月不是第一次寫了。
我那份每日發文的責任文件,把三件事留給我自己:選題要我拍板、對外發布要等我明示同意、讀者回覆也要另外確認。
情報日報可以排序候選、可以提出建議,但不能把建議變成「作者已經採用」的立場。
所以架構選項從來就不是「固定程式」跟「Agent」二選一。遇到作者偏好、具名經驗、對外動作的時候,停在人面前就是正確答案。
這裡要分開兩件常被混在一起的事,一件是語意能力,一件是行動授權。模型讀得懂,跟模型可以替你按下發布,中間隔著一整條責任線。
每個工作單元至少要回答九件事:它現在長什麼樣、最省的做法是什麼、步驟能不能事先列完、會不會被回饋牽著走、誰來驗、卡住的時候交給誰、裁決是什麼、成效跑沒跑過,以及為什麼是這個裁決。
欄位名是程式裡的原文,對照一下:simplest_baseline 是最省的做法、enumerable_steps 是步驟能不能列完(partly =只有一部分能)、observation_changes_next_action 是會不會被回饋牽著走、human_exit 是卡住時的人工出口、verdict 是裁決、agent_effectiveness 是成效跑沒跑過。
{
"work_unit_id": "threads-source-followup",
"simplest_baseline": "deterministic_reference_then_bounded_agent_candidate",
"enumerable_steps": "partly",
"observation_changes_next_action": "yes",
"human_exit": "return_not_found",
"verdict": "agent_candidate",
"agent_effectiveness": "not_run"
}
最後那個欄位是整份稽核裡最誠實的一欄。它寫著「沒跑過」,而且四個工作單元都是這樣。
稽核另外綁了 Day 18 保存的資料,以及一份去識別控制流快照的摘要。兩份都是把整份內容正規化之後重算摘要再比對,對不上就直接拒絕,連偽造一份輸入來自我驗證都會被擋掉。
不過那個比對是對「正規化後的內容」算的,欄位順序或排版改掉不影響結果,所以它擋的是內容被換,不是檔案被動過一個位元組。而且那個摘要沒有金鑰,只能用來檢查內容有沒有變,不是簽章,也不能證明快照就等同那份受保護的原始程式。
還有兩件事得說在前面。欄位裡那個「沿用哪份驗收契約」,寫的是 Day 18 那套契約的名字,意思是「將來要驗就用這套」——Day 19 本身沒有真的跑過它。另外快照上那三個「已移除儲存庫識別、已移除絕對路徑、已移除機密」的標記,是宣告;程式只檢查這三個欄位存在而且為真,不會去驗證清除動作真的做過。
這支的測試 10 條全過。但比「全過」更值得講的是它拒絕了什麼。
有一條專門測「查無支持卻硬答」:參考控制器如果在沒有證據的情況下給出結論,稽核要擋下來。有一條測偽造:拿一份假的上游稽核來自我驗證,要被拒絕。還有一條測得更偏執:做深層比較的時候不准執行物件自己的 toJSON,也不吃 Proxy 或 getter 那種會在被讀取時偷偷改變回傳值的東西。
這幾條的共同點是:它們假設送進來的資料會騙人。這跟前兩天那個「產物自己說通過不算數」是同一個念頭,只是往上又搬了一層。
今天只做採用前的稽核,只回答一個設計期的問題:這個工作單元,有沒有資格讓模型自己決定下一步?
留下來的那些候選要能碰哪些工具、有哪些權限、什麼時候必須停,那是 Day 20 的事。執行時到底由程式還是模型選下一站,留給 Day 21。多 Agent 架構值不值得,要到 Day 24。
今天我不宣稱現行那四個呼叫安全、穩定,或比其他做法好。我也沒有任何速度、成本、成功率或正式流量的數字可以給你。
我只做了一件事:把包裝拆開,逐份問它憑什麼需要一個 Agent。 問完之後,四份工作裡有一份該拆開、一份連單次模型基線都還沒試,只有兩份留著待測。
這個結果對我來說已經夠有用了。在那之前,這條流程裡就只是寫著四個 agent(),沒有一行字說得出它們各自憑什麼。