You want an agent that reads a short situation and returns exactly one of three words — escalate, automate, or ignore. How do you stop the model from saying "Escalate, because..." instead of just "escalate"?
Some kind of system prompt telling it to answer in one word? Or parse the string and hope it contains one of the labels?
You could, but there is a cleaner contract. typing.Literal as result_type tells PydanticAI the only valid strings. The model now has to return one of them — nothing else validates. The smallest call:
from typing import Literal
agent = Agent(model, result_type=Literal["escalate", "automate", "ignore"])
result = agent.run_sync("Database is on fire")
print(result.output)So the type annotation is the prompt? I do not have to write "answer only with one of these"?
The type annotation becomes the contract. PydanticAI builds a JSON schema from Literal[...], passes it to the model as a structured-output constraint, and validates the reply. If the model drifts, the library retries. Wrapped in a function:
def decide_action(situation: str) -> str:
agent = Agent(model, result_type=Literal["escalate", "automate", "ignore"])
result = agent.run_sync(situation)
return result.outputAnd result.output is already one of the three strings? No .strip().lower() safety net needed?
Not needed. With result_type=Literal[...], result.output is validated to be exactly one of the members. Pydantic rejects anything else before your code ever sees it. That is the payoff of using a type instead of a prompt.
So the same agent handles "Server down" and "Weekly digest email" — one function, any situation, a clean routable label out?
One function, any input, a typed decision. This is the smallest unit of an agent loop — a call that returns a discrete action, ready for your code to route on.
TL;DR: result_type=Literal["a","b","c"] forces the agent to return one of the listed strings.
Literal[...] — closed set of allowed outputsresult.output is already one of the membersWithout result_type | With Literal |
|---|---|
| Might return "Escalate." | Returns exactly "escalate" |
You strip().lower() | No post-processing |
| Silent drift possible | Validator fails fast |
Use Literal whenever the decision space is finite and known at code time.
You want an agent that reads a short situation and returns exactly one of three words — escalate, automate, or ignore. How do you stop the model from saying "Escalate, because..." instead of just "escalate"?
Some kind of system prompt telling it to answer in one word? Or parse the string and hope it contains one of the labels?
You could, but there is a cleaner contract. typing.Literal as result_type tells PydanticAI the only valid strings. The model now has to return one of them — nothing else validates. The smallest call:
from typing import Literal
agent = Agent(model, result_type=Literal["escalate", "automate", "ignore"])
result = agent.run_sync("Database is on fire")
print(result.output)So the type annotation is the prompt? I do not have to write "answer only with one of these"?
The type annotation becomes the contract. PydanticAI builds a JSON schema from Literal[...], passes it to the model as a structured-output constraint, and validates the reply. If the model drifts, the library retries. Wrapped in a function:
def decide_action(situation: str) -> str:
agent = Agent(model, result_type=Literal["escalate", "automate", "ignore"])
result = agent.run_sync(situation)
return result.outputAnd result.output is already one of the three strings? No .strip().lower() safety net needed?
Not needed. With result_type=Literal[...], result.output is validated to be exactly one of the members. Pydantic rejects anything else before your code ever sees it. That is the payoff of using a type instead of a prompt.
So the same agent handles "Server down" and "Weekly digest email" — one function, any situation, a clean routable label out?
One function, any input, a typed decision. This is the smallest unit of an agent loop — a call that returns a discrete action, ready for your code to route on.
TL;DR: result_type=Literal["a","b","c"] forces the agent to return one of the listed strings.
Literal[...] — closed set of allowed outputsresult.output is already one of the membersWithout result_type | With Literal |
|---|---|
| Might return "Escalate." | Returns exactly "escalate" |
You strip().lower() | No post-processing |
| Silent drift possible | Validator fails fast |
Use Literal whenever the decision space is finite and known at code time.
Create a free account to get started. Paid plans unlock all tracks.