LangChain v0.1 クイックスタートガイド - Python版
Python版の「LangChain」のクイックスタートガイドをまとめました。
【最新版の情報は以下で紹介】
1. LangChain
「LangChain」は、「大規模言語モデル」 (LLM : Large language models) と連携するアプリの開発を支援するライブラリです。
「LLM」という革新的テクノロジーによって、開発者は今まで不可能だったことが可能になりました。しかし、「LLM」を単独で使用するだけでは、真に強力なアプリケーションを作成するのに不十分です。真の力は、それを他の 計算 や 知識 と組み合わせた時にもたらされます。「LangChain」は、そのようなアプリケーションの開発をサポートします。
主な用途は、次の3つになります。
v0.1 ではlangchainパッケージが次の3つのパッケージに分割されました。すべて下位互換性のある方法で行われました。
2. LangChain のモジュール
「LangChain」は、言語モデル アプリケーションの構築に使用できる多くのモジュールを提供します。モジュールを組み合わせて複雑なアプリケーションを作成したり、個別に使用したりできます。
主なモジュールは、次のとおりです。
モジュールは、単純なアプリケーションではモジュール単体で使用でき、より複雑なユースケースではモジュールをチェーンで繋げて利用することができます。
3. インストール
Google Colabでのインストール手順は、次のとおりです。
(1) パッケージのインストール。
# パッケージのインストール
!pip install langchain==0.1.16
!pip install langchain_openai
(2) 環境変数の準備。
左端の鍵アイコンで「OPENAI_API_KEY」を設定してからセルを実行してください。
import os
from google.colab import userdata
# 環境変数の準備 (左端の鍵アイコンでOPENAI_API_KEYを設定)
os.environ["OPENAI_API_KEY"] = userdata.get("OPENAI_API_KEY")
4. Model I/O
LLMアプリケーションの中核はLLMです。「LangChain」は、様々なLLMを手順で操作できる共通インタフェースを提供します。
主な構成要素は、次の3つです。
4-1. Language Model
「LangChain」の最も基本的な機能は、LLMを呼び出すことです。「Language Model」は、LLMを呼び出すモジュールになります。
次の2種類のインタフェースを提供します。
・LLM
今回は例として、「テキスト生成モデル」でLLMの呼び出しを行います。テキスト→テキストのインタフェースになります。
from langchain.llms import OpenAI
# LLMの準備
llm = OpenAI(temperature=0.9)
# LLMの実行
output = llm.invoke("コンピュータゲームを作る日本語の新会社名をを1つ提案してください。")
print(type(output))
print(output)
<class 'str'>
ツクルゲームス
LLMの入力は文字列、出力は文字列になります。Messageリストで入力することも可能です。
・ChatModel
次に、「チャットモデル」でLLMの呼び出しを行います。メッセージリスト→メッセージのインタフェースになります。
from langchain.chat_models import ChatOpenAI
from langchain.schema import HumanMessage
# ChatModelの準備
chat_model = ChatOpenAI(temperature=0.9)
# ChatModelの実行
messages = [
HumanMessage(content="コンピュータゲームを作る日本語の新会社名をを1つ提案してください。")
]
output = chat_model.invoke(messages)
print(type(output))
print(output)
<class 'langchain_core.messages.ai.AIMessage'>
content='「夢遊計画」(ゆめあるけいかく)' response_metadata={'token_usage': {'completion_tokens': 18, 'prompt_tokens': 38, 'total_tokens': 56}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None} id='run-93614b2e-aaba-40c6-ace3-f6abced6610e-0'
ChatModelの入力はMessageリスト、出力はMessageになります。文字列で入力することも可能です。
メッセージは役割 (システム、ユーザー、AIなど) とコンテンツの情報を持ちます。「LangChain」の主なメッセージ型は、次の3種類です。
「Language Model」の使い方について詳しくは、「Language Models」を参照してください。
4-2. Prompt Template
「Prompt Template」は、ユーザー入力からプロンプトを生成するためのテンプレートです。アプリケーションで LLM を使用する場合、通常、ユーザー入力を直接LLM に渡すことはありません。ユーザー入力を基に「Prompt Template」でプロンプトを作成して、それをLLMに渡します。
今回は例として、ユーザー入力「作るもの」を基に「○○を作る日本語の新会社名をを1つ提案してください」というプロンプトを生成します。
from langchain.prompts import PromptTemplate
# プロンプトテンプレートの準備
prompt_template = PromptTemplate(
input_variables=["product"],
template="{product}を作る日本語の新会社名をを1つ提案してください",
)
# プロンプトテンプレートの実行
output = prompt_template.invoke({"product": "家庭用ロボット"})
print(type(output))
print(output)
<class 'langchain_core.prompt_values.StringPromptValue'>
text='家庭用ロボットを作る日本語の新会社名をを1つ提案してください'
「Prompt Template」の入力は辞書、出力は「PromptValue」です。
「PromptValue」は、LLMとChatModelの入力となるクラスです。文字列(LLMの入力)にキャストするto_string()と、Messageリスト(ChatModelの入力)にキャストするto_messages()を持ちます。
「Prompt Template」の使い方について詳しくは、「Prompts」を参照してください。
4-3. Output Parser
「Output Parser」 は、「Language Model」の出力を用途にあわせて変換するモジュールです。
主な用途は次のとおりです。
今回は、「StrOutputParser」でMessageリストをプレーンテキストに変換します。
from langchain_core.output_parsers import StrOutputParser
from langchain.schema import AIMessage
# Output Parserの準備
output_parser = StrOutputParser()
# Output Parserの実行
message = AIMessage(content="AIからのメッセージです")
output = output_parser.invoke(message)
print(type(output))
print(output)
<class 'str'>
AIからのメッセージです
「StrOutputParser」の入力は「Language Model」の出力 (文字列またはMessageリスト)、出力は文字列になります。
提供されている「OutputParser」は、次のとおりです。
5. Chain
単純なアプリケーションであれば「LLM」や「ChatModel」の単独使用で問題ありませんが、それらモジュール (Runnable) をチェーンで繋げることで、複雑なアプリケーションを構築することができます。
Chainの実装方法には、次の2種類があります。
「LangChain」ではこのチェーンを「LCEL」(LangChain Expression Language)と呼ばれる表現言語で記述します。基本的な使い方は、モジュールを「|」で繋げるだけになります。
from langchain.prompts import PromptTemplate
from langchain.chat_models import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
# プロンプトテンプレートの準備
prompt_template = PromptTemplate(
input_variables=["product"],
template="{product}を作る日本語の新会社名を1つ提案してください",
)
# ChatModelの準備
chat_model = ChatOpenAI(temperature=0.9)
# OutputParserの準備
output_parser = StrOutputParser()
# チェーンをつなげて実行
chain = prompt_template | chat_model | output_parser
output = chain.invoke({"product": "家庭用ロボット"})
print(output)
家庭ロボットテクノロジー株式会社
「LCEL」の使い方については「LangChain Expression Language (LCEL)」を参照してください。
6. Agent
6-1. Agentの概要
「Agent」は、ユーザーの要求に応じて、どの「Action」をどういう順番で実行するかを決定するモジュールです。「Chain」の機能の実行の順番はあらかじめ決まっていますが、「Agent」はユーザーの要求に応じてLLM自身が決定します。この「Agent」が「Action」で実行する特定の機能のことを「Tool」と呼びます。
今回は例として、次の2つのToolを使うAgentを作成します。
6-2. Tavility Toolの準備
(1) パッケージのインストール。
「Tavily」のパッケージをインストールします。
# パッケージのインストール
!pip install tavily-python
(2) 環境変数の準備。
左端の鍵アイコンで「TAVILY_API_KEY」を設定してからセルを実行してください。
import os
from google.colab import userdata
# 環境変数の準備 (左端の鍵アイコンでTAVILY_API_KEYを設定)
os.environ["TAVILY_API_KEY"] = userdata.get("TAVILY_API_KEY")
(3) Tavilityツールの準備。
from langchain_community.tools.tavily_search import TavilySearchResults
# Tavilyの準備
tavily_tool = TavilySearchResults()
# 動作確認
tavily_tool.invoke("東京の天気は?")
[{'url': 'https://weather.yahoo.co.jp/weather/jp/13/4410.html',
'content': '東京(東京)の天気予報。今日・明日の天気と風と波、...'},
{'url': 'https://weathernews.jp/onebox/35.691667/139.750000/q=東京&v=7568ec9017b1ee619b719b2e27bb2222ff3533c3d047419f40d2980258c0a799&temp=c&lang=ja',
'content': '午後20%\n日差しに暖かさを感じそう...'},
{'url': 'https://weather.yahoo.co.jp/weather/jp/13/',
'content': '日本海には高気圧があって、...'},
{'url': 'https://tenki.jp/forecast/3/16/',
'content': '東京都の天気予報です。市区町村別の今日の天気、...'},
{'url': 'https://weathernews.jp/onebox/tenki/tokyo/',
'content': '東京の最新天気情報。よく当たる1時間毎のピンポイント天気、...'}]
6-3. Retriever Toolの準備
(1) パッケージのインストール。
ベクトルストア関連のパッケージをインストールします。
# パッケージのインストール
!pip install unstructured faiss-cpu
(2) ドキュメントの準備。
今回は、マンガペディアの「ぼっち・ざ・ろっく!」のドキュメントを用意しました。
・bocchi.txt
(3) Colabにdataフォルダを作成して配置。
(4) Retrieverの準備。
from langchain.document_loaders import DirectoryLoader
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
# ドキュメントの準備
loader = DirectoryLoader('./data/')
docs = loader.load()
documents = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200
).split_documents(docs)
# ベクトルストアの準備
vector = FAISS.from_documents(documents, OpenAIEmbeddings())
# Retrieverの準備
retriever = vector.as_retriever()
# 動作確認
retriever.invoke("ぼっち・ざ・ろっくのぼっちちゃんの本名は?")
[Document(page_content='後藤ひとり(ごとうひとり)\n\n秀華高校に通う女子。...', metadata={'source': 'data/bocchi.txt'}),
Document(page_content='長谷川あくび(はせがわあくび)\n\nメタルバンド...', metadata={'source': 'data/bocchi.txt'}),
Document(page_content='2号(にごう)\n\n美術大学の映像学科に在籍する女子。...', metadata={'source': 'data/bocchi.txt'}),
Document(page_content='山田リョウ(やまだりょう)\n\n下北沢高校に通う女子。...', metadata={'source': 'data/bocchi.txt'})]
(5) Retriever Toolの準備。
from langchain.tools.retriever import create_retriever_tool
# Retriever Toolの準備
retriever_tool = create_retriever_tool(
retriever,
"bocchi_search",
"ぼっち・ざ・ろっくに関する情報を検索します。ぼっち・ざ・ろっくに関する質問がある場合は、このツールを使用する必要があります。",
)
6-4. Agentの準備
(1) Toolsの準備。
# Toolsの準備
tools = [tavily_tool, retriever_tool]
(2) プロンプトテンプレートとモデルの準備。
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
# プロンプトテンプレートの準備
prompt = ChatPromptTemplate.from_messages([
("system", "you're a helpful assistant. Please respond in Japanese."),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
])
# 言語モデルの準備
model = ChatOpenAI(model="gpt-4-turbo", temperature=0)
(3) Agentの準備。
from langchain.agents import create_tool_calling_agent, AgentExecutor
# エージェントの準備
agent = create_tool_calling_agent(model, tools, prompt)
# AgentExecutorの準備
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
(3) 動作確認1。
オンライン検索が必要な場合は、「Tavility Tool」が呼ばれます。
# 動作確認
output = agent_executor.invoke({"input": "東京の天気は?"})
print(output)
> Entering new AgentExecutor chain...
Invoking: `tavily_search_results_json` with `{'query': '東京の天気'}`
[{'url': 'https://weathernews.jp/onebox/tenki/tokyo/', 'content': '東京の最新天気情報。...'}...]
東京の天気情報をお伝えしますね。現在の東京の天気は冬晴れで、日中は日差しの温もりを感じることができます。気温は最高14℃、最低3℃です。降水確率は午前10%、午後10%となっています。明日の天気予報では、最高気温11℃、最低気温3℃で、午前10%の降水確率が予想されています。冬晴れの日が続く中、体感温度の調節に注意してください。朝晩は冷え込むので、体調管理に気を付けてください。詳細な天気情報は以下のリンクからご確認いただけます:\n[東京の天気情報](https://weathernews.jp/onebox/tenki/tokyo/)
> Finished chain.
{'input': '東京の天気は?', 'output': '東京の天気情報をお伝えしますね。現在の東京の天気は冬晴れで、日中は日差しの温もりを感じることができます。気温は最高14℃、最低3℃です。降水確率は午前10%、午後10%となっています。明日の天気予報では、最高気温11℃、最低気温3℃で、午前10%の降水確率が予想されています。冬晴れの日が続く中、体感温度の調節に注意してください。朝晩は冷え込むので、体調管理に気を付けてください。詳細な天気情報は以下のリンクからご確認いただけます:\n[東京の天気情報](https://weathernews.jp/onebox/tenki/tokyo/)'}
(4) 動作確認2。
ローカル検索が必要な場合は、「Retriever Tool」が呼ばれます。
# 動作確認2
output = agent_executor.invoke({"input": "ぼっち・ざ・ろっくのぼっちちゃんの本名は?"})
print(output)
> Entering new AgentExecutor chain...
Invoking: `bocchi_search` with `{'query': 'ぼっち・ざ・ろっく ぼっちちゃん 本名'}`
後藤ひとり(ごとうひとり)...
ぼっち・ざ・ろっくのぼっちちゃんの本名は後藤ひとり(ごとうひとり)です。
> Finished chain.
{'input': 'ぼっち・ざ・ろっくのぼっちちゃんの本名は?', 'output': 'ぼっち・ざ・ろっくのぼっちちゃんの本名は後藤ひとり(ごとうひとり)です。'}
「Agent」の使い方について詳しくは、「Agents」を参照してください。
7. Memory
これまでの「Chain」や「Agent」はステートレスでしたが、「Memory」を使うことで、「Chain」や「Agent」で過去の会話のやり取りを記憶することができます。過去の会話の記憶を使って、会話することができます。
Agentに「Memory」を追加する手順は、次のとおりです。
(1) AgentExecutorをRunnableWithMessageHistoryでラップ。
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
# Memoryの準備
message_history = ChatMessageHistory()
# Memory付きAgentの準備
agent_with_chat_history = RunnableWithMessageHistory(
agent_executor,
lambda session_id: message_history,
input_messages_key="input",
history_messages_key="chat_history",
)
現実世界のほとんどのシナリオではセッション IDが必要になります。今回は、単純なメモリ内の「ChatMessageHistory」を使用しているため、ここでは実際には使用されていません。
(2) 動作確認1。
# 動作確認1
output = agent_with_chat_history.invoke(
{"input": "うちのネコの名前は白子です。"},
config={"configurable": {"session_id": "<foo>"}},
)
print(output)
> Entering new AgentExecutor chain...
白子という名前はとてもかわいいですね!白子ちゃんは元気ですか?何か質問やお手伝いがあればお知らせくださいね。
> Finished chain.
{'input': 'うちのネコの名前は白子です。', 'chat_history': [], 'output': '白子という名前はとてもかわいいですね!白子ちゃんは元気ですか?何か質問やお手伝いがあればお知らせくださいね。'}
(3) 動作確認2。
過去の会話内容を覚えていることがわかります。
# 動作確認2
output = agent_with_chat_history.invoke(
{"input": "うちのネコの名前を呼んでください"},
config={"configurable": {"session_id": "<foo>"}},
)
print(output)
> Entering new AgentExecutor chain...
白子ちゃん、おはよう!元気にしてるかな?白子ちゃん、白子ちゃん、こっちに来て〜♪
> Finished chain.
{'input': 'うちのネコの名前を呼んでください', 'chat_history': [HumanMessage(content='うちのネコの名前は白子です。'), AIMessage(content='白子という名前はとてもかわいいですね!白子ちゃんは元気ですか?何か質問やお手伝いがあればお知らせくださいね。')], 'output': '白子ちゃん、おはよう!元気にしてるかな?白子ちゃん、白子ちゃん、こっちに来て〜♪'}
「Memory」の使い方について詳しくは、「Memory」を参照してください。
関連
この記事が気に入ったらサポートをしてみませんか?