Compose Agents with Pydantic AI v2 Capabilities (2026) — the upgrade from “tools on an Agent” to composable bundles of instructions, tools, settings, and hooks.
You already have typed agents with Pydantic AI. v2 (stable mid-2026) centers one primitive: the capability. Pair it with FastMCP toolsets or handoffs when you need other stacks.
TL;DR
- A
Capabilitybundles instructions + tools (+ optional settings/hooks) - Pass
capabilities=[...]onAgent(...) defer_loading=Truekeeps a workflow as a one-line catalog until the model loads it- Migrate from v1 by clearing deprecation warnings on latest v1 first
Install
uv add pydantic-ai
# or: pip install pydantic-ai
export OPENAI_API_KEY=sk-...
Example 1 — Capability with a tool
from pydantic_ai import Agent
from pydantic_ai.capabilities import Capability
orders = Capability(
id="orders",
description="Use for order tracking or delivery status.",
instructions="Always quote the order ID in your reply.",
)
@orders.tool_plain
def order_status(order_id: str) -> str:
"""Look up shipping status for an order."""
return f"Order {order_id}: shipped, ETA Friday."
agent = Agent(
"openai:gpt-4o-mini",
instructions="You are a concise support assistant.",
capabilities=[orders],
)
result = agent.run_sync("Where is order ABC-123?")
print(result.output)
Example 2 — on-demand (deferred) capability
from pydantic_ai import Agent
from pydantic_ai.capabilities import Capability
refunds = Capability(
id="refunds",
description="Use for refund eligibility, status, or processing a refund.",
instructions="Always confirm the order ID before issuing a refund.",
defer_loading=True, # catalog only until the model loads it
)
@refunds.tool_plain
def refund_status(order_id: str) -> str:
"""Look up the refund status for an order."""
return f"Order {order_id}: refund issued on 2026-05-01."
agent = Agent(
"openai:gpt-4o-mini",
instructions="You are a customer support assistant.",
capabilities=[refunds],
)
# First model turn sees a compact catalog; load_capability reveals tools + instructions
print(agent.run_sync("Was my refund for order ABC-123 processed?").output)
Deferred capabilities cut token bloat and bad tool picks once you pass ~30–50 tools. Load activates the whole bundle — instructions, tools, settings, and hooks together.
When to use what
- Always-on Capability — used on most turns
- defer_loading=True — multi-workflow agents (orders vs refunds vs security)
- Hooks / AbstractCapability — logging, approvals, custom mid-run rewrites
- Instructor — one-shot schema extraction (not a full agent loop); see the Instructor tutorial
Production tips
- Give every deferred capability a stable explicit
idfor history resume - Upgrade latest v1 and clear deprecations before jumping to v2
- Note:
openai:names may use Responses API in v2; useopenai-chat:if you need Chat Completions - Keep secrets in env; pin model IDs
Wrap-up
Pydantic AI v2 makes agent extensions composable. Start with Capability for tools + instructions, then flip defer_loading=True when workflows multiply — progressive disclosure without rewriting the agent loop.