見出し画像

ChatGPTで独自データを扱うためのエンべディング

【2023/11/7追記】
OpenAI Dev Dayにて、開発者向けの大型アップデートが発表されました。この記事で紹介している手法は、Retrieval-Augmented Generation(RAG)と呼ばれてきましたが、今回のアップデートでコンテクスト長(やりとりできるテキストの長さの上限)がこれまでの8Kから128K(12万8千トークン)に大幅にアップするため、一般的な本の内容は1冊分丸ごと渡すことができるようになります。独自データベースとの連携という意味では、ここで紹介している手法も引き続き有効な手法ですが、API関連でも様々な機能が追加されているので、リリースやSam Altmanによるキーノートは要チェックです。


ChatGPTは、膨大な量のテキストを学習してはいますが、天気予報のような最新の情報や、ある特定の本の内容や、特定のサービスの詳細についてはじめから知っているわけではありません。独自のサービスやアプリにChatGPTを取り入れようと思うと、プロンプトに収まらない長い文章や独自データをChatGPTに何らかの方法で教えたり学習させる必要があります。今回はその手法として、エンべディングについて説明してみたいと思います。

その前にまず、ChatGPTをサービスやアプリに組み込むサンプルとして前回の記事で紹介した天気予報AIについて、改めて何をしていたのか振り返ってみます。


「東京の明日の天気は?」

ChatGPTの特徴は、こうした自然言語の質問や指示を正しく理解出来るところです。自然な会話文から何を聞かれているかをきちんとわかってくれる訳です。最近だいぶ慣れてきてしまいましたが、改めて考えるとその能力には驚かされます。

ただ、何を聞かれているかわかっても明日の天気予報の情報を持っていなければ答えることはできません。”素の”ChatGPTは、膨大な知識を学習していても、明日の天気はわからないのです。

"素の"ChatGPTとの対話例
"素の"ChatGPTとの対話例

ChatGPTが知らない情報を教える

ユーザーがChatGPTへ入力するプロンプトには質問だけでなく、さまざまな指示や付加情報を与えることが出来ます。例えば「あなたは優秀なアシスタントです。」といった役割を与えたり、「小学生にもわかるように回答してください。」といった表現形式を指示したり、アイデア次第でいろいろな工夫ができるのですが、プロンプトでChatGPTが知らないことを事前に伝えておくこともできます。

つまり、必要な天気予報のデータをどこからか取ってきて事前に伝えることができれば、その情報にもとづいて自然な言葉で明日の天気をユーザーに伝えることができるというわけです。

取得したデータを使ってプロンプトをつくる例
取得したデータを使ってプロンプトをつくる例

前回の記事では、天気予報のデータを取得することができるWeatherAPIというサービスを利用しました。WeatherAPIは、例えば次のようにURLに都市名や日付をつけると、天気予報のデータがJSONという形式で返ってきます。

http://api.weatherapi.com/v1/forecast.json?...q=tokyo&dt=2023-04-02
{
     "maxtemp_c": 14.3,
     ...
     "condition": {
          "text": "Patchy rain possible",
          ...
          "code": 1063
     }
}

そして、返ってくる天気予報のJSONデータをそのままプロンプトに突っ込んでも、いい感じに天気を読み取ってくれることもわかりました。

外部APIから取得したデータを使ってプロンプトをつくる例
外部APIから取得したデータを使ってプロンプトをつくる例

これは一つの例ですが、独自のサービスやアプリにChatGPTを活用するイメージがなんとなく持てたでしょうか?

「アメリカから注文できますか?」

今日の本題はここからです。
今回は、ECサイトのカスタマーサポートにChatGPTを使うことを考えてみましょう。アメリカの住んでいるユーザーから「アメリカから注文できますか?」という質問が来たとします。当たり前ですが、"素の"ChatGPTはあなたのECサイトが海外からの注文に対応しているかどうかは知りません。
まず思いつく一番雑な方法は、サイトにあるFAQのデータをまるごとChatGPTに教えることですが、少なくとも現状ではプロンプトの文字数(トークン数)に制限があり、大量のデータをまるごとプロンプトに詰め込むことはできません。さてどうしましょう、、?

文字数に制限がありすべての情報をプロンプトに含めることはできない
すべての情報をプロンプトに含めることはできない


