2025年12月8日

ENSOUを使った問い合わせ対応&ナレッジ自動生成エージェントの作成方法

ENSOUのカスタムチャットボット機能を使って、問い合わせ対応とナレッジの自動生成を行う問い合わせ対応エージェントの作成方法を画像やコード付きで徹底解説します。

守屋陽平
守屋陽平
営業・マーケティング
ENSOUを使った問い合わせ対応&ナレッジ自動生成エージェントの作成方法

はじめに

エージェントとは、特定の条件やルールに基づいて自律的にアクションを実行するソフトウェアやシステムのことです。

本記事では弊社のENSOU AIをベースにした、問い合わせ対応とナレッジの自動生成を行うエージェントの作成方法を画像やコピペして使えるコードを用いながらわかりやすく解説します。

株式会社Digeonでは生成AI導入のファーストステップとして最適な法人向けの生成AIサービスである「ENSOU AI」を提供しています。

無料ですぐに使えるフリープランのご利用開始はこちらから👇

ENSOU Chatbot

問い合わせ対応自動化エージェントのメリット

本記事で作成するエージェントは、以下の課題・悩みを解決します。

  • 人力での問い合わせ対応に多くの時間や労力を浪費してしまっている。
  • 人力だと問い合わせできる時間帯が限られる。
  • 問い合わせ対応の履歴をデータ化するのが面倒。
  • 問い合わせ対応の履歴をナレッジデータとして蓄積したい。
  • 問い合わせ対応にチャットボットを使っているが、運用コストがかかる。

今回のエージェントでは、ナレッジにないがゆえにAIチャットボットでは対応できない問い合わせに対して、担当者がスプレッドシートに入力した回答をGeminiを用いてナレッジとして自動で生成します。

このエージェントによって、同じ問い合わせが発生しない仕組みが構築され、自動的に日々ナレッジが蓄積されていきます。

ユーザーはチャットボット単体では対応できなかった問い合わせについても、以前に同じ問い合わせがあれば、担当者に連絡することなく解決できます。

問い合わせ対応の担当者は、スプレッドシートに回答を一度記入すれば以降は同じ問い合わせに対応する必要がなくなります。

今回作成するエージェントの概要

本記事で作成するエージェントの全体像は以下の通りです。

  1. カスタムチャットボットで回答が得られなかった場合にGoogleフォーム(問い合わせ申請)のリンクを出力する。
  2. Googleフォームに記載された問い合わせ内容が担当者に送信される。
  3. Googleフォームの内容がスプレッドシートに自動で記録される。
  4. 連携されたスプレッドシートの問い合わせ内容に対して回答を記入する。
  5. そのスプレッドシートをもとにGeminiを用いてナレッジファイル用のQ&Aスプレッドシートを生成させる。
  6. 生成されたスプレッドシートはナレッジ連携されているので、次回以降はその問い合わせに対してチャットボットが回答する。

システムのイメージ図はこのようになります。

システムのイメージ図

このエージェントで使用するGeminiAPIについて「無料サービス」を使用する場合は、送信データがGeminiの学習やGoogleのプロダクト開発に利用されるので、プライベート情報や機密情報、個人情報は送信しないように注意してください。ただし、「有料サービス」を使用する場合はこの限りではありません。

詳細についてはこちらをご覧ください。

エージェントの作成

それでは、実際にエージェントを画面・コード付きで分かりやすく解説していきます。

使用するツール

今回の構築に使用するツールは以下の4つです。

  • ENSOU AI
  • Googleスプレッドシート
  • Googleフォーム
  • Gemini

ENSOU AIとGoogleのアカウントがあれば誰でも構築が可能です。

Googleスプレッドシートを作成

Googleドライブを開き、「+新規」をクリックし「Googleスプレッドシート」を選択します。

タイトル名は「社内問い合わせ対応Q&A」などとして下さい。

そして、「ツール」から「新しいフォームを作成」をクリックします。

スプレッドシートからGoogleフォームを作成

Googleフォームの作成

先程作成されたGoogleフォームに以下のように項目を設定します。

  • 部署名(記述式・短文)
  • 氏名(記述式・短文)
  • メールアドレス(記述式・短文)
  • 問い合わせ内容(段落)
Googleフォームの作成

