LangChainのQuickstartを読む (1) - LLM, プロンプトテンプレート, チェイン
本シリーズでは、LangChainの Quickstart の内容を元にLangChainの使い方について紹介します。
今回は、LLM、プロンプトテンプレート、チェインを扱います。
1. インストール
langchain
とそのOpenAI拡張のlangchain-openai
をインストールします。
pip install langchain
pip install langchain-openai
-
今回使用するバージョンは以下のとおりです。
現状、LangChainは破壊的変更が多く、バージョンが異なると正常に動作しない可能性があるため注意してください。$ pip list|grep langchain langchain 0.1.17 langchain-community 0.0.37 langchain-core 0.1.52 langchain-openai 0.1.6 langchain-text-splitters 0.0.1
2. APIキー設定
次に、OpenAIのAPIキーを環境変数OPENAI_API_KEY
に設定します。
python-dotenv
のようなライブラリも存在しますが、セキュリティリスク等を考慮して、極力サードパーティ製ライブラリは使用しない方針で進めます。
2.1. ファイルにAPIキーを保存
作業用ディレクトリに.openai
ファイルを作成して、その中にAPIキーを保存します。
APIキーはここから取得します。
2.2. APIキーを環境変数 OPENAI_API_KEY
に設定する
先ほど作成した.openai
ファイルの内容を読み込み、環境変数OPENAI_API_KEY
に設定します。
import os
with open('.openai') as f:
os.environ['OPENAI_API_KEY'] = f.read().strip()
3. LangChainを使用してChatGPTと会話する
3.1. LLMを初期化
初めに、OpenAIのチャットボット(LLM)を読み込みます。
何も引数を指定しない場合はモデル gpt-3.5-turbo
がデフォルトで使用されます。
from langchain_openai import ChatOpenAI
llm = ChatOpenAI()
3.2. LLMと会話する
LLMと会話するにはinvoke
メソッドを使用します。
llm.invoke("LangChainとは何でしょうか?")
実行すると以下のような出力が得られます。
(使用しているgpt-3.5-turbo
の訓練データは2021年9月が最新であるため、出力内容は間違っています。)
AIMessage(content='LangChainは、...', response_metadata={'token_usage': {'completion_tokens': 189, 'prompt_tokens': 19, 'total_tokens': 208}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-xxxxx')
直近でOpenAIでは、APIの課金方式が月末払いから事前払い(プリペイド方式)に変更されました。
そのため、以下のようなエラーが発生する場合はOpenAIのドキュメントを参照して、事前に課金しておきましょう。
(課金後、反映されるまでに少し時間がかかります。)
RateLimitError: Error code: 429 - {'error': {'message': 'You exceeded your current quota, please check your plan and billing details. For more information on this error, read the docs: https://platform.openai.com/docs/guides/error-codes/api-errors.', 'type': 'insufficient_quota', 'param': None, 'code': 'insufficient_quota'}}
4. プロンプトのテンプレートを使用する
同じ形式のプロンプトを何回も使用する場合、テンプレートを使用することで処理を簡略化できます。
以下はシステムメッセージとして「あなたは優秀なドキュメントライターです。」という文章を渡し、
ユーザの会話をinput
という名前のキーで渡すためのテンプレートを作成しています。
from langchain_core.prompts import ChatPromptTemplate
template = ChatPromptTemplate.from_messages([
("system", "あなたは優秀なドキュメントライターです。"),
("user", "{input}")
])
作成されたテンプレートのinvoke
メソッドを使用すると、プロンプトを生成できます。
入力として、input
キーを持つ辞書を渡します。
template.invoke({"input": "LangChainとは何でしょうか?"})
実行すると以下のプロンプトが出力されます。
ChatPromptValue(messages=[SystemMessage(content='あなたは優秀なドキュメントライターです。'), HumanMessage(content='LangChainとは何でしょうか?')])
このプロンプトをLLMに入力することで回答を生成することが出来ます。
(引き続き、回答内容は間違っています。)
prompt = template.invoke({"input": "LangChainとは何でしょうか?"})
llm.invoke(prompt)
-
実行結果
AIMessage(content='LangChainは、...', response_metadata={'token_usage': {'completion_tokens': 297, 'prompt_tokens': 43, 'total_tokens': 340}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-xxxxx')
5. 複数の処理をまとめる (チェイン)
先程のテンプレートを使用した例では、以下のような処理を行っていました。
ユーザの入力 => テンプレート => LLM => 回答
LangChainでは、このような複数の処理をチェインと呼ばれる1つの処理にまとめる仕組みが存在します。
チェインを作成するには、各処理をパイプ(|
)でつなげます。
chain = template | llm
作成されたチェインのinvoke
メソッドにユーザの入力を渡すと、一連の処理を実行した結果が得られます。
chain.invoke({"input": "LangChainとは何でしょうか?"})
-
実行結果(回答内容は間違っています)
AIMessage(content='LangChainは、...', response_metadata={'token_usage': {'completion_tokens': 315, 'prompt_tokens': 43, 'total_tokens': 358}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-xxxxx')
文字列として出力する
上記コードを実行すると AIMessage
オブジェクトが出力されます。
このオブジェクトを文字列に変換するには、StrOutputParser
を使用します。
from langchain_core.output_parsers import StrOutputParser
output_parser = StrOutputParser()
chain = template | llm | output_parser
chain.invoke({"input": "LangChainとは何でしょうか?"})
-
実行結果(回答内容は間違っています)
'LangChainは、...'