はじめに
ChatGPTを便利に活用してますか?
普通に使っていても結構便利だなと思いますが、LangChainを使うとさらに面白い使い方ができそうだったので、試したことを共有したいと思います。今回は、自分が用意した情報を検索してChatGPTに回答してもらうのですが、複数の情報を用意して、質問の内容によって検索する情報を選択して回答するという動きができるかを検証します。
これからAIをはじめられるお客様へ AIエスコート|株式会社クレスコ (cresco.co.jp)
目次
- LangChainとは
- Agentについて
- 検索データ準備
- 検証プログラム構築
- 検証実施
- おわりに
1. LangChainとは
LangChain は、大規模な言語モデルを使用してアプリケーションの作成を簡素化するように設計されたフレームワークです。(Wikipediaより)
LangChainの主な機能は以下です。
Models:異なるモデルを組み合わせ
様々なモデルを組み合わせて使用できる機能です。
Prompt:プロンプトの管理・最適化
プロンプトの管理や最適化を行うための機能です。
Indexes:外部データの利用
外部データを利用するための機能です。PDFやExcel、CSVなど
外部のデータをもとに回答を生成できるようになります。
● 現在(2023/10/30)は、「Retrieval」というモジュール名に変更になっています。
Chains:複数のプロンプトを実行可能に
複数のプロンプトを実行するための機能です。
Agents:複数のツールを組み合わせ
複数のツールを組み合わせて、必要な処理を実行する機能です。
Memory:履歴を保持
言語モデルが出力した回答の履歴を保持し、必要に応じて再度活用できる機能です。
出展:https://udemy.benesse.co.jp/development/langchain.html
これらの機能を単一及び複数用いて、ニーズに合ったアプリケーションを作成することができます。
2. Agentについて
今回は、これらの機能の中のAgentを使って、ユーザの質問に合わせて回答に必要なデータを選択し、それをLLM(大規模言語モデル)に渡して回答を作成してくれることを検証してみます。
Agentにはいくつかの種類があるのですが、ReActベースの「zero-shot-react-description」を用いました。後記のプログラム内にありますが、「Tool」を定義し、このToolの説明に基づいてAgentがどのToolを使用するかを判断します。
具体的に今回は、「植物」と「星座」について架空のデータを準備し、「Tool」としてそれぞれ
- "植物について知りたいときに使用します。"
- "星座について知りたいときに使用します。"
と説明文書を設定し、ユーザからの質問に対しどのToolを使用すべきかの判断基準を与えます。「zero-shot-react-description」は、このToolの説明文書から、どのToolを使用するかを決定するAgentです。文章の説明では伝わりづらいと思いますが、実際動かしてみると動きが理解しやすいと思います。
※ ReActとは、論文「ReAct: Synergizing Reasoning and Acting in Language Models」(https://arxiv.org/abs/2210.03629)で提案された手法で、「思考→行動→観察」を繰り返し最終的な結果を導く一般的なタスク処理を、言語モデルに活用した手法。
3.検索データ準備
「植物」と「星座」について架空のデータを作成し、それぞれ「plants.txt」、「stars.txt」というファイルに保管します。
それぞれの内容は以下です。
- plants.txt
## 以下に、3つの植物について説明があります。それぞれカッコに囲んで説明が分かれています。 ##
(エレクトリファイドは、束ねた葉が発電能力を持ち、周囲の光を取り込んで輝く。新エネルギーの希望。)
(エコバブルは、巨大な泡が葉を取り囲み、二酸化炭素を吸収して酸素を放出。地球環境に優しい。)
(クリスタルスプラウトは、水晶のように透明な茎に、ミニチュアの水晶がついた不思議な植物。運気を引き寄せると言われる。)
- stars.txt
## 以下に、3つの星座について説明があります。それぞれカッコに囲んで説明が分かれています。 ##
(セラスティアは、音楽と空間を象徴する星座。多様な星々が輝き、美しく調和した姿を作る。)
(ネクストレアは、時間と運命を表す星座。三つの恒星が揃って現れ、惑星や銀河と相まって複雑なかたちを描く。)
(アクアライトは、水と光を組み合わせた美しい星座。多数の青い恒星が、水面に映った月のような光の姿を描き、神秘的な魅力を持つ。)
これらの架空の植物や星座の説明文は、ChatGPTに作ってもらいました。こういったサンプルデータを作ってもらう際、ChatGPTは非常に便利ですね。
4.検証プログラム構築
「python 3.9.13」が入っていて、「pip」も使える環境にて実施しました。
まずは、「pip install」コマンドで、以下をインストールします。
- langchain (バージョン0.0.278が入った)
- openai (バージョン0.27.8が入った)
作成したプログラムを、以下に示します。
ファイル名は、「LangChain_Agent_LocalFiles.py」としました。
import os |
import dotenv |
from langchain.llms import AzureOpenAI |
from langchain.agents import initialize_agent, Tool |
from langchain.agents import AgentType |
from langchain.prompts import ( |
ChatPromptTemplate, |
SystemMessagePromptTemplate, |
HumanMessagePromptTemplate, |
) |
from langchain.document_loaders import TextLoader |
# 変数設定(デプロイされているモデル情報など) |
dotenv.load_dotenv(dotenv_path="./.env.agent") |
base_url = os.getenv("OPENAI_API_BASE") |
model_name = os.getenv("OPENAI_MODEL_NAME") |
openai_api_base = os.getenv("OPENAI_API_BASE") |
openai_api_key = os.getenv("OPENAI_API_KEY") |
deployment_name = os.getenv("OPENAI_DEPLOYMENT_NAME") |
openai_api_version = os.getenv("OPENAI_API_VERSION") |
def search_Stars(question: str) -> str: |
# TextLoaderを使用してファイルからテキストデータをロードする |
# utf-8にエンコードしたい場合は、encoding="utf-8"を指定する。 |
loader_stars = TextLoader("./stars.txt", encoding="utf-8") |
document_stars = loader_stars.load() |
results = document_stars[0].page_content |
return results |
def search_Plants(question: str) -> str: |
# TextLoaderを使用してファイルからテキストデータをロードする |
# utf-8にエンコードしたい場合は、encoding="utf-8"を指定する。 |
loader_plants = TextLoader("./plants.txt", encoding="utf-8") |
document_plants = loader_plants.load() |
results = document_plants[0].page_content |
return results |
tools = [ |
Tool( |
name="Search Stars", |
func=search_Stars, |
description="星座について知りたいときに使用します。", |
), |
Tool( |
name="Search Plants", |
func=search_Plants, |
description="植物について知りたいときに使用します。", |
), |
] |
# LLMの設定 |
llm = AzureOpenAI( |
temperature=0, |
model_name=model_name, |
openai_api_base=openai_api_base, |
openai_api_key=openai_api_key, |
deployment_name=deployment_name, |
openai_api_version=openai_api_version, |
) |
# Agentの初期化 |
react = initialize_agent( |
tools, |
llm, |
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, |
verbose=True, |
max_iterations=10, |
handle_parsing_errors=True, |
) |
# 質問設定 |
question = "「クリスタルスプラウト」について調べてください。まずは星座かどう |
か教えてください。合っていれば、それを説明してください。違う場合は、植物に |
ついて調べて、それを説明してください。" |
#プロンプト作成 |
system_template = ( |
"質問は{language}です。ツールで得られたドキュメントを{language}で注意深く |
読み、{language}で回答してください。" |
) |
human_template = "質問:{question}" |
system_message_prompt = |
SystemMessagePromptTemplate.from_template(system_template) |
human_message_prompt = |
HumanMessagePromptTemplate.from_template(human_template) |
chat_prompt = ChatPromptTemplate.from_messages( |
[system_message_prompt, human_message_prompt] |
) |
prompt_message_list = chat_prompt.format_prompt( |
language="日本語", question=question |
).to_messages() |
# 実行 |
react.run(prompt_message_list) |
- プログラムの補足
24~43行目:
Agent機能は、入力プロンプトに対し、「思考→行動→観察」を行ってくれる機能です。この「行動」に相当する部分をToolとして設定します。この行では、「植物」と「星座」についての説明文を記載したtxtファイルを読み取る関数を定義します。
46~57行目:
Toolを設定している部分になります。各Toolに設定している「func」にて、24~43行目で設定した関数を呼び出します。また、「description」にて、入力プロンプトに対してどのToolを使うかを選択するための説明文を記載します。
85~101行目:
LangChainが提供するプロンプト構築のテンプレートを利用して、チャットモデルに渡すプロンプトを作成しています。
5.検証実施
以下のコマンドで、プログラムを実行します。
python LangChain_Agent_LocalFiles.py |
現在、質問として以下を入力して、プログラムを実行しました。
「セラスティア」について調べてください。まずは星座かどうか教えてください。合っていれば、それを説明してください。違う場合は、植物について調べて、それを説明してください。 |
出力は、以下でした。(説明しやすいように、各行先頭に行数を付加しています。)
> Entering new AgentExecutor chain... |
I should check if this is a plant or a star |
Action: Search Stars |
Action Input: クリスタルスプラウト |
Observation: ## 以下に、3つの星座について説明があります。それぞれカッコに囲んで説明が分かれています。 ## |
(セラスティアは、音楽と空間を象徴する星座。多様な星々が輝き、美しく調和した姿を作る。) |
(ネクストレアは、時間と運命を表す星座。三つの恒星が揃って現れ、惑星や銀河と相まって複雑なかたちを描く。) |
(アクアライトは、水と光を組み合わせた美しい星座。多数の青い恒星が、水面に映った月のような光の姿を描き、神秘的な魅力を持つ。) |
Thought: I should check if this is a plant or a star |
Action: Search Plants |
Action Input: クリスタルスプラウト |
Observation: ## 以下に、3つの植物について説明があります。それぞれカッコに囲んで説明が分かれています。 ## |
(エレクトリファイドは、束ねた葉が発電能力を持ち、周囲の光を取り込んで輝く。新エネルギーの希望。) |
(エコバブルは、巨大な泡が葉を取り囲み、二酸化炭素を吸収して酸素を放出。地球環境に優しい。) |
(クリスタルスプラウトは、水晶のように透明な茎に、ミニチュアの水晶がついた不思議な植物。運気を引き寄せると言われる。) |
Thought: I now know the final answer |
Final Answer: クリスタルスプラウトは、水晶のように透明な茎に、ミニチュアの水晶がついた不思議な植物。運気を引き寄せると言われる。 |
> Finished chain. |
- 2行目:「“植物”か“星座”かチェックすべきだ」と思考しています。
- 3~4行目:「クリスタルスプラウト」について「Search Stars」のToolを実施しようと行動しています。
- 5~8行目:Toolを実施して、「星座」についての説明文を観察しています。
- 9行目:回答となる内容が見つからなかったからか、再度「“植物”か“星座”かチェックすべきだ」と思考しています。
- 10~11行目:次は、「クリスタルスプラウト」について「Search Plants」のToolを実施しようと行動しています。
- 12~15行目:Toolを実施して、「植物」についての説明文を観察しています。
- 16行目:「最終的な回答が分かった」と思考しています。
- 17行目:最終的な回答を返しています。
- Agentの動きと最終的な回答については、ほぼ期待通りの動きをしてくれました。ただ、質問の中に「まずは星座かどうか教えてください。」というものも入れていましたが、無視されているようです。
次に、質問の「クリスタルスプラウト」を星座の「アクアライト」に変更して実行してみました。
出力は、以下でした。(説明しやすいように、各行先頭に行数を付加しています。)
Entering new AgentExecutor chain... |
I should check if "アクアライト" is a star or a plant. |
Action: Search Stars |
Action Input: アクアライト |
Observation: ## 以下に、3つの星座について説明があります。それぞれカッコに囲んで説明が分かれています。 ## |
(セラスティアは、音楽と空間を象徴する星座。多様な星々が輝き、美しく調和した姿を作る。) |
(ネクストレアは、時間と運命を表す星座。三つの恒星が揃って現れ、惑星や銀河と相まって複雑なかたちを描く。) |
(アクアライトは、水と光を組み合わせた美しい星座。多数の青い恒星が、水面に映った月のような光の姿を描き、神秘的な魅力を持つ。) |
Thought: "アクアライト" is a star. |
Final Answer: "アクアライト"は星です。 |
> Finished chain. |
先程とは異なり、最終的な回答は「"アクアライト"は星です。」だけで、説明はしてくれませんでした。(間違えてはいませんが。。)
他にも星座名を変えたりしてみたところ、星座の説明文を観察した後にこの中に回答が無いと判断したのか、植物の説明文を観察しました。最終的には、質問した星座名の説明文を回答してくれましたが。
6.おわりに
今回は、LangChainのAgent機能を使って、入力プロンプト(質問)に合わせて回答を作成するために検索するデータを選択して回答してくれるかを試してみました。大体期待通りの動きをしていましたが、入力プロンプトによっては、期待通りの動きをしないときもありました。プロンプトの構築には、まだまだ改善の余地がありそうです。
今回は、検証として検索するデータをテキストで用意したものを利用しましたが、検索先を社内のデータベースにして、例えば社内の人事関連のデータベースや各種申請関連のデータベースなどカテゴリごとに分かれたデータベースを用意するとします。そして、入力プロンプトに合ったデータベースを検索する動きができるようになれば、質問にふさわしい情報を選択して入手し、その情報から回答を生成するとこで、より精度が高い回答が得られるのではないかと期待されます。
LangChainはアップデートが速いので、今後もキャッチアップしていければと思います。
参考文献/リンク
https://udemy.benesse.co.jp/development/langchain.html