Google スプレッドシートで、自然言語で質問できる関数を作ってみよう(Google Cloud Vertex AI 中編)

2024年3月29日掲載

Google Cloud

システムエンジニアの成瀬です。

日々刻々と進化を続けているAIやクラウドサービスを検証したり、AIを活用したアプリを作ったりしています。

目次

  • この記事は、「Google スプレッドシートで、自然言語で質問できる関数を作ってみよう(Google Cloud Vertex AI 」の中編になります。(前・中・後の3部構成に変更したため、今回は前編の続きとなります)
  • 前編「Google スプレッドシートで、自然言語で質問できる関数を作ってみよう(Google Cloud Vertex AI 前編)」では、Text Embedding APIを使用して、テキストどうしの意味的な類似度を判定する方法について説明しました。
  • 今回は、Vertex AI のテキスト生成APIを使用して、質問に関連するテキストから回答を生成する方法について説明します。

テキスト生成AIをQ&Aに使ってみよう

テキスト生成AIで利用されている大規模言語モデル(基盤モデル)は、色々なことを良く知っていて、流暢な言葉で質問に答えてくれます。

その一方で、以下のような困った回答に出くわすこともしばしばあります。
 

  • 答えを知らない(プライベートな日記や非公開資料などについて)
  • 情報が古い(社会情勢や人事、ランキングなど)
  • 事実と異なる(ハルシネーション)
  • 偏った意見(偏見や差別など)
  • 以前の回答と矛盾している(自己矛盾)
  • 意味不明(単語の繰り返しや記号の羅列など)

そもそも、生成AIモデルの知識はトレーニング時点の学習データに基づいているため、学習データに含まれていない情報や、最新情報については答えることができません。

また、生成AIモデルの学習データの大部分は、インターネットなどから入手可能な公開情報を利用しているために、不正確・不完全・非中立・非公正な情報が含まれていることが多々あります。

そのような玉石混交の知識の中から、質問に関係のありそうなことを答えているだけで、正しいかどうかを判断しているわけではありません。

また、知識が膨大であるだけに、質問の内容が漠然としているほど回答も発散してしまい、精度も下がってしまいます。

以上のことから、生成AIをQ&Aに利用するにあたって(特に最新情報や非公開情報について)、望ましい回答を引き出すことは、簡単ではないことがわかっていただけたかと思います。

では、どうすればよいでしょうか?

あなたは新入社員の教育係です

fig.1

世の中のことは良く知っているけど、業務のことはよくわかっていない...

生成AIモデルって、なんだか新入社員と良く似ていませんか?

ここでは、新入社員の教育係になったつもりで対策を考えてみましょう。
 

1. 知らないことは教えてあげる(知識を与える)

   新入社員は色々な資料を読んで仕事に必要な知識を身につけます。

   生成AIモデルにも質問を受けた時に参照すべき情報を教えてあげましょう。

2. 間違った回答をしないように導いてあげる(指示を明確にする)

   知識があるからといって、正しい回答ができるとは限りません。

   回答の作法や禁句など、指示を明確にすることによって、与えられた知識からどのように回答すればいいのか導いてあげましょう。

 

では、今回の対策の「知識を与える」「指示を明確にする」のそれぞれの具体的な方法について、これから見ていきましょう。

生成AIモデルに知識を与える

生成AIモデルに知識を与える方法としては、主に以下の3つが挙げられます。

  • 事前学習(プリトレーニング)
  • ファインチューニング(追加学習、微調整)
  • グラウンディング

事前学習(プリトレーニング)

事前学習は、ゼロから生成AIモデルをトレーニングする方法で、膨大なコンピューティングリソースを使いながら、大量のトレーニングデータでモデルに学習させます。

これにより、生成AIモデルは言語的素養や世の中に関する知識を身につけます。

トレーニングにかかる費用は莫大で、あるモデル(1800億パラメータ)では55日間で、24億円かかったそうです。

ファインチューニング(追加学習、微調整)

ファインチューニングは、事前学習によってトレーニングされた生成AIモデルに対して、性能改善や、特定の分野の課題に適応させるために、独自のデータでさらにトレーニングします。

ファインチューニングされたモデルはカスタムモデルなどと呼ばれます。

ほとんどのクラウドサービスでも利用可能ですが、基盤モデルが限定されています。

グラウンディング

グラウンディングは、プロンプトを経由して外部の情報を与えることで、生成AIモデルの知識を一時的に補強します。

外部から知識を与えることが可能になるために、回答の情報源を明らかにすることができます。

 

以下にそれぞれの方法のポジティブな点・ネガティブな点について、簡単にまとめてみました。

方法ポジティブな点ネガティブな点
事前学習

どんなモデルでも作れる

トレーニングが必要

コストが莫大

AIの専門知識が必要

ファインチューニング

プロンプトが小さくてすむ

対象モデルが限定される

トレーニングが必要

グラウンディング

トレーニング不要

情報源を明らかにできる

プロンプトが大きくなる

グラウンディングを試してみよう

それでは、生成AIモデルに知識を与える方法として、最も手軽なグラウンディングを利用してみたいと思います。

実際にプロンプトを試してみながら、よりよい回答を引き出す方法について考えていきましょう。

※ 生成AIの回答はモデルのバージョンやリクエストパラメータによって異なる可能性があります。常に例と同じ結果になるわけではないことに注意してください。

カスタム関数の作成

プロンプトからテキストを生成するカスタム関数

概要

入力されたプロンプトからテキストを生成します。

関数の構文

GENERATE_TEXT(PROMPT)

PROMPT:プロンプトです。

使用例

GENERATE_TEXT( "日本の内閣総理大臣は誰ですか?" )

戻り値

生成テキスト

Vertex AI テキスト生成 APIの使用方法

基盤モデル

今回使用するテキスト生成APIの基盤モデルは、日本語にも対応している PaLM2 for Text の最新版を使用します。

Vertex AI モデル情報

モデル名バージョン最大入力トークン数最大出力トークン数
text-bison

最新版

81922048
text-bison@002

安定版

81921024

※1トークンは英数字で約4文字、漢字で約 1 文字に相当します。

リクエストURL

POST https://us-central1-aiplatform.googleapis.com/v1/projects/{プロジェクトID}/locations/us-central1/publishers/google/models/text-bison:predict

リクエストヘッダ
名称説明

Content-Type
(必須)

"application/json"

リクエストデータの種類(JSON)

Authorization
(必須)

"Bearer {アクセストークン}"

サービス認証に必要

BASE64でエンコードする

※ アクセストークンは別途APIで取得する必要があります。取得方法については、前編の「アクセストークンの取得方法」を参照してください。

リクエストデータ (JSON)(一部省略)
フィールド名データ型説明

instances

オブジェクトの配列

入力プロンプト情報

(複数は不可)

 

prompt

テキスト

モデルが応答を生成するための入力テキスト

parametersオブジェクト調整パラメータ
 candidateCount

整数

(1~8)

回答のバリエーションの数

デフォルト: 1

maxOutputTokens

整数

(1~2048)

生成する最大トークン数

デフォルト: 1024

temperature

実数

(0.0~1.0)

生成結果の多様性

0.0は低い、1.0は高い

デフォルト 0.0

topK

整数

(1~40)

予測確率上位のサンプリング数

デフォルト: 40

topP

実数

(0.0~1.0)

予測確率上位のサンプリング割合

デフォルト: 0.95

stopSequenceテキストの配列

応答内でいずれかの文字列が見つかった場合にテキストの生成を停止するようにモデルに指示するテキストのリストを指定。大文字と小文字は区別。

デフォルト: []

リクエストデータのサンプル
{
  instances: {
    prompt: "日本の内閣総理大臣は誰ですか?"
  },
  parameters: {
    candidateCount: 1,
    maxOutputTokens: 1024,
    temperature: 0.0,
    topP: 0.1,
    topK: 1,
    opt_out: true,
  }
}
レスポンスデータ (JSON)(一部省略)
フィールド名データ型説明

predictions

オブジェクトの配列

生成結果

リクエストデータのparameters.candidateCountに対応する件数の生成結果が格納されます

 

content

テキスト

生成テキスト

safetyAttributes

オブジェクト

安全属性情報

 

categories

テキストの配列

生成されたコンテンツに関連付けられた安全属性カテゴリの表示名

順序はスコアと一致します

blocked

ブーリアン

モデルの入力または出力がブロックされたかどうか

scores

数値の配列

各カテゴリの信頼度スコア

値が大きいほど信頼度が高いことを意味します。

metadataオブジェクトメタデータ
 tokenMetadataオブジェクト

トークン情報

 input_token_countオブジェクト

入力トークン情報

 total_tokens整数

合計トークン数

 output_token_countオブジェクト

出力トークン情報

 total_tokens整数

合計トークン数

レスポンスデータのサンプル(一部省略)
{
  predictions: [
    {
      content: '私の知識は2021年1月までの情報に基づいているため、現在の内閣総理大臣は菅義偉氏です。ただし、この情報は古くなっている可能性があるため、最新の情報を取得するには、内閣府のウェブサイトや他の信頼できる情報源を確認することをお勧めします。' 
    },
  ],
  metadata: {
    tokenMetadata: { 
      inputTokenCount: { 
        totalTokens: 10
      },
      outputTokenCount: { 
        totalTokens: 63 
      }
    }
  }
}

上のサンプルの場合、カスタム関数の戻り値として返すためには、レスポンスデータの predictions[0].content をセットすればよいことになります。

なお、Vertex AI APIのリクエストは、デフォルトで1分あたり30回の利用制限があります。利用制限を超過した場合、以下のエラーレスポンスが返ってきます。

利用制限超過時のレスポンスデータ
{
  code: 429, 
  message: 'Quota exceeded for aiplatform.googleapis.com/online_prediction_requests_per_base_model with base model: textembedding-gecko. Please submit a quota increase request. https://cloud.google.com/vertex-ai/docs/quotas.',
  status: 'RESOURCE_EXHAUSTED'
}

カスタム関数の登録

※ これから登録するコードは、前編で作成したAppsScriptのプロジェクトを前提にしています。

前編と同様にカスタム関数をスクリプトエディタから登録します。

  1. スプレッドシートのメニューから、「拡張機能」 -> 「Apps Script」を選択して、スクリプトエディタを開きます。
fig.2
  1. 「+」ボタン(ファイルを追加)をクリックして、「スクリプト」を選択します。
fig.3
  1. ファイル名を「無題」から「PART2」に変更して、エンターキーを押します。
fig.27
  1. ファイル「PART2.gs」内の1〜3行目を選択して、デリートキーかバックスペースキーを押してクリアします。
fig.27
  1. 以下のコードを全て選択してコピーします。
/**
 * 生成AI APIを使用して、テキストを生成します。
 *
 * @param {"トイレはどこですか"} PROMPT プロンプト {文字列}
 *     プロンプトのテキストです。
 * @return {string}
 *
 * @customfunction
 * copyright (c) 2024 SoftBank Corp.
 */
function GENERATE_TEXT(PROMPT, MODEL = "text-bison") {

  let access_info;
  try {
    access_info = get_access_token_(GCP_CREDS.client_email, GCP_CREDS.private_key)
  }
  catch (e) {
    console.error(e)
    throw "内部エラーが発生しました"
  }
  const access_token = access_info.access_token


  const headers = {
    "Authorization": "Bearer " + access_token
  }


  const API_ENDPOINT = "us-central1-aiplatform.googleapis.com"
  const url = `https://${API_ENDPOINT}/v1/projects/${GCP_CREDS.project_id}/locations/us-central1/publishers/google/models/${MODEL}:predict`


  const payload = {
    instances: [
      {
        prompt: PROMPT
      },
    ],
    parameters: {
      "candidateCount": 1,
      "maxOutputTokens": 1024,
      "temperature": 0.0,
      "topP": 0.1,
      "topK": 1,
      "opt_out": true,
    }
  }


  const params = {
    method: "post",
    contentType: "application/json",
    headers: headers,
    payload: JSON.stringify(payload),
    muteHttpExceptions: true,
  }


  const res = UrlFetchApp.fetch(url, params)
  if (res.getResponseCode() != 200) {
    console.error(res.getContentText())
    throw "内部エラー"
  }


  const res_json = JSON.parse(res.getContentText())

  return res_json.predictions[0].content

}
  1. コピーしたコードを、ファイル「PART2.gs」内にペーストして、「プロジェクトを保存」ボタンをクリックします。
fig.1

カスタム関数を試してみよう

それでは、スプレッドシートからカスタム関数を実行してみましょう。

セルA1に以下の式を入力して、エンターキーを押します。

=GENERATE_TEXT("日本の内閣総理大臣は誰ですか?")

情報の鮮度はさておき、以下のような答えが返ってくれば成功です。

fig.1

もしも、以下のようなエラーが発生した場合は少し時間を空けてからもう一度実行してみてください。

2,3回リトライしてみても改善しなければ、そのまま次に進んでください。

fig.1

テキスト生成AIの応答は時間がかかることがよくあります。

原因としては、入力・出力時のトークンの長さ、モデルの種類やバージョン、サービスの環境や利用状況などが考えられます。

実は、Google スプレッドシート上で実行するカスタム関数は30秒以内に完了しないと、上のようなエラー( Exceeded maximum execution time ) が発生して、強制的に処理を中断させられてしまいます。

そこで、エラーを気にせず試せるように、カスタム関数をUIから実行できるようにコードを追加します。

UI実行用コードの登録

  1. スクリプトエディタに戻ります。
  2. ファイル「PART2.gs」内で、全ての行を選択して、デリートキーかバックスペースキーを押してクリアします。
  3. 以下のコードを全て選択してコピーします。
/**
 * スプレッドシートを開いたときにカスタムメニューを表示します。
 *
 * copyright (c) 2024 SoftBank Corp.
 */
function onOpen() {
  const ui = SpreadsheetApp.getUi();
  ui.createMenu("プロンプト実験室")
    .addItem('開く', 'show_prompt_labo_')
    .addToUi();
}



/**
 * サイドバーを表示します。
 *
 * copyright (c) 2024 SoftBank Corp.
 */
function show_prompt_labo_() {
  const html = HtmlService.createHtmlOutputFromFile('PROMPT_LABO')
    .setTitle('プロンプト実験室');
  SpreadsheetApp.getUi()
    .showSidebar(html);
}



/**
 * 生成AI APIを使用して、テキストを生成します。
 *
 * @param {"トイレはどこですか"} PROMPT プロンプト {文字列}
 *     プロンプトのテキストです。
 * @return {string}
 *
 * @customfunction
 * copyright (c) 2024 SoftBank Corp.
 */
function GENERATE_TEXT(PROMPT, MODEL = "text-bison") {

  let access_info;
  try {
    access_info = get_access_token_(GCP_CREDS.client_email, GCP_CREDS.private_key)
  }
  catch (e) {
    console.error(e)
    throw "内部エラーが発生しました"
  }
  const access_token = access_info.access_token

  const headers = {
    "Authorization": "Bearer " + access_token
  }

  const API_ENDPOINT = "us-central1-aiplatform.googleapis.com"
  const url = `https://${API_ENDPOINT}/v1/projects/${GCP_CREDS.project_id}/locations/us-central1/publishers/google/models/${MODEL}:predict`

  const payload = {
    instances: [
      {
        prompt: PROMPT
      },
    ],
    parameters: {
      "candidateCount": 1,
      "maxOutputTokens": 1024,
      "temperature": 0.0,
      "topP": 0.1,
      "topK": 1,
      "opt_out": true,
    }
  }

  const params = {
    method: "post",
    contentType: "application/json",
    headers: headers,
    payload: JSON.stringify(payload),
    muteHttpExceptions: true,
  }

  const res = UrlFetchApp.fetch(url, params)
  if (res.getResponseCode() != 200) {
    console.error(res.getContentText())
    throw "内部エラー"
  }

  const res_json = JSON.parse(res.getContentText())

  return res_json.predictions[0].content

}
  1. コピーしたコードを、ファイル「PART2.gs」内にペーストして、「プロジェクトを保存」ボタンをクリックします。
  2. 次に、「+」ボタン(ファイルを追加)をクリックして、今度は「HTML」を選択します。
fig.9
  1. ファイル名を「無題」から「PROMPT_LABO」に変更して、エンターキーを押します。
  2. ファイル「PROMPT_LABO.html」内で、全ての行を選択して、デリートキーかバックスペースキーを押してクリアします。
fig.1
  1. 以下のコードを全て選択してコピーします。
<!DOCTYPE html>
<html>

<head>
  <base target="_top">
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/purecss@3.0.0/build/pure-min.css"
    integrity="sha384-X38yfunGUhNzHpBaEBsWLO+A0HDYOQi8ufWDkZ0k9e0eXz/tH3II7uKZ9msv++Ls" crossorigin="anonymous">
</head>

<body>
  <form class="pure-form-stacked">
    <h3>プロンプト</h3>
    <textarea style="width:98%;" rows="10" id="prompt" class="pure-input-1" ></textarea>
    <button id="run" class="pure-button pure-button-primary" onclick="generate()">実行</button>
  </form>
  <br>
  <form class="pure-form-stacked">
    <h3>回答</h3>
    <p id="answer"></p>
  </form>

  <script src="https://code.jquery.com/jquery-3.7.1.min.js"
    integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
  <script>
    function generate() {
      $("#answer").html("ただいま生成中です")
      let prompt = $("#prompt").val()    
      google.script.run
      .withSuccessHandler( function(res) {
        $("#answer").text(res)
      })
      .GENERATE_TEXT(prompt)
    }
  </script>

</body>

</html>
  1. コピーしたコードを、ファイル「PROMPT_LABO.html」内にペーストして、「プロジェクトを保存」ボタンをクリックします。
  2. スプレッドシートに戻ります。
  3. ブラウザのリロードボタンなどで、スプレッドシートを再読み込みします。
fig.11
  1. メニューの「ヘルプ」の後ろに「プロンプト実験室」が表示されるはずです。
fig.12

実験してみよう

それでは、UIからプロンプトを実験してみましょう。

まず、プロンプト実験室を開きます。

  1. メニューの「プロンプト実験室」をクリックして、「開く」を選択します。
fig.13

※ もしも、ここで認証ダイアログが表示された場合は、以下のa~dの手順を実施します。

a. 認証ダイアログで「OK」をクリックします。

b. 許可するアカウントを選択します。

c. 許可ボタンをクリックします。

d. もう一度、メニューの「プロンプト実験室」をクリックして、「開く」を選択します。

  1. シートの右側にプロンプト実験室のUIが表示されます。
fig.17

実験の準備ができたところで、まだ世の中に出ていない情報(永遠に発売未定の全自動掃除機「おそうじボット」)について、質問してみましょう。

  1. プロンプトに以下の質問を入力します。
おそうじボットの電源の入れ方を教えて
  1. 次に実行ボタンをクリックします。
fig.18
  1. すると、以下のように回答が返ってきます。
fig.19

知っているはずのないことを、あたかも知っているかのように答えてしまっています。

これがハルシネーション(幻覚)と呼ばれる症状ですね。

コンテキストを与える

では、「おそうじボット」の架空の取扱説明書に記載されている、電源のオン・オフについての情報(コンテキスト)をプロンプトに追加してみましょう。

プロンプトは以下の通りです。

# 電源のオン・オフ

## 電源をオンにする。
おそうじボットの電源ボタンを押すと電源がオンになり、おそうじボットの両目(LED)が点灯します。

## 電源をオフにする。
おそうじボットの電源ボタンを30秒以上押すと電源がオフになり、おそうじボットの両目(LED)が消灯します。

質問: おそうじボットの電源の入れ方を教えて
回答:

実行すると、以下のように正しい回答が返ってきました。

プロンプトに追加されたコンテキストを認識できているようですね。

fig.20

では、コンテキストと関係のない質問として、アラームの設定方法を聞いてみましょう。

# 電源のオン・オフ

## 電源をオンにする。
おそうじボットの電源ボタンを押すと電源がオンになり、おそうじボットの両目(LED)が点灯します。

## 電源をオフにする。
おそうじボットの電源ボタンを30秒以上押すと電源がオフになり、おそうじボットの両目(LED)が消灯します。

質問: おそうじボットのアラームの設定方法を教えて
回答:

実行すると、以下のように回答が返ってきました。

fig.21

またまた、ハルシネーションが起きてしまいました。

コンテキストの内容に質問と関連する情報がなかった場合でも、嘘の回答は困りますね。

その場合、どうすればいいでしょうか?

指示を与える

それでは、コンテキストの前に生成AIモデルへの指示を追加して、回答に使用する情報をコンテキストだけに限定させてみましょう。

以下の情報だけを使用して、質問に回答してください。

# 電源のオン・オフ

## 電源をオンにする。
おそうじボットの電源ボタンを押すと電源がオンになり、おそうじボットの両目(LED)が点灯します。

## 電源をオフにする。
おそうじボットの電源ボタンを30秒以上押すと電源がオフになり、おそうじボットの両目(LED)が消灯します。

質問: おそうじボットのアラームの設定方法を教えて
回答:

回答は以下の通りです。

fig.22

これで嘘は言わなくなりましたね。

ただ、内部的な事情をそのまま質問者に伝えてしまっては、あまり都合が良くないですね。

コンテキストに関連する情報が含まれていなかった場合の回答として、質問者向けには「わかりません」とだけ答えてもらうようにしましょう。

では、指示を追加した以下のプロンプトで実行してみましょう。

以下の情報だけを使用して、質問に回答してください。
回答が見つからない場合は「わかりません」とだけ答えてください。

# 電源のオン・オフ

## 電源をオンにする。
おそうじボットの電源ボタンを押すと電源がオンになり、おそうじボットの両目(LED)が点灯します。

## 電源をオフにする。
おそうじボットの電源ボタンを30秒以上押すと電源がオフになり、おそうじボットの両目(LED)が消灯します。

質問: おそうじボットのアラームの設定方法を教えて
回答:

結果は以下の通り、「わかりません」とだけ回答してくれました。

fig.23

実験結果のまとめ

生成AIモデルに質問する場合、ただ質問文を与えるだけでなく、プロンプトの組み立て方によって以下の効果があることがわかっていただけたかと思います。

  • プロンプトにコンテキストを与えることで、生成AIモデルの知識を外部から補強することができる
  • プロンプトに指示を与えることで、ハルシネーションの軽減や望ましい回答に誘導することができる

質問に関連する情報をどのように用意すればいいか?

プロンプト実験室では、質問内容に関連する情報をあらかじめ想定して、コンテキストに与えていました。

では、取扱説明書の中から質問に関連する情報をどうやって抽出すればよいでしょうか?

後編に続きます

ちょっと長くなってしまったので、今回はここまでにしたいと思います。

次回の後編では、プロンプト実験室で題材にした「おそうじボット」について、一問一答型のアプリを作ってみたいと思います。

Vertex AI DIYプランの紹介

「活用のためのアイデア」でも触れた通り、Q&Aの精度を上げるためには色々な試行錯誤が必要です。また、データセットが大規模になるほど、精度を維持することも難しくなります。

そこで、生成AI導入やシステム構築に不安がある方向けに「Vertex AI DIYプラン」をご紹介します。

Vertex AI DIYプランでは、Vertex AI Search による、 社内文書などのエンタープライズ検索の構築をエンジニアがサポートしてくれます。

興味のある方は、一度相談してみてはいかがでしょうか?

詳細については、関連サービスの「Vertex AI DIYプラン」からご確認ください。

関連サービス

Vertex AI DIYプラン

Vertex AI Search を使って社内文書を検索する生成AIを構築してみませんか?

ソフトバンクのエンジニアが構築をサポートします。

Google の生成AIの導入を考えている方はもちろん、どのようなものか確認したいという方でもご活用いただけます。

Google Workspace

Google スプレッドシート、Gmail、Google カレンダー、Google Chat、Google ドライブ、Google Meet などのさまざまなサービスがあらゆる働き方に対応する業務効率化を実現します。

Google Cloud

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

おすすめの記事

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