extract_contact from yesterday uses result_type=Contact to guarantee the exact schema. Your inbox triage assigns urgency to co-author messages. classify_sentiment from Day 6 uses a system prompt and might return "High." with a period. How do you guarantee exactly "high" with no punctuation?
Use result_type=Literal["high","medium","low"]. The model must return one of those three strings exactly — like a pre-defined response category list. A Likert scale the model has to stay within.
That's it. No .strip().lower() needed. The Literal type enforces the constraint at the API level:
from typing import Literal
result = Agent(model, result_type=Literal["high", "medium", "low"]).run_sync(text)
return result.outputWhat happens if the model tries to return "urgent" because it thinks that fits better?
PydanticAI rejects the response and retries with a correction prompt explaining the model must return exactly one of the three values. If after retries it still fails, the call raises a validation error. The retry adds latency on edge cases; the guarantee is worth it for codebook-compliant classification.
So the Literal type is exactly like a pre-registered coding schema — the model can only mark cells that exist in my codebook. That's the methodological rigour I expect from any RA.
And it's reproducible. Every call returns "high", "medium", or "low" — you can aggregate, sort, and join without normalising strings first.
Forty co-author messages, three categories, no manual triage. Sort by urgency == "high", respond to those first. That's my Monday morning queue.
The triage queue is just a list filter:
labels = [classify_urgency(msg) for msg in messages]
high = [m for m, l in zip(messages, labels) if l == "high"]Urgency is a signal; your judgment on context is the second filter. The model classifies based on the content. Urgency is a signal; your judgment on context is the second filter.
from typing import Literal
result = Agent(model, result_type=Literal["high", "medium", "low"]).run_sync(text)
return result.output # guaranteed "high", "medium", or "low"| Approach | Guarantee | Retry on bad output? |
|---|---|---|
system_prompt | None — model may add punctuation | No |
result_type=Literal | Hard constraint | Yes — PydanticAI retries automatically |
Use system_prompt for format guidance where occasional variation is acceptable (summaries, rewrites). Use result_type=Literal for classifications that feed downstream sorting, filtering, or database writes — anywhere a period or capitalisation would break the pipeline.
extract_contact from yesterday uses result_type=Contact to guarantee the exact schema. Your inbox triage assigns urgency to co-author messages. classify_sentiment from Day 6 uses a system prompt and might return "High." with a period. How do you guarantee exactly "high" with no punctuation?
Use result_type=Literal["high","medium","low"]. The model must return one of those three strings exactly — like a pre-defined response category list. A Likert scale the model has to stay within.
That's it. No .strip().lower() needed. The Literal type enforces the constraint at the API level:
from typing import Literal
result = Agent(model, result_type=Literal["high", "medium", "low"]).run_sync(text)
return result.outputWhat happens if the model tries to return "urgent" because it thinks that fits better?
PydanticAI rejects the response and retries with a correction prompt explaining the model must return exactly one of the three values. If after retries it still fails, the call raises a validation error. The retry adds latency on edge cases; the guarantee is worth it for codebook-compliant classification.
So the Literal type is exactly like a pre-registered coding schema — the model can only mark cells that exist in my codebook. That's the methodological rigour I expect from any RA.
And it's reproducible. Every call returns "high", "medium", or "low" — you can aggregate, sort, and join without normalising strings first.
Forty co-author messages, three categories, no manual triage. Sort by urgency == "high", respond to those first. That's my Monday morning queue.
The triage queue is just a list filter:
labels = [classify_urgency(msg) for msg in messages]
high = [m for m, l in zip(messages, labels) if l == "high"]Urgency is a signal; your judgment on context is the second filter. The model classifies based on the content. Urgency is a signal; your judgment on context is the second filter.
from typing import Literal
result = Agent(model, result_type=Literal["high", "medium", "low"]).run_sync(text)
return result.output # guaranteed "high", "medium", or "low"| Approach | Guarantee | Retry on bad output? |
|---|---|---|
system_prompt | None — model may add punctuation | No |
result_type=Literal | Hard constraint | Yes — PydanticAI retries automatically |
Use system_prompt for format guidance where occasional variation is acceptable (summaries, rewrites). Use result_type=Literal for classifications that feed downstream sorting, filtering, or database writes — anywhere a period or capitalisation would break the pipeline.
Create a free account to get started. Paid plans unlock all tracks.