問い合わせ対応を担当者から次の担当者へ渡すとき、要約だけでは「何を確認してから返すのか」が抜けます。本記事では、問い合わせの原文を正本に残したまま、要約・根拠・不足項目・リスク・担当・期限を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
decision は pending, 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_ref、missing_fields、risk_flags、next_owner、due_at の5項目を埋められるか確認してください。
この構造なら、AIを人の代わりに判断させず、判断に必要な情報だけを次の人へ渡せます。Miraigentでは、こうした「どこまでAIに任せ、どこから人へ戻すか」を業務ごとに整理するところから導入を始めています。
