ここまで
LangChain v0.3のその2では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_API = "<<ほにゃらら>>"
今回のモチベーション
英語と日本語で大喜利させて、その結果から日本語文化と英語文化の違いを出力させたいと思います。
ま、こんなこと実際にはやらないけどね。笑
ライブラリのインポート
import os
from dotenv import load_dotenv
# from openai import AzureOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import AzureChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnableSequence, RunnableParallel, RunnableLambda
load_env(',env')
LangSmithのために環境変数を用意
os.environ["LANGCHAIN_TRACING_V2"]="true"
os.environ["LANGCHAIN_ENDPOINT"]="https://api.smith.langchain.com"
os.environ["LANGCHAIN_API_KEY"]=os.getenv("LANG_SMITH_API")
os.environ["LANGCHAIN_PROJECT"]="langchain_test"
やっと少しLangSmith
が理解できたんだけど、ちゃんと環境変数に入れてあげないと動かないんだね。汗
モデルの準備
model = AzureChatOpenAI(
model='gpt-4o-mini',
azure_endpoint=os.getenv("END_POINT"),
api_version=os.getenv("API_VERSION"),
api_key=os.getenv("API_KEY")
)
プロンプトテンプレートの用意
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')
])
outputparserの準備
output_parser = StrOutputParser()
Parallelチェーンの用意
ここで、入力(日本語)をそのまま大喜利させたり、入力(日本語)を英語に変えて、英語で大喜利させる並列に実行させます。
parallel_chain = RunnableParallel({
'Japanese': prompt_template0 | model | output_parser,
'English': topic2english | model | oogiri_prompt | model | output_parser
})
RunnableLambdaの用意(今日のメイン)
parallel
チェーンを取り込むための関数を作ります。
その関数をRunnableLambda
でチェーンを作ります。
こうすることで、invoke
やbatch
などの関数が使えるようになるんですね。
def comparison_template_func(result):
English = result['English']
Japanese = result['Japanese']
template = ChatPromptTemplate([
('system', 'あなたはお笑いを客観的に分析ができる優秀な評論家です。'),
('user', '''以下は英語で書かれたものと、日本語で掛かれた大喜利です。これらの大喜利を英語社会の背景、日本語社会の背景を鑑みてそれぞれの文化の違いを解説してください。
\n##英語の大喜利##{English}\n##日本語の大喜利##{Japanese}''')
])
return template
comparison_template = RunnableLambda(comparison_template_func)
再度、全体のChainを作る
comparison_chain = parallel_chain | comparison_template | model | output_parser
こんな感じの流れになります
- 入力
- parallel_chainで以下の二つを実行する
- 1の入力を使って日本語で大喜利させる(
prompt_template0 | model | output_parser
) - 1の入力を英語に直して英語で大喜利させる(
topic2english | model | oogiri_prompt | model | output_parser
)
- 1の入力を使って日本語で大喜利させる(
- 2の結果を受け取り、英語、日本語の結果を渡して、文化の違いを解説させる(
comparison_templete | model
) - 出力の処理を行う(
output_parser
)
推論
comparison_result = comparison_chain.invoke('靴下')
comparison_result
結果
めっちゃがっつり解答してくれました。笑
'英語の大喜利と日本語の大喜利には、それぞれの文化的背景や言語特性が反映されており、ユーモアのスタイルや内容に違いが見られます。\n\n### 英語の大喜利\n英語のジョークは、特に言葉遊びやダブルミーニングを用いたものが多いです。この例では、「pair-fect」という言葉が「perfect」と「pair(ペア)」の音をかけており、靴下の「ペア」という特性を利用したユーモアが強調されています。英語圏では、こうした言葉遊びが一般的であり、シンプルでありながらも聴衆に考えさせる要素を持っています。また、英語圏では自己表現や個性の重要性が強調されるため、靴下の「選択」や「パートナーシップ」をテーマにしたジョークも、軽いトーンで楽しむことができます。\n\n### 日本語の大喜利\n日本語の大喜利では、言葉遊びや言語の特性を活かしたユーモアが中心になっています。例えば、「片方どこ行った?」という質問は、靴下の特性を利用し、日常的な悩みをユーモラスに表現しています。また、日本語の大喜利は、より具体的な文脈や状況を想起させるような内容が多く、聴衆が共感しやすい傾向にあります。靴下の「香水」や「選挙に出馬する」というアイデアは、 absurd(不条理)な状況を楽しむ日本のユーモアの典型例です。\n\n### 文化的背景の違い\n1. **言葉遊びのスタイル**: 英語の大喜利はしばしば言葉の音や意味の重なりを利用し、シンプルで直接的なユーモアを提供します。一方、日本語の大喜利は、文脈や文化的な背景を踏まえた言葉遊びが多く、より多層的な意味を持つことが多いです。\n\n2. **社会的なテーマ**: 日本の大喜利は、日常生活に根ざしたテーマが多く、聴衆が共感しやすい内容が好まれます。英語のジョークは、個人の感情や選択に焦点を当てることが多く、より個人的な視点が強調されます。\n\n3. **ユーモアのトーン**: 英語のユーモアは、軽快で楽しいトーンから、時には皮肉や風刺を含むこともあります。日本の大喜利は、一般的に和やかで親しみやすいトーンが強調され、聴衆との一体感を大切にする傾向があります。\n\nこのように、英語と日本語の大喜利は、それぞれの文化や社会的背景を反映したスタイルの違いがあり、言語の特性を活かしたユーモアを楽しむことができます。'
LangSmithで確認してみましょう
ちゃんとパラレルになってからマージされて結果が出力されてます。
LCEL
って結構なんでもできそうですね。そして、LangSmith
便利。
ということで、今度はLangGraphに挑戦予定。
ドキュメント読むのに時間がかかりそうなので夜は寝て待て!w