PydanticAI ビジュアルガイド

Lesson CH03-L01

@agent.tool 基礎

Pythonの関数をそのままToolとして公開する最短パス。

読了目安
10 min
Colab目安
16 min
合計
26 min
前提
TestModelとの併用

関連: 公式ドキュメント

一行サマリ

@agent.tool で Python 関数を 「LLM が必要に応じて呼べるツール」 として登録できる。型ヒント + docstring から JSON Schema が自動生成 され、LLM はその情報をもとに どのツールを・どの引数で呼ぶか を自分で判断する。

ヒーロー: Tool で Agent が「外と繋がる」ようになる

これまでの Agent は「LLM 1 往復で完結」する閉じた箱でした。Tool を付けると、LLM が 必要に応じて Python 関数を呼び、その結果を踏まえて応答 するようになります。

図を読み込み中…
図1. Tool ありの Agent 実行サイクル

概念: Tool は「LLM が呼ぶ Python 関数」

ポイントは 「LLM が判断して呼ぶ」 こと。開発者が手動で関数を呼ぶわけではありません。Agent に登録した tools は、LLM への prompt に JSON Schema として 同梱され、LLM は質問内容を見て「この問いには get_weather が必要だ」と判断し、引数を組み立てて呼び出します。

概念何を担う
@agent.tool関数を Tool として登録するデコレータ
関数の 引数の型ヒントLLM が引数を組み立てるための JSON Schema になる
関数の docstringLLM に「この tool はいつ使うか」を伝える説明文
関数の 戻り値LLM への入力 (次のステップで踏まえる情報)
RunContext[Deps] (任意)第 1 引数で受けると Ch2 の DI を tool 内で使える

コード: 3 つのパターン

パターン 1: 最小の tool — @agent.tool_plain

RunContext が要らない (deps を使わない) シンプルな tool には @agent.tool_plain を使います。

from datetime import datetime
from zoneinfo import ZoneInfo
from pydantic_ai import Agent
 
agent = Agent('google-gla:gemini-3-flash-preview', instructions='短く日本語で答えてください。')
 
@agent.tool_plain
def current_time_jst() -> str:
    """現在の日本時刻 (JST) を ISO8601 形式で返します。"""
    return datetime.now(ZoneInfo('Asia/Tokyo')).isoformat()
 
result = agent.run_sync('今、日本では何時ですか?')
print(result.output)
# LLM は instructions と質問を見て、内部で current_time_jst() を呼び、その結果を踏まえて応答する

ポイント:

  • docstring は LLM への命綱。「この tool は何をするか」を 1〜2 行で明記
  • 戻り値の型ヒント (-> str) も schema に乗る。int, dict, Pydantic Model 等もそのまま使える
  • LLM は current_time_jst() を呼ぶか呼ばないかを判断する。「今何時?」のような質問だと自動で呼ばれる

パターン 2: 引数を受ける tool — @agent.tool_plain with args

引数の型ヒントから JSON Schema が組み立てられ、LLM がその引数を埋めて呼び出します。

from pydantic_ai import Agent
 
agent = Agent('google-gla:gemini-3-flash-preview', instructions='答えは日本語で。')
 
# モック天気データ
WEATHER_DB = {
    'Tokyo': '晴れ、22度',
    'Osaka': '曇り、19度',
    'Sapporo': '雪、-2度',
}
 
@agent.tool_plain
def get_weather(city: str) -> str:
    """指定した都市の現在の天気を返します。city は英字の都市名 (例: Tokyo, Osaka)。"""
    return WEATHER_DB.get(city, f'{city} の天気データは未登録です')
 
result = agent.run_sync('東京と札幌の天気を教えて')
print(result.output)
# LLM は get_weather('Tokyo') と get_weather('Sapporo') を 2 回呼び、まとめて答える

ポイント:

  • 型ヒント city: str から「文字列の引数 city が必要」と LLM が認識
  • docstring の 「city は英字の都市名」 のような追加情報が LLM の引数組み立て精度を上げる
  • 1 回の run で 同じ tool を複数回呼ぶ (Tokyo と Sapporo) のは LLM の自律的な判断

パターン 3: RunContext 経由で deps を使う — @agent.tool

@agent.tool (_plain なし) を使うと、第 1 引数で RunContext[Deps] を受け、Ch2 で組んだ Deps を tool 内で参照できます。これで HTTP / DB / 設定値を tool が安全に使えます。

from dataclasses import dataclass
import httpx
from pydantic_ai import Agent, RunContext
 
@dataclass
class WeatherDeps:
    http: httpx.AsyncClient
    api_base: str
 
agent_w = Agent(
    'google-gla:gemini-3-flash-preview',
    deps_type=WeatherDeps,
    instructions='答えは日本語で。',
)
 
@agent_w.tool
async def get_weather(ctx: RunContext[WeatherDeps], city: str) -> str:
    """指定都市の現在天気を外部 API から取得します。"""
    url = f'{ctx.deps.api_base}/weather?city={city}'
    response = await ctx.deps.http.get(url)
    response.raise_for_status()
    return response.json()['summary']
 
# 利用側
import asyncio
async def main():
    async with httpx.AsyncClient() as http:
        deps = WeatherDeps(http=http, api_base='https://api.example.com')
        result = await agent_w.run('Tokyo の天気は?', deps=deps)
        print(result.output)
 
asyncio.run(main())

ポイント:

  • @agent.toolRunContext 必須@agent.tool_plainRunContext なし
  • async def でも def でも書ける。async を使えば I/O 待ちで他の処理を回せる
  • HTTP / DB アクセスのような副作用は tool 内に封じ込め、Agent 本体はテスタブルに保つ
図を読み込み中…
図2. tool と tool_plain の使い分け

いつ tool を使うか — 判断軸

状況選ぶべき道具
静的に決まる役割や口調Static Instructions (Ch1-L01)
外から渡せる軽い文脈 (時刻・ユーザー設定)Dynamic Instructions (Ch1-L02)
重いリソースを Agent 内のあちこちで使うDeps (Ch2-L01)
LLM が「いま必要だ」と判断して呼ぶ情報Tool (本レッスン)
出力を構造化したいoutput_type (Ch4)

「LLM が能動的に呼ぶ」という性質が tool の核心。何をいつ呼ぶかを LLM に決めさせたい ときに使います。

まとめ

  • @agent.tool / @agent.tool_plain で Python 関数を Tool として登録できる
  • LLM は 型ヒント + docstring から組み立てた schema を見て、自律的に呼ぶ
  • DI が要るときは @agent.tool で第 1 引数に RunContext[Deps]、要らないときは @agent.tool_plain
  • 副作用や外部 API 呼び出しは tool 内に閉じ込め、Agent 本体をテスタブルに保つ

次レッスンでは、Pydantic で tool 引数を型 + バリデータで守る パターン (Annotated / Field / BaseModel as arg) を扱います。

Colab で実際に動かす

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

Open in Colab

notebooks/ch03/01-tool-basics.ipynb