語音代理聽起來可能很專業、回應即時,卻可能在短短一句話中造成信任危機:「不要再打電話給我。」

如果該請求只更新 SMS 路徑,你的代理可能明天仍繼續撥打。若僅更新通話逐字稿,你的後續工作流程可能仍持續發送簡訊。對於推出 AI 撥號器、收件匣代理、排程機器人或多步驟推廣工作流程的開發者而言,同意不再是靜態的勾選框,而是執行階段的狀態。

這正是 AI 同意記錄 的用武之地。它為每個代理動作提供簡單規則:在聯絡、豐富、錄製或升級某人之前,先從單一持久來源檢查最新的同意狀態。

本指南將說明如何設計該記錄,而不讓你的產品變成合規迷宮。

本文件提供技術架構指導,並非法務建議。若你的工作流程涉及受管制的推廣、健康、金融、就業或敏感個人資料,請務必諮詢合格的法務審查人員。

為什麼 AI 代理讓同意管理變得更困難

傳統應用程式通常在可預期的時機要求權限:註冊、電子報訂閱、Cookie 橫幅、電話號碼擷取,或帳單同意。

AI 代理模糊了這個界線。

一個實際運作的代理可能:

  • 接聽來電
  • 摘要語音信箱
  • 傳送後續連結簡訊
  • 排程另一次通話
  • 豐富 CRM 紀錄
  • 觸發下週的活動步驟
  • 將案件轉交給真人
  • 工具呼叫失敗後重試
  • 從語音切換至 SMS 或電子郵件

每個步驟本身可能都合理,但當同意在某個頻道變更,而工作流程的其他部分卻未察覺時,風險便會浮現。

常見的失敗模式很簡單:

  1. 使用者在眼前頻道撤銷權限。
  2. 代理將訊息記錄為對話文字。
  3. 另一個工作流程因未檢查撤銷狀態而持續執行。

這不是 LLM 的問題,而是狀態管理問題。

什麼是 AI 同意記錄?

AI 同意記錄 是一份附加式權限事件紀錄,加上快速讀取模型,用以回答一個問題:

這個特定代理現在是否被允許對這個人執行這個特定動作?

該記錄應追蹤跨頻道、身分、代理、工作流程、工具與時間的同意與撤銷。

它不只是一欄 subscribed: true

實用的記錄會儲存:

  • 同意屬於誰
  • 適用於哪個頻道
  • 涵蓋什麼目的
  • 何時授予或撤銷
  • 如何擷取
  • 哪個工作流程或代理對其採取行動
  • 支持決策的證據
  • 撤銷是否應停止單一頻道或所有相關推廣

對 AI 工作流程而言,最重要的不是日誌,而是動作前的政策檢查。

團隊最常忽略的同意接觸點

首先,請繪製出代理可能建立、使用或變更權限狀態的每個位置。

1. 語音撤銷

使用者可能說:

  • 「不要再打電話給我。」
  • 「把我從名單中移除。」
  • 「不要再聯絡這個號碼。」
  • 「只寄電子郵件給我。」
  • 「改傳簡訊給我。」
  • 「我沒有要求這個。」

不要將這些語句埋在逐字稿中。請將它們萃取為候選同意事件。

語音撤銷的困難在於代理可能在長對話中聽到。你需要一個獨立的分類器或確定性語句層,專門監控權限變更,而非僅產生最終摘要。

2. SMS 關鍵字與自然語言

多數團隊會先處理 STOPUNSUBSCRIBESTART。這是必要的,但使用者不一定會使用精確關鍵字。

你也需要捕捉自然語言:

  • 「請不要再傳簡訊給我」
  • 「打錯號碼」
  • 「改打我辦公室電話」
  • 「不感興趣,請移除我」

精確關鍵字可採用確定性處理;自然語言則可先分類,不確定時再路由至確認或人工審核。

3. 電子郵件與通知偏好設定

代理可能從原本以語音為基礎的工作流程起草或傳送電子郵件。若電子郵件有獨立的同意目的,記錄必須知道這一點。

同意不應因為代理有其他可用工具而悄悄擴張。

4. CRM 匯入與過時名單

許多 AI 工作流程從匯入的聯絡人開始。該匯入可能包含舊的同意標記、部分頻道歷史,或完全沒有證據。

請將匯入的權限視為較低信任等級,直到驗證為止。儲存來源與時間戳記,以便代理選擇更安全的模式。

