Yesterday the agent summarized a snippet. Today you want a yes/no signal — is the top result actually relevant to the query, or did the engine surface something tangential?
A classifier. Feed in the snippet plus the query, ask the agent to decide. But how do I stop the model from returning "sort of relevant" or "mostly yes"?
result_type=Literal[...] — the same constraint tool from ai-for-beginners. Declare the two valid strings and the agent is forced to return exactly one of them:
from typing import Literal
agent = Agent(model, result_type=Literal["relevant", "off-topic"])
result = agent.run_sync(f"Query: {query} Snippet: {snippet} Is this relevant?")
print(result.output) # guaranteed "relevant" or "off-topic"So the two strings are a closed set. No "somewhat relevant" slipping through, no capitalization drift, no fallback branch in my code?
Exactly. Pydantic validates the response and retries invisibly if the model drifts. Your downstream code can compare against the exact strings with total confidence:
def classify_result_relevance(query: str) -> str:
results = search(query, count=5)
snippet = results[0]["snippet"]
agent = Agent(model, result_type=Literal["relevant", "off-topic"])
prompt = f"Query: {query} | Snippet: {snippet} | Is this relevant?"
return agent.run_sync(prompt).outputWould this be one line shorter if I chained .run_sync(...).output at the end?
Yes, and you could. Naming the agent first makes the result_type easier to read at a glance; inlining it is terser but denser. Both compile identically — choose for clarity on the day you write it. For a two-value classifier, the named-agent form reads naturally aloud: "build the agent, run it, return the label."
So the result is always one of two strings — I can branch on it directly, without any defensive normalization?
Exactly. That is the whole point of Literal as result_type — the downstream code gets simpler because the upstream promise is stronger. Week 2's agent is yesterday's unconstrained string; today's agent is a validated two-value label.
TL;DR: result_type=Literal["a", "b"] guarantees the output is one of two strings — no defensive code needed.
from typing import Literal — one import== against the exact strings| Output shape | Use |
|---|---|
| Two labels | Literal["a", "b"] |
| Three+ labels | Literal["a", "b"', "c"] |
| Free-form string | no result_type |
Every closed-set answer is a candidate for Literal — enum-level safety in one annotation.
Yesterday the agent summarized a snippet. Today you want a yes/no signal — is the top result actually relevant to the query, or did the engine surface something tangential?
A classifier. Feed in the snippet plus the query, ask the agent to decide. But how do I stop the model from returning "sort of relevant" or "mostly yes"?
result_type=Literal[...] — the same constraint tool from ai-for-beginners. Declare the two valid strings and the agent is forced to return exactly one of them:
from typing import Literal
agent = Agent(model, result_type=Literal["relevant", "off-topic"])
result = agent.run_sync(f"Query: {query} Snippet: {snippet} Is this relevant?")
print(result.output) # guaranteed "relevant" or "off-topic"So the two strings are a closed set. No "somewhat relevant" slipping through, no capitalization drift, no fallback branch in my code?
Exactly. Pydantic validates the response and retries invisibly if the model drifts. Your downstream code can compare against the exact strings with total confidence:
def classify_result_relevance(query: str) -> str:
results = search(query, count=5)
snippet = results[0]["snippet"]
agent = Agent(model, result_type=Literal["relevant", "off-topic"])
prompt = f"Query: {query} | Snippet: {snippet} | Is this relevant?"
return agent.run_sync(prompt).outputWould this be one line shorter if I chained .run_sync(...).output at the end?
Yes, and you could. Naming the agent first makes the result_type easier to read at a glance; inlining it is terser but denser. Both compile identically — choose for clarity on the day you write it. For a two-value classifier, the named-agent form reads naturally aloud: "build the agent, run it, return the label."
So the result is always one of two strings — I can branch on it directly, without any defensive normalization?
Exactly. That is the whole point of Literal as result_type — the downstream code gets simpler because the upstream promise is stronger. Week 2's agent is yesterday's unconstrained string; today's agent is a validated two-value label.
TL;DR: result_type=Literal["a", "b"] guarantees the output is one of two strings — no defensive code needed.
from typing import Literal — one import== against the exact strings| Output shape | Use |
|---|---|
| Two labels | Literal["a", "b"] |
| Three+ labels | Literal["a", "b"', "c"] |
| Free-form string | no result_type |
Every closed-set answer is a candidate for Literal — enum-level safety in one annotation.
Create a free account to get started. Paid plans unlock all tracks.