🦁

【LangChain基礎学習】PydanticOutputParser(その1)

2024/12/30に公開

LangChain

LangChainの学習を進め、ようやくLangGraphについて理解してきた。
そして、LangGraphを効果的に使うには、応答整形はについてはキッチリやっておかないと駄目そうですね。
今まで曖昧にしていたPydanticOutputParserについて慣れておくべき時が来たようです。

PydanticOutputParser

LLMが便利すぎるので、なぁなぁにしてきたけど基本が大事ということで3例ほどサンプル使ってお勉強しておきます。

スポットで理解を深めておくのが基本ですし。

ユーザープロフィール

UserProfile.py
from pydantic import BaseModel, Field
from langchain_core.output_parsers import PydanticOutputParser

class UserProfile(BaseModel):
    name: str = Field(description="ユーザーのフルネーム")
    age: int = Field(description="ユーザーの年齢")
    interests: list[str] = Field(description="ユーザーの興味・趣味のリスト")


if __name__=="__main__":
    output_parser = PydanticOutputParser(pydantic_object=UserProfile)
    # format_instructions = output_parser.get_format_instructions() # デバッグ用
    # print(format_instructions) # デバッグ用
    # 正常なJSONデータ
    valid_json = '''
    {
        "name": "山田太郎",
        "age": "30",
        "interests": ["読書", "旅行", "プログラミング"]
    }
    '''
    # エラー系のなJSONデータ
    valid_json_error = '''
    {
        "name": "山田太郎",
        "age": ["30"],
        "interests": ["読書", "旅行", "プログラミング"]
    }
    '''

    try:
        # JSONをパース
        parsed_output = output_parser.parse(valid_json)
        print("正常ケース:")
        print(parsed_output)
        parsed_output = output_parser.parse(valid_json_error)
        print("異常ケース:")     # ここに入らず、exceptへ
        print(parsed_output)    # ここに入らず、exceptへ
    except Exception as e:
        print(f"エラー: {e}")
正常ケース:
name='山田太郎' age=30 interests=['読書', '旅行', 'プログラミング']
エラー: Failed to parse UserProfile from completion {"name": "\u5c71\u7530\u592a\u90ce", "age": ["30"], "interests": ["\u8aad\u66f8", "\u65c5\u884c", "\u30d7\u30ed\u30b0\u30e9\u30df\u30f3\u30b0"]}. Got: 1 validation error for UserProfile
age
  Input should be a valid integer [type=int_type, input_value=['30'], input_type=list]
    For further information visit https://errors.pydantic.dev/2.10/v/int_type
For troubleshooting, visit: https://python.langchain.com/docs/troubleshooting/errors/OUTPUT_PARSING_FAILURE

異常系

validation error for UserProfile
age
  Input should be a valid integer [type=int_type, input_value=['30'], input_type=list]
    # エラー系のなJSONデータ
    valid_json_error = '''
    {
        "name": "山田太郎",
        "age": ["30"],
        "interests": ["読書", "旅行", "プログラミング"]
    }
    '''

のage変数をListで寄越すな!というエラーですね。

正常系で、ageを文字列で送ったところ、これは普通に変換してくれましたが、数値変換できない"a"とかを送るとエラーを返してくれました。

後続構文

これをChatTemplateで設定し、partialメソッドで設定を反映させてinvokeすれば、指定した型で応答してくれるってことですね。

あと2つほど試しておきます。

映画レビュー

MovieReview.py
from pydantic import BaseModel, Field
from langchain_core.output_parsers import PydanticOutputParser

class MovieReview(BaseModel):
    title: str = Field(description="映画のタイトル")
    rating: float = Field(description="5段階評価での評価点")
    pros: list[str] = Field(description="映画の良かった点のリスト")
    cons: list[str] = Field(description="映画の改善点のリスト")



if __name__=="__main__":
    output_parser = PydanticOutputParser(pydantic_object=MovieReview)
    # format_instructions = output_parser.get_format_instructions()
    # print(format_instructions)
    # 正常なJSONデータ
    valid_json = '''
    {
        "title": "xxx",
        "rating": 3.0,
        "pros": ["pros01", "pros02", "pros03"],
        "cons": ["cons01", "cons02"]
    }
    '''
    # エラー系のなJSONデータ(型が定義と異なる)
    valid_json_error = '''
    {
        "title_error": "xxx",
        "rating": 3.0,
        "pros": ["pros01", "pros02", "pros03"],
        "cons": ["cons01", "cons02"]
    }
    '''

    try:
        # JSONをパース
        parsed_output = output_parser.parse(valid_json)
        print("正常ケース:")
        print(parsed_output)
        parsed_output = output_parser.parse(valid_json_error)
        print("異常ケース:") 
        print(parsed_output) 
    except Exception as e:
        print(f"エラー: {e}")

