You have a batch of 200 performance reviews. You need themes and an urgency score for each one. A single agent could try to do both — but what happens when you ask one model to summarise and classify in the same prompt?
compare_tones used two separate agents with different system prompts. I'd guess one agent doing both things at once is harder to constrain — the output format gets messier.
Exactly. Two concerns in one prompt means two failure modes. The structured approach is to chain them: one agent summarises, a second agent classifies the summary. The first uses a system prompt to keep it to two sentences; the second uses result_type=Literal["high","medium","low"] so it can only return one of three values:
from typing import Literal
def ai_pipeline(text: str) -> dict:
summarizer = Agent(model, system_prompt="Summarize in 2 sentences.")
classifier = Agent(model, result_type=Literal["high", "medium", "low"])
summary = summarizer.run_sync(text).output
urgency = classifier.run_sync(summary).output
return {"summary": summary, "urgency": urgency}Why pass summary into the classifier instead of passing the original text? Wouldn't the classifier get more signal from the full review?
The classifier works better on a compressed signal. A 2-sentence summary strips the noise — filler phrases, pleasantries, repeated context — so the Literal constraint isn't fighting a wall of ambiguous prose. Think of it as a two-step brief:
summary = summarizer.run_sync(text).output # step 1: compress
urgency = classifier.run_sync(summary).output # step 2: score the compressionSo the summary is doing double duty — it's both the deliverable and the cleaned input for the next step.
That's the pipeline mindset. Each agent has one job. The output of one is the input of the next — like a two-step brief where the first contractor distils and the second scores.
I'm chaining these like functions now. Summarise → classify → return a typed dict. This is a complete triage system in eight lines.
And it scales to 200 reviews without changing a line of the pipeline logic. Next you'll run this against a list of texts in a loop — batch classify an entire inbox in one pass.
Each agent in the pipeline has a single responsibility. The summariser compresses free text to two sentences; the classifier maps that summary to one of three Literal values.
Why chain on the summary, not the original text? A compressed signal reduces ambiguity for the classifier. Literal constraints work best when the input is already focused — passing raw prose risks the model hedging between labels.
.output on both agents. summarizer.run_sync(text).output is a string. classifier.run_sync(summary).output is one of "high", "medium", or "low" — enforced by PydanticAI before your code sees it.
Do not reuse the same Agent instance for both roles. Each agent carries its system_prompt and result_type configuration — two separate agents, two separate configs, clean separation.
You have a batch of 200 performance reviews. You need themes and an urgency score for each one. A single agent could try to do both — but what happens when you ask one model to summarise and classify in the same prompt?
compare_tones used two separate agents with different system prompts. I'd guess one agent doing both things at once is harder to constrain — the output format gets messier.
Exactly. Two concerns in one prompt means two failure modes. The structured approach is to chain them: one agent summarises, a second agent classifies the summary. The first uses a system prompt to keep it to two sentences; the second uses result_type=Literal["high","medium","low"] so it can only return one of three values:
from typing import Literal
def ai_pipeline(text: str) -> dict:
summarizer = Agent(model, system_prompt="Summarize in 2 sentences.")
classifier = Agent(model, result_type=Literal["high", "medium", "low"])
summary = summarizer.run_sync(text).output
urgency = classifier.run_sync(summary).output
return {"summary": summary, "urgency": urgency}Why pass summary into the classifier instead of passing the original text? Wouldn't the classifier get more signal from the full review?
The classifier works better on a compressed signal. A 2-sentence summary strips the noise — filler phrases, pleasantries, repeated context — so the Literal constraint isn't fighting a wall of ambiguous prose. Think of it as a two-step brief:
summary = summarizer.run_sync(text).output # step 1: compress
urgency = classifier.run_sync(summary).output # step 2: score the compressionSo the summary is doing double duty — it's both the deliverable and the cleaned input for the next step.
That's the pipeline mindset. Each agent has one job. The output of one is the input of the next — like a two-step brief where the first contractor distils and the second scores.
I'm chaining these like functions now. Summarise → classify → return a typed dict. This is a complete triage system in eight lines.
And it scales to 200 reviews without changing a line of the pipeline logic. Next you'll run this against a list of texts in a loop — batch classify an entire inbox in one pass.
Each agent in the pipeline has a single responsibility. The summariser compresses free text to two sentences; the classifier maps that summary to one of three Literal values.
Why chain on the summary, not the original text? A compressed signal reduces ambiguity for the classifier. Literal constraints work best when the input is already focused — passing raw prose risks the model hedging between labels.
.output on both agents. summarizer.run_sync(text).output is a string. classifier.run_sync(summary).output is one of "high", "medium", or "low" — enforced by PydanticAI before your code sees it.
Do not reuse the same Agent instance for both roles. Each agent carries its system_prompt and result_type configuration — two separate agents, two separate configs, clean separation.
Create a free account to get started. Paid plans unlock all tracks.