The problem: passing runtime state without globals
In the LangChain course, if a tool needed access to something like a database connection or the current user's ID, you'd usually reach for a closure, a global, or stuff it awkwardly into the prompt. Pydantic AI gives this a first-class mechanism: deps_type and RunContext.
Declaring what an agent depends on
from dataclasses import dataclass
from dotenv import load_dotenvfrom pydantic_ai import Agent, RunContext
load_dotenv()
@dataclassclass AppDeps: user_name: str is_admin: bool
agent = Agent("google:gemini-3.5-flash-lite", deps_type=AppDeps)deps_type is just documentation-as-a-type: it tells Pydantic AI, and your type checker, what shape of object every run_sync call must supply as deps=. It can be a dataclass, a plain class, a dict, an open database connection, whatever your agent's tools and prompts actually need at runtime.
Reading deps inside the run
Any function that Pydantic AI calls during a run, a dynamic system prompt, a tool, an output validator, can accept a RunContext[Deps] as its first parameter and read ctx.deps off it.
@agent.system_promptdef greet(ctx: RunContext[AppDeps]) -> str: role = "an admin" if ctx.deps.is_admin else "a regular user" return f"The user's name is {ctx.deps.user_name}, and they are {role}."
def main() -> None: result = agent.run_sync( "Greet me and tell me what my permission level is.", deps=AppDeps(user_name="Nolan", is_admin=False), ) print("Output:", result.output)Notice deps are passed to run_sync, not to Agent(...). The agent object is stateless and reusable across many runs and many different callers; the deps are what makes each individual run specific to one user or one request. This is the same shape as constructing a LangChain agent once and passing per-request context through RunnableConfig, just typed end to end.
Checkpoint
deps_type=onAgent(...)declares what shape of runtime state the agent expects.deps=onrun_sync(...)supplies the actual value, per run, not per agent.RunContext[Deps]is how tools, dynamic system prompts, and output validators all readctx.deps.
If anything here still feels unclear, ask before moving to Lesson 6, where tools use exactly this mechanism.