操作員審核迴路 是做什麼的?
一個與外部對方溝通的人工智慧代理,永遠不應僅憑自身判斷就發送訊息,並且應在內部隨時告知操作員。此技能定義了合約:每個外送草稿都作為一項義務被歸檔,由操作員決定確切的文字,並由送達帳本證明實際已發送的內容。
使用時機
- 代理在共享頻道、電子郵件或聊天中,為客戶、供應商、投資者或合作夥伴草擬回覆,且必須經由人類批准才能發送。
- 你需要將每則已發送訊息與其確切的草稿文字、批准的操作員以及決策時間連結起來的審計軌跡。
- 你曾看過一個過時的批准釋放出被重寫的草稿,或兩名工作者兩次送達了相同的已批准訊息。
- 草稿不斷地向對方索取帳本上已有的資訊。
運作方式
物件
| 物件 | 意義 |
|---|---|
| 義務 (Obligation) | 我們欠對方的一件事。狀態依序為 drafted(已草擬)、approved(已批准)或 rejected(已拒絕),最後為 sent(已傳送)。帶有 direction(方向)、counterparty(對方)、channel(頻道)和一個 updated_at(更新時間)紀元。 |
| 草稿 (Draft) | 側車資料列,包含確切的草稿文字、該文字的 sha256 雜湊、來源座標(平台、頻道、討論串、使用者)以及優先級(P0 至 P3)。每個義務一個,重新歸檔時會取代。 |
| 決策 (Decision) | 操作員的批准或拒絕,記錄操作員 ID、一個隨機數以及做出決策時的草稿紀元。 |
| 批准快照 (Approval snapshot) | 由已授權的決策寫入器記錄的不可變文字、雜湊、紀元和目的地。缺少快照則無法授予傳送權限。 |
| 聲明 (Claim) | 帶有隨機令牌和狀態的持久保留;每個義務最多一個活躍聲明。 |
| 送達 (Delivery) | 針對一個(義務, 決策)配對,證明已進行一次傳送或通知的帳本資料列。 |
參考 schema 位於 references/approval-ledger.sql。
歸檔草稿
- 清理輸入。移除控制字元,壓縮單行欄位中的空白,並強制執行長度上限(草稿、摘要、上下文、對方)。拒絕空值或超出大小限制的欄位,而非靜默截斷。
- 執行基線關卡(如下)。它可能拒絕歸檔。
- 使用 sha256 計算草稿文字的雜湊值。雜湊前綴會放入摘要中,以便審核面板顯示其正在批准的內容。
- Upsert。如果對於同一個(對方, 頻道)組合,已存在一個狀態為
drafted的開放義務,則取代草稿側車並推進義務的updated_at。此推進即為紀元輪替:任何基於舊紀元的決策都無法再釋放新文字。否則,插入一個新的義務,狀態為drafted。 - 僅將歸檔收據路由到一個已設定、經驗證的內部運營目的地。如果來源本身就是該內部目的地,則在那裡確認。永不靜默意味著內部報告,而非自動的外部回覆。將草稿雜湊、批准狀態、操作員身份和工作流程元數據,隔離在對方可見的頻道之外。未知或未分類的來源保持靜默;直接訊息並非自動視為內部。
如果無法使用經驗證的內部目的地,則將歸檔結果保留在內部工具結果或操作員介面中。絕不降級回退到外部或未知的來源。對外公開的工具結果不是內部介面。
歸檔草稿並不授權外部回覆。任何政策允許的釐清問題或中立的回覆,都是一個獨立的外送決策,必須遵守對方-頻道-紀律中既有的提及、頻道、唯草稿、凍結和永不的限制。它不得揭露內部的批准元數據。
基線關卡
在任何草稿歸檔之前,查詢該對方的當前基線(一個時間帳本、合約儲存庫或 CRM):
- 記錄中已有已簽署或已送達的合約:拒絕歸檔,並附上證據和建議。在簽約後向對方詢問規格,正是此關卡旨在阻止的確切失敗情況。
- 操作員覆寫:
force_despite_signed_contract允許歸檔通過,並在草稿上下文中蓋上[BASELINE_OVERRIDE_SIGNED_CONTRACT]戳記。 - 關卡服務無法連線:歸檔繼續進行,並在上下文中蓋上
[BASELINE_CHECK_UNAVAILABLE]戳記。面板會看到該防護已關閉。失敗絕不會悄悄停用關卡。 - 當事實可用時,將最新的幾筆事實以
[BASELINE FACTS: ...]摘要附加到上下文中,以便草稿基於當前真相。
決策流程
審核面板列出狀態為 drafted 且方向為 we_owe_them 的義務。批准或拒絕會寫入一個帶有草稿紀元(draft_updated_ts)的決策資料列,並在同一個交易中翻轉義務狀態。紀元與當前 updated_at 不匹配的決策視為過期,不得釋放任何內容。
對於已授權的批准決策,同一個交易會插入一個不可變的 obligation_approval_snapshots 資料列:包含決策和義務 ID、當前草稿紀元、確切文字和 SHA-256、平台/頻道/討論串,以及 kind draft_sent。決策寫入器必須在寫入前建立授權;參考實作不會驗證操作員或製造決策。自動批准政策不會被參考實作啟用或擴展。沒有快照的舊版決策需要明確的人工協調或重新批准;切勿從當前可變的草稿回溯填補權限。
傳送作業
SQLite 參考實作為 references/approval_claims.py。它授予傳送權限,但絕不會呼叫傳輸層。使用從 SQL 測試資料初始化的現有本地參考資料庫;此模組不應用 schema 或生產環境遷移。只有受信任的決策寫入器才能填入批准記錄。所有寫入器都必須啟用外鍵和遞迴觸發器,並遵守 schema 保護機制;管理員對資料庫的篡改不在此模型範圍內。
- 發現已綁定的批准草稿。發現本身不是權限。
claim()會開啟自己的BEGIN IMMEDIATE交易,驗當前的批准紀元、確切文字、計算出的 SHA-256 和完整目的地是否與快照相符,然後在返回其令牌之前插入一個唯一的聲明。衝突會在實際傳送前阻止該工作者。已完成的收據不能被再次聲明。 begin_dispatch()重新驗證綁定,並使用令牌將狀態從claimed原子地更改為dispatching。只有勝出的呼叫者才能在提交後收到確切的draft_text和目的地。絕不重新產生文字、為傳送重新讀取可變的側車,或為另一次嘗試重用 payload。巢狀的呼叫者交易會被拒絕;權限不能依賴於稍後的呼叫者提交。在傳送期間不得保持資料庫交易處於開啟狀態。- 已確認的成功結果會送往
complete(),該函數會原子地記錄送達座標,將聲明標記為已送達,並將義務翻轉為sent。相同的完成是無操作的;衝突的座標會失敗。收據的唯一鍵用於去重記錄,而非先前的外部影響。 - 例外、超時、begin-dispatch 後工作者死亡,或收據持久化失敗,都會留下一個被封鎖的嘗試。
mark_unknown()記錄不確定性。未知狀態的聲明永遠不會過期、重新開啟、自動重試,或允許另一個針對該義務的決策繞過它。受信任的呼叫者可以使用reconcile(),並帶入已確認成功的座標和證據;此模組不會驗證該證據。缺少收據並非未送達的證明。
保證是每個批准的決策最多有一次自動傳送嘗試,而不是外部傳送的恰好一次(exactly-once)。在 begin-dispatch 之後、傳送之前發生當機,可能會導致零次傳送和一個被持有的聲明。為新的嘗試釋放未知結果,需要隔離原始執行器並驗證提供者語義;此參考實作刻意不提供此類重試操作。
| 聲明狀態 | 允許的下一個狀態 |
|---|---|
| claimed | dispatching 或 dispatch 前取消 |
| dispatching | delivered 或 unknown |
| unknown | 僅透過受信任的 reconciliation 變為 delivered |
| delivered, cancelled | 終端狀態;決策金鑰不可重用 |
當聲明處於活躍狀態時,資料庫保護機制會凍結義務、草稿和決策的寫入,包括取代操作。快照和聲明不能被刪除。在重新歸檔前,使用其令牌取消已聲明的操作;之後舊令牌將一無所獲。一旦傳送開始,保留新的編輯或撤銷以進行 reconciliation。這會序列化變更,而不是假裝能召回正在進行中的操作。
被拒絕的決策,以及沒有草稿側車/快照的舊版資料列,永遠不會進入此外部草稿-傳送路徑。在內部操作員介面上回報它們,以便手動處理。內部收據頁尾保持內部:approved by <operator> · receipt <decision_id> · draft sha256 <prefix>。絕不修改已批准的外部文字來附加工作流程元數據。
聚焦的本機驗證使用臨時資料庫、獨立連線和一個模擬的嘗試計數器,而非提供者或真實訊息:
python3 -m unittest discover -s tests/skills -p 'test_approval_delivery_claims.py'。
測試需要 Python 3.11+ 且支援 SQLite 序列化;參考實作僅使用標準函式庫。現有的桌面模式(desk-pattern)合約檢查仍是獨立的一項相容性檢查。
限時自動批准(可選)
草稿可以附帶 auto_send_after(紀元秒數)。一個掃描程序會批准那些截止時間已過且尚無決策的草稿,記錄操作員為 auto-ttl,然後傳送過程會透過正常路徑進行。操作員的動作永遠優先:決策會在掃描程序看到之前翻轉狀態,而重新歸檔會輪替紀元並移除或清除截止時間。掃描程序會在寫入交易內部重新檢查狀態和紀元,因此競爭條件會解析為無操作。沒有截止時間的草稿將永遠保持硬性閘控。
訊號連結
草稿可以指定它所回應的入站義務(signal_obligation_id)。這是用於延遲測量(入站訊號到草擬回覆)的唯一真實連結,並讓 SLA 掃描程序將該入站項目視為已回覆。如果引用的資料列不存在,則拒絕歸檔。
範例
歸檔草稿
file_request(
draft="Thanks, we can hold the slot until Friday. Which start date works?",
counterparty="acme-supplier",
context="reply to delivery window question",
origin_platform="slack", origin_channel="#acme-shared",
origin_thread="1712345678.000100", priority="P1",
signal_obligation_id=412)
-> {obligation_id: 431, draft_sha256: "9f2c...", refiled: false}
已設定、經驗證的內部運營目的地會看到:
Draft filed for approval (P1, sha 9f2c8a1b). Waiting on operator.
對方可見的來源頻道不會收到任何歸檔通知。如果沒有可用的經驗證內部目的地,收據會留在內部工具結果或操作員介面中,無外部回退。
操作員引導後重新歸檔
操作員要求一個更簡短的草稿。再次為同一個(對方, 頻道)組合歸檔會回傳 refiled: true,側車文字和雜湊會改變,且 updated_at 會推進。在舊面板資料列上點擊的批准會帶有舊紀元,並被忽略。
關卡拒絕
DeskApprovalError: baseline gate refused this draft: the ledger shows a
signed contract for 'acme-supplier'. Evidence: master agreement executed
2026-08-14. Recommendation: do not ask. Re-file with
force_despite_signed_contract=true if this is genuinely a new thread.
內部頻道的送達頁尾
Confirmed for Friday, start date 2026-09-08.
approved by operator-a · receipt 118 · draft sha256 9f2c8a1b2d3e4f50
需要測試的不變量
- 歸檔收據僅發送到已設定、經驗證的內部運營;僅當來源本身就是該經驗證的內部目的地時,來源才會收到一份。
- 未知的來源保持靜默。無法使用的內部目的地則使用內部工具結果或操作員介面,無外部回退。
- 為同一個(對方, 頻道)組合歸檔兩次會產生一個義務與兩個紀元。
- 帶有過期紀元的決策絕不會產生送達資料列。
- 兩個並發的聲請者會產生一個傳送權限;失敗者絕不嘗試傳送。
- 未知結果和收據持久化失敗永遠不會啟用自動重試。
- 成功的完成會在一個交易中記錄收據和已傳送狀態。
- 更改過的紀元、文字、雜湊或目的地無法取得或開始一個聲明。
- 活躍的聲明會阻止重新歸檔;只有傳送前取消才能釋放該鎖定。
- 關卡無法使用會蓋上標記;有關卡且已簽署則會拒絕,除非使用強制覆寫。
- Auto-ttl 絕不會針對操作員後來重新歸檔的文字觸發。