PydanticAI ビジュアルガイド

Lesson CH01-L04

静的型チェック

Pyrightとの組み合わせで Agent の入出力を型で守る。

読了目安
10 min
Colab目安
16 min
合計
26 min
前提
Reflection

関連: 公式ドキュメント

一行サマリ

Agentジェネリッククラス Agent[DepsT, OutputT]deps_type=output_type= を渡すと Pyright / mypy が型を自動推論 し、result.output の補完・agent.run(deps=...) の引数チェック・Tool / Validator の引数まで全部 IDE で間違いを赤線にできる

ヒーロー: 型なし vs 型あり Agent

PydanticAI の Agent は型付きで設計されています。output_typedeps_type を渡すかどうかで、IDE 体験が大きく変わります。

図を読み込み中…
図1. 型なし Agent と 型あり Agent の体験差

概念: なぜ Agent に静的型が必要か

Agent はテキストを LLM に投げて返ってくる "ふわっとした" インタフェースです。だからこそ 境界面 (入出力 / 依存) を型で固める とコードが堅くなります。

具体的に効く 4 つの場面:

  1. result.output の補完output_type=Booking と書けば result.output.party_size のように Pydantic フィールドが補完される
  2. agent.run(..., deps=...) の型一致deps_type=UserContext を宣言すれば、deps=DifferentType() を渡したら Pyright が赤線を出す
  3. Tool / Validator の RunContext[DepsT]ctx.deps の中身が補完で出る
  4. リファクタリング耐性 — Pydantic モデルにフィールド追加 → IDE が利用箇所をハイライト → 直す

これらは 実行しないと気付けないバグを書き始める前に潰せる、という型システム本来の効能を Agent コードでも享受するためのものです。

コード: 4 段階で型を効かせる

ステップ 0: 型なし (反例)

from pydantic_ai import Agent
 
agent = Agent('google-gla:gemini-3-flash-preview')
result = agent.run_sync('Mojito とは?')
 
# result.output は str として推論される (デフォルト)
print(result.output.upper())   # OK だが、構造化情報が一切無い
print(result.output.party_size)  # ← 実行時 AttributeError、IDE は気付かない

これでは Agent から取れる情報が "テキスト 1 本" だけで、構造化されません。

ステップ 1: output_type で出力を型付け

from pydantic import BaseModel
from pydantic_ai import Agent
 
class Cocktail(BaseModel):
    name: str
    origin: str
    abv_percent: float  # アルコール度数
 
agent = Agent(
    'google-gla:gemini-3-flash-preview',
    output_type=Cocktail,  # ← これを渡すだけで result.output: Cocktail と推論される
)
 
result = agent.run_sync('Mojito の情報を返してください')
# Pyright は result.output を Cocktail として認識する
print(result.output.name)         # ✅ 補完が効く
print(result.output.abv_percent)  # ✅ 補完が効く
print(result.output.party_size)   # ❌ Pyright が "no attribute" の赤線を出す

ポイント: output_type= の引数は クラスそのもの を渡します。Pyright はそのクラスを OutputT として保持し、run_sync().output の型に伝播します。

ステップ 2: deps_type で依存も型付け

from dataclasses import dataclass
from pydantic_ai import Agent, RunContext
 
@dataclass
class CocktailDeps:
    user_lang: str
    is_minor: bool  # 未成年フラグ
 
agent = Agent(
    'google-gla:gemini-3-flash-preview',
    deps_type=CocktailDeps,
    output_type=Cocktail,
)
 
@agent.instructions
def lang_policy(ctx: RunContext[CocktailDeps]) -> str:
    if ctx.deps.is_minor:
        return 'ノンアルコール版を提案してください。'
    return f'回答は {ctx.deps.user_lang} で。'
 
# Pyright は deps の型を CocktailDeps と知っている
result = agent.run_sync(
    'Mojito の情報',
    deps=CocktailDeps(user_lang='ja', is_minor=False),  # ✅
)
# 違う型を渡したら IDE で赤線:
# result = agent.run_sync('...', deps={'lang': 'ja'})  # ❌ dict は CocktailDeps ではない

ポイント:

  • deps_type= を渡すと、agent.run(..., deps=...) の型が CocktailDeps に固定される
  • RunContext[CocktailDeps] の型注釈で ctx.deps.user_langctx.deps.is_minor補完される
  • deps_type を渡さない場合、deps= を渡すこと自体が型エラーになる (PydanticAI v0.x 時点)

ステップ 3: ジェネリック型を明示宣言する書き方

ステップ 2 と等価ですが、Agent の型を変数アノテーションで明示 する書き方もあります。テストで Mock Agent を渡したいときなどに役立ちます。

from pydantic_ai import Agent
 
agent: Agent[CocktailDeps, Cocktail] = Agent(
    'google-gla:gemini-3-flash-preview',
    deps_type=CocktailDeps,
    output_type=Cocktail,
)

Agent[CocktailDeps, Cocktail] の型パラメタは Agent[DepsT, OutputT] の順番です。これを覚えておくと、関数の引数で Agent を受けたいとき (テストやサービス層) に正確な型を書けます。

def run_cocktail_query(
    agent: Agent[CocktailDeps, Cocktail],
    query: str,
    deps: CocktailDeps,
) -> Cocktail:
    return agent.run_sync(query, deps=deps).output
図を読み込み中…
図2. 型情報がコード全体に伝播する流れ

Pyright の最小セットアップ

ローカル開発で型チェックを効かせるには:

# プロジェクトに入れる場合
pip install pyright
 
# 1 ファイルだけチェック
pyright my_agent.py
 
# 監視モードで保存ごとに再チェック
pyright --watch

VS Code を使うなら Pylance 拡張 を入れるだけで Pyright が IDE に統合されます。pyrightconfig.json で strict モードを有効化すると、型注釈漏れも警告できます。

{
  "include": ["src"],
  "typeCheckingMode": "strict",
  "reportMissingTypeStubs": false
}

どんなときに型を "省く" 選択をするか

型を全部書くのが正解ではありません。次のような状況では deps_type / output_type 省略も妥当です。

状況推奨
1 行のスクリプト・REPL でテキスト応答だけ欲しい型なしで十分
Colab セルで挙動確認しているだけ型なし or output_type だけ
業務ロジックに組み込む / 複数人で触るdeps_type + output_type 両方を必ず付ける
LLM 応答を後段の関数に渡すoutput_type 必須 (型不一致を IDE で検出)
Agent 自体を関数引数で受けるAgent[DepsT, OutputT] を関数シグネチャに書く

まとめ

  • Agent[DepsT, OutputT] はジェネリッククラス。deps_type= / output_type= を渡せば Pyright が型を自動推論する
  • 効く場面は 4 つ: result.output の補完 / deps= の型一致 / RunContext[DepsT]ctx.deps 補完 / リファクタリング耐性
  • 関数引数で Agent を受けるときは Agent[DepsT, OutputT] をシグネチャに書く
  • スクリプト用途なら型省略も OK。業務コード・複数人開発では両方必須

これで Ch1「Core: Agents」全 4 レッスンが完了です。次の Ch2「Dependencies」 からは、Agent に外部リソース (DB / HTTP クライアント / 設定) を安全に注入する DI のパターンと、TestModel と組み合わせたユニットテストを扱います。

Colab で実際に動かす

本レッスンの内容を Google Colab 上で実行できるノートブックを用意しています。下のボタンから自分のColab環境に開けます (要 Google アカウント / GOOGLE_API_KEY)。

Open in Colab

notebooks/ch01/04-static-type-check.ipynb