langchain 0.1.11 一通り確認(1)
langchain 0.1.11 一通り確認(1)
公式サイトのcookbook Prompt+LLMにあるサンプルコードを一通り試す
こんにちは、makokonです。
皆さんlangchainを使っていますか。
2023年12月14日にv0.1.0へのメジャーアップデートと思ったら、もうv0.1.11になっていますね。今のところ使っていて、いきなり従来のプログラムが誤作動するような大きな変更にぶつかっていませんが、いちいち使い方が古いと責められては、気持ちがもやもやします。
一度、公式ページのコードを一通り実行して、もやもやを消しておこうと思います。やっぱり自分の環境で動いてもらわないとね。
ですから、基本的に公式ページの焼き直しなので、そんなに新しい報告はないです。むしろ自分用の備忘録です。
準備
python 仮想環境
まずは、環境の準備をしましょう。
お試しということもあり、pythonの仮想環境を用意します。
今回はlinux上で試すことにしたので、こんな感じ
$ mkdir langchain-0.1.11
$ python -m venv langchain-0.1.11
$ cd langchain-0.1.11/
$ source bin/activate
$ cat /etc/issue
Ubuntu 22.04.3 LTS \n \l
$ python --version
Python 3.10.12
$ pip list
Package Version
---------- -------
pip 22.0.2
setuptools 59.6.0
$ pip install --upgrade pip
$ pip list
Package Version
---------- -------
pip 24.0
setuptools 59.6.0
とりあえずpipも新しくして、準備完了
コーディング
Prompt + LLM
まずは基本ですね。
PromptTemplate / ChatPromptTemplate -> LLM / ChatModel -> OutputParser
これを試してみます。なお、LLMはOPENAIを利用します。
$ pip install –upgrade –quiet langchain langchain-openai
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
prompt = ChatPromptTemplate.from_template("tell me a joke about {foo}")
model = ChatOpenAI()
chain = prompt | model
# result
print(chain.invoke({"foo": "bears"}))
prompt = ChatPromptTemplate.from_template("{foo}に関するジョークを日本超で話して")
chain = prompt | model
# result
print(chain.invoke({"foo": "カラーテレビ"}))
"bears"に関するジョークを返してくれました。
日本語のプロンプトと回答も当然ですが問題ないですね。
ジョークの出来は悪いけど
なお、今回はpromptが固定なので、promptを変更したときはchainも再定義が必要です。ご注意を。
Attaching Stop Sequences
ストップシーケンスの設定のサンプルもありますね。ストップシーケンスとは処理を停止するための指示やデータを示すものです。
サンプルは改行コードをストップシーケンスに設定しています。temperature=0.0にして、その挙動を確認してみましょう。
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
prompt = ChatPromptTemplate.from_template("tell me a joke about {foo}")
model = ChatOpenAI(temperature = 0.0)
chain = prompt | model
# result
print(chain.invoke({"foo": "bears"}))
# test stop sequences
chain = prompt | model.bind(stop=["\n"])
for i in range(5):
print(chain.invoke({"foo": "bears"}))
後ろの5つの応答には、改行コードが含まれていません。質問文で切れているので、改行コードが発生したところで処理を停止したのでしょう。
なお、temperature=0.0でも回答に若干のゆらぎはある模様。
関数呼び出し
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
prompt = ChatPromptTemplate.from_template("tell me a joke about {foo}")
model = ChatOpenAI(temperature = 0.0)
functions = [
{
"name": "joke",
"description": "A joke",
"parameters": {
"type": "object",
"properties": {
"setup": {"type": "string", "description": "The setup for the joke"},
"punchline": {
"type": "string",
"description": "The punchline for the joke",
},
},
"required": ["setup", "punchline"],
},
}
]
chain = prompt | model.bind(function_call={"name": "joke"}, functions=functions)
print(chain.invoke({"foo": "bears"}, config={}))
問題なく動いていますね。なお、function_callがどういうものかについては下記リンクを読むとイメージが掴めるかと思います。今回は動いてOKで終わりです。以前と使い方もほぼ同じなので、ちょっと安心しました。
PromptTemplate + LLM + OutputParser
出力パーサーも利用可能です。出力パーサーは出力を扱いやすい形式にしてくれます。今回は普通に文字列に変更してみます。
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
prompt = ChatPromptTemplate.from_template("tell me a joke about {foo}")
model = ChatOpenAI(temperature = 0.0)
chain = prompt | model
# result
print(chain.invoke({"foo": "bears"}))
# output parser
from langchain_core.output_parsers import StrOutputParser
print("use output parser:")
chain = prompt | model | StrOutputParser()
print(chain.invoke({"foo": "bears"}))
出力結果に"content= XXXXX"やらが、普通に文字列だけになって、読みやすくなりましたね。
関数出力も出力パーサー
関数出力に対しても適切な整形ができます。
このサンプルでは、必要な出力'setpu','punchline'のみをjson形式で出力します。
また、出力するキー(例えばsetup)だけを指定することもできます。
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
prompt = ChatPromptTemplate.from_template("tell me a joke about {foo}")
model = ChatOpenAI(temperature = 0.0)
functions = [
{
"name": "joke",
"description": "A joke",
"parameters": {
"type": "object",
"properties": {
"setup": {"type": "string", "description": "The setup for the joke"},
"punchline": {
"type": "string",
"description": "The punchline for the joke",
},
},
"required": ["setup", "punchline"],
},
}
]
chain = prompt | model.bind(function_call={"name": "joke"}, functions=functions)
print(chain.invoke({"foo": "bears"}, config={}))
print("user output parser:")
# output parser
from langchain.output_parsers.openai_functions import JsonOutputFunctionsParser
chain = (
prompt
| model.bind(function_call={"name": "joke"}, functions=functions)
| JsonOutputFunctionsParser()
)
print(chain.invoke({"foo": "bears"}))
print("set output key")
from langchain.output_parsers.openai_functions import JsonKeyOutputFunctionsParser
chain = (
prompt
| model.bind(function_call={"name": "joke"}, functions=functions)
| JsonKeyOutputFunctionsParser(key_name="setup")
)
print(chain.invoke({"foo": "bears"}))
確かに見やすいし、この出力を再利用することを考えると圧倒的に使いやすいですよね。
Simplifying input
RunnableParallelを使えば、入力をシンプルにすることもできます。
今まで毎回、chain.invoke({"foo":"bears"}))とか入れてましたけど、"foo"なのは決まり切っている(ような使い方も多い)のだから、省略して勝手に入力辞書を作って欲しいですよね。
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
prompt = ChatPromptTemplate.from_template("tell me a joke about {foo}")
model = ChatOpenAI(model="gpt-4-turbo-preview",temperature = 0.0)
functions = [
{
"name": "joke",
"description": "A joke",
"parameters": {
"type": "object",
"properties": {
"setup": {"type": "string", "description": "The setup for the joke"},
"punchline": {
"type": "string",
"description": "The punchline for the joke",
},
},
"required": ["setup", "punchline"],
},
}
]
print("use runnablePassthrough:")
from langchain.output_parsers.openai_functions import JsonKeyOutputFunctionsParser
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
map_ = RunnableParallel(foo=RunnablePassthrough())
chain = (
map_
| prompt
| model.bind(function_call={"name": "joke"}, functions=functions)
| JsonKeyOutputFunctionsParser(key_name="setup")
)
print(chain.invoke("bears"))
このように"foo"に対してパススルー設定を加えて、最初にチェインすることで、無事入力を省略することができました。
これで、prompt + LLM に含まれるサンプルコードはすべて、そのまま動くし、従来からの利用方法と大きく変わるところはありませんでした。
一安心です。
今回の確認部分はlangchain-coreに集約されているので、楽ちんでしたね。
存外長くなったので、別のサンプルコードは次の機会に検証したいと思います。
この記事が気に入ったらサポートをしてみませんか?