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 needSchema
Exactly one labelLiteral[...]
Any subset of labelsList[Literal[...]]
A taxonomy pathA model with parent / child
Marked substringsA 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.

Next steps

TaskGuide
Extract typed fieldsData extraction
Score outputs against a rubricLLM as judge
Add reviewer agreementQuality pipeline

Developer Resources