音声エージェントは洗練された応答を瞬時に返せても、一言「もう電話しないで」で信頼を損なうことがあります。

そのリクエストがSMS経路のみを更新する場合、エージェントは翌日も発信を続けるかもしれません。通話記録のみを更新する場合、フォローアップワークフローはテキスト送信を続け続けるかもしれません。AI発信ツール、受信トレイエージェント、スケジューリングボット、または多段階アウトリーチワークフローを提供する開発者にとって、同意はもはや静的なチェックボックスではなく、実行時の状態です。

そこで役立つのがAI同意台帳です。連絡、情報拡充、記録、エスカレーションを行う前に、1つの耐久性のある場所から最新の同意状態を確認するというシンプルなルールをすべてのエージェントアクションに与えます。

本ガイドでは、製品をコンプライアンスの迷路にしないための台帳設計方法を示します。

これは技術アーキテクチャのガイダンスであり、法的助言ではありません。ワークフローが規制対象のアウトリーチ、健康、金融、雇用、または機密個人データに関わる場合は、資格を有する法務担当者に相談してください。

AIエージェントが同意を難しくする理由

従来のアプリは通常、登録時、ニュースレターのオプトイン、クッキーバナー、電話番号取得、または請求同意など、予測可能なタイミングで許可を求めます。

AIエージェントはこの境界を曖昧にします。

本番環境のエージェントは次のことを行う可能性があります。

  • 着信通話に応答する
  • ボイスメールを要約する
  • フォローアップリンクをテキスト送信する
  • 別の通話をスケジュールする
  • CRMレコードを拡充する
  • 翌週のキャンペーンステップをトリガーする
  • ケースを人間に引き継ぐ
  • ツールコールの失敗後に再試行する
  • 音声からSMSまたはメールに切り替える

各ステップは単独では有効かもしれませんが、リスクは同意が1つのチャネルで変更され、ワークフローの残りがそれを認識しない場合に現れます。

一般的な失敗の形はシンプルです。

  1. ユーザーが目の前のチャネルで許可を取り消す。
  2. エージェントがそのメッセージを会話テキストとして記録する。
  3. 別のワークフローが取り消し状態を確認せずに実行を続ける。

これはLLMの問題ではなく、状態管理の問題です。

AI同意台帳とは?

AI同意台帳は、許可イベントの追記専用記録と、次の1つの質問に答える高速読み取りモデルです。

この特定のエージェントは、この特定の人物に対して、この特定のアクションを今すぐ実行できるか?

台帳は、チャネル、アイデンティティ、エージェント、ワークフロー、ツール、時間にわたる同意と取り消しを追跡する必要があります。

単なるsubscribed: trueカラムではありません。

有用な台帳は以下を保存します。

  • 同意の所有者
  • 適用されるチャネル
  • 対象とする目的
  • 許可または取り消しが行われた日時
  • 取得方法
  • どのワークフローまたはエージェントがそれに基づいて行動したか
  • 決定を裏付ける証拠
  • 取り消しが1つのチャネルのみを停止するか、関連するすべてのアウトリーチを停止するか

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: トランスクリプトスパンを取得する

完全なトランスクリプトのblobを保存するだけでなく、時間コード付きのスパンを保存します。

{
  "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アーキテクチャとのつながり

同意台帳は、他のランタイム制御と並んで機能するときに最も効果的です。

  • ランタイムポリシー はツールコールの安全性と可否を決定します。
  • レート制限 は頻度と支出を制御します。
  • テナント分離 は顧客間の状態漏洩を防ぎます。
  • 出力の出所 は生成された決定の証拠を保存します。
  • 承認ゲート はリスクのあるアクションをレビュー用に一時停止します。

同意はより大きなシステムにおける1つの境界です。しかし、それはユーザーが即座に理解する境界です。ユーザーが「止めて」と言えば、システムは止めるべきです。

FAQ

AI同意台帳とは何ですか?

AI同意台帳は、同意および取り消しイベントの追記専用記録と、AIエージェントが人物に連絡、記録、拡充、または行動できるかどうかを決定するランタイム読み取りモデルです。

これは音声エージェント専用ですか?

いいえ。音声エージェントは問題を明確にしますが、同じパターンはSMSエージェント、メールエージェント、サポートコパイロット、CRM自動化、通知システム、個人データを使用するAIワークフローに適用されます。

LLMは同意の有無を判断できますか?

LLMは「私を放っておいてください」などの乱雑な言語を分類するのに役立ちますが、最終的な強制レイヤーであるべきではありません。候補イベントを書き込み、信頼度ルールを適用し、バックエンドポリシーに決定を任せます。

1つのチャネルでの取り消しはすべてのチャネルを停止すべきですか?

ユーザーの発言、製品ポリシー、および法的文脈によります。「テキストを止めて」はチャネル固有である可能性があります。「連絡しないで」は通常、すべてのアウトリーチを停止する必要があります。これはポリシーマトリックスにエンコードします。

キューに入れられたジョブは再度同意を確認する必要がありますか?

はい。昨日スケジュールされたジョブは今日無効になる可能性があります。すべてのキューに入れられた連絡アクションは、実行直前に最新の同意状態を確認する必要があります。

最初に何を構築すべきですか?

取り消しから始めます。SMSキーワード、発話された停止フレーズ、アウトバウンドアクション前の現在の状態チェック、ワークフローのキャンセルを捕捉します。その後、目的レベルの許可、レビューのキュー、より豊富な証拠レシートを追加します。

最後に

AIエージェントはワークフローを高速化しますが、速度は同意のバグをより高価にします。最も安全なパターンはシンプルです。エージェントは連絡を提案できますが、台帳が連絡が許可されるかどうかを決定します。

ある場所で許可が取り消された場合、関連するすべてのワークフローは、次のツールコールが実行される前にそれを認識する必要があります。