2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LangChainとPydanticを用いたLLM出力の構造化:実践ガイド

Posted at

はじめに

大規模言語モデル(LLM)の出力を構造化することは、多くの実践的なアプリケーションにおいて重要です。
本記事では、PydanticとLangChainを組み合わせて、LLMの出力を構造化する方法を解説します。

  • ドキュメントはこちらです。環境構築等は適宜ドキュメントを参照してください。

前提: なぜ出力の構造化が重要か?

出力の構造化をする理由は大きく3点です。

  1. データの一貫性:定義された構造に従うことで、出力の一貫性が保証される
  2. 後処理の簡素化:構造化されたデータは、プログラムで扱いやすくなる
  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クラスで定義したようにanswerreasonメンバー変数が存在していることがわかります。

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公式

2
2
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
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?