5. 人工覆寫

人類需要覆寫路徑,但覆寫應為帶有理由的明確事件,而非隱形的管理員編輯。

良好的覆寫紀錄應回答:

  • 誰變更了狀態
  • 為什麼變更
  • 審核了哪些證據
  • 變更是暫時還是永久

實用的同意資料模型

保留寫入模型為附加式。從中建立獨立的目前狀態檢視。

以下是簡潔的 TypeScript 風格模型:

type ConsentChannel = "voice" | "sms" | "email" | "push" | "in_app";
type ConsentPurpose =
  | "support_followup"
  | "appointment_reminder"
  | "marketing_outreach"
  | "transactional_update"
  | "recording"
  | "data_enrichment";

type ConsentEventType =
  | "granted"
  | "revoked"
  | "limited"
  | "confirmed"
  | "expired"
  | "human_override";

type ConsentEvent = {
  id: string;
  tenantId: string;
  subjectId: string;          // person/customer/contact
  normalizedContact: string;  // phone/email/device id hash
  channel: ConsentChannel;
  purpose: ConsentPurpose;
  eventType: ConsentEventType;
  scope: "single_channel" | "all_channels" | "all_outreach";
  source: "voice_agent" | "sms_keyword" | "web_form" | "crm_import" | "human";
  evidenceRef: string;        // transcript span, form id, message id, admin note
  confidence: number;         // 0..1 for AI-extracted events
  workflowRunId?: string;
  agentId?: string;
  createdAt: string;
  expiresAt?: string;
};

Enter fullscreen mode Exit fullscreen mode

有幾個細節很重要:

  • scope 可防止「不要打電話」在政策未允許的情況下意外變成「停止一切」。
  • purpose 可避免預約提醒的同意被誤用為行銷推廣。
  • evidenceRef 讓你能夠解釋系統為何做出該決定。
  • confidence 可讓不確定的 AI 擷取事件暫停,而非盲目行動。

每個代理動作所需的執行階段檢查

在任何狀態變更或聯絡動作之前,先向記錄索取決策。

type ConsentDecision = {
  allowed: boolean;
  reason: string;
  matchedEventIds: string[];
  requiresHumanReview?: boolean;
  safeAlternative?: "do_not_contact" | "in_app_only" | "ask_for_confirmation";
};

async function canAgentAct(input: {
  tenantId: string;
  subjectId: string;
  channel: ConsentChannel;
  purpose: ConsentPurpose;
  action: "call" | "text" | "email" | "record" | "enrich";
  workflowRunId: string;
}): Promise<ConsentDecision> {
  const state = await consentStore.currentState(input);

  if (state.hasGlobalRevocation) {
    return {
      allowed: false,
      reason: "Subject revoked all outreach",
      matchedEventIds: state.blockingEvents,
      safeAlternative: "do_not_contact",
    };
  }

  if (state.channelRevoked) {
    return {
      allowed: false,
      reason: `${input.channel} permission was revoked`,
      matchedEventIds: state.blockingEvents,
      safeAlternative: "in_app_only",
    };
  }

  if (!state.hasPurposeGrant) {
    return {
      allowed: false,
      reason: `No active consent for ${input.purpose}`,
      matchedEventIds: [],
      safeAlternative: "ask_for_confirmation",
    };
  }

  return { allowed: true, reason: "Active consent found", matchedEventIds: state.grantEvents };
}

Enter fullscreen mode Exit fullscreen mode

代理不應擁有最終決定權。它可以請求動作,但由你的後端決定該動作是否被允許。

如何從語音逐字稿處理撤銷

語音代理需要在逐字稿周圍建立小型管線。

步驟 1:擷取逐字稿片段

不要只儲存完整的逐字稿區塊。請儲存帶有時間碼的片段。

{
  "span_id": "span_928",
  "speaker": "user",
  "text": "Please stop calling this number. Texts too.",
  "start_ms": 184200,
  "end_ms": 188700
}

Enter fullscreen mode Exit fullscreen mode

步驟 2:萃取同意意圖

對明顯語句使用確定性規則,對較模糊的語言則使用 LLM 分類器。

{
  "intent": "revocation",
  "channels": ["voice", "sms"],
  "scope": "all_outreach",
  "confidence": 0.94,
  "evidence_span_id": "span_928"
}

