0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

litellm/langchainとpydanticで構造化出力/バッチ処理

Last updated at Posted at 2025-08-04

はじめに

litellmやlangchainで、pydanticを使って構造化出力する方法をよく忘れるのでメモしました。
バッチ処理を合わせて使うことも多いので、そのやり方もメモしました。

環境

  • macOS
  • python 3.12
  • uvを使用
% uv run pip list | grep langchain
langchain-core                0.3.72
langchain-litellm             0.2.2
langchain-openai              0.3.28

準備

  • 環境変数OPENAI_API_KEYを設定
mkdir test
cd test
uv init
uv add litellm langchain-openai langchain-litellm

litellm

pydantic.BaseModelを継承したスキーマクラスを定義して、litellm.completionのresponse_formatに与えます。
レスポンスからcontentを取得します。
このcontentはjsonの文字列なので、BaseModel.model_validate_jsonでスキーマ型にできます。

litellm_structured_output.py
import litellm
from pydantic import BaseModel, Field
class Person(BaseModel):
    """Person Information"""
    name: str = Field(..., description="name of the person.")
    age: int = Field(..., description="age of the person.")

def generate_person() -> Person:
    response = litellm.completion(
        messages=[
            {"role": "user", "content": "人の情報を生成して"}
        ],
        model="gpt-4.1-mini",
        response_format=Person
    )

    content = response['choices'][0]['message']['content']
    person = Person.model_validate_json(content)
    return person

if __name__ == "__main__":
    person = generate_person()
    print(person)
 % uv run litellm_structured_output.py 
name='佐藤太郎' age=28

バッチ処理をしたい場合はbatch_completionを使います。

litellm_structured_output_batch.py
import litellm
from pydantic import BaseModel, Field
class Person(BaseModel):
    """Person Information"""
    name: str = Field(..., description="name of the person.")
    age: int = Field(..., description="age of the person.")

def generate_persons() -> list[Person]:
    messages_list = []
    messages_list.append([
        {"role": "user", "content": "男性の情報を生成して"}
    ])
    messages_list.append([
        {"role": "user", "content": "女性の情報を生成して"}
    ])
    response = litellm.batch_completion(
        messages=messages_list,
        model="gpt-4.1-mini",
        response_format=Person
    )
    persons = []
    for response in response:
        content = response['choices'][0]['message']['content']
        person = Person.model_validate_json(content)
        persons.append(person)
    return persons

if __name__ == "__main__":
    person = generate_persons()
    print(person)
 % uv run litellm_structured_output_batch.py 
[Person(name='拓海', age=30), Person(name='佐藤 花子', age=29)]

langchain

langchainでも試してみます。
litellm同様に、モデル名を簡単に入れ替えられるようにChatLiteLLMを使います。
OpenAI APIしか使う予定がないのであればfrom langchain_openai import ChatOpenAIを代わりに使ってもよいです。

langchainを使う場合のポイントは以下です。

  • チャットモデル宣言時にwith_structured_outputでスキーマを紐づけ
  • messagesがlist[dict]ではなくlist[tuple]
  • llmの呼び出しがcompletionではなくinvoke
  • 戻り値は(なにもしなくても)スキーマ型
langchain_structured_output.py
from langchain_litellm import ChatLiteLLM
from pydantic import BaseModel, Field
class Person(BaseModel):
    """Person Information"""
    name: str = Field(..., description="name of the person.")
    age: int = Field(..., description="age of the person.")

def generate_person() -> Person:
    chat = ChatLiteLLM(model="gpt-4.1-mini").with_structured_output(Person)

    messages = [
        ("user", "人を生成して"),
    ]
    response = chat.invoke(messages)
    return response

if __name__ == "__main__":
    person = generate_person()
    print(person)
% uv run langchain_structured_output.py
name='太郎' age=30

バッチ処理をしたい場合はChatLiteLLM.batchにmessagesのリストを入力します。

langchain_structured_output_batch.py
from langchain_litellm import ChatLiteLLM
from pydantic import BaseModel, Field
class Person(BaseModel):
    """Person Information"""
    name: str = Field(..., description="name of the person.")
    age: int = Field(..., description="age of the person.")

def generate_persons() -> list[Person]:
    chat = ChatLiteLLM(model="gpt-4.1-mini").with_structured_output(Person)

    messages_list = []
    messages_list.append([
        ("user", "男性の情報を生成して")
    ])
    messages_list.append([
        ("user", "女性の情報を生成して")
    ])
    response = chat.batch(messages_list)
    return response

if __name__ == "__main__":
    person = generate_persons()
    print(person)
[Person(name='山田太郎', age=30), Person(name='美咲', age=28)]

おわりに

litellmとlangchainの使い分けは好みです。
litellmのほうがopenaiライブラリの仕様に準拠しており覚えることが少ないですが、なれると、スキーマ型を直接返せるlangchainも魅力です。
個人的には、単体で使うときはlitellmにすることが多く、チェインの機能を使いたい場合はlanchainも使うと思います。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?