DEV Community

Lukas Hamm
Lukas Hamm

Posted on

Extending Pydantic AI Agents with Dependencies — Adding Context to Your AI Agents

In the first part of this series, we built a simple Pydantic AI agent in Python that could process user input and return structured, predictable responses.

In this part, we’ll take it a step further by giving our agent contextual information with dependencies, defining who is asking and which project the request belongs to.

This is where dependencies come into play. By using deps_type in Pydantic AI, we can define structured data that provides the agent with essential background information. This makes the agent more intelligent, consistent, and better suited for real-world applications.

Why Dependencies Are Crucial for Python AI Agents in PydanticAI

In real-world software systems, an AI agent rarely operates in isolation. It usually acts within a larger environment — for example, handling requests for specific users, working on particular projects, or referencing external data sources.

This context helps create more reliable and relevant agent behavior. Pydantic AI offers a clean and type-safe way to provide that context through dependencies. By explicitly defining what the agent should know about its environment, we ensure that every run starts with the right information.

Defining Dependencies

Let’s start by defining a simple dependency for our Python AI Task Agent that specifies who is creating a task and to which project it belongs to. We’ll use a Python dataclass to store this structured information, enabling our AI agent to access contextual data reliably.

dependencies.py

from dataclasses import dataclass

@dataclass
class TaskDependency:
    username: str
    project: str
Enter fullscreen mode Exit fullscreen mode

This class defines a structured data object that our agent can later access when it needs to generate a task description.

Updating the Agent

Now we’ll update our existing TaskAgent so that it can make use of this dependency. In a first step we enhance the output model to include project and creator information.

model.py

from pydantic import BaseModel, Field

class TaskModel(BaseModel):
    task: str = Field(description="The title of the task.")
    description: str = Field(description="A brief description of the task specifying its steps.")
    priority: int = Field(description="The priority of the task on a scale from 1 (high) to 5 (low).")
    project: str = Field(description="The project the task belongs to.")
    created_by: str = Field(description="The name of the person who created the task.")
Enter fullscreen mode Exit fullscreen mode

This updated model ensures that each task generated by the agent not only contains the task title, description, and priority, but also explicitly includes who created the task and which project it belongs to.

For the agent the key additions are the deps_type parameter and the @agent.system_prompt decorator.

agent.py

from pydantic_ai.models.mistral import MistralModel
from pydantic_ai.providers.mistral import MistralProvider
from pydantic_ai import Agent, RunContext

from LearnPydanticAI.dependecies import TaskDependency
from LearnPydanticAI.model import TaskModel

import os


class TaskAgent():
    def __init__(self):
        self.agent = self._init_agent()

    def _init_agent(self) -> Agent:
        agent = Agent(
            model = MistralModel(model_name=os.getenv("LLM_MISTRAL_MODEL"), provider=MistralProvider(api_key=os.getenv("MISTRAL_API_KEY"))),
            output_type=TaskModel,
            deps_type=TaskDependency,
            )

        @agent.system_prompt
        def create_system_prompt(ctx: RunContext[TaskDependency]) -> str:
            return (f"""
                    Create a brief task from the user's request. 
                    The task is created by {ctx.deps.username}.
                    The taks belongs to the project {ctx.deps.project}.
                    """)

        return agent

    def run(self, query: str) -> str:
        deps = TaskDependency(username="sudo", project="LearnPydanticAI")
        result = self.agent.run_sync(query, deps=deps)
        return result.output
Enter fullscreen mode Exit fullscreen mode

Let’s look more closely at what changed here:

  • deps_type=TaskDependency:
    This tells the agent what kind of structured data it will receive as dependency information. In this case, it expects a TaskDependency object with a username and project name.

  • @agent.system_prompt decorator:
    This decorator defines a function that dynamically generates the system prompt every time the agent runs. The function receives a RunContext object, which includes the dependency data as ctx.deps. By referencing ctx.deps.username and ctx.deps.project, we can build a prompt that adapts to the given context at runtime.

This approach provides much more flexibility than using a static prompt string. It allows your agent to respond differently based on who uses it or what project it’s currently handling.

Running the Agent with Context

Now that we’ve added dependencies in PydanticAI, the agent can include user- and project-specific information, generating responses that are context-aware and more useful in real-world automation scenarios.

% poetry run python src/LearnPydanticAI/app.py
task='Learn about Pydantic AI' description='Research and learn about Pydantic AI, its features, and applications.' priority=3 project='LearnPydanticAI' created_by='sudo'
Enter fullscreen mode Exit fullscreen mode

Instead of producing a generic task, the output now reflects who created the task and where it belongs. This makes the agent’s responses far more meaningful and adaptable to different use cases.

Why Dependencies Are Essential in Real Projects

Dependencies are a key component when integrating AI agents into production systems. In real projects, agents often need to:

  • Access user-specific data (permissions, preferences, or roles)
  • Operate within project contexts (repositories, workspaces, or tenants)
  • Use environmental settings (API tokens, configuration values, or runtime parameters)

With Pydantic AI, you can manage all of this using strongly typed dependencies. It enforces structure and reliability while keeping your code clean and predictable. This approach aligns well with common software development practices, allowing developers to design AI features with the same structure and reliability as any other part of their system.

What’s Next

With PydanticAI dependencies in place, our agent can now understand its environment and produce more meaningful, context-aware results.

In the next part of this PydanticAI tutorial, we’ll extend this foundation by integrating external tools, enabling the agent to interact with databases, APIs, and other real-world systems.

💻 Code on GitHub: hamluk/LearnPydanticAI/part-2

📘 Read Part 3: Extending Pydantic AI Agents with Function Tools

Top comments (0)