LCEL
LangChainのLCEL。ま、コアな部分の一つだよね。
きっとこれらを使うと便利なものが作れるんだろうね。
ということでもう少し踏み込んでみました。
実は「ドキュメントを読む練習」というのは内緒である。
ということで直線的な処理と並行させる処理をやらせてみました
バージョン関連
Python 3.10.8
langchain==0.3.7
python-dotenv
langchain-openai==0.2.5
langgraph>0.2.27
langchain-core
※LLMのAPIはAzureOpenAIのgpt-4o-miniを使いました
準備
.env
ファイルに以下を用意しましょうね
END_POINT="https://<<ほにゃらら>>.openai.azure.com/"
API_KEY="<<ほにゃらら>>"
API_VERSION="2023-05-15"
LANG_SMITH = "<<ほにゃらら>>"
やらせてみたこと
大喜利。それも英語で
復習
前回のもみてね
シーケンシャルな処理の場合
langchain_core
のrunnables
からRunnableSequence
をインポートして使います。
from langchain_core.runnables import RunnableSequence
プロンプトを準備
prompt_template0 = ChatPromptTemplate([
('system', 'あなたは偉大な漫才師です。'),
('user', '{topic}について大喜利してください。')
])
topic2english = ChatPromptTemplate([
('system', 'あなたは優秀な英語への翻訳者です。翻訳した内容だけを回答してください。'),
('user', '{topic}を翻訳してください')
])
oogiri_prompt = ChatPromptTemplate([
('system', 'You are a great comedian'),
('user', 'Please create OOGIRI about {topic} in English')
])
シーケンシャルに組む
chain_oogiri_english = RunnableSequence(
topic2english,
model,
oogiri_prompt,
model,
output_parser
)
実はこれ、以下と同じ
chain_oogiri_english = topic2english | model | oogiri_prompt | model | output_parser
なんやねんて。
ま、直線的に組むだけですからそうなりますわな。
実行してプリント
result = chain_oogiri_english.invoke('靴下')
print(result)
Sure! Here’s an OOGIRI (a form of Japanese comedy) themed around socks:
---
**Q:** Why did the sock break up with the shoe?
**A:** Because it found someone more supportive!
---
**Q:** What do you call a sock that can do magic?
**A:** A sock-cerer!
---
**Q:** Why did the sock refuse to play hide and seek?
**A:** Because it always got lost in the wash!
---
Hope that brings you a chuckle!
並列処理の場合
from langchain_core.runnables import RunnableParallel
今度はRunnalbleParallelを使います。
parallel_chain = RunnableParallel({
'Japanese': prompt_template0 | model | output_parser,
'English': topic2english | model | oogiri_prompt | model | output_parser
})
こんな風に辞書形式でそれぞれぶっ込みます。
今回は辞書の中はパイプ「|
」で繋いでます
実行!
result_parallel = parallel_chain.invoke('靴下')
結果を表示。まず日本語から。
print(result_parallel['Japanese'])
もちろん、靴下についての大喜利いきますよ!
1. 靴下が出会い系アプリを始めた理由は?
- 「足元から恋を育てたい!」
2. 短い靴下と長い靴下、どっちが人気?
- 「短い靴下、いつも『あたしも見て!』ってアピールしてるから!」
3. 靴下が自分の存在意義を考えた結果?
- 「やっぱり、足元を支えるのが私の使命だと気づいた!」
4. 靴下が言う「これが私のスタイル!」とは?
- 「色んな柄で、足元から個性を主張!」
5. 靴下が選ぶ理想のデートコースは?
- 「靴屋巡り。だって、いい靴にはいい靴下が必要でしょ!」
どうでしょう?靴下の魅力を引き出しつつ、笑いを誘う感じになりましたか?
まぁまぁ大喜利しやがる!さすがGPT-4o-mini
今度は英語
print(result_parallel['English'])
Sure! Here’s an OOGIRI (a Japanese form of comedic wordplay) about socks:
**Q:** Why did the sock break up with the shoe?
**A:** Because it found someone who really "fits" its sole!
Feel free to ask for more jokes or a different topic!
えっと、英語は苦手なんでぇ・・・よくわからん。w
日本語は5個も作ってくれたけど、英語はひとつなのね。笑
大事だと思うこと
これらのライブラリ、継承しているクラスを遡っていくとRunnableクラスにたどり着きます。
ここで、RunnableクラスのDocStringsを和訳してもらいました。(GPT-4o)
以下の108行目
LangChainのRunnableクラスは、データを処理するための作業単位を表す概念で、さまざまな方法での呼び出しや構成が可能です。このクラスには以下の主要なメソッドや特徴が備わっています。
主なメソッド
• invoke/ainvoke:1つの入力を1つの出力に変換します。ainvokeは非同期対応。
• batch/abatch:複数の入力を効率的に処理し、出力を得ます。
• stream/astream:1つの入力に対し出力をストリーミングとして返します。
• astream_log:出力と中間結果をリアルタイムでストリーミングします。
組み込みの最適化
• バッチ処理:デフォルトではスレッドプールを使って並列実行し、効率化を図ります。
• 非同期処理:メソッド名に「a」がついているものは非同期処理で、標準的には同期版を非同期化していますが、オーバーライドしてネイティブな非同期対応も可能です。
各メソッドにはオプションのconfig引数があり、実行設定やデバッグのためのメタデータ追加に利用されます。また、input_schemaやoutput_schemaを使って入出力形式の情報を提供します。
LangChain Expression Language(LCEL)と構成
LCELは、Runnableをチェーン状に構成するための宣言的な方法です。これにより、同期・非同期・バッチ・ストリーミングの全機能を持つチェーンを簡単に構築できます。主な構成方法には以下があります。
• RunnableSequence:複数のRunnableを順に呼び出し、一つの出力を次の入力として利用します。|演算子やリストで構成できます。
• RunnableParallel:複数のRunnableを並列に呼び出し、同じ入力を渡して異なる出力を取得します。辞書リテラルを使って構成可能です。
つまり、Runnableの機能としてinvoke/ainvoke
、batch/abatch
、stream/astream
、astream_log
これらの機能がとても重要なんですね。
あとで少しコードを読んでみようかな。
まとめ
ということでパラレルに動かすってことをやってみたかったので、RunnableSequence
とRunnableParallel
を比較してみました。
使ってみると挙動がよくわかります。
sosite,
LCELの発展2に続きます。