異常系

validation error for MovieReview
title
  Field required [type=missing, input_value={'title_error': 'xxx', 'r...': ['cons01', 'cons02']}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.10/v/missing
For troubleshooting, visit: https://python.langchain.com/docs/troubleshooting/errors/OUTPUT_PARSING_FAILURE
    # エラー系のなJSONデータ(型が定義と異なる)
    valid_json_error = '''
    {
        "title_error": "xxx",
        "rating": 3.0,
        "pros": ["pros01", "pros02", "pros03"],
        "cons": ["cons01", "cons02"]
    }
    '''

のtitle_errorが定義されていない!というエラーですね。

製品仕様

ProductSpec.py
from pydantic import BaseModel, Field
from langchain_core.output_parsers import PydanticOutputParser

class ProductSpecification(BaseModel):
    name: str = Field(description="製品名")
    category: str = Field(description="製品カテゴリー")
    price: float = Field(description="製品価格(円)")
    features: list[str] = Field(description="製品の主な特徴のリスト")
    dimensions: dict = Field(description="製品の寸法(幅、高さ、奥行き)")



if __name__=="__main__":
    output_parser = PydanticOutputParser(pydantic_object=ProductSpecification)
    # format_instructions = output_parser.get_format_instructions()
    # print(format_instructions)
    # 正常なJSONデータ
    valid_json = '''
    {
        "name": "ノートパソコン",
        "category": "電子機器",
        "price": 120000.0,
        "features": ["軽量設計", "高性能プロセッサ", "長時間バッテリー"],
        "dimensions": {
            "width": 32.5,
            "height": 1.8,
            "depth": 22.7
        }
    }
    '''

    # エラー系のなJSONデータ(型が定義と異なる)
    valid_json_error = '''
    {
        "name": "ノートパソコン",
        "category": "電子機器",
        "price": 120000.0,
        "dimensions": {
            "width": 32.5,
            "height": 1.8,
            "depth": 22.7
        }
    }
    '''

    try:
        # JSONをパース
        parsed_output = output_parser.parse(valid_json)
        print("正常ケース:")
        print(parsed_output)
        parsed_output = output_parser.parse(valid_json_error)
        print("異常ケース:") 
        print(parsed_output) 
    except Exception as e:
        print(f"エラー: {e}")
正常ケース:
name='ノートパソコン' category='電子機器' price=120000.0 features=['軽量設計', '高性能プロセッサ', '長時間バッテリー'] dimensions={'width': 32.5, 'height': 1.8, 'depth': 22.7}
エラー: Failed to parse ProductSpecification from completion {"name": "\u30ce\u30fc\u30c8\u30d1\u30bd\u30b3\u30f3", "category": "\u96fb\u5b50\u6a5f\u5668", "price": 120000.0, "dimensions": {"width": 32.5, "height": 1.8, "depth": 22.7}}. Got: 1 validation error for ProductSpecification
features
  Field required [type=missing, input_value={'name': 'ノートパソ...t': 1.8, 'depth': 22.7}}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.10/v/missing
For troubleshooting, visit: https://python.langchain.com/docs/troubleshooting/errors/OUTPUT_PARSING_FAILURE

異常系

validation error for ProductSpecification
features
  Field required [type=missing, input_value={'name': 'ノートパソ...t': 1.8, 'depth': 22.7}}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.10/v/missing
For troubleshooting, visit: https://python.langchain.com/docs/troubleshooting/errors/OUTPUT_PARSING_FAILURE
    # エラー系のなJSONデータ(featuresキーがない)
    valid_json_error = '''
    {
        "name": "ノートパソコン",
        "category": "電子機器",
        "price": 120000.0,
        "dimensions": {
            "width": 32.5,
            "height": 1.8,
            "depth": 22.7
        }
    }

のfeaturesキーがない!というエラーですね。

希望する型でLLMから応答返してくれたら確かにありがたいので、もう少し詰めたいと思います。

Discussion