🧑‍🎓

StreamlitでLangChainのAgentアプリを作成しよう!

2023/08/18に公開

2023年9月2日追記
アプリの公開をしました!streamlitとgithubで公開しています。
ぜひチェックしてみてください。リンクは一番下に置いています。


最近streamlitが熱いです!どうやらstreamlitとLangChainがコラボしているみたいです。
https://blog.streamlit.io/langchain-streamlit/
その中でもAgentが実装出来る機能が公開されていました。早速試してみましょう!

Streamlitとは?

Streamlitは、PythonでWebアプリケーションを素早く作成するためのオープンソースライブラリです。データ分析、可視化、機械学習モデルのデモなどに特に適しており、コーディングの専門知識がなくても使いやすいツールです。
https://streamlit.io/

Agentとは?

Agentは、LangChainで使われる賢いヘルパーみたいなものです。言語モデルを使って、どんなアクションを取るかを考えてくれます。簡単に言えば、チャットボットをもっと賢くするための工夫の一つって感じですね!具体的に言えばネット検索したり、計算したり、データベース照会したり様々なアクションを実行出来るようになるんです!

早速実装しよう!

以下の記事を参考にしています。
https://python.langchain.com/docs/integrations/callbacks/streamlit?ref=blog.streamlit.io#installation-and-setup

必要なライブラリのインストール

pip install streamlit
pip install openai
pip install langchain
pip install duckduckgo-search

OpenAIのAPI keyが必要です!取得していない方は他の方の記事を参考に取得して下さい。

from langchain.chat_models import ChatOpenAI
from langchain.agents import AgentType, initialize_agent, load_tools
from langchain.callbacks import StreamlitCallbackHandler
import streamlit as st

openai.api_key = 'your-api-key-here'
llm = ChatOpenAI(temperature=0, streaming=True)
tools = load_tools(["ddg-search"]) # DuckDuckGoの検索ツールをロードする

# ReActエージェントを初期化する。このエージェントはzero-shot学習と説明を組み合わせたもの
agent = initialize_agent(
    tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True
)

if prompt := st.chat_input(): # Streamlit のチャット入力がある場合に実行する
    st.chat_message("user").write(prompt) # ユーザの入力メッセージをStreamlitのチャットに表示する
    with st.chat_message("assistant"): # アシスタントの応答を表示するためのブロックを開始する
        st_callback = StreamlitCallbackHandler(st.container()) # Streamlitのコンテナをコールバックとして使用するハンドラを初期化する****
        response = agent.run(prompt, callbacks=[st_callback]) # エージェントを使って
        st.write(response) # 応答をStreamlitのチャットに表示する

大事な所は説明しますね!

agent = initialize_agent(
    tools, llm, agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose=True
)

Agentは、LLMを使用してどう行動するかを決定します。LangChainにはさまざまなタイプのAgentがありそれぞれ個性があります。ここではCHAT_ZERO_SHOT_REACT_DESCRIPTIONという汎用的なReactのAgentを使用しています。
https://python.langchain.com/docs/modules/agents/agent_types/

tools = load_tools(["ddg-search"])

Agentが呼び出す機能をtoolと呼びます。LangChainは多数のtoolがあります。適切なtoolをAgentに提供すると様々な目標を達成することが出来るんですね。
今回はDuckDuckGo Searchという検索エンジンを使用しています。この検索エンジンはAPI keyや登録なしで使用することが出来てとても便利です!
https://python.langchain.com/docs/integrations/tools/

別のAgentも試してみよう!

先程のコードはリンク先のコードそのままでしたので、少し手を加えてみます。
Agentとtoolを変更してみます!個人的に良いと思っているAgentはOpenAI functionsです。
toolについては計算toolを追加してみましょう。

from langchain.callbacks import StreamlitCallbackHandler
import streamlit as st
from langchain.tools import DuckDuckGoSearchRun
from langchain.chat_models import ChatOpenAI
from langchain.agents import AgentType, initialize_agent, Tool
from langchain.callbacks import StreamlitCallbackHandler
from langchain import LLMMathChain
openai.api_key = 'your-api-key-here'
st_callback = StreamlitCallbackHandler(st.container())
search = DuckDuckGoSearchRun()
llm = ChatOpenAI(temperature=0, streaming=True, model="gpt-3.5-turbo")
llm_math_chain = LLMMathChain.from_llm(llm=llm, verbose=True)

# 使用可能なツールのリストを作成する
tools = [
    Tool(
        name = "ddg-search",
        func=search.run,
        description="useful for when you need to answer questions about current events. You should ask targeted questions"
    ),
    Tool(
        name="Calculator",
        func=llm_math_chain.run,
        description="useful for when you need to answer questions about math"
    ),
]

# エージェントを初期化する。このエージェントはOpenAIの関数を使用
agent = initialize_agent(
    tools, llm, agent=AgentType.OPENAI_FUNCTIONS, verbose=True
)

if prompt := st.chat_input():
    st.chat_message("user").write(prompt)
    with st.chat_message("assistant"):
        st_callback = StreamlitCallbackHandler(st.container())
        response = agent.run(prompt, callbacks=[st_callback])
        st.write(response)

変更箇所について説明しますね!

agent = initialize_agent(
    tools, llm, agent=AgentType.OPENAI_FUNCTIONS, verbose=True
)

OPENAI_FUNCTIONSというAgentを選択しました。このAgentはChatGPTがtoolを呼び出すべきタイミングを検知し、そのtoolに渡すべき入力を応答するように調整されています。特に便利と思うのは、toolを使わないで良いと判断すれば使わずにChatGPT自身が応答してくれるという所です。(他Agentでは「検索せずともLLMが知っているであろうこと」も検索するという事象がありました。)

tools = [
    Tool(
        name = "ddg-search",
        func=search.run,
        description="useful for when you need to answer questions about current events. You should ask targeted questions"
    ),
    Tool(
        name="Calculator",
        func=llm_math_chain.run,
        description="useful for when you need to answer questions about math"
    ),
]

今回はtoolを検索toolと計算toolの2つを選択してみました。先程はload_toolsという関数を使いましたが今回は自身で上記のようにtoolを設定しています。
 
以下はWho is Leo DiCaprio's girlfriend? What is her current age raised to the 0.43 power?/レオナルドディカプリオの彼女の年齢の0.43乗は?と聞いています。
(何故かは知りませんがLangChainではこのpromptがよく使われます。)
レオナルドディカプリオの彼女の年齢を検索toolでネット検索した後、計算toolでその年齢の0.43乗を計算してくれていますね。

いかがでしたか?
基本的にLLMは学習後の新しいデータを知らない上、数学の能力も限定的です。しかし、Agentを導入することで、これらの制約を克服することができました!LLMの弱点をAgentの導入により補う事が出来たのです。私はこれをとても感動的な進化と感じましたが皆さんはどう思いましたか??
 
streamlitとLangChainのコラボはまだ始まったばかりです。また、Agentに関して私はまだまだ勉強中です。さらに便利な機能があれば(出てきたら)、皆さんとシェアするつもりです!Happy coding!

アプリの公開

今回のアプリをstreamlit shareで公開しています!ぜひ使ってみてください。
左のスライドバーにOpenAIのAPI Keyを設定してください。
https://app-app-6tgeomrpkgarrf3vy59fbl.streamlit.app/
また、これまで作成したアプリはgithubでも公開しています!ぜひチェックしてみてください。
https://github.com/tsuzukia21/streamlit-app

Discussion