13
10

LangChain Expression Language(LCEL)はじめの一歩 on Azure OpenAI

Last updated at Posted at 2024-02-09

はじめに

みなさんは、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の主な特徴

  1. チェーンのシンプルな表現
  2. ストリーミングのサポート
  3. 非同期のサポート
  4. バッチのサポート
    などがあります。

以下は、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社のモデルを使うことを例として書かれていましたので、一部変更しています。本来のコードの使い方とは異なる部分もあるかもしれませんので、原ブログも参考にして頂ければと思います。

13
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
10