エンべディングを使ってプロンプトをつくる

そこで登場するのが、大量の情報からユーザーの入力に関連する情報を抽出するためのエンべディング(Embedding)という手法です。

関連情報を抽出してプロンプトをつくるイメージ
関連情報を抽出してプロンプトをつくるイメージ

では、「質問に関連した内容」を大量の独自データから取り出すにはどうしたらいいでしょう?
そこで活用されているのがベクトルデータベースと呼ばれるものです。やや専門的になってきますが、ベクトルデータベースとは、ざっくり言えば下の図のように各データを数値化(ベクトル化)し、空間上にマッピングしたようなデータベースです。下の図では2次元空間ですが、実際には自然言語のベクトルデータベースは1,000次元以上(!)の多次元空間上にマッピングされています。
このベクトルデータベースに対して、ユーザーが入力した文章も同じように数値化(ベクトル化)して同じ空間上にマッピングすることで、空間上で近くにある情報(=関連する情報)を抜き出してくることができるわけです。

エンべディングを活用して抽出した関連情報をプロンプトに追加するイメージ
エンべディングを活用して抽出した関連情報をプロンプトに追加するイメージ

エンべディングと言われる手法が何をやっているか、少しイメージできたでしょうか?

ここまで見てきたように、独自データのエンべディングは、プロンプトに含められる文字数(トークン数)に制限がある中で、ChatGPTが独自データを扱えるようにするための手法とも言えます。
そして図からわかることは、エンべディングによってChatGPTが独自データがうまく扱えるようになるかどうかは、実はChatGPTのモデルの性能だけでなく、その手前で独自データから精度の高いベクトルデータベースをつくれるか、ユーザーの入力文をもとにそのベクトルデータベースから精度高く関連情報を抽出できるかがとても重要になるということです。
ユーザーの入力文に対して、ベクトルデータベースから見当違いな情報しか抽出できなければ、どんなにChatGPTが優秀でも満足のいく回答は得られないのです。

LlamaIndexを使う

では、具体的にはどうすれば独自データのエンべディングを行うことができるでしょうか。
実は独自データをベクトル化するためのエンべディング用モデルもOpenAI から提供されており、直接そのAPIを使うことも可能ですが、使い勝手のよいツールもいくつか開発されています。その中の一つがLlamaIndexと呼ばれるライブラリです。LlamaIndexを使うと、

  • テキストファイルなどの独自データをベクトルデータベース化する

  • ユーザーの入力文から、関連するデータを抽出する

  • 抽出したデータをプロンプトに追加した上でユーザーの入力文をChatGPTに渡す

といったことが比較的簡単にできるようになっています。
また、テキストファイルだけでなく、ウェブサイトやPDFなど様々なフォーマットのデータをベクトル化するテンプレートが、Llama Hubというサイトで公開されており、ライブラリから簡単に使えることも特徴です。

「ChatGPTはコンヴィヴィアル・テクノロジーと言えますか?」

最後に、LlamaIndexを使った具体的なコードを紹介します。
拙著『コンヴィヴィアル・テクノロジー』の原稿テキストデータを使って、「『コンヴィヴィアル・テクノロジー』を読んだChatGPT」をつくってみます。

以下のコードは、Google ColabなどのPython実行環境で試すことができます。まずは、OpenAIとLlamaIndexのライブラリをインストールします。

!pip install openai llama-index

import os
os.environ["OPENAI_API_KEY"] = "your_openai_api_key"

そして次のように、文章のベクトルデータベース化、ユーザーの入力と類似度が高い部分の抽出し、その部分を追加したプロンプトの生成を短いコードで行うことができます。

from llama_index import GPTVectorStoreIndex, SimpleDirectoryReader

# dataというフォルダ内のテキストファイル(原稿データ)をベクトルデータベース化
documents = SimpleDirectoryReader("data").load_data()
index = GPTVectorStoreIndex.from_documents(documents)

# ユーザーの入力文を処理するエンジンの作成
query_engine = index.as_query_engine()

# ユーザーの入力文に関連する部分を抽出し、プロンプトに追加した上でユーザーの入力文をChatGPTに渡す
response = query_engine.query("ChatGPTはコンヴィヴィアル・テクノロジーと言えますか?"))
print(response)

