AutoGenをガッツリ試してみる:RAGを試してみる
概要
前回までの内容はAutoGenの一番最初のサンプルを色々なアプローチで試してみたものであった。今回からはAutoGenの色々な機能を試していこう。まずは手始めに、LangChainやLlama IndexでもおなじみのRAGをAutoGenでも利用できるので試してみた。
RAGとは
RAGは"Retrieval-Augmented Generation"の略である。これは、自然言語処理の領域で、大量のテキストデータからの情報取得と、その情報に基づくテキスト生成のためのモデルである。質問応答や文章生成タスクでの利用が考えられる。RAGの動作は、大きく分けて2つのステップに分かれる。まず、第1のステップとして「Retrieval」が行われる。これは、質問やプロンプトに関連した情報や文書を大規模なデータベースやコーパスから取得する工程である。次に、第2のステップとして「Generation」が行われる。これは、取得された情報を基にして、質問に対する回答や文章を生成する工程である。
RAGの特徴としては、Transformerベースの生成モデル(例: BERTやGPT)とRetrievalを組み合わせて動作することが挙げられる。RAGの最大の利点は、ある質問やタスクに対して、関連する情報や文書を大量のテキストデータから効率的に取得できることである。
RAGの実装として、Llama IndexやLangChainを用いたものがLLM界隈ではよく利用されているが、AutoGenでも利用可能ということで、ここではAutoGen版のRAGの仕組みについて試してみる。
RAGを試してみる
データの準備
ここではOnePieceのWikipediaのテキストを利用することとした。ダウンロードについても、せっかくなのでAutoGenを使ってみよう。
from autogen import AssistantAgent, UserProxyAgent
config_list = [
{
"model": "gpt-3.5-turbo",
"api_key": "<OpenAI APIのキーを入力>"
}
]
assistant = AssistantAgent("assistant", llm_config={"config_list": config_list})
user_proxy = UserProxyAgent("user_proxy", code_execution_config={"work_dir": "coding", "use_docker": False})
user_proxy.initiate_chat(
assistant,
message="""以下のWikipediaのページの本文データを抽出して、ONE_PIECE.txtというファイル名で保存してください。
https://ja.wikipedia.org/wiki/ONE_PIECE""")
得られたテキストデータにはWikipediaのテキストが含まれる。今回はストーリーが分かればよいので、あらすじっぽい文章以外は手動で消した。これで準備は完了。
インストール
RAGを使う場合はパッケージが異なるようで、以下をインストールする必要がある。
pip install "pyautogen[retrievechat]"
RAGの実行
コードは以下だ。Agentとして、RetrieveAssistantAgentとRetrieveUserProxyAgentを利用する。RetrieveUserProxyAgentではRetriveに関するretrieve_configというパラメータを入力する。taskにはqaとcodeモードがある。clientには、ChromaDBを利用しており、もし他のDBを使いたければretrieve_docsをオーバーライドすれば良いとのこと。chunk_modeにはone_lineとmulti_linesというのがあるらしいがマニュアルに詳細が書いてなかったのでコードを読む必要がありそう。embedding_modelとしては、デフォルトではall-MiniLM-L6-v2、より高性能なall-mpnet-base-v2というのが使えるようだ。他にもhttps://www.sbert.net/docs/pretrained_models.htmlにあるようなモデルが使えるらしい
import chromadb
from autogen.agentchat.contrib.retrieve_assistant_agent import RetrieveAssistantAgent
from autogen.agentchat.contrib.retrieve_user_proxy_agent import RetrieveUserProxyAgent
config_list = [
{
"model": "gpt-3.5-turbo",
"api_key": "<OpenAI APIのキーを入力>"
}
]
assistant = RetrieveAssistantAgent(
name="assistant",
system_message="You are a helpful assistant.",
llm_config={
"request_timeout": 600,
"seed": 42,
"config_list": config_list,
},
)
# 先程保存したワンピースのあらすじのテキストファイル
corpus_file = "./coding/ONE_PIECE.txt"
ragproxyagent = RetrieveUserProxyAgent(
name="ragproxyagent",
human_input_mode="NEVER",
max_consecutive_auto_reply=10,
retrieve_config={
"task": "qa",
"docs_path": corpus_file,
"chunk_token_size": 2000,
"model": "gpt-3.5-turbo",
"client": chromadb.PersistentClient(path="./db"),
"collection_name": "natural-questions",
"chunk_mode": "one_line",
"embedding_model": "all-MiniLM-L6-v2",
},
)
ragproxyagent.initiate_chat(
assistant,
problem="ゴムゴムの実とは何ですか?", n_results=30
)
結果は以下のようになった。ちゃんと出来てそうね。
ゴムゴムの実とは、主人公ルフィが食べた悪魔の実であり、彼にゴムの体質を与えました。
じゃあこの質問はどうだろう、みんな気になるよね。
assistant.reset()
ragproxyagent.initiate_chat(assistant,
problem="ひとつなぎの大秘宝(ワンピース)が具体的にどういった秘宝なのかについて教えてください", n_results=30
)
ネタバレ来なかった。
「ひとつなぎの大秘宝(ワンピース)」は、海賊王ゴールド・ロジャーが残した宝物であり、この宝物を巡って多くの海賊たちが争っています。具体的な内容はまだ明かされていません。
次はこんな質問をしてみる。ワンピース外の質問をするとどうなるかな?
assistant.reset()
ragproxyagent.initiate_chat(assistant,
problem="悟空とベジータはどちらが強い?", n_results=30
)
すると面白いことに、Retriveしたドキュメント中に回答が見つからなかったら、再度Retriveを実行するようだ。中々優秀じゃないか。詳細なログは長いので省略するが、どのコンテキストが使われているかを出力してくれており、何度か検索していることを確認できる。以下のようにUPDATE CONTENTという結果が返り、それに続いて再実行されている。
1回目
UPDATE CONTEXT
2回目
UPDATE CONTEXT
3回目 (分からなかったら質問文がそのまま返ってくるのかな?)
悟空とベジータはどちらが強い?
ついでに他の質問もしてみよう。
assistant.reset()
ragproxyagent.initiate_chat(assistant,
problem="ぼっちちゃんの本名は?", n_results=30
)
結果はこうなった。まじか。
モンキー・D・ルフィ
終わりに
他のライブラリでもおなじみのRAGをAutoGenでも試してみた。他のRAGと異なり、結果が見つからなかったら再検索するといったAgentっぽい振る舞いも見られて、有効性を感じられた。ただし、ぼっちちゃんの本名は後藤ひとりだと思う。次回は、RAGのより高度な例としてライブラリのリファレンスマニュアルを与えて、そこからコードを生成するというのをやってみよう。