見出し画像

ChatGPTに自社データを組み込んで新しい検索体験を模索してみました

イントロ

ChatGPTやBing、NotionAIなどの大規模自然言語モデル(LLM)を活用したサービスが注目を集めています。対話、要約、翻訳、アイデア生成などの多様なタスクにおいて、とても性能が高いです。ただ、ChatGPTでは、ときどき嘘が混じっていたり、文献が捏造されたりすることがあります。

ChatGPTとの対話画面(結果の書籍は存在しない)

それを防ぐために、BingやPerplexityでは、文献を引用した上で、なるべく嘘が紛れ込まない形で回答してくれます。

Perplexityでは引用もつけてくれる

しかし、これらのAIは、Web上の公開されている一部のデータを元に学習しているので、公開されてないデータに対しては当然ながら、正しく回答できません。

そこで、この記事では、自社が保有しているデータをChatGPTに組み込んで、自社オリジナルのPerplexityのようなシステムを作る方法について、まとめたいと思います。また、大規模自然言語モデルを活用すると、どんな新しい検索体験ができるかも簡単にまとめたいと思います。

2023年3月1日に、ChatGPTの裏側のモデルであるgpt-3.5-turboが、API経由で利用できるようになりました。今回の記事では、このモデルを使って検証していきます。

システム概要

大規模自然言語モデルに、自社データを組み込む方法には、大きく3つの方法があります。

  • 学習段階から、自社データを学習データに入れておく

  • 学習済みのモデルに、自社データを入れてファインチューニングする

  • プロンプトに、自社データをコンテキストとして、入力する

現時点(2023/3/1)では、3つ目の方法がコストが低く簡単に試すことができるので、3つ目の方法を紹介していきます。(この領域の進展のスピードはすごく早いので、1つ目や2つ目の選択肢も今後は選択肢の視野に入ってくると思います。)

ツール

外部データとの連携を簡単に実現するツールとして、LlamaIndex(旧GPT Index)LangChainなどのライブラリが活発に開発されています。それらのツールがどのように、外部データをChatGPTに組み込んでいるかの概要を解説します。

やっていることは、とてもシンプルです。ユーザーからの入力に対して、それに関連するデータがあるなら、該当箇所の文章を抜き出します。その文章をプロンプトに入れて、その情報に基づいて回答するようにChatGPTにお願いするというものです。

具体例があったほうが分かりやすいと思うので、私が所属するユビー社の社員が今まで書いたnoteの記事をChatGPTと連携させて、それに基づいた回答ができるシステムを考えます。

ユビーの社員が書いた記事は下記にまとまっており、162本あります。こちらの記事を手元にダウンロードしておき、ChatGPTと連携させていきます。

例えば、「国家公務員出身の方がユビーではどのように働いていますか?」という質問に対して、そのままChatGPTに入力しても、適切な回答は得られません。ユビーには、国家公務員出身の方が複数名在籍しており、ユビーでの働き方についてのnote記事を書いています。

その記事の一部をプロンプトに組み込むことで、適切に回答できるようにします。「国家公務員出身の方がユビーではどのように働いていますか?」という質問に対して、note記事のその情報が書かれている部分を抜き出して、それをコンテキスト情報として、プロンプトに入れると、ChatGPTはそれに基づいて回答してくれます。
プロンプトは、このようになります。

コンテキスト情報
---------------------------------------------------
{質問文に関連する文章1の内容}
{質問文に関連する文章2の内容}
{質問文に関連する文章3の内容}
---------------------------------------------------
事前知識ではなくコンテキスト情報を活用して、質問文に回答してください。

ChatGPTにお願いするプロンプトのテンプレート

しかし、プロンプトには文字制限(約3000字)があるため、関連する情報を全部入力することはできません。そこで、関連する情報を数百字以内で抜き出して、それをプロンプトに入力する必要があります。

LlamaIndexやLangChainではそれを簡単にする関数が用意されています。まずは、取り込みたいデータをインデックス化するという処理をします。まずは、文章を数百字のチャンクに分割し、その中に現れるキーワードを抽出します。その後に、それぞれのキーワードがどのチャンクに出現しているかという情報を保持しておきます。

インデックス化

そうすると、ユーザーから、入力があったときに、どの箇所をプロンプトに組み込めば良いかがすぐに分かります。