このままでも動きますが、LlamaIndex側でデフォルトのプロンプトテンプレートが使われていたり、ChatGPTのモデルもGPT-3ベースのものだったりするので、少しカスタマイズします。

from llama_index import GPTVectorStoreIndex, SimpleDirectoryReader, LLMPredictor, PromptHelper, ServiceContext, QuestionAnswerPrompt, download_loader
from langchain import OpenAI

# dataというフォルダ内のテキストファイル(原稿)をベクトルデータベース化
documents = SimpleDirectoryReader("data").load_data()

# 使用するLLMやパラメータをカスタマイズする
llm_predictor = LLMPredictor(llm=OpenAI(temperature=0, model_name="gpt-4"))
max_input_size = 4096
num_output = 256
max_chunk_overlap = 20
prompt_helper = PromptHelper(max_input_size, num_output, max_chunk_overlap)
service_context = ServiceContext.from_defaults(llm_predictor=llm_predictor, prompt_helper=prompt_helper)
index = GPTVectorStoreIndex.from_documents(
    documents, service_context=service_context
)

# プロンプトのテンプレートをカスタマイズする
QA_PROMPT_TMPL = (
    "関連する情報は以下の通りです。"
	  "---------------------\n"
    "{context_str}"
    "\n---------------------\n"
    "{query_str}\n"
)
QA_PROMPT = QuestionAnswerPrompt(QA_PROMPT_TMPL)
query_engine = index.as_query_engine(
    text_qa_template=QA_PROMPT
)

# ユーザーの入力文に関連する部分を抽出し、プロンプトに追加した上でユーザーの入力文をChatGPTに渡す
response = query_engine.query("ChatGPTはコンヴィヴィアル・テクノロジーと言えますか?")
print(response)

特に、デフォルトのプロンプトテンプレートは次のようになっていて、

DEFAULT_TEXT_QA_PROMPT_TMPL = (
"Context information is below. \n"
"---------------------\n"
"{context_str}"
"\n---------------------\n"
"Given the context information and not prior knowledge, "
"answer the question: {query_str}\n"
)

そのままだと、プロンプトが英語なのでたまに英語で回答が返ってきたり、”Given the context information and not prior knowledge,(提供されたコンテキスト情報に基づき、先行知識を用いずに) "となっていて、与えられた情報だけを使うような条件付けがされているので、(本に書かれていない)ChatGPTについて聞いても「ChatGPTについての情報がないので回答できません。」といった回答が返ってきてしまいます。さきほどのようなカスタマーサポートに使おうと思ったらその方が余計なことを言わないので安心ですが、今回は素直に「ユーザーの入力文に関連した独自データ」+「ユーザーの入力文」をChatGPTに渡すようにしてみました。

果たして『コンヴィヴィアル・テクノロジー』を読んだChatGPTは「ChatGPTはコンヴィヴィアル・テクノロジーと言えますか?」という問いにうまく答えてくれるでしょうか?

回答は以下のようなものでした。

ChatGPTは、コンヴィヴィアル・テクノロジーと言えるかどうかは、上記の6つの問いに対する回答によって判断されます。以下にそれぞれの問いに対する回答を示します。

1. 人間から自然環境の中で生きる力を奪っていないか?
- ChatGPTは、人間と自然環境との関係に直接的な影響を与えるものではありませんが、過度な依存が生活の質を低下させる可能性があります。
2. 他にかわるものがない独占をもたらし、人間を依存させていないか?
- ChatGPTは、他のAI技術やコミュニケーション手段と競合しており、独占的な状況ではありません。ただし、過度な依存は避けるべきです。
3. プログラム通りに人間を操作し、人間を思考停止させていないか?
- ChatGPTは、ユーザーが自分で考えることを助けることを目的としていますが、過度に依存することで思考停止を引き起こす可能性があります。
4. 操作する側とされる側という二極化と格差を生んでいないか?
- ChatGPTは、多くの人々に利用可能であり、技術的な格差を縮小する可能性があります。ただし、アクセスや利用方法によっては格差が生じる可能性もあります。
5. すでにあるものの価値を過剰な速さでただ陳腐化させていないか?
- ChatGPTは、情報や知識の価値を高めることができますが、過度な依存や過信によって陳腐化させる可能性もあります。
6. フラストレーションや違和感を感じてはいないか?
- ChatGPTは、ユーザーにとって有益であることを目指していますが、誤った情報や不適切な回答がフラストレーションや違和感を引き起こす可能性があります。

