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 関数を呼び、その結果を踏まえて応答 するようになります。
概念: Tool は「LLM が呼ぶ Python 関数」
ポイントは 「LLM が判断して呼ぶ」 こと。開発者が手動で関数を呼ぶわけではありません。Agent に登録した tools は、LLM への prompt に JSON Schema として 同梱され、LLM は質問内容を見て「この問いには get_weather が必要だ」と判断し、引数を組み立てて呼び出します。
| 概念 | 何を担う |
|---|---|
@agent.tool | 関数を Tool として登録するデコレータ |
| 関数の 引数の型ヒント | LLM が引数を組み立てるための JSON Schema になる |
| 関数の docstring | LLM に「この 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.toolはRunContext必須、@agent.tool_plainはRunContextなしasync defでもdefでも書ける。asyncを使えば I/O 待ちで他の処理を回せる- HTTP / DB アクセスのような副作用は tool 内に封じ込め、Agent 本体はテスタブルに保つ
いつ 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)。
notebooks/ch03/01-tool-basics.ipynb