次に「回答」タブから「スプレッドシートで表示」をクリックします。

ここで、スプレッドシートに項目が反映されていることを確認してください。

スプレッドシートで表示

公開範囲については公開をクリックすると表示される画面で管理を押下し、回答者ビューを「リンクを知っている全員」に設定します。その後、「完了」を押し、続けて「公開」をクリックします。

公開範囲を設定

組織でGoogleアカウントを配布している場合は回答者ビューが制限付きのままでも大丈夫です。

スプレッドシートについてA~E列はGoogleフォームをもとに自動で作成されます。

F列に回答用の「回答(人間による入力)」を追加します。

スプレッドシートの作成

GASの構築

新たにスプレッドシートを作成します。

タイトルは「ENSOU生成Q&A」とします。

A列に「タイムスタンプ」、B列に「問い合わせ内容」、C列に「問い合わせ回答」を入力します。

スプレッドシートの作成

メニューの「拡張機能」→「Apps Script」の順にクリックします。

スプレッドシートの拡張機能

「コード.gs」に下記のソースコードをコピー&ペーストして画像のように貼り付けます。

コード.gsにコードをコピペ

ソースコード

/******** 設定ここから ********/
// ▼ フォーム連携スプレッドシート(ファイルA)のIDを貼る
// URLの /d/ と /edit の間の文字列
const SRC_SPREADSHEET_ID = 'ここにフォーム連携スプシのIDを貼る'; // ← ここだけ編集
// ▼ フォーム連携側のシート名
const SRC_SHEET_NAME = 'フォームの回答 1'; // 実際の名前に合わせて変更OK
// ▼ 清書用Q&Aスプレッドシート側のシート名
const DEST_SHEET_NAME = 'シート1'; // 実際の名前に合わせて変更OK
// ▼ Gemini APIキー(★スクリプトプロパティから取得★)
const GEMINI_API_KEY =
  PropertiesService.getScriptProperties().getProperty('GEMINI_API_KEY');
// ▼ Geminiのエンドポイントとモデル
const GEMINI_ENDPOINT =
'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent';
/******** 設定ここまで ********/

/**
 * メイン処理
 * - フォーム連携スプシ(A)の全行を読む
 * - 「問い合わせ内容+回答」が同じものを1つにまとめる(完全一致ベース)
 * - 清書用Q&Aスプシ(B)をヘッダー以外クリアして、
 *   UniqueなQ&AだけをGeminiで整形 → タイムスタンプ・質問・回答の3列で書き込む
 */
function rebuildQAWithGemini() {
  // フォーム連携スプシ(A)
  const srcSS = SpreadsheetApp.openById(SRC_SPREADSHEET_ID);
  const srcSheet = srcSS.getSheetByName(SRC_SHEET_NAME);

  // 清書用Q&Aスプシ(B = このスクリプトが紐づいているファイル)
  const destSS = SpreadsheetApp.getActiveSpreadsheet();
  const destSheet = destSS.getSheetByName(DEST_SHEET_NAME);

  const lastRow = srcSheet.getLastRow();

  if (lastRow < 2) {
    Logger.log('フォーム連携シートにデータがありません');
    clearDestBody_(destSheet);
    return;
  }

  // A2〜最終行まで取得
  const lastCol = srcSheet.getLastColumn();
  const values = srcSheet.getRange(2, 1, lastRow - 1, lastCol).getValues();

  // ---- 「問い合わせ内容+回答」が同じものを1つにまとめる ----
  const uniqueMap = new Map(); // key: normalized question+answer, value: 最初のレコード

  for (let i = 0; i < values.length; i++) {
    const row = values[i];

    const timestamp = row[0];  // A: タイムスタンプ
    const department = row[1]; // B: 部署名
    const name = row[2];       // C: 氏名
    const email = row[3];      // D: メールアドレス
    const question = row[4];   // E: 問い合わせ内容
    const answer = row[5];     // F: 回答(人間による入力)

    // 回答が空の行はスキップ(まだ対応中など)
    if (!answer) continue;

    // 正規化してキーを作る(前後の空白や改行の違い程度は潰す)
    const key = normalizeQAKey_(question, answer);

    if (!uniqueMap.has(key)) {
      uniqueMap.set(key, {
        timestamp,
        department,
        name,
        email,
        question,
        answer
      });
    }
  }

  Logger.log(`Unique Q&A count: ${uniqueMap.size}`);

  // ---- 清書用Q&Aシート(B)をヘッダー以外クリア ----
  clearDestBody_(destSheet);

  // ---- UniqueなQ&Aだけ、1件ずつGeminiで整形して書き込み ----
  for (const [, record] of uniqueMap) {
    const { timestamp, department, name, email, question, answer } = record;
    const prompt = createPromptForQA(question, answer, department, name, email, timestamp);
    const rawResponse = callGemini(prompt);

    if (!rawResponse) {
      Logger.log(`Gemini返却なし: timestamp=${timestamp}, name=${name}`);
      continue;
    }

    const qa = parseGeminiJson_(rawResponse);
    if (!qa) {
      Logger.log(`JSONパース失敗: timestamp=${timestamp}, name=${name}, raw=${rawResponse}`);
      continue;
    }

    // 清書用Q&Aスプシには「タイムスタンプ」「問い合わせ内容」「問い合わせ回答」の3列で書き込む
    destSheet.appendRow([
      timestamp,
      qa.question,
      qa.answer
    ]);

    // レート制限対策(必要に応じて調整)
    Utilities.sleep(1200);
  }
}