これらの回答に基づいて、ChatGPTはある程度コンヴィヴィアル・テクノロジーと言えるかもしれませんが、過度な依存や過信を避けることが重要です。ユーザーがバランスを保ち、適切な使い方をすることで、コンヴィヴィアル・テクノロジーとして機能する可能性があります。

ChatGPTによる回答

ちょっと優等生すぎる気もしますが、なかなかの回答です。レポートで提出されたら次第点は取れるといったところでしょうか。私がイリイチの思想に依拠しつつまとめたコンヴィヴィアル・テクノロジーに向けた6つの問いをうまく抽出して、それぞれの問いに照らし合わせながら回答していて、確かに本を読んでくれていると感じます。

さてこの時、実際にはどんな情報がプロンプトに渡されているでしょうか?
実行中のログを表示するようにしてみます。

!pip install openai llama-index
import os
os.environ["OPENAI_API_KEY"] = "your_openai_api_key"

# ログを出力する
import logging
import sys
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG, force=True)

実際にChatGPTに渡されているプロンプトは以下のようになっていました。

関連する情報は以下の通りです。
---------------------
そのテクノロジーは、操作する側とされる側という二極化と格差を生んでいないか?  そのテクノロジーは、すでにあるものの価値を過剰な速さでただ陳腐化させていないか?  そのテクノロジーに、わたしたちはフラストレーションや違和感を感じてはいないか?  いま、「コンヴィヴィアリティのための道具」だったはずのパーソナルコンピュータやインターネットがもたらした情報テクノロジーは、エネルギーやパワーといった物理的な力ではなく、情報処理能力や計算能力といった知的な力において再び第二の分水嶺を超えつつある。ここで注意すべきは、AIは敵か味方かといったように、あるテクノロジーを是か否か、善か悪かと二元論的に語ることはできないということだ。そうではなく、あらゆる道具に不足と過剰の二つの分水嶺は存在するのだ。しかも、分水嶺が二つあるということは、運命を分ける分岐点は一点ではないということ、つまり、不足と過剰の間の「ちょうどいい」には幅があるということでもある。 もちろん幅があるとはいえ、「ちょうどいい」バランスを保つことは言うは易しで簡単なことではない。ただ、テクノロジーは本来、例えばエアコンが設定温度を上回れば温度を下げ、下回れば温度を上げるといったフィードバック制御でちょうどいい温度をキープするように、不足と過剰をコントロールしながら目標に向かうことは得意なはずである。しかし、テクノロジーも専門化とサイロ化が進むと、狭い専門領域に閉じて既存性能を上回る最高性能(state-of-the-art)の競い合いになってしまう。未来のテクノロジーは、より統合的で長期的な視野に立って「ちょうどいい」を目標に設定し、そこに向かうことを目指すべきだろう。  

第6章 コンヴィヴィアル・テクノロジーへ  本書は、かつてイヴァン・イリイチが提示した「コンヴィヴィアリティ」という概念を足がかりに、これからのテクノロジーはどうあるべきかを考えてきた。そこで見えてきた現代版「コンヴィヴィアリティのための道具」とも言うべきコンヴィヴィアル・テクノロジーとはどのようなものか。最後に改めて振り返ってみたい。  ちょうどいい道具 あらゆる道具には、人間に力を与えてくれる第一の分水嶺と、逆に人間から力を奪う第二の分水嶺がある。それがイリイチの指摘した、道具の「二つの分水嶺」という捉え方だった。道具が第二の分水嶺を超えると、人間が道具を使っているようでいて、逆に人間が道具に使われている状況が生まれてしまう。イリイチは『コンヴィヴィアリティのための道具』の中で、そうならないための多元的なバランスについて「生物学的退化」「根元的独占」「過剰な計画」「二極化」「陳腐化」「フラストレーション」という6つの視点を提示した。もう一度、それらを読み解いた次の6つの問いを振り返ってみよう。  そのテクノロジーは、人間から自然環境の中で生きる力を奪っていないか?  そのテクノロジーは、他にかわるものがない独占をもたらし、人間を依存させていないか?  そのテクノロジーは、プログラム通りに人間を操作し、人間を思考停止させていないか?  そのテクノロジーは、操作する側とされる側という二極化と格差を生んでいないか?  そのテクノロジーは、すでにあるものの価値を過剰な速さでただ陳腐化させていないか?  そのテクノロジーに、わたしたちはフラストレーションや違和感を感じてはいないか?
---------------------
ChatGPTはコンヴィヴィアル・テクノロジーと言えますか?

