Eric TechBlog
AIAI Assistant

Human-in-the-Loop

HITL 安全機制,涵蓋讀寫分類策略、工具包裝攔截、前後端狀態同步,以及對話式人工介入流程設計。

設計問題

AI 助理能幫你查信件、搜資料、回答問題。但如果它從 email 裡找到了 deadline,接著還能幫你「發信」「建行事曆」「刪任務」呢?

這些操作一旦執行就無法輕易撤銷。一個誤判可能導致:

  • 發了一封錯誤的郵件給老闆
  • 把明天的重要會議刪掉了
  • 在不對的時間建了行事曆事件

核心問題:如何在 AI 的自主性和安全性之間取得平衡?讓它能做事,但重要的事要人類先確認。


原則:讀取自由,寫入需要 HITL

最簡單的分界線:

讀取操作 → 自動執行
寫入操作 → 需要用戶確認

但實務上沒這麼簡單。有些「讀取」也涉及隱私(查看行事曆日程),有些「寫入」的風險很低(標記 email 已讀)。

分類策略

策略一:名稱模式匹配

工具名稱包含特定動詞 → 需要人工介入:

create, update, delete, edit, add, book, move,
reschedule, cancel, complete, remove, write, send

這是一個粗糙但有效的啟發式規則。它不需要人工維護每個工具的分類,只要新接入的工具遵守命名慣例,就能自動被正確分類。

策略二:明確列表

某些工具名稱不包含上述動詞,但仍需人工介入:

findCalendarEvents     ← 名字像「讀取」,但涉及日程隱私
retrieveEventById      ← 同上

這是對策略一的補充,用來覆蓋命名慣例無法捕捉的例外。

兩層組合:先匹配模式,再查例外列表。大部分工具由模式自動分類,只有少數需要手動維護。


HITL(人工介入)流程設計

整體流程

用戶發送請求

用戶:「幫我把 John 那封信裡提到的 deadline 加到行事曆」

Approval Agent 快速判斷

判斷這個請求需要行事曆工具,工具被呼叫但被 HITL 攔截。

前端顯示人工介入請求

┌─────────────────────────────────┐
│  建立行事曆事件                  │
│  參數:下週五 17:00, 合約截止日   │
│                                 │
│  [Approve]  [Reject]            │
└─────────────────────────────────┘

用戶決定

  • 批准 → 執行工具,返回結果
  • 拒絕(附帶原因)→ Agent 看到原因,調整策略或放棄

關鍵設計:工具包裝

HITL 的核心技巧是工具包裝。它會把需要人工介入的工具「包」一層,讓工具看起來一模一樣(相同的名稱、描述、參數 schema),但執行時不真正運行,而是拋出一個信號。

原始工具:
  findCalendarEvents.execute(input)
  → 呼叫 Google Calendar API
  → 返回事件列表

HITL 包裝後的工具:
  findCalendarEvents.execute(input)
  → 不呼叫 API
  → 記錄工具名稱和參數
  → 拋出 ApprovalRequiredError

Agent 完全不知道工具被包裝了。它照常決定要呼叫什麼工具、傳什麼參數,真正執行時才會被攔截。

和其他章節的關係

這篇專注在「HITL 機制怎麼做」。如果你想知道 Agent 為什麼會先找 email、再提出建立行事曆的請求,可以搭配閱讀 Agent OrchestrationExternal Integration

為什麼用包裝而非 Agent 層面的判斷?

替代方案:在 system prompt 中告訴 Agent「這些工具需要 HITL,先問用戶再呼叫」。問題是:

  1. 不可靠:LLM 可能忽略指示,直接呼叫
  2. 不安全:安全機制不應該依賴 prompt compliance
  3. 多餘的 token:每次都要在 prompt 中列出哪些工具需要人工介入

包裝的方式是架構層面的保證。即使 LLM 選擇呼叫工具,程式碼也會阻止它直接執行。


前後端狀態同步

人工介入的生命週期

每個 HITL 請求都有一個唯一 ID,經歷以下狀態:

requested → approved → executed
                    → failed
         → rejected

狀態追蹤

