PydanticAI ビジュアルガイド

Lesson CH00-L02

同期 vs 非同期

run_sync / run / run_stream の使い分けを掴む。

読了目安
10 min
Colab目安
18 min
合計
28 min
前提
初Agent

一行サマリ

run_sync / run / run_stream3 つの API は同じ Agent に対する 3 つの呼び出し方 で、用途と返ってくる型が違う。

ヒーロー: 3 つの API の関係

PydanticAI の Agent はどの API を使っても 同じ Agent オブジェクト・同じ instructions・同じツール を共有します。違うのは「結果の受け取り方」だけです。

図を読み込み中…
図1. 3 つの run メソッドの位置づけ

概念: なぜ 3 つも API があるのか

LLM 呼び出しは ネットワーク I/O で、応答が返ってくるまで数秒かかります。この「待ち時間」をどう扱うかで API が分かれます。

  • run_sync — 結果が返るまでスレッドをブロックする。Colab セルや CLI スクリプトのように 「1 件ずつ順番に動かせばよい」 場面で最も簡単
  • runawait で待つ。同じプロセスで 複数の Agent 呼び出しを並列に走らせたい 場合や、FastAPI / Starlette のような async な Web フレームワーク から呼ぶときに使う
  • run_streamasync for部分的な応答を逐次受け取る。Web UI で「タイピング中」を表現したり、長い応答を体感速度よく見せたりするのに使う

混乱しがちなのは「run_sync だけが同期で、他の 2 つは非同期」「run_streamrun の上位互換ではなく、用途が違う」の 2 点です。

図を読み込み中…
図2. 用途別の使い分けマップ

コード: 3 つを並べて比較

run_sync — もっとも簡単

from pydantic_ai import Agent
 
agent = Agent(
    'google-gla:gemini-3-flash-preview',
    instructions='日本語で簡潔に答えてください。',
)
 
# Cell 全体がブロックされ、応答が返るまで次のセルに進めない
result = agent.run_sync('PydanticAIを一言で')
print(result.output)

ポイント:

  • 戻り値は AgentRunResult.output で文字列を取り出す
  • 内部では asyncio.run(agent.run(...)) 相当の処理を行っている
  • Colab のように すでに動いているイベントループ がある環境では run_sync は使える (内部で nest_asyncio 相当の処理がある)

run — async から呼ぶ

import asyncio
from pydantic_ai import Agent
 
agent = Agent(
    'google-gla:gemini-3-flash-preview',
    instructions='日本語で簡潔に答えてください。',
)
 
async def main():
    # 単発呼び出し
    result = await agent.run('PydanticAIを一言で')
    print(result.output)
 
    # 複数を並列に走らせる (これが run の本領)
    queries = ['Agentとは?', 'Toolとは?', 'output_typeとは?']
    results = await asyncio.gather(*(agent.run(q) for q in queries))
    for r in results:
        print('-', r.output[:60], '...')
 
asyncio.run(main())

ポイント:

  • 戻り値は同じく AgentRunResultrun_sync との違いは 呼び出し側が await するか否か だけ
  • asyncio.gatherN 個のクエリを並列に投げる と、合計時間がほぼ最長 1 件分になる
  • FastAPI のエンドポイントは関数を async def で書けば、その中で await agent.run(...) をそのまま使える

run_stream — 部分応答を逐次

import asyncio
from pydantic_ai import Agent
 
agent = Agent(
    'google-gla:gemini-3-flash-preview',
    instructions='日本語で簡潔に答えてください。',
)
 
async def main():
    async with agent.run_stream('PydanticAIの強みを3つ教えて') as response:
        async for chunk in response.stream_text():
            # chunk はそれまでに得られたテキスト全体 (デフォルト)
            # 末尾の差分だけ欲しい場合は delta=True を渡す
            print(chunk, end='\r', flush=True)
        print()  # 改行
        # ループを抜けたら最終結果が確定している
        final = await response.get_output()
        print('FINAL:', final)
 
asyncio.run(main())

ポイント:

  • async withStreamedRunResult を開く必要がある
  • stream_text()部分テキストの async iterator を返す
  • 入力途中のテキストを画面に流したいだけなら delta=True で末尾差分だけ受け取るとシンプル
  • 最終応答全体は get_output() で確定させる
図を読み込み中…
図3. 3 つの API のシーケンス比較

いつ何を選ぶか — 早見表

状況選ぶ API理由
Colab セルで実験run_syncawait なしで書ける
単発の CLI スクリプトrun_syncプロセス全体が同期で済む
FastAPI など async Web フレームワークからrunフレームワークがすでに event loop を回している
N 件のクエリを並列に処理asyncio.gather(*(agent.run(q) for q in qs))I/O 待ちが重なって体感時間が短くなる
Web UI に「タイピング中」を出すrun_stream最終応答を待たずに見せられる
1 文字ずつ TTS にかける / 部分処理を挟むrun_stream (delta=True)差分だけ取れる

まとめ

  • run_sync / run / run_stream同じ Agent への 3 つの呼び出し方。中身は同じ
  • Colab・CLI なら run_sync、async Web フレームワークなら run、逐次表示なら run_stream
  • 並列に投げるときは asyncio.gather + run。これが体感速度を一番伸ばす

次レッスンでは、これまで使ってきた 'google-gla:' プレフィックス (Google AI Studio) と、企業向けの 'google-vertex:' プレフィックス (Vertex AI) の違いと使い分けを扱います。

Colab で実際に動かす

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

Open in Colab

notebooks/ch00/02-sync-vs-async.ipynb