関連情報が追加されたプロンプト

確かにエンべディングによって、「ChatGPTはコンヴィヴィアル・テクノロジーと言えますか?」という入力文に関連した文章が抽出されていると言えなくはないですが、ベクトルデータベース化した6万字程度の原稿に対して、類似度が高いと抽出されたのは第6章の冒頭1300字程度。細かく言うと、第6章の冒頭の2つのチャンク(文章のかたまり)が抽出されていて、max_chunk_overlap=20と指定しているので2つのチャンクは若干文章がオーバーラップしていて、なおかつ単に類似度が高い順に並べているので文章としては順序が逆になっています。

「ChatGPTはコンヴィヴィアル・テクノロジーと言えますか?」という質問にこの程度の回答をするためには、とりあえず第6章の冒頭を1000字くらい読めばいいのか、、と著者としてはちょっと複雑な気持ちになりますが、いずれにしても、エンべディングによってChatGPTが本の全文を読むというわけではなく、ChatGPTはあくまで最終的に生成されたこのプロンプトを受け取って回答しているだけなのだということが、詳しく中身を見てみるとわかります。

ちなみに、拙著『コンヴィヴィアル・テクノロジー』の第6章は、ウェブサイトで全文公開しています。発売からもうすぐ2年経ちますが、改めてこうしたAIの登場によって「人間とテクノロジーが共に生きる社会」が現実味を帯びていると感じています。ぜひご興味あれば読んでみてください。


解像度を上げて中身を知ること

以上のように、エンべディングという手法を使うと、ChatGPTなどの大規模言語モデル(LLM)を独自のサービスやアプリと連携させることができますが、前述したように、ベクトルデータベースからユーザーの入力文に関連した情報を抽出する部分がかなり重要であるということがわかりますし、そこはChatGPTとは別の仕組みで動いている点も知っておくべきでしょう。厳密に言えば、ChatGPTが与えた独自データを学習しているわけではないのです。

エンべディングとは別に、「プロンプトとそれに対して期待される回答」のセットを独自データとして用意して追加学習させるファインチューニングと呼ばれる手法もありますが、現時点(2023/5/12)では、少なくともOpenAIが提供するモデルでファインチューニングが可能なのはGPT-3のベースモデル(text-davinci-003など)に限られるので、GPT-3.5やGPT-4の能力を引き出すことができません。GPT-3をファインチューニングするか?エンべディングを使ってGPT-3.5やGPT-4を使うか?という選択になり悩ましいところです。

また、OpenAI以外にもたくさんの大規模言語モデル(LLM)が日々登場しているので、今後は様々な選択肢から用途目的に応じて適したモデルや手法を選んでいくことになるのだと思います。

ただいずれにしても言えることは、「ChatGPTをカスタマイズする」「独自のサービスやアプリにChatGPTを活用する」と言う時、具体的にどんな仕組みが使われているのか、少し解像度を上げて中身を知っておくことは、AIを活用したサービスやアプリを考える上でも、またAIに使われずにAIを使っていく上でも重要だと思います。

【追記】「埋め込み」ってどっちの話?

自然言語のような複雑で大量のデータから類似した特徴を抽出するための「エンべディング(Embedding)=埋め込み」と、抽出した情報をプロンプトへ「埋め込む」という表現が混在してしまっていたので文言を修正しました。(ご指摘ありがとうございます。)

Google Cloudの説明にもあるように、機械学習における「エンべディング(Embedding)=埋め込み」とは、あくまで「高次元ベクトルの低次元空間への変換」を意味します。

埋め込みとは?
埋め込みとは、高次元ベクトルの低次元空間への変換です。埋め込みでは、意味的に類似した入力を埋め込み空間内で近くに配置し、入力の意味性を捉えることが理想的です。

Google Cloudより


この記事が参加している募集

AIとやってみた

この記事が気に入ったらサポートをしてみませんか?