Dependencies: giving tools your data
Dependencies are the objects a run needs, like the customer and a database connection. You pass them to run_sync and tools read them from RunContext.
from dataclasses import dataclass
from pydantic_ai import Agent, RunContext
from shop_model import shop_model
@dataclass
class Desk:
customer: str
orders: dict[str, str]
agent = Agent(shop_model, deps_type=Desk)@agent.tool
def lookup_order(ctx: RunContext[Desk], order_id: str) -> str:
"""Look up the status of one of this customer's orders."""
return ctx.deps.orders.get(order_id, "not one of this customer's orders")deps_type=Desk tells the agent, and your type checker, what the dependencies will be. @agent.tool, not tool_plain, passes a RunContext as the first argument, and ctx.deps is the object given to this run. ctx is not part of the tool's schema; the model never sees it.
asha = Desk(customer="Asha", orders={"A-1001": "shipped on 12 March"})
ravi = Desk(customer="Ravi", orders={"A-1002": "waiting for stock"})
print(agent.run_sync("Where is A-1001?", deps=asha).output)
print(agent.run_sync("Where is A-1001?", deps=ravi).output)One agent, two customers. Each run looks only at the orders it was given, so Ravi cannot read Asha's order even by quoting its number. With a global dictionary instead, every run would see every order.
Instructions from dependencies
def spy(messages, info):
return ModelResponse(parts=[TextPart(info.instructions)])
agent = Agent(FunctionModel(spy), deps_type=Desk, instructions="You answer support tickets.")
@agent.instructions
def customer(ctx: RunContext[Desk]) -> str:
return f"The customer is {ctx.deps.customer}. Orders on file: {len(ctx.deps.orders)}."
print(agent.run_sync("hi", deps=Desk("Asha", {"A-1001": "shipped"})).output)Instruction functions, output validators and output functions can take RunContext too. Besides deps, it has the run's usage, messages and retry count.
Desk with made-up orders and nothing else changes. In a web app, each request builds its own dependencies, so one customer's data never leaks into another's run.- Run without
deps=and read what the tool gets. - Add
refund_limit: floattoDeskand mention it in the instructions. - Print
ctx.usage.requestsinsidelookup_order.
Little by little, you're building something great.