Google スプレッドシートで Vertex AI Search を使った問い合わせシステムを構築、さらに Gemini を利用し回答を最適化してみた!

2024年8月22日掲載

8月に行われた Google Cloud Next Tokyo ’24 では、Google Cloud の 生成AI の進化と最新情報、ユースケースなど、生成AI がメインテーマだ!と言ってもいいほど、たくさんのコンテンツがありました。その中で、注目を浴びている生成AI サービスの一つが、Vertex AI Agent Build の Vertex AI Search - マネージドRAG サービスです。 

今回は、Vertex AI Search の API と Gemini API を利用し、Google スプレッドシートで Vertex AI Search を使った問い合わせシステムを構築、さらに Gemini を利用して回答を最適化してみた内容をお届けします!

目次

1.仕組み

Google Apps Script (以降 GAS) を用いて作成したスプレッドシートのサイドバーを画面UIとして利用し、質問を投げると Vertex AI Search のアプリを呼び出して回答を取得、Gemini を利用して回答を生成、生成した回答をもう一度 Gemini を利用し最適化してユーザーに返す、と言う流れになっています。

今回は最新バージョンの Gemini 1.5 pro を利用しております。

利用サービス:
・UI(ユーザーインターフェース)/ログ格納:Googleスプレッドシート
・検索ツール:Vertex AI Search(*)
・データ格納場所:Cloud Storage

(*) Vertex AI Search は、Google Cloud が提供する生成AI を活用した検索エンジン構築サービスとなり、企業内でのドキュメント検索や、顧客向けサービス内での検索機能に適用することで、ユーザー体験の向上や業務効率化を図ることができます。また、AI や機械学習の専門知識がなくても、簡単に生成AIアプリケーションを作成できる点が特長です。

2. 事前準備

検索対象ファイルの準備

以下の2つの資料を検索対象にします。
当社(ソフトバンク株式会社) 決算説明会資料
・厚生労働省の栄養・食生活に関する資料
 出典:厚生労働省のPDFファイル一覧


Vertex AI Search アプリの作成

次に、Vertex AI Search アプリを作成します。
今回は2つのデータストアを作成し、それぞれ検索対象のPDFを入れておきます。そしてVertex AI Search アプリは、2つのデータストアと紐づけて作成します。

詳細については、こちらのブログ「ノーコードで Vertex AI Search を利用してGoogle サイトでRAG構築してみた」をご覧ください。Vertex AI Search で構築した検索アプリを Google Cloud Storage (GCS) で公開する方法や、精度向上方法に関する記事においては、本記事の一番下にある関連記事をご確認ください。

アプリ作成後のイメージです。

検索結果を要約する際、Gemini 1.5 Pro を利用するように設定します。

試しに、プレビュー画面で2つの質問をしてみたいと思います。
質問1:2024年度Q1の売上高を教えて

2つのデータストアから検索し、質問にあった回答を返してくれました。

Vertex AI Search 検索結果

もう一つのデータストアに関連する質問もしてみます。
質問2:食生活の重要性を教えて

質問の意図を把握し、他のデータストアから質問に関連する内容を抽出、LLMで回答を生成してくれました。

この回答で十分ですが、今回ご紹介する仕組みでもっと簡素な回答を得るようにしたいと思います。

3. スプレッドシートのサイドバーを利用した問い合わせシステムの構築

この内容はすべてスプレッドシートの GAS で行います。

サイドバーを作成します。

<!DOCTYPE html>
<html>
<head>
  <base target="_top">
  <link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
  <style>
    .submit-button {
      background-color: #1a73e8;
      color: #000000; /* 文字色を黒に設定 */
      border: none;
      padding: 0 24px;
      font-size: 14px;
      font-weight: 500;
      border-radius: 4px;
      cursor: pointer;
      transition: background-color 0.3s ease;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      height: 36px;
      min-width: 80px;
      text-transform: uppercase;
      letter-spacing: 0.5px;
      box-shadow: 0 1px 2px 0 rgba(60,64,67,0.3), 0 1px 3px 1px rgba(60,64,67,0.15);
    }
    .submit-button:hover {
      background-color: #185abc;
      box-shadow: 0 1px 3px 0 rgba(60,64,67,0.3), 0 4px 8px 3px rgba(60,64,67,0.15);
    }
    .submit-button:focus {
      outline: none;
      box-shadow: 0 0 0 2px #4285f4;
    }
    .spinner {
      display: none;
      margin-left: 10px;
      border: 4px solid rgba(255, 255, 255, 0.3);
      border-top: 4px solid #000;
      border-radius: 50%;
      width: 20px;
      height: 20px;
      animation: spin 1s linear infinite;
    }
    @keyframes spin {
      0% { transform: rotate(0deg); }
      100% { transform: rotate(360deg); }
    }
    .loading .spinner {
      display: inline-block;
    }
    .loading .submit-button-text {
      display: none;
    }
  </style>
