Lesson CH01-L02
Dynamic Instructions
依存値や時刻に応じてシステムプロンプトを差し替える。
- 読了目安
- 11 min
- Colab目安
- 18 min
- 合計
- 29 min
- 前提
- Static Instructions
関連: 公式ドキュメント
一行サマリ
@agent.instructions デコレータで関数を登録すると、毎回の run ごとに instructions を組み立て直せる。現在時刻・ユーザー固有値・DI で渡したオブジェクトなど「実行時にしか分からない情報」を system message に流し込めるようになる。
ヒーロー: Static と Dynamic の関係
Static Instructions (前レッスン) と Dynamic Instructions は 排他ではなく合算 されます。Agent を作るときの固定文字列 + 関数で生成した文字列の 両方 が、毎回の run で system message として LLM に渡されます。
概念: なぜ動的が必要か
Static Instructions はコードを書く時点で確定する固定文字列でした。しかし実用シナリオでは、「コード時点では決められない情報」 を毎回の run に流し込みたいことがあります。
代表例:
- 現在時刻 — 「今日は 2026 年 5 月 10 日です。これを基準に答えてください」
- ユーザー固有情報 — 「ユーザー名は 山田さん。敬称は『さん』を使う」
- 状況依存の制約 — 「現在 メンテナンスモードのため、注文関連の質問は受け付けない」
- データソースの状態 — 「現時点で DB には 1,234 件の商品があります」
これらを Static instructions にハードコードできず、また Tool (Ch3) を使って LLM に取りに行かせるほどでもないとき、Dynamic Instructions が "出すだけで効く" 最適な層 になります。
コード: 3 つの代表パターン
パターン 1: 現在時刻を毎回注入する
最も単純で効くのが「現在時刻」です。LLM 自体は内部に時刻概念を持たないので、外から教える必要があります。
from datetime import datetime
from zoneinfo import ZoneInfo
from pydantic_ai import Agent
agent = Agent(
'google-gla:gemini-3-flash-preview',
instructions='あなたは予約サポート担当です。日本語で簡潔に答えてください。',
)
@agent.instructions
def current_time() -> str:
now = datetime.now(ZoneInfo('Asia/Tokyo'))
return f'現在時刻 (JST): {now.strftime("%Y-%m-%d %H:%M")}。日付計算ではこの時刻を基準にしてください。'
# 毎回の run で current_time() が呼ばれ、戻り値が system message に追加される
print(agent.run_sync('明日の予約は?').output)ポイント:
@agent.instructionsは 関数を登録するデコレータ。関数本体は run ごとに毎回呼ばれる- 戻り値
strがそのまま system message に 追記 される - Static instructions (Agent コンストラクタの引数) と 共存 する
パターン 2: 引数なしの軽量な関数を複数登録
@agent.instructions は 何個でも重ねて貼れます。役割ごとに小さく分割するとテストしやすくなります。
import os
from pydantic_ai import Agent
agent = Agent(
'google-gla:gemini-3-flash-preview',
instructions='あなたは社内 Help Desk です。',
)
@agent.instructions
def env_label() -> str:
env = os.getenv('APP_ENV', 'dev')
return f'現在の環境: {env}'
@agent.instructions
def language_policy() -> str:
return '日本語で答え、専門用語には括弧書きで英語を併記してください。'
print(agent.run_sync('VPN が繋がりません').output)Agent の Static instructions に「あなたは社内 Help Desk です」、Dynamic 2 件で「環境ラベル」と「言語ポリシー」を 責務ごとに分離 しました。実プロジェクトでは「機能フラグの状態」「現在のユーザー権限」など、運用上 ON/OFF したい指示をこのレイヤーで切り替えるとメンテナンスしやすくなります。
パターン 3: RunContext 経由で DI から値を取る
Ch2「Dependencies」で詳しく扱いますが、@agent.instructions の関数に RunContext[DepsT] を引数として受けると、agent.run(..., deps=...) で渡したオブジェクトを参照できます。
from dataclasses import dataclass
from pydantic_ai import Agent, RunContext
@dataclass
class UserContext:
user_name: str
plan: str # 'free' | 'pro' | 'enterprise'
agent = Agent(
'google-gla:gemini-3-flash-preview',
deps_type=UserContext,
instructions='あなたはサポート担当です。',
)
@agent.instructions
def personalize(ctx: RunContext[UserContext]) -> str:
u = ctx.deps
return (
f'呼びかけは「{u.user_name} さん」を使ってください。\n'
f'現在のプラン: {u.plan}。'
f'{"高度な機能の質問にも詳しく答えてください。" if u.plan == "enterprise" else ""}'
)
# run のたびに deps を変えられる
result = agent.run_sync('ログインできません', deps=UserContext('山田', 'enterprise'))
print(result.output)ポイント:
- 関数の 第 1 引数を
RunContext[YourDepsType]にすると、PydanticAI が自動で渡してくれる deps_type=を Agent 作成時に宣言しておくのが必須 (型安全のため)- 1 つの Agent インスタンスでユーザー A 用 / B 用と deps を差し替えるだけ で出し分けできる
いつ Dynamic Instructions を使うか — 判断軸
| 状況 | 選ぶべき道具 |
|---|---|
| ハードコードできる固定指示 | Static instructions (前レッスン) |
| run ごとに変わる軽い文脈 (時刻 / ユーザー名 / 環境) | @agent.instructions (本レッスン) |
| LLM に「自分で取りに行ってもらう」情報 (天気・在庫・社内 DB) | Function Tool (Ch3) |
| run のたびに 大量の 構造化データを読ませる | Tool で取得 → 結果を返す (Ch3) |
「外から渡す軽い文脈」 vs 「LLM に取りに行かせる重い情報」の境界を意識すると設計が散らかりません。
まとめ
@agent.instructionsデコレータで関数を登録すると、run のたびに instructions を組み立て直せる- Static + 複数の Dynamic は 合算 されて 1 つの system message になる
- 軽い文脈 (時刻 / ユーザー名 / 環境フラグ) は Dynamic、重い情報取得は Tool (Ch3) に振り分ける
- 関数は 純関数 + 軽い処理 で書く。重い I/O や副作用は別レイヤーへ
次レッスンでは Reflection — Agent が自身の出力を内省して再修正する output_validator と再試行のしくみ — を扱います。
Colab で実際に動かす
本レッスンの内容を Google Colab 上で実行できるノートブックを用意しています。下のボタンから自分のColab環境に開けます (要 Google アカウント / GOOGLE_API_KEY)。
notebooks/ch01/02-dynamic-instructions.ipynb