Classification and span labeling
Assign one label, a set of labels, a taxonomy path, or marked spans.
Use a Literal for one label and a List[Literal] for multiple labels.
output_schema requests structured output and Agno attempts to parse it. A failed or unparseable run can leave content as text. Check RunStatus.completed and the expected Pydantic type before reading fields, indexing, or writing downstream. These examples stop on failure; an application can instead send the original input to a review queue. Schema validation checks the shape and constraints, so verify extracted facts against the source separately.
from agno.run.base import RunStatus
from typing import Literal
from agno.agent import Agent
from agno.models.google import Gemini
from pydantic import BaseModel, Field
class Classification(BaseModel):
label: Literal["positive", "negative", "neutral"] = Field(
..., description="The assigned sentiment label"
)
agent = Agent(
model=Gemini(id="gemini-3.5-flash"),
instructions="You classify product reviews by sentiment.",
output_schema=Classification,
)
result_run = agent.run("It works as described, nothing special.")
if result_run.status != RunStatus.completed or not isinstance(result_run.content, Classification):
raise RuntimeError("No validated Classification; send the input to review before continuing")
result = result_run.content
# Classification(label='neutral')For a successfully parsed result, Literal restricts the label to the values defined in the schema.
Multi-label
A review can touch several aspects. Return any subset.
from typing import List, Literal
from pydantic import BaseModel, Field
Aspect = Literal["food", "service", "value", "atmosphere", "cleanliness"]
class Tagging(BaseModel):
tags: List[Aspect] = Field(
..., description="Every aspect the reviewer commented on; empty if none"
)Hierarchical
For a taxonomy, return the parent and child path.
from typing import List, Literal
from pydantic import BaseModel, Field
Parent = Literal["sports", "politics", "tech", "business", "health"]
class HierarchicalTag(BaseModel):
parent: Parent
child: str = Field(..., description="Sub-category under the parent")
class Tagging(BaseModel):
tags: List[HierarchicalTag]Span labeling
Asking the model to count characters is unreliable. Have it return the exact substring and locate offsets in Python.
from agno.run.base import RunStatus
from typing import List, Literal
from agno.agent import Agent
from agno.models.google import Gemini
from pydantic import BaseModel, Field
class Entity(BaseModel):
text: str = Field(..., description="Exact substring from the input")
label: Literal["PERSON", "ORG", "LOCATION", "DATE"]
class Entities(BaseModel):
entities: List[Entity]
agent = Agent(
model=Gemini(id="gemini-3.5-flash"),
instructions=(
"Extract all named entities. Return the exact substring as it "
"appears, with its label. Do not paraphrase or normalize."
),
output_schema=Entities,
)
text = "On March 3rd, Sarah Johnson left Acme Corp to join Lumen Labs."
result_run = agent.run(text)
if result_run.status != RunStatus.completed or not isinstance(result_run.content, Entities):
raise RuntimeError("No validated Entities; send the input to review before continuing")
result = result_run.content
for e in result.entities:
start = text.find(e.text)
end = start + len(e.text) if start >= 0 else None
print(e.label, e.text, start, end)str.find() returns -1 when the returned text is not a verbatim substring, which is the signal that the model paraphrased despite the instructions. Guard the offset before you use it. find() also returns the first match only. When the same substring appears more than once, track the search offset or match occurrences in order before assigning spans.
The same shape drives PII redaction: detect the spans, then replace each with its tag in post-processing.
Choosing the shape
| You need | Schema |
|---|---|
| Exactly one label | Literal[...] |
| Any subset of labels | List[Literal[...]] |
| A taxonomy path | A model with parent / child |
| Marked substrings | A model with text + label, offsets in Python |
Other modalities
Image, audio, video, and document classification follow the same schema pattern with a different input argument. See Multimodal inputs.
| Modality | Cookbook |
|---|---|
| Image | image_classification |
| Audio | audio_classification |
| Video | video_classification |
| Document | document_classification |
Next steps
| Task | Guide |
|---|---|
| Extract typed fields | Data extraction |
| Score outputs against a rubric | LLM as judge |
| Add reviewer agreement | Quality pipeline |