🎃
LlamaIndex v0.6.4 を LangChain の Tools として使ってみた
想定読者
- v0.6.0 より大きな変更があった LlamaIndex を LangChain でどのように使うか知りたい方
- 独自のデータを利用しつつ、過去のやりとりを記憶した AI ツールを作りたい方
LlamaIndex v0.6 について
LlamaIndex が v0.6.0 より大きな変更がありました。クエリロジックをカスタマイズしやすくなったりする一方で、コード実行方法も変更になりました。変更内容の詳細や LlamaIndex 単体の使い方を知りたい方には、以下の npaka さんの記事をおすすめします。
LangChain との連携方法も変わるか
LangChain の Tools として利用するのは変わりませんが、コード実行方法に少し変更があるようです。今回は以下の公式ドキュメントも参考にしながら実際に連携を試してみたいと思います。
やってみた
Google Colab を使ってやっていきます。
ドキュメントの準備
LlamaIndex のリポジトリにあるダミーデータを利用します。
Google Colab を開きます。左袖から以下を作成します。
- フォルダ:
data
- ファイル:
paul_graham_essay.txt
(データは上記ダミーデータをコピペ)
パッケージのインストール
!pip install langchain
!pip install openai
!pip install tiktoken
!pip install llama-index==0.6.4
環境変数の設定
sk-xxxxxxxxxxxx
には OpenAI API のトークン(有料)を設定します。
import os
os.environ["OPENAI_API_KEY"] = "sk-xxxxxxxxxxxx"
コードの準備
import openai
from langchain.agents import AgentType, Tool, initialize_agent
from langchain.chat_models import ChatOpenAI
from langchain.memory import ConversationSummaryBufferMemory
from llama_index import GPTVectorStoreIndex, SimpleDirectoryReader
documents = SimpleDirectoryReader("./data/").load_data()
index = GPTVectorStoreIndex.from_documents(documents=documents)
tools = [
Tool(
name="LlamaIndex",
func=lambda q: str(index.as_query_engine().query(q)),
description="useful for when you need to answer questions about graham",
return_direct=True,
),
]
llm = ChatOpenAI(
temperature=0,
client=openai,
)
memory = ConversationSummaryBufferMemory(
llm=llm,
memory_key="chat_history",
max_token_limit=1000,
)
llm = ChatOpenAI(temperature=0)
prefix = """Anser the following questions as best you can, but speaking Japanese. You have access to the following tools:"""
suffix = """Begin! Remember to speak Japanese when giving your final answer."""
agent_chain = initialize_agent(
tools,
llm,
agent=AgentType.CONVERSATIONAL_REACT_DESCRIPTION,
memory=memory,
prefix=prefix,
suffix=suffix,
verbose=True,
)
実行
LlamaIndex のインデックスを参照した回答ができるか
agent_chain.run(input="What did graham do growing up?")
> Entering new AgentExecutor chain...
Thought: Do I need to use a tool? Yes
Action: LlamaIndex
Action Input: Graham
Observation: chose to work on Bel because...?
Graham chose to work on Bel because he wanted to create a Lisp interpreter that could be written in itself, and he was intrigued by the challenge of making it work. He also wanted to explore the potential of macros and embedded languages, which he felt had been largely unexplored. Finally, he wanted to prove to himself that he could complete a difficult project, and he was motivated by the idea of being able to make art and be independent without having to rely on a boss or research funding.
> Finished chain.
chose to work on Bel because...?
Graham chose to work on Bel because he wanted to create a Lisp interpreter that could be written in itself, and he was intrigued by the challenge of making it work. He also wanted to explore the potential of macros and embedded languages, which he felt had been largely unexplored. Finally, he wanted to prove to himself that he could complete a difficult project, and he was motivated by the idea of being able to make art and be independent without having to rely on a boss or research funding.
TOOL として LlamaIndex が選択され、ダミーデータのインデックスを元に回答できました。
LangChain を使って過去のやりとりができるか
agent_chain.run(input='私の名前は筧です。')
> Entering new AgentExecutor chain...
Thought: Do I need to use a tool? No
AI: こんにちは、筧さん!私はあなたのお手伝いができます。何かお困りのことはありますか?
> Finished chain.
こんにちは、筧さん!私はあなたのお手伝いができます。何かお困りのことはありますか?
ダミーデータに関係ない質問だったので、TOOL は利用しないで回答できました。
agent_chain.run(input='私の名前を覚えていますか?')
> Entering new AgentExecutor chain...
Thought: Do I need to use a tool? No
AI: はい、覚えています。あなたの名前は筧さんですね。
> Finished chain.
はい、覚えています。あなたの名前は筧さんですね。
直近のやりとりを覚えており、それを踏まえて回答できました。
おわりに
最後まで読んでいただきありがとうございました。LlamaIndex の大きな変更があったものの、公式ドキュメントには使い方の説明があり、すぐに使うことができました。参考になった場合は、Like やバッジを贈っていただけると励みになります!それではまた!
Discussion
LlamaIndexの事を知りたくて、ド素人ですが、「LlamaIndex google colab」と検索してこの記事に辿り着きました。
とりあえず、内容の通りコピペして実行するのですが、以下のようなエラー?が出てきます。
何がダメなんでしょう(;^_^A
GPTに質問しましたが良く分からずorz
AttributeError Traceback (most recent call last)
<ipython-input-35-bf4c1f72580d> in <cell line: 1>()
----> 1 agent_chain.run(input="What did graham do growing up?")
9 frames
/usr/local/lib/python3.10/dist-packages/langchain/chains/base.py in run(self, callbacks, *args, **kwargs)
237
238 if kwargs and not args:
--> 239 return self(kwargs, callbacks=callbacks)[self.output_keys[0]]
240
241 if not kwargs and not args:
/usr/local/lib/python3.10/dist-packages/langchain/chains/base.py in call(self, inputs, return_only_outputs, callbacks)
138 except (KeyboardInterrupt, Exception) as e:
139 run_manager.on_chain_error(e)
--> 140 raise e
141 run_manager.on_chain_end(outputs)
142 return self.prep_outputs(inputs, outputs, return_only_outputs)
/usr/local/lib/python3.10/dist-packages/langchain/chains/base.py in call(self, inputs, return_only_outputs, callbacks)
132 try:
133 outputs = (
--> 134 self._call(inputs, run_manager=run_manager)
135 if new_arg_supported
136 else self._call(inputs)
/usr/local/lib/python3.10/dist-packages/langchain/agents/agent.py in _call(self, inputs, run_manager)
951 # We now enter the agent loop (until it returns something).
952 while self._should_continue(iterations, time_elapsed):
--> 953 next_step_output = self._take_next_step(
954 name_to_tool_map,
955 color_mapping,
/usr/local/lib/python3.10/dist-packages/langchain/agents/agent.py in _take_next_step(self, name_to_tool_map, color_mapping, inputs, intermediate_steps, run_manager)
818 tool_run_kwargs["llm_prefix"] = ""
819 # We then call the tool on the tool input to get an observation
--> 820 observation = tool.run(
821 agent_action.tool_input,
822 verbose=self.verbose,
/usr/local/lib/python3.10/dist-packages/langchain/tools/base.py in run(self, tool_input, verbose, start_color, color, callbacks, **kwargs)
253 except (Exception, KeyboardInterrupt) as e:
254 run_manager.on_tool_error(e)
--> 255 raise e
256 run_manager.on_tool_end(str(observation), color=color, name=self.name, **kwargs)
257 return observation
/usr/local/lib/python3.10/dist-packages/langchain/tools/base.py in run(self, tool_input, verbose, start_color, color, callbacks, **kwargs)
247 tool_args, tool_kwargs = self._to_args_and_kwargs(parsed_input)
248 observation = (
--> 249 self._run(*tool_args, run_manager=run_manager, **tool_kwargs)
250 if new_arg_supported
251 else self._run(*tool_args, **tool_kwargs)
/usr/local/lib/python3.10/dist-packages/langchain/tools/base.py in _run(self, run_manager, *args, **kwargs)
348 )
349 if new_argument_supported
--> 350 else self.func(*args, **kwargs)
351 )
352
<ipython-input-33-d8a0ef5efb88> in <lambda>(q)
12 Tool(
13 name="LlamaIndex",
---> 14 func=lambda q: str(index.as_query_engine().query(q)),
15 description="useful for when you need to answer questions about graham",
16 return_direct=True,
/usr/local/lib/python3.10/dist-packages/llama_index/indices/query/base.py in query(self, str_or_query_bundle)
18 if isinstance(str_or_query_bundle, str):
19 str_or_query_bundle = QueryBundle(str_or_query_bundle)
---> 20 return self._query(str_or_query_bundle)
21
22 async def aquery(self, str_or_query_bundle: QueryType) -> RESPONSE_TYPE:
AttributeError: 'RetrieverQueryEngine' object has no attribute 'callback_manager'
pythonのバージョンを3.10にするとできました‼
お騒がせしましたm(__)m