前端需要追蹤哪些 HITL 請求還沒處理:

所有 HITL 請求的 ID → Set A
所有已決定的 ID   → Set B

未決定 = A - B(Set difference)

如果還有未處理的人工介入請求,輸入框就會被禁用。用戶必須先處理完所有待確認事項。

為什麼要禁用輸入?

如果允許用戶在人工介入尚未完成時繼續對話:

  • Agent 會困惑:「用戶之前要我建行事曆,但還沒說 OK,現在又問了新問題」
  • 狀態管理變複雜:這個決定要插到哪裡?
  • 用戶體驗差:多條待處理的事項混在一起

禁用輸入是最清晰的 UX,一次只處理一件事。

拒絕與回饋

用戶拒絕時,可以附帶原因:

用戶拒絕:"不要明天,改成下週一。"

這個原因會被轉成文字,注入後續的 Agent 上下文:

"The user rejected the tool: 不要明天,改成下週一。"

Agent 看到後可以自動調整參數,重新提出人工介入請求。這形成了一個自然的對話式 HITL 流程。


訊息歷史的處理

問題

人工介入的 data parts(請求、決定、結果)不是標準的 LLM 訊息格式。LLM 不認識 data-approval-request 這種型別。

解法:文字化

在送給 LLM 之前,把 data parts 轉成文字:

data-approval-request  → "The assistant requested to run findCalendarEvents
                          with input: { start: 'tomorrow', end: 'tomorrow' }"

data-approval-decision → "The user approved the tool."
                      or "The user rejected the tool: [reason]"

data-approval-result   → "The tool returned this result: { events: [...] }"

這樣 LLM 就能理解完整的人工介入歷史,在後續對話中做出合理的判斷。


HITL 的 UI 設計

資訊充分

用戶看到人工介入請求時,必須有足夠的資訊做出決定:

┌──────────────────────────────────────────┐
│  🔧 Approval Request: findCalendarEvents │
│                                          │
│  Parameters:                             │
│  {                                       │
│    "start": "tomorrow at 3:00pm",        │
│    "end": "tomorrow at 4:00pm",          │
│    "searchTerm": "team meeting"          │
│  }                                       │
│                                          │
│  [Approve]  [Reject]                     │
└──────────────────────────────────────────┘

用戶應該能回答:「這個工具要做什麼?用什麼參數?我同意嗎?」

拒絕流程

拒絕時,輸入框切換為「填寫原因」模式:

原本:[What would you like to know?]
切換:[Why are you rejecting this tool?]

placeholder 的變化提示用戶「現在要給回饋」。


生產考量

人工介入超時

如果用戶一直不處理人工介入請求怎麼辦?

  • 前端:確認按鈕持續顯示,輸入保持禁用
  • 後端:不設超時,因為這是用戶的決定,不應該自動取消
  • UX:考慮加入「稍後提醒」或「取消此操作」按鈕

批次人工介入

如果 Agent 需要執行多個寫入操作(如建立 3 個行事曆事件)?

  • 逐一確認:最安全,但 UX 繁瑣
  • 批次確認:一次顯示所有,用戶逐一決定
  • 全部批准 / 全部拒絕:最快,但可能不夠細粒度

目前的設計是逐一確認,但保留了擴展到批次確認的可能。

HITL 的安全邊界

HITL 不是萬能的安全機制

它假設:

  • 用戶能理解工具的參數和後果
  • 用戶會認真審查而非盲目批准
  • 工具的 description 正確描述了它的行為

對於高風險操作(如金融交易),可能需要更強的保護(如二次確認、限額)。


重點總結

設計決策選擇原因
分類策略動詞模式 + 例外列表自動覆蓋大部分工具,手動處理例外
攔截方式工具包裝架構層面保證,不依賴 prompt compliance
控制流ApprovalRequiredError利用框架的錯誤管道,無需額外中斷機制
前端狀態禁用輸入直到全部決定簡化狀態管理,清晰的 UX
拒絕機制附帶原因,注入 Agent 上下文形成自然的對話式 HITL 流程
歷史處理Data parts → 文字化讓 LLM 理解完整的人工介入歷史

Last updated on

On this page