0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

問い合わせの引き継ぎを止めない:コンテキスト・パケットをSheetsとGASで作る

0
Posted at

問い合わせ対応を担当者から次の担当者へ渡すとき、要約だけでは「何を確認してから返すのか」が抜けます。本記事では、問い合わせの原文を正本に残したまま、要約・根拠・不足項目・リスク・担当・期限を1行にまとめるコンテキスト・パケットをGoogleスプレッドシートとGASで作ります。

AIは整理と返信案の下書きまでに限定し、事実確認、例外判断、送信承認は人間が行います。

問い合わせを根拠付きで人へ引き継ぐレビューゲート

作るもの

INQUIRIESを問い合わせの正本、PACKETSを引き継ぎ用の作業台とします。本文を別シートへ複製せず、raw_refで正本の行を参照します。

INQUIRIES: inquiry_id, received_at, source, raw_ref, customer_ref
PACKETS: packet_id, inquiry_id, summary_draft, evidence_ref,
         missing_fields, risk_flags, next_owner, due_at, decision, state

decisionpending, approved, rejected の3値に固定します。approved は返信内容が正しいというAIの評価ではなく、人間が確認した結果です。

ヘッダー名で列を参照する

列番号を直接コードに書くと、シートへ列を追加したときに別の値を上書きしやすくなります。まずヘッダーから列番号を作ります。

const PACKET_SHEET = 'PACKETS';
const REQUIRED = ['packet_id', 'inquiry_id', 'summary_draft', 'evidence_ref',
  'missing_fields', 'risk_flags', 'next_owner', 'due_at', 'decision', 'state'];

function columnMap_(headers) {
  return Object.fromEntries(headers.map((value, index) => [String(value).trim(), index]));
}

function getPacketSheet_() {
  const sheet = SpreadsheetApp.getActive().getSheetByName(PACKET_SHEET);
  if (!sheet) throw new Error(`Sheet not found: ${PACKET_SHEET}`);
  return sheet;
}

引き継ぎ可能かを検査する

必須項目が空のまま、次担当へ通知できないようにします。リスクがあれば、情報を補ってからではなく人間確認へ戻します。

function validatePacket_(packet) {
  const errors = REQUIRED.filter((key) => !String(packet[key] ?? '').trim());
  const flags = String(packet.risk_flags || '').split(',').map((v) => v.trim()).filter(Boolean);
  const blocked = ['personal_data', 'contract', 'price', 'complaint', 'unknown_fact'];

  if (errors.length) return {ok: false, reason: `必須項目不足: ${errors.join(', ')}`};
  if (flags.some((flag) => blocked.includes(flag))) {
    return {ok: false, reason: 'リスクフラグあり: 人間確認へ戻す'};
  }
  if (packet.decision !== 'approved') {
    return {ok: false, reason: '人間の確認承認が未完了'};
  }
  return {ok: true, reason: '引き継ぎ可能'};
}

AIの下書きを保存する境界

AIの返り値を受け取ったら、そのままメールやチャットの送信関数へ渡しません。次のように、下書きと承認結果を別の列へ保存します。

function saveDraft_(packetId, draft) {
  const sheet = getPacketSheet_();
  const values = sheet.getDataRange().getValues();
  const map = columnMap_(values.shift());
  const row = values.findIndex((r) => String(r[map.packet_id]) === packetId);
  if (row < 0) throw new Error(`Packet not found: ${packetId}`);

  const targetRow = row + 2;
  sheet.getRange(targetRow, map.summary_draft + 1).setValue(draft.summary || '');
  sheet.getRange(targetRow, map.evidence_ref + 1).setValue(draft.evidence_ref || '');
  sheet.getRange(targetRow, map.state + 1).setValue('human_review');
}

実際の送信処理を追加する場合も、入口で次を再検査します。

function canSend_(packet) {
  const result = validatePacket_(packet);
  return result.ok && packet.state === 'approved_for_send';
}

decision === 'approved' だけで送信を許可せず、送信直前の状態も分けるのがポイントです。承認後に本文、宛先、添付が変更された場合は、再び human_review に戻します。

運用チェックリスト

  • 問い合わせIDと原文の正本がある
  • 要約に確認可能な根拠参照がある
  • 不足項目と次に聞く担当が残っている
  • 個人情報・契約・料金・苦情は人間確認へ戻る
  • 次担当と期限が空のまま進めない
  • AIの下書きと送信済み本文を区別する
  • 差し戻し理由をFAQ、フォーム、ルールの改善先へ戻す
  • 承認後の本文・宛先・添付変更で再確認する

まとめ

引き継ぎの品質は、要約の短さではなく、次担当者が根拠と未決事項を再確認できるかで決まります。まずは1週間分の問い合わせから、evidence_refmissing_fieldsrisk_flagsnext_ownerdue_at の5項目を埋められるか確認してください。

この構造なら、AIを人の代わりに判断させず、判断に必要な情報だけを次の人へ渡せます。Miraigentでは、こうした「どこまでAIに任せ、どこから人へ戻すか」を業務ごとに整理するところから導入を始めています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?