Architecture - 2026-09-20 - 5 分鐘閱讀

企業導入 AI 第四階:寫入與送出,要有人核准

企業導入 AI 的第四階,把寫入與送出拆開,人審擋在工具層而不是寫在 prompt 裡,核准紀錄由系統留下,不靠 agent 自己回報。

Enterprise AIArchitectureAI-Native EngineeringGovernance

這是系列的第四篇。系列從第 0 篇的完整參考架構圖開始,第 1 篇講身份與 gateway,第 2 篇講資料與檢索,第 3 篇講沙箱裡的 agent 與唯讀連接器。第四階對應圖上編號④的那幾格:AGENTS & TOOLS 裡的 Write connectors 與 Send connectors,以及下面那個虛線的 Human approval 方塊,標註寫的是「send & write need a person」。圖上核准的箭頭只連到寫入與送出兩個連接器,Read connectors 不在後面,因為讀取是第三階的工作。這一階變的是出錯的性質。到上一階為止,跑壞了不會在公司外面留下東西。從這一階起,紀錄會被改掉,或者訊息送出去就收不回來。

第四階:寫入與送出,前面擋著人工核准

公司沿用第 1 到第 3 篇的晴川,約 40 人,8 個工程師、2 個行銷。晴川是編的,只用來把這一階走一遍。第三階做完之後,所有人都從身份提供者登入,每通 call 帶著角色走 gateway,問內部材料回來的答案按提問者分過範圍,agent 也可以在沙箱裡自己跑步驟,透過唯讀連接器讀 repo 與工單系統,而且每次跑都留下一份 agent 改不動的紀錄。晴川的 agent 目前做的每一件事,公司外面都看不到。

Write connectors:做錯了還有 diff

第一個方塊把 Agent runtime 接到它可以改的內部系統。在晴川就是一支可以在內部工具 repo 改檔、commit、推分支的 agent,以及一支可以把回覆草稿寫進工單的 agent。

寫入跟送出的差別在於:改動留在公司自己控制的系統裡,而且有一個先前狀態可以回去。錯的 commit 有 diff,復原花的是內部的時間,不是客戶看得到的東西。這也是為什麼圖上寫入跟讀取是兩個連接器,而不是同一個連接器加一個開關:能讀整個 repo 是一個合理的設定,同樣範圍拿來寫就不是。做到了是這樣:每個寫入連接器寫明它能改哪些系統、系統裡的哪些東西,每一次寫入都留下 diff 或可還原的版本,人不必問 agent 就能還原,而且這次寫入掛在為該工作流開的帳號上,不是掛在當初順手借出帳號的那個人身上。

Send connectors:做錯了已經在外面

第二個方塊是任何會離開公司的東西。在晴川就是回給開單客戶的那則回覆、發到公司自有管道的貼文、寄給供應商的信。

這裡沒有 diff。內容寫得好不好,跟它該不該送出去,是兩個問題,第二個問題事後問已經來不及。我自己對外發佈的規則,是最接近這個方塊的實際作法:每一次對外發佈都要有人在當下點頭,不是事前一次授權一整批。有一個推論很容易漏掉:核准只覆蓋當初給的那個動作,不會順延到旁邊那一個。最近一次發佈,兩則貼文都已經核准,其中一則的編輯視窗被一個「請同意更新後的服務條款」的對話框蓋住。同意條款跟發貼文是兩回事,所以那一輪就停在那裡等人,沒有自己點過去。做到了是這樣:送出連接器列得出自己有哪些管道、送給誰,每一次送出都帶著放行它的那筆核准,而且一筆核准對的是一次送出,不是一類送出。

Human approval:「不可以」實際擋在哪裡

第三個方塊畫成虛線,顏色跟連接器不一樣,位置在 Agent runtime 跟上面兩個連接器中間,標註寫的是這裡需要一個人。多數公司蓋這個方塊的方式,是把規則寫進 prompt:不要發佈、不要 merge、不要動客戶資料。

prompt 是一個請求。模型可能誤讀,可能在長 run 裡忘掉,也可能在想幫忙的時候把它繞過去。一個被拒絕的動作不是請求,沒有另作解釋的餘地。我自己的設定裡,這道拒絕擋在工具層:推分支過得去,merge pull request 跟刪遠端分支會被工具擋下來,擋的不是一句叫 agent 不要做的話。這件事我是實測過的,不是假設。實際效果是 session 把 PR 備好,merge 由我自己按。

對公司來說有兩件事跟著成立。每一條「agent 不能做這個」都要附上它擋在哪裡:作業系統層、工具層,或平台上的帳號權限。只寫在 prompt 裡的是提醒,而設下真正那道擋的人,是管帳號與工具的人,不是寫 prompt 的人。第二件是邊界的大小。我自己的 runtime 強制的邊界是檔案系統,不是 agent 搆得到的一切。被關起來的 agent 仍然會透過網路跟它的模型供應商通訊,那段流量不在箱子裡。做到了是這樣:每一個寫入、每一個送出,都指得出一個執行點,而且把 prompt 裡所有關於權限的句子刪掉,agent 能做的事不變。

核准的紀錄

一筆事後找不回來的核准,只對當初點頭的那個人存在過。這一階至少要留下四格:哪個 agent 或哪個人動的手、對什麼、何時、誰點頭。

我自己還沒做到,而沒做到的部分正好是重點。我的發佈紀錄有時間、品牌、文章代號、語言、標題、平台、狀態、備註、網址,「誰點頭」躺在備註那段自由文字裡,所以要回答某一則是誰放行的,得讀句子,不是查一個欄位。它應該是欄位。至於紀錄為什麼要放在動手的那個工具之外,我有過一次真的踩到:發佈用的 key 綁在舊帳號上,腳本跑完沒有報錯,草稿全建在那個舊帳號,而我在看的帳號顯示 0 篇。沒有人貼錯任何東西,工具回報的是成功。世界的真實狀態,只有從工具自己帳號以外的紀錄才看得出來。做到了是這樣:核准紀錄由執行動作的系統寫,核准人是欄位不是敘述,而且這筆紀錄跟 agent 自己回報了什麼無關,獨立存在。

進第五階之前的出場檢查

拿真的流量跑一次。挑上週的一次寫入跟一次送出,只靠紀錄、不問 agent,答出各是誰核准的、什麼時候核准的。如果答案是一段要人讀完再解讀的句子,那還不算紀錄。

第二半是拒絕測試。在測試帳號上,拿一個照規定要經過核准的送出,把核准那一步拿掉,然後試著做。這個動作必須被某個東西拒絕,而且你要說得出是什麼拒絕了它。如果它就這樣過去了,那個核准方塊就只是文件,它先前產出的每一筆核准紀錄,描述的都是一個不存在的控制。這兩半都要由系統來記、由系統來擋,通過之前,第五階沒有紮實的東西可以治理:第五階的 audit ledger 跟 policy 檢查是疊在這些紀錄上面的,而 policy 版本與 run 層級的停止是第五階的工作,不是這一階的。

AGENTS & TOOLS 這一欄在自架版的圖上畫法一樣,這一階跟怎麼託管沒什麼關係:寫入對的是內部系統,送出對的是外部管道,兩版都一樣。第 5 篇講治理收緊,宣告的 policy 會拿去跟實際發生的事對照,audit ledger 記下哪一版 policy 允許了哪個動作,而跑出界的 run 可以在還在跑的時候被停下來。

正在做類似的東西?

我協助團隊交付 AI 原生系統——架構、可治理的自主性,以及支撐它們的證據紀律。一次對話就能看出合不合適。

洽談合作