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?

AIに問い合わせを渡す前に、FAQ候補とCRM項目を同じログで管理する

0
Last updated at Posted at 2026-05-31

この記事は、問い合わせ対応にAIを入れる前に、Googleフォーム、スプレッドシート、GASで「FAQ候補」と「CRM記録」を同じ受付ログに残すための実装メモです。

AI返信やAI要約は、問い合わせ本文だけを見ても安定しません。現場で本当に必要なのは、次のような判断材料です。

  • よくある質問として整備できる内容か
  • 個別対応としてCRMに残すべき内容か
  • AIに渡してよい情報か
  • 人間が確認すべき理由は何か

この記事では、AI APIには接続しません。AIへ渡す前段のログ設計だけを作ります。

作るもの

Googleフォームの問い合わせ回答をスプレッドシートに受け取り、GASで次の列を補完します。

問い合わせフォームから受付ログへ集約し、FAQ候補・CRM項目・AI利用可否を同じ行で判断する流れ

  • inquiry_id: 問い合わせID
  • status: 対応状態
  • crm_stage: CRM上の現在地
  • inquiry_type: 問い合わせ種別
  • faq_candidate: FAQ候補にするか
  • ai_transfer: AIに渡す前の扱い
  • review_reason: 人間確認が必要な理由
  • next_action: 次にやること

完成形は、AI導入前の軽い受付CRMです。返信を自動化する前に、問い合わせを「FAQ化できるもの」「個別対応が必要なもの」「AIに渡さないもの」に分けます。

シート列の設計

フォーム回答列に、運用列を足します。

項目 用途
A timestamp 2026/05/31 11:15 受付時刻
B name 山田太郎 相談者名
C company サンプル株式会社 会社名
D email sample@example.com 返信先
E inquiry_body 料金プランを知りたい 問い合わせ本文
F channel Webフォーム 流入元
G inquiry_id INQ-20260531-001 問い合わせID
H status 未対応 対応状態
I crm_stage 新規受付 CRM上の現在地
J inquiry_type 料金・プラン 問い合わせ分類
K faq_candidate yes FAQ候補か
L ai_transfer masked_summary_only AIに渡す範囲
M review_reason 料金条件の確認が必要 人間確認理由
N next_action FAQ既存文言を確認 次アクション

ポイントは、FAQ用の列とCRM用の列を分けすぎないことです。

同じ問い合わせを見て、FAQ化するか、個別商談として進めるか、AIに渡す前に止めるかを同じ行で判断できるようにします。

GASの実装

スプレッドシートで Apps Script を開き、次のコードを貼ります。

const CONFIG = {
  headerRow: 1,
  columns: {
    timestamp: 1,
    name: 2,
    company: 3,
    email: 4,
    inquiryBody: 5,
    channel: 6,
    inquiryId: 7,
    status: 8,
    crmStage: 9,
    inquiryType: 10,
    faqCandidate: 11,
    aiTransfer: 12,
    reviewReason: 13,
    nextAction: 14
  }
};

function onFormSubmit(e) {
  const sheet = e.range.getSheet();
  const row = e.range.getRow();
  const values = readInquiry_(sheet, row);
  const decision = decideInitialHandling_(values.inquiryBody);

  sheet.getRange(row, CONFIG.columns.inquiryId).setValue(buildInquiryId_(values.timestamp, row));
  sheet.getRange(row, CONFIG.columns.status).setValue('未対応');
  sheet.getRange(row, CONFIG.columns.crmStage).setValue(decision.crmStage);
  sheet.getRange(row, CONFIG.columns.inquiryType).setValue(decision.inquiryType);
  sheet.getRange(row, CONFIG.columns.faqCandidate).setValue(decision.faqCandidate);
  sheet.getRange(row, CONFIG.columns.aiTransfer).setValue(decision.aiTransfer);
  sheet.getRange(row, CONFIG.columns.reviewReason).setValue(decision.reviewReason);
  sheet.getRange(row, CONFIG.columns.nextAction).setValue(decision.nextAction);
}

function readInquiry_(sheet, row) {
  const c = CONFIG.columns;
  return {
    timestamp: sheet.getRange(row, c.timestamp).getValue(),
    name: sheet.getRange(row, c.name).getValue(),
    company: sheet.getRange(row, c.company).getValue(),
    email: sheet.getRange(row, c.email).getValue(),
    inquiryBody: String(sheet.getRange(row, c.inquiryBody).getValue() || ''),
    channel: sheet.getRange(row, c.channel).getValue()
  };
}

function buildInquiryId_(timestamp, row) {
  const date = timestamp instanceof Date ? timestamp : new Date();
  const yyyy = date.getFullYear();
  const mm = String(date.getMonth() + 1).padStart(2, '0');
  const dd = String(date.getDate()).padStart(2, '0');
  const serial = String(row - CONFIG.headerRow).padStart(3, '0');
  return `INQ-${yyyy}${mm}${dd}-${serial}`;
}

