はじめに
こんにちは、慶應義塾大学理工学部機械工学科3年の金賢佑です!
私は東大発AIベンチャーの株式会社2WINSの元でインターンをしています!
これからの記事では自分がインターンを通して最強のAIエンジニアを目指していきます!
第八回はLCELの基礎を記録しました!
LCELって?
LCELは、LangChain Expression Languageの略!
前回のday6ではテンプレートを作って、それを実際にLLMに送ったりしましたよね!
その他出力をPythonオブジェクトにしたりとか。
それらを連鎖的に行うのがLCELです!
前回も使いましたが、以下のコードでテンプレートを作ってみたください!
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate(
[
("system", "ユーザーが入力した料理のレシピを教えてください。"),
("human", "{dish}"),
]
)
続いてChatOpenAIを準備します。
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model_name='gpt-4o', temperature=0)
次にchain
でこれら二つを繋ぎます!
chain = prompt | model
その後実行します!
ai_message = chain.invoke({"dish": 'ハンバーグ'})
print(ai_message.content)
以下のように、ちゃんとレシピが作成されましたね!
ハンバーグのレシピをご紹介します。これは基本的なハンバーグの作り方ですが、お好みでアレンジしてみてください。
### 材料(4人分)
- 牛ひき肉:250g
- 豚ひき肉:250g
- 玉ねぎ:1個(みじん切り)
- パン粉:1/2カップ
- 牛乳:1/4カップ
- 卵:1個
- 塩:小さじ1/2
- こしょう:少々
- ナツメグ:少々(お好みで)
- サラダ油:大さじ1
### ソース(お好みで)
- ケチャップ:大さじ3
- ウスターソース:大さじ2
### 作り方
1. **玉ねぎを炒める**
フライパンにサラダ油を熱し、みじん切りにした玉ねぎを透明になるまで炒め、冷ましておきます。
2. **パン粉を湿らせる**
ボウルにパン粉を入れ、牛乳を加えてしばらく置き、パン粉を湿らせます。
3. **材料を混ぜる**
大きなボウルに牛ひき肉、豚ひき肉、冷ました玉ねぎ、湿らせたパン粉、卵、塩、こしょう、ナツメグを入れ、よく混ぜ合わせます。
4. **成形する**
手に少量のサラダ油をつけ、肉だねを4等分し、空気を抜くようにして楕円形に成形します。
5. **焼く**
フライパンにサラダ油を熱し、中火でハンバーグを焼きます。片面に焼き色がついたら裏返し、蓋をして弱火で中まで火が通るまで焼きます(約10分)。
6. **ソースを作る(お好みで)**
ハンバーグを取り出した後のフライパンにケチャップとウスターソースを入れ、軽く煮詰めてソースを作ります。
7. **盛り付ける**
焼き上がったハンバーグを皿に盛り付け、ソースをかけて完成です。
お好みで、付け合わせにサラダや温野菜を添えてお楽しみください。
LCELの裏側
ではLCELは裏で何を行なっているのでしょうか?
|
って実際にはなんなのでしょうか?
先に結論から言うと、|
は「演算子オーバーロード」と言うものです。
私たちが普段使っている+
や-
も「演算子オーバーロード」なのです。
例えば、私たちが
3 + 5
"Hello" + "!"
と入力したとき、裏では__add__()
メソッドが呼び出されているのです。
3.__add__(5)
"Hello".__add__("!")
その結果、int同士が足されたり、文字列同士が合わさったりしているのです。
また、__add__()
は+
が使われたときに呼び出される関数なので、もし自分のクラス内で定義すれば、
class Dog:
def __init__(self, name):
self.name = name
def __add__(self, other):
return f"{self.name}と{other.name}が仲良しになった!"
a = Dog("ポチ")
b = Dog("ハチ")
print(a + b) # → ポチとハチが仲良しになった!
なんて使い方もできます!
では、演算子|
を使うとどんなメソッドが呼び出されているのでしょうか。
正解は、__or__()
メソッドが呼び出されています。
つまり、prompt | model
はprompt.__or__(model)
を表しています。
実際に__or__()
メソッドの中身は
def __or__(
self,
other: Union[
Runnable[Any, Other],
Callable[[Any], Other],
Callable[[Iterator[Any]], Iterator[Other]],
Mapping[str, Union[Runnable[Any, Other], Callable[[Any], Other], Any]],
],
) -> RunnableSerializable[Input, Other]:
"""Compose this Runnable with another object to create a RunnableSequence."""
return RunnableSequence(self, coerce_to_runnable(other))
読み解くのが大変なので要点だけ説明すると、
prompt.__or__(model)
が呼び出されるので、self = prompt
, other = model
になります。
Union
からはother
に渡せるものの種類を表記しています。
->
からは返り値の型が入っています。
まとめ
今回は私たち人間が読みやすいように.text
を用いましたが、次はさらにPydanticOutputParser
を使えば後でリストから取り出すこともできるようになりますね!
お疲れ様でした!
参考文献
LangChainとLangGraphによるRAG・AIエージェント〈実践〉入門/西見公宏/吉田真吾/大嶋勇樹