Enter fullscreen mode Exit fullscreen mode

步驟 3:套用信心政策

範例政策:

  • 信心 >= 0.90:立即寫入撤銷事件
  • 信心 0.65 - 0.89:暫停工作流程並請求人工審核
  • 信心 < 0.65:儲存為訊號,不自動變更狀態

對於撤銷,寧可誤判也應避免持續不必要的聯絡;對於新的同意授予,則應更嚴格。

步驟 4:停止進行中的工作流程

記錄寫入應發出事件,以取消或暫停相關工作流程。

await eventBus.publish("consent.revoked", {
  tenantId,
  subjectId,
  channels: ["voice", "sms"],
  scope: "all_outreach",
  evidenceRef: "call_123:span_928",
});

Enter fullscreen mode Exit fullscreen mode

接著工作程式應停止後續步驟:

on("consent.revoked", async (event) => {
  await workflowStore.pauseRuns({
    tenantId: event.tenantId,
    subjectId: event.subjectId,
    affectedChannels: event.channels,
    reason: "consent_revoked",
  });
});

Enter fullscreen mode Exit fullscreen mode

若撤銷未能取消已排程的工作,該記錄就只是一本日記,而非控制系統。

設計頻道感知規則

並非每個權限事件都有相同的意義。

請使用政策矩陣:

使用者陳述 建議範圍 預設動作
“Stop texting me” 僅限 SMS 封鎖 SMS,允許其他已授權的頻道
“Stop calling me” 僅限語音 封鎖通話,允許其他已授權的頻道
“Do not contact me” 所有推廣 封鎖語音、SMS、電子郵件、推播
“Wrong number” 聯絡方式 封鎖該電話號碼,並標記身分品質
“Email me instead” 頻道偏好 封鎖目前頻道,要求檢查電子郵件權限
“Do not record this” 錄製目的 停止錄製,僅在工作流程允許時繼續

此矩陣應存在於程式碼或政策設定中,而非提示詞內。

記錄在架構中的定位

簡單的生產流程如下:

  1. 代理提出動作。
  2. 執行階段政策檢查工具權限。
  3. 同意記錄檢查使用者權限。
  4. 速率限制器檢查預算與頻率。
  5. 工具執行者執行動作。
  6. 稽核日誌記錄決策與證據。

此順序很重要。請勿先呼叫工具,再檢查同意。

對於語音代理,請在兩個方向放入記錄:

  • 在撥出通話或簡訊之前
  • 在即時通話中出現撤銷時
  • 在通話結束後處理摘要時
  • 在活動重試之前
  • 在人工交接後續動作之前

可觀測性:應記錄什麼

每次同意決策都應產生小型收據。

{
  "decision_id": "cd_456",
  "workflow_run_id": "run_789",
  "agent_id": "voice_followup_agent",
  "subject_id": "contact_123",
  "requested_action": "sms.followup",
  "purpose": "appointment_reminder",
  "allowed": false,
  "reason": "sms permission revoked",
  "matched_event_ids": ["ce_111"],
  "created_at": "2026-07-30T06:08:00Z"
}

Enter fullscreen mode Exit fullscreen mode

這有助於除錯與使用者信任。當有人詢問代理為何聯絡或未聯絡時,你能提供具體答案。

請追蹤以下指標:

  • 各頻道偵測到的撤銷次數
  • 需要審核的不確定同意事件
  • 被封鎖的代理動作
  • 撤銷後暫停的工作流程
  • 從撤銷到工作流程取消的時間
  • 有匯入同意但無證據的聯絡人
  • 誤判與漏判的審核結果

關鍵指標不是「傳送了多少則訊息」,而是「有多少動作被正確允許、封鎖或暫停」。

常見錯誤

錯誤 1:將提示詞視為政策

系統提示詞可以告訴代理尊重同意,但無法在重試、工作程式、佇列與整合中強制執行同意。

政策應屬於後端檢查。

錯誤 2:僅儲存目前狀態

單一 can_contact=false 旗標會隱藏決策原因。你需要事件歷史以進行稽核、除錯與安全還原。

錯誤 3:忽略目的

傳送登入碼的權限,不等於傳送行銷序列的權限。請將同意與目的綁定。

錯誤 4:讓已排程工作繞過檢查

佇列中的工作應在執行時檢查同意,而非僅在排程時檢查。同意可能在排程與傳送之間發生變化。

