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]"
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>
For this, we’ll also install the python-dotenv package.
# install python-dotenv as dependency
poetry add python-dotenv
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
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)
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.
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
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
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
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).")
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
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)