DEV Community

Lukas Hamm
Lukas Hamm

Posted on

Getting Started with PydanticAI: Basics for AI Agents in Python

What's the Reason behind all of that?

For many developers, AI Agents are still mostly an idea rather than something implemented in real projects. These agents have the potential to change the way software projects are built, becoming a standard part of future codebases. They can organize, validate, and structure information in ways that make AI-driven workflows more predictable and reliable.

In this series, we'll take a closer look at Pydantic AI - a Python agent framework - and how to bring these AI agents to life, starting with the basics and gradually exploring more advanced possibilities.

Getting Started with Pydantic AI and Mistral

We’ll start this series by building our first working example of an AI agent. We'll cover the basics of PydanticAI and how it works, including step-by-step instructions and practical code examples. This will establish the foundation for the following tutorials, where we’ll explore more advanced features and workflows.

Setting Up the Project

Let's start by setting up a clean Python environment and installing the required dependencies. I’ll be using Poetry, a dependency management and packaging tool for Python, but feel free to use any setup method you prefer.

In this series, I’ll work with the Mistral model. Since Pydantic AI is a model-agnostic framework, you can easily use a different model if you like.

# create project folder structure
poetry new LearnPydanticAI
cd LearnPydanticAI

# install PydanticAi and Mistral dependencies
poetry add "pydantic-ai-slim[mistral]"
Enter fullscreen mode Exit fullscreen mode

To use your model, make sure the API key is available as an environment variable. I prefer to store these values in a .env file and load them in my application using load_dotenv().

.env

LLM_MISTRAL_MODEL=<mistral_model>
MISTRAL_API_KEY=<mistral_api_key>
Enter fullscreen mode Exit fullscreen mode

For this, we’ll also install the python-dotenv package.

# install python-dotenv as dependency
poetry add python-dotenv
Enter fullscreen mode Exit fullscreen mode

Core Concepts — Agents and Structured Output

The first two core concepts of Pydantic AI that we are going to cover are Agents and Structured Output.

An Agent in Pydantic AI is a self-contained component that can take instructions, interact with a language model, and return results. Unlike calling an LLM directly, agents are designed to be reusable, predictable, and easily integrated into larger workflows. Each agent can be configured with specific behaviors, prompts, and validation rules, which allows you to build reliable AI-driven processes.

The second concept - and one of Pydantic AI's key features - is its ability to produce structured output. Instead of receiving free-form text from the model, you define a data model using Pydantic. The agent ensures that the AI’s response conforms to this model, which reduces errors and makes downstream processing straightforward.
Structured output allows developers to focus on practical use cases, rather than parsing and cleaning model responses. It makes AI Agents not just an experimental tool, but a component that can reliably interact with other parts of a software project.

Build Your First Agent

Now that we’ve covered the basic concepts, it’s time to build our first working AI agent. We’ll start small — creating an agent that takes a user request and returns a concise task description.

agent.py

from pydantic_ai.models.mistral import MistralModel
from pydantic_ai.providers.mistral import MistralProvider
from pydantic_ai import Agent
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"))
            ),
            system_prompt="Create a brief task from the user's request."
        )
        return agent

    def run(self, query: str) -> str:
        result = self.agent.run_sync(query)
        return result.output
Enter fullscreen mode Exit fullscreen mode

With our agent defined, we can now write a simple app.py to run it for the first time.

app.py

from dotenv import load_dotenv
from LearnPydanticAI.agent import TaskAgent

load_dotenv()  # load environment variables from .env

agent = TaskAgent()
answer = agent.run("I want to learn more about Pydantic AI")
print(answer)
Enter fullscreen mode Exit fullscreen mode

Here’s an example of what the output might look like:

% poetry run python src/LearnPydanticAI/app.py
Task: Research Pydantic AI

1. Objective: Gather information about Pydantic AI to understand its features, use cases, and benefits.

2. Steps:
   - Visit the official Pydantic documentation or website.
   - Read about Pydantic's core features and how it integrates with AI/ML workflows.
   - Explore tutorials or case studies showing Pydantic AI in action.
   - Check community discussions on GitHub or Stack Overflow.
   - Summarize key insights such as data validation and type safety for AI projects.

3. Deliverable: A concise overview of Pydantic AI — what it is, how it works, and why it matters.
Enter fullscreen mode Exit fullscreen mode

Add Structured Output

Now that the agent is working, let’s make its responses structured and predictable. We’ll do this by defining a response schema using Pydantic models.

model.py

from pydantic import BaseModel

class TaskModel(BaseModel):
    task: str
    description: str
    priority: int
Enter fullscreen mode Exit fullscreen mode

We then connect this model to the agent by using the output_type argument in its constructor.

agent.py

from pydantic_ai.models.mistral import MistralModel
from pydantic_ai.providers.mistral import MistralProvider
from pydantic_ai import Agent
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, # new line
            system_prompt="Create a brief task from the user's request."
        )
        return agent

    def run(self, query: str) -> str:
        result = self.agent.run_sync(query)
        return result.output
Enter fullscreen mode Exit fullscreen mode

Running the agent again now produces a structured response that matches the schema we defined:

% poetry run python src/LearnPydanticAI/app.py
task='Research Pydantic AI' description='Learn about the features, use cases, and benefits of Pydantic AI.' priority=3
Enter fullscreen mode Exit fullscreen mode

Bonus — Add Field Descriptions

Defining the output with a Pydantic BaseModel is one of Pydantic AI’s most powerful features.
Not only does it guarantee structured output and eliminate the need for manual parsing — it also allows you to guide the model by describing each field in more detail.

You can do this by using Pydantic’s Field() function:

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 goal.")
    priority: int = Field(description="The task priority on a scale from 1 (high) to 5 (low).")
Enter fullscreen mode Exit fullscreen mode

With these field descriptions, the agent receives clearer context about the expected structure and meaning of each value — which results in more detailed and reliable outputs.

% poetry run python src/LearnPydanticAI/app.py
task='Research Pydantic AI' description="1. Open a web browser and go to a search engine like Google. 2. Type 'Pydantic AI' in the search bar and press enter. 3. Review relevant links and gather key information." priority=3
Enter fullscreen mode Exit fullscreen mode

Wrapping Up

In this first part, we created a simple yet functional AI Agent using Pydantic AI and the Mistral model.
You learned how to initialize an agent, run it, and structure its responses using Pydantic models — making the output both predictable and ready for integration into real applications. With this foundation in place, you’re ready to move on to more complex scenarios.

In the next part, we’ll build on this foundation by exploring how to handle dependencies, extend agent capabilities, and connect your AI Agent with external data sources.

💻 You can find the complete source code for this tutorial on GitHub
👉 github.com/hamluk/LearnPydanticAI

Top comments (0)