錯誤 5:跨頻道擴張同意

若使用者提供電話號碼用於提醒,不要假設代理可永久撥打、傳送簡訊、豐富資料、錄製並寄送電子郵件。擴張必須是明確的。

小型實作檢查清單

可作為初步檢查:

  • [ ] 列出代理可能聯絡、錄製、豐富或更新個人的所有動作。
  • [ ] 為每個動作定義目的。
  • [ ] 建立附加式同意事件。
  • [ ] 建置目前狀態讀取模型。
  • [ ] 在工具執行前加入後端同意檢查。
  • [ ] 從語音與 SMS 萃取撤銷。
  • [ ] 在撤銷後暫停進行中的工作流程。
  • [ ] 儲存證據參照,而非僅儲存旗標。
  • [ ] 為不確定的 AI 擷取事件加入人工審核。
  • [ ] 記錄同意決策收據。
  • [ ] 在撤銷後測試佇列工作。
  • [ ] 個別審核匯入的 CRM 同意。

測試記錄

根據真實失敗模式建立測試案例。

it("blocks scheduled SMS after spoken all-channel revocation", async () => {
  await ledger.append({
    subjectId: "c1",
    channel: "voice",
    purpose: "marketing_outreach",
    eventType: "revoked",
    scope: "all_outreach",
    source: "voice_agent",
    confidence: 0.96,
    evidenceRef: "call_1:span_9",
  });

  const decision = await canAgentAct({
    tenantId: "t1",
    subjectId: "c1",
    channel: "sms",
    purpose: "marketing_outreach",
    action: "text",
    workflowRunId: "run_1",
  });

  expect(decision.allowed).toBe(false);
  expect(decision.reason).toContain("revoked");
});

Enter fullscreen mode Exit fullscreen mode

也請測試:

  • SMS STOP 在政策設定為所有推廣時,封鎖後續語音。
  • 「改寄電子郵件給我」不會在未取得電子郵件權限時寄送電子郵件。
  • 匯入的 CRM 同意會過期或需要驗證。
  • 低信心撤銷會暫停工作流程。
  • 人工覆寫會建立事件與收據。
  • 重試中的工作程式會在執行前重新檢查同意。

與更廣泛 AI 架構的連結

同意記錄最適合與其他執行階段控制並存:

  • 執行階段政策 決定工具呼叫是否安全。
  • 速率限制 控制頻率與支出。
  • 租戶隔離 防止跨客戶狀態洩漏。
  • 輸出來源 儲存生成決策的證據。
  • 核准閘道 暫停高風險動作以供審核。

同意是大型系統中的一條界線。但這是使用者能立即理解的界線。如果他們說停,系統就應該停。

常見問題

什麼是 AI 同意記錄?

AI 同意記錄是一份附加式同意與撤銷事件紀錄,加上執行階段讀取模型,用以決定 AI 代理是否可以聯絡、錄製、豐富或代表某人採取行動。

這只適用於語音代理嗎?

不是。語音代理讓問題變得明顯,但相同的模式也適用於 SMS 代理、電子郵件代理、支援副駕、CRM 自動化、通知系統,以及使用個人資料的 AI 工作流程。

LLM 可以決定同意是否存在嗎?

LLM 可以協助分類「請讓我安靜」等模糊語言,但不應作為最終強制執行層。請撰寫候選事件、套用信心規則,並由後端政策做出決定。

單一頻道的撤銷是否應停止所有頻道?

這取決於使用者陳述、產品政策與法律情境。「不要再傳簡訊給我」可能是頻道專屬;「不要聯絡我」通常應停止所有推廣。請將此編碼在政策矩陣中。

佇列中的工作是否需要再次檢查同意?

需要。昨天排程的工作今天可能已失效。每個佇列中的聯絡動作都應在執行前立即檢查最新的同意狀態。

我應該先建置什麼?

從撤銷開始。擷取 SMS 關鍵字、語音停止語句、在撥出動作前進行目前狀態檢查,以及工作流程取消。之後再加入目的層級授予、審核佇列與更豐富的證據收據。

結語

AI 代理讓工作流程更快,但速度也讓同意錯誤的代價更高。最安全的模式很簡單:代理可以提出聯絡,但由記錄決定聯絡是否被允許。

如果某人在某處撤銷權限,所有相關工作流程都應在下一個工具呼叫執行前收到通知。