/**
 * 質問+回答から、重複判定用のキーを作る
 */
function normalizeQAKey_(question, answer) {
  const normalize = (text) => {
    if (!text) return '';
    return String(text)
      .replace(/\s+/g, ' ')
      .trim();
  };

  return normalize(question) + '||' + normalize(answer);
}

/**
 * 清書用Q&Aシートのヘッダー以降をクリアする
 */
function clearDestBody_(sheet) {
  const lastRow = sheet.getLastRow();
  const lastCol = sheet.getLastColumn();
  if (lastRow > 1) {
    sheet.getRange(2, 1, lastRow - 1, lastCol).clearContent();
  }
}

/**
 * RAG用にQ&Aを整形するためのプロンプト
 * - 出力はJSONのみ({"question": "...", "answer": "..."}) 
 */
function createPromptForQA(question, answer, department, name, email, timestamp) {
  return `
あなたは社内ヘルプデスクのナレッジ整形担当です。
以下の「質問」と「それに対する回答」を、ベクトル検索ベースのRAGシステムに登録しやすいように整形してください。

【目的】
- 後から検索しやすいように、「問い合わせ内容」と「それに対する回答」をそれぞれ分かりやすい文章に整形する
- 問い合わせの背景・前提条件・質問の意図を、質問文の中に自然に含める
- 回答は、要点が分かりやすく、社内ドキュメントとしてそのまま使えるレベルの文章にする
- 不要な個人情報(電話番号・住所など)は削除する
- 間違った情報を推測で含めないようにしてください

【出力フォーマット(重要)】
- JSON形式のみで出力してください。日本語の説明文などは一切書かないでください。
- フォーマットは次のとおりです:

{
  "question": "整形後の問い合わせ内容をここに入れる。日本語、敬体(〜です/〜ます)。",
  "answer": "整形後の問い合わせ回答をここに入れる。日本語、敬体(〜です/〜ます)。"
}

【メタ情報】
- 部署: ${department}
- 氏名: ${name}
- メールアドレス: ${email}
- 問い合わせ日時: ${timestamp}

【元の質問】
${question}

【元の回答】
${answer}
  `;
}

/**
 * Gemini APIを呼び出してテキストを生成する関数
 * - 戻り値は「モデルが返したテキスト全体」(JSON文字列の想定)
 */
function callGemini(prompt) {
  if (!GEMINI_API_KEY) {
    throw new Error('GEMINI_API_KEY がスクリプトプロパティに設定されていません。');
  }

  const url = `${GEMINI_ENDPOINT}?key=${GEMINI_API_KEY}`;

  const payload = {
    contents: [
      {
        parts: [
          { text: prompt }
        ]
      }
    ]
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(payload),
    muteHttpExceptions: true
  };

  const res = UrlFetchApp.fetch(url, options);
  const code = res.getResponseCode();
  const body = res.getContentText();

  if (code !== 200) {
    Logger.log('Gemini error: ' + code + ' ' + body);
    return null;
  }

  const data = JSON.parse(body);

  const text =
    data.candidates &&
    data.candidates[0] &&
    data.candidates[0].content &&
    data.candidates[0].content.parts &&
    data.candidates[0].content.parts[0].text;

  return text || '';
}

