はじめに
大規模言語モデル(LLM)の出力を構造化することは、多くの実践的なアプリケーションにおいて重要です。
本記事では、PydanticとLangChainを組み合わせて、LLMの出力を構造化する方法を解説します。
- ドキュメントはこちらです。環境構築等は適宜ドキュメントを参照してください。
前提: なぜ出力の構造化が重要か?
出力の構造化をする理由は大きく3点です。
- データの一貫性:定義された構造に従うことで、出力の一貫性が保証される
- 後処理の簡素化:構造化されたデータは、プログラムで扱いやすくなる
- 型安全性:Pydanticを使用することで、静的型チェックが可能になる
ワークフローエンジニアリングをする方としては1,2の要素は必須ですし、静的型チェックができると保守性が高まります。
内容
事前準備
今回LLMでOpenAIのモデルを使います。LangChainでOpenAIのモデルを使うためにはlangchain-openai
ライブラリが必要です。また今回pydantic
を使うので、pydantic
ライブラリのインストールも行います。
(venv) $ pip install langchain-openai pydantic
OpenAIのキーも忘れずに設定して下さい。
import os
os.environ["OPENAI_API_KEY"] = "あなたのAPIキー"
また今回紹介する手法はOpenAIの他に、Anthropic、Fireworks、Mistralで使用可能です。
プログラム
from langchain_openai import ChatOpenAI
#from pydantic.v1 import BaseModel # <-- v1 namespace
from pydantic import BaseModel
class Output(BaseModel):
"""Output Structure"""
answer: str
reason: str
model = ChatOpenAI(model="gpt-4o-mini", temperature=0).bind(seed=0)
model = model.with_structured_output(Output)
output = model.invoke('世界で住みやすい都市を理由をつけて教えて下さい。')
model.with_structured_output(Output)
の部分で、LLMの出力を構造化する設定をしています。
ここで出力の構造はPydanticのBaseModel
を継承したOutput
を用いています。
Pydanticは2023年6月にv2がリリースされており、LangChainは近い将来(暫定的に2024年9月)にv1のサポートを停止するそうです。今回の記事執筆は2024年8月のため、v1にも対応するプログラムを2行目に記載しています。
model.invoke()
の出力であるoutput
は以下です。(わかりやすく改行を入れています。)
Output(
answer='1. ウィーン(オーストリア): ウィーンは、公共交通機関が発達しており、教育や医療の質が高いことで知られています。また、文化的なイベントや美術館、音楽のイベントが豊富で、住民の生活の質が高いです。さらに、緑地が多く、自然環境も整っています。\n\n2. メルボルン(オーストラリア): メルボルンは、多様な文化と食文化が魅力で、アートや音楽のシーンも活発です。教育機関が充実しており、医療サービスも高水準です。さらに、公共交通機関が便利で、住みやすい環境が整っています。\n\n3. カナダ・バンクーバー: バンクーバーは、美しい自然環境に囲まれた都市で、アウトドア活動が豊富です。多文化共生が進んでおり、教育や医療の質も高いです。また、環境への配慮が強く、持続可能な都市づくりが進められています。',
reason='これらの都市は、公共サービスの質、文化的な豊かさ、自然環境、住民の幸福度など、住みやすさを決定づける要素が整っているため、世界で住みやすい都市として評価されています。'
)
Outputクラスで定義したようにanswer
とreason
メンバー変数が存在していることがわかります。
output
から特定のメンバーの値を抜き出すことも可能です。
print(output.answer)
1. ウィーン(オーストリア): ウィーンは、公共交通機関が発達しており、教育や医療の質が高いことで知られています。また、文化的なイベントや美術館、音楽のイベントが豊富で、住民の生活の質が高いです。さらに、緑地が多く、自然環境も整っています。
2. メルボルン(オーストラリア): メルボルンは、多様な文化と食文化が魅力で、アートや音楽のシーンも活発です。教育機関が充実しており、医療サービスも高水準です。さらに、公共交通機関が便利で、住みやすい環境が整っています。
3. カナダ・バンクーバー: バンクーバーは、美しい自然環境に囲まれた都市で、アウトドア活動が豊富です。多文化共生が進んでおり、教育や医療の質も高いです。また、環境への配慮が強く、持続可能な都市づくりが進められています。
output
のクラスはBaseModel
を継承しているため、定義されていないメンバー変数を定義しようとするとすると、BaseModel
内部の__setattr__()
の処理でエラーが発生します。
output.foo = 1 #エラーが発生
ValueError: "Output" object has no field "foo"
まとめ
LangChainとPydanticを組み合わせることで、LLMの出力を効果的に構造化できます。これにより、データの一貫性が保たれ、後続の処理が容易になります。
宣伝
8/8(木) 19:00より弊社で論文紹介をするので、良かったら聞きに来てください!!
参考
-
langchain_openai.ChatOpenAI
の使い方
- Pydantic公式