エージェントに「Web検索」と「コード実行サンドボックス」と「セッションをまたぐ記憶」を足したい。よくあるフレームワークだと、この作業は一箇所では終わらない。ツールを登録する場所、システムプロンプトを書き足す場所、実行中にモデルへ渡す文脈を差し替えるフック、モデル設定のノブ、それぞれが別のレイヤーに散らばっていて、機能を1つ増やすたびに4〜5箇所を触ることになる。
Pydantic AI v2 が出した答えは、その散らばりを1個のオブジェクトに畳むことだった。7回のベータを経て、v2.0.0 が2026年6月23日に安定版になっている。
capability は、4つの層を束ねた1個の部品
v2 の中心概念が capability(ケイパビリティ)だ。これは「命令文(instructions)・ツール・ライフサイクルフック・モデル設定」という、エージェントを構成する4つの層を1つにまとめた合成可能な単位を指す。つまり機能追加とは「capability を1個 Agent に渡すこと」に統一される。ミドルウェアをアプリに use() するのに近い感覚だと思えばいい。
たとえばコード実行・Hacker News の MCP サーバー・Web検索を積んだエージェントは、公式リポジトリの例だとこう書ける。
from pydantic_ai import Agent
from pydantic_ai.capabilities import MCP, WebSearch
from pydantic_ai_harness import CodeMode
agent = Agent(
'anthropic:claude-opus-4-7',
capabilities=[
CodeMode(),
MCP('https://hn.caseyjhand.com/mcp', native=False),
WebSearch(native=False),
],
)
capabilities=[...] に並べたものが、それぞれ内部でツールもプロンプトもフックも登録していく。呼び出し側はリストに一行足すだけで、その機能が要求する全レイヤーの配線が済む。WebSearch(native=False) の native は、プロバイダがネイティブ検索を持つならそれを使い、無ければローカル実装にフォールバックする指定だ。CodeMode() は Monty というサンドボックスで動き、本来 N 回に分かれるツール呼び出しを1回の run_code にまとめる。Thinking(effort='high') のように、プロバイダごとにバラバラだった拡張思考を横断で揃える capability もある。
本当のレバレッジは、実行中にモデルへの入力を書き換えるフック
capability が強いのは、ツールを足すだけでなくエージェントの実行ループそのものに割り込めるからだ。v2 のフックは層ごとに整然と分かれていて、命名も規則的になっている。
| フックの層 | 何に割り込むか |
|---|---|
| Run | エージェントの実行全体 |
| Node | 実行グラフの各ノード |
| Model Request | モデルへのリクエスト送信 |
| Tool Validate / Execute | ツール引数の検証・実行 |
| Output | 出力の検証・後処理 |
各層に before_* / after_* / wrap_* / on_*_error の4種が揃う。wrap_* は前後を包むミドルウェア型、on_*_error は失敗時だけ走る。たとえばモデルへ送る直前に文脈を差し替えるならこうだ。
@hooks.on.before_model_request
async def log_request(ctx: RunContext, request_context: ModelRequestContext) -> ModelRequestContext:
print(f'Sending {len(request_context.messages)} messages to the model')
return request_context
request_context を受け取り、加工して返す。ここでメッセージ列を削れば文脈圧縮になり、機密情報を伏せればマスキングになる。「モデルが実際に見る内容を実行中に書き換える」処理を、外付けの capability として配れるようになったのが v2 の勘所だ。プロンプト圧縮やガードレールが、フレームワーク本体をフォークせずに一個の pip パッケージとして流通する。
core は小さく保ち、電池は Harness に外出しした
v2 でもう一つ効いているのが、ライブラリを2つに割った判断だ。
| インストール | 中身 | |
|---|---|---|
core(pydantic-ai) |
uv add pydantic-ai |
実行ループ、各プロバイダ、capability と hooks の API、深いプロバイダ連携が要る基幹 capability |
Harness(pydantic-ai-harness) |
uv add pydantic-ai-harness |
メモリ、ガードレール、文脈管理、ファイルシステム、コード実行などの「電池」 |
CodeMode の Monty サンドボックスなどは追加依存が要るので、uv add "pydantic-ai-harness[codemode]" のように extras で入れる。Harness 側が抱える capability は幅広い。ファイル操作の FileSystem(パストラバーサル防止つき)、コマンド実行の Shell(許可・拒否リストとタイムアウト)、スライディングウィンドウや LLM による文脈圧縮、セッションをまたぐキーバリューの永続メモリ、コスト/トークン予算・ツールのアクセス制御・秘密情報のマスキング・承認フローといったガードレール群が並ぶ。
割った狙いははっきりしている。core は後方互換を厳格に守って安定させ、動きの速い機能は Harness で速く回す。そして広く必須だと分かった capability は core へ「昇格」させる。React が安定 API と実験 API を分けているのと同じ、成熟度でレイヤーを切る発想だ。
実務で触るときの注意
移行する場合、いきなり v2 に飛ばずまず v1 の最新まで上げて deprecation 警告を全部消すのが公式の勧めで、破壊的変更の多くはそこで顕在化する。OpenAI 系のモデル名は Responses API 準拠に変わっている点、capability を遅延ロードする defer_loading=True がある点も移行時に効いてくる。
設計として気になるのは、capability が「命令・ツール・フック・設定」を全部飲み込む万能部品ゆえに、複数の capability が同じ before_model_request でプロンプトを触り合ったとき、最終的にモデルへ何が渡ったかを追いにくくなりうることだ。リストに並べた順序が挙動を左右する以上、フックの実行順とデバッグ手段はチーム内で早めに握っておいたほうがいい。
とはいえ、エージェント拡張を「配れる1個の部品」に落とし込んだ抽象は素直に良い。自分のエージェントに機能を足すたびに設定ファイルを5箇所いじっていた人ほど、この設計の身軽さは効いてくるはずだ。