技術的な詳細としては、キーワードベースとベクトルベースのものがあります。それぞれ簡単に説明します。(技術詳細はエンジニア向けに書いていますので、適宜読み飛ばしてください。)

キーワードベース

キーワード抽出には、形態素解析を活用して、名詞だけを抜き出すということが行われます。ChatGPTの面白いところは、このキーワード抽出のタスクもお願いすることができます。

あなたは日本語の文章からキーワードを抽出するアシスタントAIです。userが入力した文章から、検索観点でインデックスするべき重要なキーワードを10個を','区切りで改行なしで出力しなさい。

キーワード抽出のタスクをChatGPTにお願いするテンプレート

このテンプレートを使うとユーザーが入力した文章から、キーワードを抽出してくれます。ただ、ときどき、”,”ではなく”、”で出力したり、余計な文章を入れたりしてくるので、そのままは使えませんでした。(プロンプトの指示文を改善すれば、解決できるかもしれません。各キーワードの重要度scoreを付与してもらったり、類義語や表記ゆれを考慮してのキーワード抽出もお願いできて、柔軟さはすごいです。)

ユーザーの入力から、該当箇所を抜き出す方法は、まず入力の質問文からユーザーの意図を理解した上で、キーワードを抜き出します。抜き出し方は、形態素解析でのやり方もありますし、キーワード抽出をChatGPTにお願いしてしまうやり方もあります。

キーワードが抽出できたら、どの文章チャンクと合致するかを計算します。計算方法は、tf-idfやBM25などのやり方で計算できます。

ベクトルベース

最近は、ベクトルベースでの検索も増えています。文章を数百字のチャンクに分割し、それぞれをWord2vecやBertなどのアルゴリズムで、数百次元のベクトルにするというものです。このベクトル化は、公開されている学習済みのモデルを使用することもできますし、OpenAIのEmbeddingのAPIを使うこともできます。また、最近ではGoogleのVertex AI Matching Engineなどのベクトル検索のツールも増えてきています。

ベクトルベースのインデックス化

ユーザーが質問文を入力すると、その質問文もベクトル化し、そのベクトルと各文章チャンクの距離を計算し、近いものを抽出し、それをプロンプトに組み込みます。

キーワードベースとベクトルベースは、それら単体で使うというよりか、組み合わせて使うと検索精度が高まります。例えば、「ユビー」という単語は、ベクトルベースでは、学習時のデータに入ってないことも多く、適切に単語がベクトル化されず、検索精度が悪いです。一方で、キーワードベースでは、「ユビー」という単語を含むものをすべて拾い上げてくれます。

 「AI王 〜クイズAI日本一決定戦〜」という質問応答のコンテストでも、キーワードベースとベクトルベースの組み合わせたものが使われています。(各チームの解法が公開されているので、とても参考になります。)

さて、実際にこの仕組みを実装してみたところ、あまり精度がよくありませんでした。なぜなら、チャンクに分割してしまったことで、文章全体の意味合いが抜けてしまって、適切に回答してくれませんでした。(※LlamaIndexやLangChainではチャンクの集約の仕組みがいくつかありましたが、今回の例ではあまり上手く動きませんでした。)

そこで、まずは、各文章を300字ほどに要約してもらって、その要約文を検索して、それをプロンプトに組み込む方法を取りました。

要約してからベクトル化

要約するときに、文章の文字数が4000字を超えるとプロンプトに入らないので、次のようなプロンプトで要約文を生成しました。

あなたは日本語の文章を要約するアシスタントAIです。
userが入力した文章を300字で要約してください。
現段階の要約文が存在している場合は、それの一部を加筆修正する形で300字で要約してください。
現段階の要約はこちらです。
--------------------------
{current_summary}

要約をお願いするテンプレート

例えば、

こちらの記事は、5000字ほどありますが、この方法を使うとChatGPTは的確に300字に要約してくれます。