/**
 * Geminiからの応答(text)をJSONとしてパースする
 */
function parseGeminiJson_(rawText) {
  if (!rawText) return null;

  let text = String(rawText).trim();

  // ```json ... ``` で囲まれている場合に中身だけ抜き出す
  const codeBlockMatch = text.match(/```(?:json)?([\s\S]*?)```/i);
  if (codeBlockMatch) {
    text = codeBlockMatch[1].trim();
  }

  // 一番最初の { から最後の } までを抜き出す
  const firstBrace = text.indexOf('{');
  const lastBrace = text.lastIndexOf('}');
  if (firstBrace === -1 || lastBrace === -1 || lastBrace <= firstBrace) {
    return null;
  }

  const jsonPart = text.substring(firstBrace, lastBrace + 1);

  try {
    const obj = JSON.parse(jsonPart);
    if (!obj.question || !obj.answer) {
      return null;
    }
    return {
      question: String(obj.question),
      answer: String(obj.answer)
    };
  } catch (e) {
    Logger.log('JSON.parse error: ' + e + ' / text=' + jsonPart);
    return null;
  }
}

ソースコードの「const SRC_SPREADSHEET_ID = `ここにフォーム連携スプシのIDを貼る`; // ← ここだけ編集」の「SRC_SPREADSHEET_ID」を以下の手順に従って変更してください。

  1. 先程の「社内問い合わせ対応Q&Aスプレッドシート」を開く
  2. URLの/d/と/edit の間にある文字をコピー
  3. コピーしたものを貼り付け

例えば”https://docs.google.com/spreadsheets/d/1ni4Adjvpasdhfjx3/edit…”のようなURLの場合は、下のようになります。

const SRC_SPREADSHEET_ID = "1ni4Adjvpasdhfjx3”;

次に、サイドバーの「プロジェクトの設定」をクリックします。

プロジェクトの設定をクリック

下部にある、「スクリプトプロパティを追加」をクリックします。

スクリプトプロパティを追加

プロパティに「GEMINI_API_KEY」を入力してください。

値はAlza...から始まるGeminiのAPIキーを入力し、「スクリプトプロパティを保存」をクリックします。

APIキーは外部に共有しないよう注意してください。

APIキーを入力

なぜ生成AIにナレッジを生成させるのか?

生のQ&Aでは口語や個人情報などナレッジファイルとして扱うには、不要な情報が多く含まれます。

また、Q&Aのデータには重複する内容も含まれるために、Q&Aをもとに生成AIに校正させることで、RAGの回答精度を向上させることが可能です。

GeminiのAPIキーの発行

Google AI Studioを開き、サイドバーのGet API keyをクリックし、「Copy API key」を選択してください。

APIキーの発行

冒頭でも紹介した通り、GeminiAPIの使用に際して「無料サービス」を利用する場合は、Geminiに送信されたコンテンツと生成された回答がGoogleのプロダクトの改善に用いられるのでプライベート情報や機密情報、個人情報は送信しないようにして下さい。

「有料サービス」の場合はこの限りではありません。

詳細はこちらをご覧ください。

GASを実行してみる

コード.gsを開いて実行をクリックする。

GASを実行

最初の実行のみ承認が必要になるので、「権限を確認」を押下して「詳細を表示」→「無題のプロジェクト(安全ではないページ)に移動」をクリックします。(GASでスプレッドシートやGeminiにアクセスする際に必ず承認が必要になります。)

権限を確認

全て選択をクリックし、続行します。

権限を承認

ENSOUのカスタムチャットボットを作成

ENSOU AIにログインしてカスタムチャットボットを選択します。

ENSOU AIのフリープランはメールアドレスのみでご利用いただけます。

ご登録はこちら

ENSOUチャットボットにログイン

すると以下のような画面になるので、Googleドライブ連携で問い合わせ対応用の任意のナレッジファイルと「ENSOU生成Q&A」を登録し、カスタム指示にプロンプトを入力します。

カスタムチャットボット作成