</head>
<body>
  <div>
    <h1>質問を記載したうえ、送信ボタンを押してください</h1>
    <textarea id="question" style="width: 100%; height: 100px;"></textarea>
    <br>
    <button class="submit-button" id="submitButton" onclick="submitQuestion()">
      <span class="submit-button-text">送信</span>
      <div class="spinner"></div>
    </button>
  </div>
  <script>
    function submitQuestion() {
      const question = document.getElementById('question').value;
      const submitButton = document.getElementById('submitButton');
      submitButton.classList.add('loading');
      google.script.run.withSuccessHandler(onSuccess).submitQuestion(question);
    }

    function onSuccess(response) {
      document.getElementById('question').value = '';
      const submitButton = document.getElementById('submitButton');
      submitButton.classList.remove('loading');
    }
  </script>
</body>
</html>


スプレッドシートでサイドバーを開けるようにメニュー追加すると同時に、質問をして送信ボタンを押すと Vertex AI Search アプリを呼び出して回答を取得するようにします。

function onOpen() {
  SpreadsheetApp.getUi()
    .createMenu('サポート')
    .addItem('お問い合わせ', 'showSidebar')
    .addToUi();
}

function showSidebar() {
  const htmlOutput = HtmlService.createHtmlOutputFromFile('Sidebar')
    .setTitle('Vertex AI Search チャットボット')
    .setWidth(400);
  SpreadsheetApp.getUi().showSidebar(htmlOutput);
}

function submitQuestion(question) {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const lastRow = sheet.getLastRow();
  const nextRow = lastRow + 1;

  // 回答を取得
  var answer = callVais(question);

  // さらに Gemini 1.5 Pro を利用して回答を最適化する
  var prompt = "プロンプト入力";
  var newAnswer = callGemini(answer, prompt,"GeminiのAPIキー入力");

  // スプレッドシートに質問とオリジナル回答、最適化された回答を保存
  sheet.getRange(nextRow, 1).setValue(question);
  sheet.getRange(nextRow, 2).setValue(answer);
  sheet.getRange(nextRow, 3).setValue(newAnswer);
  return newAnswer;
}

function callGemini(answer, prompt, apiKey) {
  const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=${apiKey}`;

  const payload = {
    "contents": [{
      "parts": [{
        "text": prompt + " 回答は " + answer
      }]
    }]
  };

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

  const response = UrlFetchApp.fetch(url, options);
  const jsonResponse = JSON.parse(response.getContentText());

  if (jsonResponse && jsonResponse.candidates && jsonResponse.candidates.length > 0) {
    const answerText = jsonResponse.candidates[0].content.parts[0].text;
    return answerText;
  } else {
    return "回答を取得できませんでした。";
  }
}


function callVais(searchQuery) {
  const projectId = "プロジェクトIDを入力";
  const location = 'global';
  const collectionId = 'default_collection';
  const engineId = "Vertex AI Search アプリIDを入力";
  const servingConfigId = 'default_config';

  const apiEndpoint = location === 'global'
    ? 'discoveryengine.googleapis.com'
    : `${location}-discoveryengine.googleapis.com`;

  const name = `projects/${projectId}/locations/${location}/collections/${collectionId}/engines/${engineId}/servingConfigs/${servingConfigId}`;

  const request = {
    pageSize: '入力',
    query: searchQuery,
    servingConfig: name,
  };

  const url = `https://${apiEndpoint}/v1beta/${name}:search`;
  
  const options = {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(request),
    headers: {
      Authorization: 'Bearer ' + ScriptApp.getOAuthToken(),
    },
    muteHttpExceptions: true,
  };

  var responseText = "";

  try {
    const response = UrlFetchApp.fetch(url, options);
    const responseData = JSON.parse(response.getContentText());
    
    if (responseData.results && responseData.results.length > 0) {
      const result = responseData.results[0];
      responseText = result.document.derivedStructData.extractive_answers[0].content;
    } else {
      responseText = "結果が見つかりません";
      console.log('No results found');
    }
  } catch (error) {
    responseText = "エラーが発生しました";
    console.error('Error:', error);
  }
  return responseText;
}

