はじめに
みなさんは、LangChain Expression Language(LCEL) をご存じでしょうか? この記事では、つい先日、LCELを初めて知った私が、LangChain blogに書かれていたLCELのサンプルコード(Python)をAzure OpenAI Serviceを使い、試したことを書いています。
LCELでは、チェーンを "| " で表し、次のように表現します。
chain = prompt | llm | output_parser
INPUT(prompt)からOUTPUT(output_parser)までの処理が、"|"をパイプ演算子のように使い書かれています。シンプルで直観的にも理解しやすい表現です。(だから、Expression Languageなんでしょうね)
LangChainは、LLM(大規模言語モデル)を利用してアプリケーションを開発するための有名なフレームワークですが、今年2024年1月に最初の安定版であるとして、LangChain v0.1.0がリリースされました。
上記LangChainブログには、古い langchain パッケージは、
1.langchain-core
2.langchain-community
3.langchain
と言う3つの個別パッケージに分割されたことが書いてあります。また、LangChain Expression Language(LCEL) により、より簡単にチェーンを構築できるとしています。
LCELとは
LangChain Expression Language(LCEL)は、LLMアプリケーション開発を簡素化するためのLangChainフレームワークの一部です。簡単なチェーンから少し複雑なアプリケーションのプロトタイピングまで、開発者はよりシンプルにチェーンを組むことができます。
LCELの主な特徴
- チェーンのシンプルな表現
- ストリーミングのサポート
- 非同期のサポート
- バッチのサポート
などがあります。
以下は、Azure OpenAI Serviceを使い、試したときのサンプルコードです。
環境
Windows10
Python v3.11.4
APIキー等の環境変数は、試したコードと同じフォルダに".env"ファイルを作り、その中に記述しました。
AZURE_OPENAI_TYPE = "azure"
AZURE_OPENAI_KEY = "YOUR AZURE OPENAI KEY"
AZURE_OPENAI_VERSION = "2023-05-15"
azure_endpoint = "YOUR AZURE ENDPOINT URL"
AZURE_OPENAI_DEPLOYMENT_NAME = "YOUR AZURE DEPLOYMENT NAME"
0.基本
冒頭にも書いた基本的なチェーンの表現方法です。
# main_basic.py
import os
from dotenv import load_dotenv
from langchain_openai import AzureChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
# 環境変数の読み込み
load_dotenv()
# API設定の変数
openai_api_key = os.getenv("AZURE_OPENAI_KEY")
azure_endpoint = os.getenv("AZURE_ENDPOINT")
api_version = os.getenv("AZURE_OPENAI_VERSION")
azure_deployment = os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME")
# AzureChatOpenAI
llm = AzureChatOpenAI(
api_version=api_version,
azure_endpoint=azure_endpoint,
openai_api_key=openai_api_key,
azure_deployment=azure_deployment,
temperature=0.5,
)
prompt = ChatPromptTemplate.from_template(
"私に、{topic}について100文字以内で説明して下さい。"
)
output_parser = StrOutputParser()
chain = prompt | llm | output_parser
result = chain.invoke({"topic": "データ連携"})
print(result)
2.ストリーミング
ストリーミングの例です。
# main_stream.py
import os
from dotenv import load_dotenv
from langchain_openai import AzureChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
# 環境変数の読み込み
load_dotenv()
# API設定の変数
openai_api_key = os.getenv("AZURE_OPENAI_KEY")
azure_endpoint = os.getenv("AZURE_ENDPOINT")
api_version = os.getenv("AZURE_OPENAI_VERSION")
azure_deployment = os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME")
# AzureChatOpenAI
llm = AzureChatOpenAI(
api_version=api_version,
azure_endpoint=azure_endpoint,
openai_api_key=openai_api_key,
azure_deployment=azure_deployment,
temperature=0.5,
)
prompt = ChatPromptTemplate.from_template(
"私に、{topic}について、500文字以内で説明して下さい。"
)
output_parser = StrOutputParser()
chain = {"topic": RunnablePassthrough()} | prompt | llm | output_parser
for chunk in chain.stream({"topic": "データ連携"}):
print(chunk, end="", flush=True)
3.非同期
非同期の例です。
# main_async.py
import os
import asyncio
from dotenv import load_dotenv
from langchain_openai import AzureChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
# 環境変数の読み込み
load_dotenv()
# API設定の変数
openai_api_key = os.getenv("AZURE_OPENAI_KEY")
azure_endpoint = os.getenv("AZURE_ENDPOINT")
api_version = os.getenv("AZURE_OPENAI_VERSION")
azure_deployment = os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME")
# AzureChatOpenAI
llm = AzureChatOpenAI(
api_version=api_version,
azure_endpoint=azure_endpoint,
openai_api_key=openai_api_key,
azure_deployment=azure_deployment,
temperature=0.5,
)
prompt = ChatPromptTemplate.from_template(
"私に、{topic}について100文字以内で説明して下さい。"
)
output_parser = StrOutputParser()
chain = prompt | llm | output_parser
# 非同期関数を定義
async def get_response(chain):
result = await chain.ainvoke({"topic": "データ連携"})
print(result)
# 非同期を実行
asyncio.run(get_response(chain))
4.バッチ
バッチの例です。
# main_batch.py
import os
from dotenv import load_dotenv
from langchain_openai import AzureChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
# 環境変数の読み込み
load_dotenv()
# API設定の変数
openai_api_key = os.getenv("AZURE_OPENAI_KEY")
azure_endpoint = os.getenv("AZURE_ENDPOINT")
api_version = os.getenv("AZURE_OPENAI_VERSION")
azure_deployment = os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME")
# AzureChatOpenAI
llm = AzureChatOpenAI(
api_version=api_version,
azure_endpoint=azure_endpoint,
openai_api_key=openai_api_key,
azure_deployment=azure_deployment,
temperature=0.5,
)
prompt = ChatPromptTemplate.from_template(
"私に、{topic}について、100文字以内で説明して下さい。"
)
output_parser = StrOutputParser()
chain = prompt | llm | output_parser
result = chain.batch( [{"topic":"データ連携"}, {"topic":"API連携"}, {"topic":"ファイル転送"}])
print(result)
requirements.txt
requirements.txtの内容は次の通りですが、pydanticのバージョンは、v1.10.9でないと動きませんでした。もし試される場合は、ご留意いただければと思います。
aiohttp==3.9.3
aiosignal==1.3.1
annotated-types==0.6.0
anyio==4.2.0
attrs==23.2.0
black==24.1.1
certifi==2023.11.17
charset-normalizer==3.3.2
click==8.1.7
colorama==0.4.6
dataclasses-json==0.6.4
distro==1.9.0
docarray==0.32.1
frozenlist==1.4.1
greenlet==3.0.3
h11==0.14.0
hnswlib==0.8.0
httpcore==1.0.2
httpx==0.26.0
idna==3.6
jsonpatch==1.33
jsonpointer==2.4
langchain==0.1.5
langchain-community==0.0.17
langchain-core==0.1.18
langchain-openai==0.0.5
langsmith==0.0.85
markdown-it-py==3.0.0
marshmallow==3.20.2
mdurl==0.1.2
multidict==6.0.5
mypy-extensions==1.0.0
numpy==1.26.3
openai==1.10.0
orjson==3.9.12
packaging==23.2
pathspec==0.12.1
platformdirs==4.2.0
protobuf==4.25.2
pydantic==1.10.9
pydantic_core==2.16.1
Pygments==2.17.2
python-dotenv==1.0.1
PyYAML==6.0.1
regex==2023.12.25
requests==2.31.0
rich==13.7.0
sniffio==1.3.0
SQLAlchemy==2.0.25
tenacity==8.2.3
tiktoken==0.5.2
tqdm==4.66.1
types-requests==2.31.0.20240125
typing-inspect==0.9.0
typing_extensions==4.9.0
urllib3==2.2.0
yarl==1.9.4
さいごに
LangChain Expression Language(LCEL) は、LangChainフレームワークにおける強力な新機能となっています。今後、LangChainを使って開発を行う場合、一部は、このLCELによるアプローチが使われていくものと思います。私も少しずつ慣れていきたいと思います。
この記事に載せたサンプルコードは、基本的には次のlangChainブログを元にしています。ブログでは、基本的にOpenAI社のモデルを使うことを例として書かれていましたので、一部変更しています。本来のコードの使い方とは異なる部分もあるかもしれませんので、原ブログも参考にして頂ければと思います。