見出し画像

ChatGPT勉強日記(#13) LangChainの総復習-第4回


本日はGreg Kamradt氏のThe LangChain Cookbook 7 Coreconceptの残りの章を最後まで復習します!


Indexes - Structuring documents to LLMs can work with them

(タイトルにタイポがあるような気がします。正しくはStructuring documents for LLMs to work with them.のような気がします)

Document Loaders

ここはオリジナルのコードがそのまま動きました。
ただ参考リンクになっている各種のドキュメントローダーのリンクがリンク切れになっていたので、探しました。↓に現在サポートされているドキュメントローダーの一覧があります。


URLs and webpages

unstructuredモジュールのインストールが必要でした。

!pip install unstructured

このモジュールをインストールしていればオリジナルのコードは動作します。

from langchain.document_loaders import UnstructuredURLLoader

urls = [
    "http://www.paulgraham.com/",
]

loader = UnstructuredURLLoader(urls=urls)

data = loader.load()

data[0].page_content

上のコードを実行するとポール・グラハムのエッセイの一部がちゃんと出力されました。

'New: How to Start Google | Best Essay | Superlinear Want to start a startup? Get funded by Y Combinator . © mmxxiv pg'

Retrievers


faissのインストールが必要です。
CPUのみ使用する場合は

!pip install faiss-cpu

(NvidiaのGPUを積んだマシーンであれば!pip install faiss-gpu)

次に、前々回のブログでやったように、OpenAIEmbeddingsのモジュールのインポート文を変更します。

#from langchain.embeddings import OpenAIEmbeddings
from langchain_openai import OpenAIEmbeddings

get_relevant_documentsのかわりにinvokeを使いました。

# docs = retriever.get_relevant_documents("what types of things did the author want to build?")
docs = retriever.invoke("what types of things did the author want to build?")

この2つの変更でオリジナルコードが動き、ベクターストアをつかってLLMからの回答を得ることができるようになりました。

VectorStores

こちらも↓のようにOpenAIEmbeddingsのクラスのimport先を変えるだけで動きます。

#from langchain.embeddings import OpenAIEmbeddings
from langchain_openai import OpenAIEmbeddings

Memory

こちらはオリジナルコードがそのまま動作します。
Langchainの各種のMemoryの一覧のリンクが切れていたので、調べました。↓にあります。


Chains

SimpleSequentialChainとLLMChainがdeprecatedなので、全面的に変えなければなりませんでした。

↓によると、LLMChainの代わりにRunnableSequenceを使えと書いてあるので、これにしたがって見ようと思いましたが、

2つ以上のRunnableSequenceを結合する方法が見つからず途方にくれました。
LangChainのドキュメントを見てみると↓のMultiple chainsというドキュメントがありました。

ここに書かれているサンプルを参考に、2つのChatPromptTemplateをStrOutputParserを経由して結合してみるとCookbookと同じように動作するchainを作ることができました。

from operator import itemgetter

from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

prompt1 = ChatPromptTemplate.from_template( 
"""Your job is to come up with a classic dish from the area that the users suggests.
% USER LOCATION
{user_location}

YOUR RESPONSE:
"""
)

prompt2 = ChatPromptTemplate.from_template(
"""Given a meal, give a short and simple recipe on how to make that dish at home.
% MEAL
{user_meal}

YOUR RESPONSE:
"""
)

model = ChatOpenAI(temperature=0, openai_api_key=openai_api_key)

chain1 = prompt1 | model | StrOutputParser()
chain2 = {"user_meal": chain1} | prompt2 | model | StrOutputParser()

chain2.invoke({"user_location": "Paris"})

ChatPromptTemplateをmodelとStrOutputParserにつなげてオブジェクトを作ります。
prompt1がmodelに入力され、出力されたAIMessageがStrOutputParserによって文字列に変換されます。
このchain1のアウトプットから{"user_meal": "chain1のアウトプット"}というPromptTemplateの入力を作り、それをprompt2 → model -> StrOutputParserとつなげます。

出来上がったChainに"Paris"をuser_locationとしてインプットすると、結果は↓となり、

'To make Coq au Vin at home, start by browning bacon in a large pot. Remove the bacon and brown chicken pieces in the bacon fat. Add chopped onions and mushrooms, then pour in red wine and chicken broth. Simmer for about an hour until the chicken is cooked through and the sauce is thickened. Serve hot with crusty bread or over mashed potatoes. Enjoy your homemade Coq au Vin!'

chain1のアウトプットが"Coq au Vin"、それをinputとしてchain2が"Coq au Vin"の作り方を説明しています。コック・オ・ヴァンは私の全く知らない料理でしたが、雄鶏の赤ワイン煮込みのようです、、料理名がわからなすぎたので、つぎにuser_locationにOsakaを入れてみると

chain2.invoke({"user_location": "Osaka"})

↓のようにお好み焼きの作り方を教えてくれました。これでやっとちゃんと動作しているなと感じることができました。

'To make Okonomiyaki at home, start by mixing together 1 cup of flour, 1 cup of grated yam, 2 eggs, and 1 cup of shredded cabbage in a bowl. Add in your choice of toppings such as pork, shrimp, or vegetables. Heat a griddle or non-stick pan and pour the batter onto the hot surface, shaping it into a pancake. Cook for a few minutes on each side until golden brown. Serve the Okonomiyaki with a drizzle of sweet and savory sauce, mayonnaise, and a sprinkle of bonito flakes on top. Enjoy your homemade Okonomiyaki!'

Summarization Chain

こちらはCookbookのコードがそのまま動いたので割愛します。

Agents

まず、google-search-resultsモジュールのインストールが必要でした。

!pip install google-search-results

下でSEAR_API_KEYを取得し、

それをsearp_api_keyに格納します。

from dotenv import load_dotenv
import os

load_dotenv()

serp_api_key=os.getenv('SERP_API_KEY', 'your_api_key')

一番大きな変更は、initialize_agent関数がdeprecatedになっていたことで、それによってAgentの呼び出し方を根本的に変えないといけない箇所でした。

from langchain.agents import load_tools
# from langchain.agents import initialize_agent
from langchain.llms import OpenAI
import json
from langchain import hub
from langchain.agents import AgentExecutor, create_react_agent

llm = OpenAI(temperature=0, openai_api_key=openai_api_key)
toolkit = load_tools(["serpapi"], llm=llm, serpapi_api_key=serp_api_key)
# agent = initialize_agent(toolkit, llm, agent="zero-shot-react-description", verbose=True, return_intermediate_steps=True)
prompt = hub.pull("hwchase17/react")
agent = create_react_agent(model, toolkit, prompt)
agent_executor = AgentExecutor(agent=agent, tools=toolkit, verbose=True)
agent_executor.invoke({"input":"what was the first album of the" 
                    " band that Natalie Bergman is a part of?"})

オリジナルのコードが”zero-shot-react-description”というメモリー(記憶)のないReActフレームワークのエージェントのインスタンスを生成していたので、↓を参考にコードを書き換えました。

ReActという言葉を知らなかったのですが、↓で説明されている推論とアクション、そこから得られたフィードバックをつなげて次の推論に移るというエージェント構築のアプローチのようです。

ここで使われている、promptはLangSmithで公開されているプロンプトで、下でそのプロンプトの中身を見ることができました。

このエージェントをVerboseモードで実行してみると、したのような推論のプロセスが走っていることがわかります。

最終的な答えは下のようになりました。

{'input': 'what was the first album of the band that Natalie Bergman is a part of?', 'output': 'Wild Belle'}

もともとの質問が"what was the first album of the band that Natalie Bergman is a part of?"、つまりNatalie Bergmanの所属するバンドの最初のアルバムの名前を教えてください、だったのですが、最終的な答えはアルバムの名前ではなく、所属するバンドの名前になってしまいました。
ログを見るとわかるのですが、エージェントの推論の過程で問題を取り違えてしまっていることがわかります。

エージェントはまだ発展途上の技術とKamradt氏もYoutubeの中で言っていました。ただどのように推論が行われるのかログを見るといろいろとLangchainを使う上で参考になることもありそうなので、今度また機会を作っていろいろなエージェントを見てみたいと思いました。

これでKamradt氏のThe LangChain Cookbook 7 Coreconcept、最後のレシピまで自分の手元で動くようになりました。

途中、いろんなものがdeprecatedになりすぎていて諦めようかと思ったものもありましたが、無事にすべてのサンプルを動作させることができました。

作ってみていて、調べきれなかった関連するものがいろいろあったので、そこを時間を作って調べたり、他のサンプルにも触れていき、またnoteで紹介できたらと思います。

ここまで読んでいただいた方、お疲れ様でした!


この記事の内容が気に入っていただけましたら、いいね、あるいはフォローをいただけると大変励みになります!

このブログに関する質問や、弊社(Goldrush Computing)へのOpenAI API、LLM、LangChain関連の開発案件の依頼は↓↓↓からお願いします。

mizutori@goldrushcomputing.com


次回は↓↓↓


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