これで終わりです!

4. 動かしてみる

今回は、さらに回答を最適化する際、Vertex AI Search からの回答をもっと簡素にするため、Gemini 1.5 Pro にプロンプト「回答よりタグを削除してください。回答をわかりやすく簡素にしてください」を設定しました。

まず、スプレッドシートからサイドバーを起動するイメージです。

プレビュー画面で質問した内容と同じ内容を質問します!

質問1:2024年度Q1のコンシューマ向け事業の営業利益を教えて

2つのデータストアから検索し、質問にあった回答を返してくれるほか、さらに Gemini によって回答が簡素化され、わかりやすくなっています。

続いて他のデータストア関連の質問もします。
質問2:食生活の重要性を教えて

こちらも簡素化された回答が返ってきました。

5. メリット

Vertex AI Search は数ステップで簡単に検索アプリを構築でき、かつサイトにコードを埋め込むだけで簡単にUIを用いた、生成AI 検索アプリが作れてしまうので、わざわざスプレッドシートで実装する必要がある?と思うかもしれません。

今回の仕組みによるメリットを3つあげます。

メリット1:ログ書き込みによるログ集約と見える化、そしてFAQの作成が可能

今回のシステムに加え、さらに BigQuery や Looker Studio を利用することで、BigQuery によるログ集約、そしてBI ツールによる可視化ができます。さらに ログ分析しFAQ を作成することで、さらなる精度向上を図ることが可能です。

FAQによる精度向上の方法については、こちらの記事「Vertex AI Search でグラフや画像データを元にした回答精度を向上させるコツ」をご参照ください。

メリット2: 精度検証ツールとして利用

スプレッドシートに質問と回答を書き込んでいるので、同じ質問をした場合の回答を見比べることで精度を比較することが可能です。さらに精度ツールとして自動化したい場合は、生成AI による採点もできるかと思います。この時、メリット1で取り上げた FAQ を採点時の質問と模範回答として利用できますね!

メリット3: 回答内容の最適化

Vertex AI Search でも回答要約時に、Gemini を含むLLM を利用していますが、今回の仕組みと検証でお見せしたように、さらに Gemini を使用してさらに指示を出すことで、もっとわかりやすく簡素な回答が返されました。

6. おわりに

今回は、スプレッドシートと GAS を使って簡単に生成AI 検索アプリを構築する方法をご紹介しました。

生成AI を使った社内検索システムを作りたい場合は、まず Vertex AI Search とオプション機能をご利用することを推奨します。

そのうえ、さらに回答を最適化してみたい、FAQ 作成時に既存 Q&A を参考にしたい等、ニーズがあれば、ぜひ本仕組みでお試してみてください。

最後に当社の Vertex AI DIY プランを宣伝して終わりにしたいと思います。

最後までお読みいただきありがとうございました!

Vertex AI DIYプランについて

Vertex AI Search を使って社内文書を検索する生成 AI を構築してみませんか?
ソフトバンクのエンジニアが構築をサポートします。

Vertex AI DIY プランでは、以下の3つのことをご体験いただけます。
詳細は、関連サービスにある「Vertex AI DIYプラン」をご確認ください。

関連サービス

Vertex AI Search を使って社内文書を検索する生成AIを構築してみませんか?
ソフトバンクのエンジニアが構築をサポートします。
Google の生成AIの導入を考えている方はもちろん、どのようなものか確認したいという方でもご活用いただけます。

Looker は定義から集計、可視化の一連のデータ分析プロセスをカバーする BI ツールを超えるデータプラットフォームです。ソフトバンクは、顧客のニーズに合わせて柔軟なサポートを提供し、Looker を活用したデータドリブンな企業変革を支援しています。

Google サービスを支える、信頼性に富んだクラウドサービスです。お客さまのニーズにあわせて利用可能なコンピューティングサービスに始まり、データから価値を導き出す情報分析や、最先端の機械学習技術が搭載されています。

MSP(Managed Service Provider)サービスは、お客さまのパブリッククラウドの導入から運用までをトータルでご提供するマネージドサービスです。

おすすめの記事

条件に該当するページがございません