元国家公務員のjuncosさんがUbie DiscoveryのPAとして入社した経緯や仕事内容、労働環境について紹介しています。彼女は守りのPAとして、事業に関係する法令等の規制についてリサーチし、会社の事業リスクを減らし、事業展開がスムーズに進むようにする役割を担っています。労働環境はフルフレックスでリモート前提であり、周囲のメンバーが皆優秀であること、質問したら何でも親切に教えてくれること、皆のwillを大切にしていてそれぞれやりたいことをやっていることが魅力的であると述べています。また、Ubie Discoveryは事業展開を加速しており、常に素晴らしい人材を募集しているため、興味がある方はお問い合わせをするよう呼びかけています。

ChatGPTによる要約

このサマリを使うことで、下記の画像のような質疑応答が可能になりました。また、Perplexityのように引用元も表示できます。(まだまだ、改善の余地はたくさんありますが。。)

自社データを組み込んだChatGPT

新しい検索体験

ChatGPTなどの自然言語処理の登場により、既存の検索がどう変わるのか、既存の検索に組み込むにはどうするかという2点をすごく簡単にまとめたいと思います。

入力の観点

今までのグーグル検索では、いわゆる「ググり力」と呼ばれるようなスキルが必要でした。知りたい情報にたどり着くためには、適切なキーワードで検索する必要がありました。ChatGPTには、文章をそのまま入力すると、高い精度で意図を読み取って、回答してくれます。

出力の観点

グーグルの検索では、該当するWebページが一覧で表示されています。それらのページを閲覧して、最終的な情報に要約するのはユーザーに委ねられています。一方で、ChatGPTやBingでは、情報を要約して提供してくれます。また、提示の仕方をユーザーが自由に設定することもできます。例えば、テーブル形式で出力することも指示できます。

テーブル形式での出力

大規模自然言語モデルを使うと究極のパーソナライズアシスタントが作れそうでワクワクします。

既存の検索に組み込む

大規模自然言語モデルを使って、まったく新しいシステムを作るのも楽しそうですが、既存のシステムの一部にChatGPTを組み込む方法もたくさんあると思います。

例えば、

  • 入力の観点で、ユーザーのクエリ理解やクエリ拡張のタスクにGPTを活用する

  • 出力の観点で、既存の検索システムを使って、結果を要約して表示する

  • 出力の観点で、結果画面をユーザーの属性に応じて文章の表現を変化させる

などが組み込みやすそうです。

自社データと連携する場合には、既存の検索システムを活用する必要があるので、大規模自然言語モデルによって、既存の検索システムが刷新されるのはもうしばらく先のような気がします。(ファインチューニングが安価に性能高くできるようになれば、分かりませんが。。)

まとめ

ChatGPTに自社データを組み込んで新しい検索体験を模索してみました。既存の検索システムを入力・出力の観点で、大きく拡張できそうでワクワクします。

TIPS(ローカルでのStream機能を使った出力)

2023年3月1日に、gpt-3.5-turboモデルがリリースされ、API経由でChatGPTを試すことができるようになりました。また、Stream機能があり、逐次文章を表示することができます。
PythonのStreamlitを使って、ローカル環境でStream機能を駆使した文章生成のやり方を説明します。

まずは、 streamlitとopenaiのライブラリをインストールします。

pip install streamlit openai
import streamlit as st
import openai

openai.api_key = "YOUR API KEY"
def main():
    system_text = st.text_area("AIアシスタントの設定", value="あなたはアシスタントAIです。")
    user_text = st.text_area("質問文", value="うどんの茹で方教えて",)
    is_generate_clicked = st.button("文章生成")

    if is_generate_clicked:
        message = [{"role": "system", "content": system_text}, {"role": "user", "content": user_text}]
        response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo",
            messages=message,
            max_tokens=2000,
            temperature=0,
            stream=True
        )

        partial_words = "" 
        answer = st.empty()

        for chunk in response:
            if chunk and "delta" in chunk["choices"][0] and "content" in chunk["choices"][0]["delta"]:
                partial_words += chunk["choices"][0]["delta"]["content"]
                answer.write(partial_words)

if __name__ == "__main__":
    main()

API_KEYにご自身のKeyを入力して、app.pyというファイル名で保存します。

streamlit run app.py

アプリを起動すると、Webブラウザで確認ができます。ストリームで出力してくれるので、体感速度もすごく速いです。

AIアシスタントの設定や質問文の調整が、簡単に行えるので、とても便利です。テーブル形式やコードブロックも良い感じに出力してくれます。

Streamでの出力


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