以下、カスタム指示の全文になります。実際に使用する場合は、{Googleフォームの回答用URL}を変更してください。

## 出力のルール
出力の最後に必ず「解決しない場合は {Googleフォームの回答用URL}からお問い合わせください」を挿入してください。

使い方のイメージ

具体的な使い方としては以下のようになります。

  1. カスタムチャットボットでGoogleフォームのURLを提示する
  2. ユーザーがカスタムチャットボットで回答を得られない場合はGoogleフォームから問い合わせ申請をさせる
  3. 担当者が回答を「社内問い合わせ対応Q&A」のF列に入力する
  4. 定期的にGASを実行する

まとめ

本記事ではENSOUのカスタムチャットボットをベースにした、問い合わせ対応とナレッジへの登録を自動化するエージェントの作成方法について、実際の画面やコピペできるコードを紹介しながら分かりやすく解説しました。

このエージェントの導入により、従業員が本来注力すべき業務に集中できるようになり、組織全体の生産性向上が期待できます。

ぜひ、この記事を参考に問い合わせ対応&ナレッジの自動生成エージェントを作成してみてください。

株式会社Digeonでは法人向けにGPT-5.1をセキュアに使えるサービスである「ENSOUチャットボット」を提供しています。

業務全体でのナレッジ活用に興味のある方は、ENSOUチャットボットをお試しください。

無料ですぐに使えるフリープランのご利用開始はこちらから👇

ENSOU AI

ご相談、無料トライアルは以下からお問い合わせください👇

サービス紹介資料はこちらからダウンロードいただけます👇

あわせて読む

ENSOUのカスタムチャットボットや問い合わせ対応に関する記事です。よろしければこちらの記事も併せてご覧ください。

フリープラン

今すぐ無料で始める

クレジットカード登録・申込不要。今すぐ始められます。

メールアドレスのみで今すぐ始められます!
無料で始める
お問い合わせ
無料でRAG構築ができる
無料で使えるプロンプトテンプレート多数
無料でGPT-5.1が使える

NEW

最新記事

ENSOUを使った問い合わせ対応&ナレッジ自動生成エージェントの作成方法

ブログ

ENSOUを使った問い合わせ対応&ナレッジ自動生成エージェントの作成方法

ENSOUのカスタムチャットボット機能を使って、問い合わせ対応とナレッジの自動生成を行う問い合わせ対応エージェントの作成方法を画像やコード付きで徹底解説します。

2025/12/08詳細を見る
NotebookLMでのスライド作成方法を徹底解説

ブログ

NotebookLMでのスライド作成方法を徹底解説

NotebookLMを用いてスライドを作成する方法を画像付きでわかりやすく解説します。

2025/12/04詳細を見る
ENSOUチャットボットとGoogleドライブを連携させてRAGを構築する方法を徹底解説

ブログ

ENSOUチャットボットとGoogleドライブを連携させてRAGを構築する方法を徹底解説

本記事ではGoogleドライブをENSOUと連携し、社内データを効率的に活用する方法を解説します。

2025/11/25詳細を見る
NanoBanana Pro 発表!画像生成・編集がプロ仕様へ進化。旧NanoBananaと徹底比較。

ブログ

NanoBanana Pro 発表!画像生成・編集がプロ仕様へ進化。旧NanoBananaと徹底比較。

NanoBanana Proが登場!旧NanoBananaと何が変わったのか。本記事ではNanoBanana Proの使い方から旧モデルとの比較を紹介しています。

2025/11/21詳細を見る
Gemini3を使って業務で使えるスライドの作成方法を徹底解説

ブログ

Gemini3を使って業務で使えるスライドの作成方法を徹底解説

2025年11月18日にGoogleよりGeminiの新モデルである「Gemini 3」が発表されました。この記事ではGemini 3を活用して業務で使えるレベルの資料作成の仕方を徹底解説します。

2025/11/20詳細を見る
Gemini3が登場 - 推論とマルチモーダル能力が大幅進化

ブログ

Gemini3が登場 - 推論とマルチモーダル能力が大幅進化

Googleより新たなLLM(大規模言語モデル)としてGemini3が発表されました。 旧モデルのGemini2.5との進化点からGPTとの比較まで徹底解説します。

2025/11/19詳細を見る