Agents

The Agent is where everything in Pydantic AI comes together — model, instructions, tools, typed dependencies, and typed output, bundled into one reusable, testable object you define once and run many times. Understanding the Agent as a configured, type-parameterized unit is the key that makes the rest of the framework fall into place.

The last post introduced Pydantic AI’s philosophy. This post covers its central primitive: the Agent. Everything else — structured outputs, tools, dependencies — hangs off the Agent, so understanding what it is and how it’s constructed is foundational. The key idea is that a Pydantic AI agent is a reusable, strongly-typed object: you define it once with its configuration and types, then run it against many inputs.

What an Agent is

An Agent in Pydantic AI bundles everything needed to accomplish a class of tasks into one object:

The important framing: an agent is defined once and reused. You don’t construct it per request; you build it as a configured component of your application — like defining a route or a service — and then run it against different inputs repeatedly. This makes agents first-class, reusable pieces of your program rather than throwaway one-off calls, which is central to how Pydantic AI encourages you to structure applications.

# Illustrative shape — see the Pydantic AI docs for exact API.
from pydantic_ai import Agent

agent = Agent(
    "openai:gpt-...",                    # the model (swappable)
    system_prompt="You are a helpful assistant.",
)

result = agent.run_sync("What is the capital of France?")
print(result.output)

Define the agent as a configured object; run it as needed. That reuse-oriented design is the first thing to internalize.

The Agent is type-parameterized

What makes Pydantic AI’s Agent distinctive is that it’s parameterized by types — specifically, by its dependency type and its output type. Conceptually, an agent isn’t just “an agent”; it’s “an agent that takes these typed dependencies and produces this typed output.” This is the type safety from the last post made concrete at the level of the core primitive:

Because the Agent carries these types, your IDE and type checker understand your agent: they know result.output is an Order, not an untyped blob, and they know what dependencies a tool can access. This is why building with Pydantic AI feels like typed Python — the Agent isn’t an opaque object but a typed contract your tooling can reason about. The next two posts unpack the output type and dependency type in depth; the key point here is that the Agent is where those types are declared and enforced.

System prompts: static and dynamic

The system prompt (instructions) shapes the agent’s behavior, and Pydantic AI supports two forms, reflecting a real need:

Dynamic system prompts are more useful than they first appear: they let the agent’s instructions incorporate runtime context (who the user is, what data is relevant now) while keeping the agent defined once. This connects directly to dependency injection — the dynamic prompt reads from the typed dependencies to build context-appropriate instructions. It’s how a single reusable agent adapts its guidance to each specific run.

Running an Agent

Pydantic AI gives you a few ways to run an agent, matching how your application executes:

Whichever you use, the run produces a result object that carries the typed output (result.output) plus metadata (the messages exchanged, usage information). The result being a typed object — not a raw string — is the payoff of the type-parameterized agent: you run the agent and get back exactly the type you declared, ready to use in the rest of your typed program.

The Agent as the unit of composition

Stepping back, the Agent is Pydantic AI’s unit of composition — the piece you build, test, reuse, and combine. Because an agent is a self-contained, typed object with its model, prompt, tools, and dependencies, you can:

This composability-of-typed-units is the structural benefit of the Agent design: instead of sprawling prompt-and-parse code, you get discrete, typed, testable agent components. With the Agent understood as the type-parameterized center of the framework, the next post covers its most distinctive feature — the typed output that makes result.output a validated object.

Key takeaways

Further reading

Sources & References