function decideInitialHandling_(body) {
  const text = normalize_(body);

  if (hasAny_(text, ['返金', '解約', '契約', 'クレーム', '個人情報', '電話番号', '住所', '法務', '税務', '医療'])) {
    return {
      crmStage: '責任者確認',
      inquiryType: '要注意相談',
      faqCandidate: 'no',
      aiTransfer: 'do_not_send',
      reviewReason: '個別判断または機微情報を含む可能性',
      nextAction: '責任者が内容を確認し、AIへ渡さず手動対応する'
    };
  }

  if (hasAny_(text, ['料金', '費用', 'プラン', '納期', '見積', '導入期間'])) {
    return {
      crmStage: '条件確認',
      inquiryType: '料金・条件',
      faqCandidate: 'yes',
      aiTransfer: 'masked_summary_only',
      reviewReason: '条件により回答が変わるため送信前確認が必要',
      nextAction: '既存FAQと料金表を確認し、必要ならFAQ候補に追加する'
    };
  }

  if (hasAny_(text, ['使い方', '方法', '設定', '連携', 'フォーム', 'スプレッドシート', 'GAS'])) {
    return {
      crmStage: 'FAQ整理',
      inquiryType: '使い方・設定',
      faqCandidate: 'yes',
      aiTransfer: 'masked_summary_only',
      reviewReason: '一般化できるが、固有情報は除外する',
      nextAction: 'FAQ候補として質問文と回答方針を整理する'
    };
  }

  return {
    crmStage: '新規受付',
    inquiryType: '未分類',
    faqCandidate: 'review',
    aiTransfer: 'human_review_first',
    reviewReason: '分類が未確定のため人間が確認する',
    nextAction: '問い合わせ本文を読み、FAQ化または個別対応を選ぶ'
  };
}

function normalize_(value) {
  return String(value || '').replace(/\s+/g, ' ').trim();
}

function hasAny_(text, keywords) {
  return keywords.some((keyword) => text.includes(keyword));
}

トリガーを設定する

Apps Script のトリガー画面で、次の設定を追加します。

項目 設定
実行する関数 onFormSubmit
イベントのソース スプレッドシートから
イベントの種類 フォーム送信時

初回実行時はGoogleの認可が必要です。このコードは外部サービスへ送信しませんが、スプレッドシートを編集する権限を使います。

FAQ候補の判断ルール

FAQ候補にするのは、次の条件を満たす問い合わせです。

  • 複数の顧客に共通する質問である
  • 回答方針を公開しても問題ない
  • 個人情報や契約内容に依存しない
  • 回答が担当者ごとに揺れている
  • 返信前に確認すべき社内ルールが明確にできる

反対に、次の内容はFAQ候補にしません。

  • 返金、解約、契約変更など個別判断が必要なもの
  • 個人情報や顧客固有の事情が中心のもの
  • 法務、医療、税務など専門判断に近いもの
  • 強い不満やクレームを含むもの

FAQ化とは、問い合わせを雑に一般化することではありません。何度も聞かれる質問を、現場が同じ基準で返せるように整えることです。

AIに渡す前の区分

ai_transfer は、AI APIへ接続する前に決めておく列です。

意味
masked_summary_only 名前、メール、電話番号などを除いた要約だけ渡す
human_review_first 人間が確認してから渡す
do_not_send AIに渡さない

最初から自動送信しない設計にしておくと、後でAI連携を足す時も安全です。

CRMステージの最小セット

crm_stage は、営業管理を作り込みすぎず、次の5つから始めます。

crm_stage 意味
新規受付 まだ読んでいない
FAQ整理 よくある質問として整理できる
条件確認 料金、納期、対応範囲の確認が必要
責任者確認 個別判断やリスク確認が必要
対応完了 初回対応が終わった

CRMを複雑にしすぎると、現場が更新しなくなります。最初は「どこで止まっているか」が分かれば十分です。

運用チェックリスト

導入前に次を確認します。

  • 問い合わせIDで1件ずつ追える
  • FAQ候補と個別対応を同じ行で見られる
  • AIに渡さない条件が列として残っている
  • 個人情報を含む問い合わせを止められる
  • 料金、契約、返金、クレームを責任者確認へ回せる
  • 未分類の問い合わせを人間が補正する運用がある
  • FAQ候補を月1回見直す担当者がいる

次に拡張するなら

受付ログが安定したら、次の順番で広げます。

  1. FAQ候補だけを別シートに転記する
  2. faq_candidate が yes の行を月次レビューする
  3. masked_summary_only の行だけAI要約を試す
  4. 生成文と人間修正文を別列に残す
  5. FAQページや社内ナレッジへ反映する

いきなりAI返信を作るより、まず問い合わせを整理するログを作る方が、後から自動化できる範囲がはっきりします。

Miraigentでは、こうしたAI導入前の問い合わせ導線やFAQ整理を無料診断の入口として扱っています。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?