You want a name and an email out of a free-text intake message. What is the fragile way to do that?
Regex on the string, or .split(",") and hope the model formats it the same way every time?
Both break the moment the model rephrases. PydanticAI has a cleaner move: define a Python class describing the shape you want, and hand it to the agent as result_type. The agent guarantees the output matches that class:
from pydantic import BaseModel
class Contact(BaseModel):
name: str
email: str
result = Agent(model, result_type=Contact).run_sync(text)
print(result.output.name, result.output.email)result.output is a Contact instance, not a string. The .name and .email attributes are already extracted and typed.
So when result_type is set, result.output is a Pydantic object instead of a string?
Exactly. The type of result.output always matches whatever you pass to result_type. Pass a Contact class, get a Contact object. PydanticAI builds a JSON schema from the class, tells the model to produce JSON that fits, then validates and parses it for you. You never write a parser:
def extract_contact(text: str) -> dict:
result = Agent(model, result_type=Contact).run_sync(text)
return result.output.model_dump()Why .model_dump() at the end? Can I just return the Contact object?
You could, but the function type is dict — .model_dump() converts a Pydantic model into a plain Python dict. That makes it easy to JSON-serialize, insert into a database, or pass to a downstream function that expects a plain dict.
And if a field is missing from the input the model does its best — invents a placeholder or leaves it empty?
Right — the model will do its best; strict input validation is your job afterwards. For this lesson every test input has both a name and an email, so the extraction is clean. Write extract_contact(text) now: define the Contact class at the top, build the agent with result_type=Contact, return the dict from model_dump().
TL;DR: pass a Pydantic class as result_type — result.output is an instance of that class.
class Contact(BaseModel) — defines the fields and types you wantAgent(model, result_type=Contact) — forces output to fit the class.model_dump() — converts a model instance into a plain dictresult_type | result.output type |
|---|---|
| none | str |
Contact | Contact instance |
list[str] | list of strings |
PydanticAI builds a JSON schema from the class, validates the model's response, and retries on shape mismatches.
You want a name and an email out of a free-text intake message. What is the fragile way to do that?
Regex on the string, or .split(",") and hope the model formats it the same way every time?
Both break the moment the model rephrases. PydanticAI has a cleaner move: define a Python class describing the shape you want, and hand it to the agent as result_type. The agent guarantees the output matches that class:
from pydantic import BaseModel
class Contact(BaseModel):
name: str
email: str
result = Agent(model, result_type=Contact).run_sync(text)
print(result.output.name, result.output.email)result.output is a Contact instance, not a string. The .name and .email attributes are already extracted and typed.
So when result_type is set, result.output is a Pydantic object instead of a string?
Exactly. The type of result.output always matches whatever you pass to result_type. Pass a Contact class, get a Contact object. PydanticAI builds a JSON schema from the class, tells the model to produce JSON that fits, then validates and parses it for you. You never write a parser:
def extract_contact(text: str) -> dict:
result = Agent(model, result_type=Contact).run_sync(text)
return result.output.model_dump()Why .model_dump() at the end? Can I just return the Contact object?
You could, but the function type is dict — .model_dump() converts a Pydantic model into a plain Python dict. That makes it easy to JSON-serialize, insert into a database, or pass to a downstream function that expects a plain dict.
And if a field is missing from the input the model does its best — invents a placeholder or leaves it empty?
Right — the model will do its best; strict input validation is your job afterwards. For this lesson every test input has both a name and an email, so the extraction is clean. Write extract_contact(text) now: define the Contact class at the top, build the agent with result_type=Contact, return the dict from model_dump().
TL;DR: pass a Pydantic class as result_type — result.output is an instance of that class.
class Contact(BaseModel) — defines the fields and types you wantAgent(model, result_type=Contact) — forces output to fit the class.model_dump() — converts a model instance into a plain dictresult_type | result.output type |
|---|---|
| none | str |
Contact | Contact instance |
list[str] | list of strings |
PydanticAI builds a JSON schema from the class, validates the model's response, and retries on shape mismatches.
Create a free account to get started. Paid plans unlock all tracks.