Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
ag2ai avatar

Ag2 Structured Output

  • 33 installs
  • 8 repo stars
  • Updated July 27, 2026
  • ag2ai/ag2-skills

ag2-structured-output is a Claude Code skill that configures an AG2 beta Agent to return a typed, validated Python value via response_schema= instead of free text.

About

This skill shows how to get a typed, validated Python value back from an AG2 beta Agent instead of free text. A developer passes response_schema= (a Pydantic model, dataclass, primitive, union, ResponseSchema, or @response_schema validator) and reads the parsed result via await reply.content(). It is used for classification, extraction, scoring, and normalisation where downstream code parses the reply, and it covers validation retries and PromptedSchema for providers without native structured output.

  • Return typed Python values from an AG2 beta Agent via response_schema= instead of parsing free text
  • Supports Pydantic models, dataclasses, primitives, unions, ResponseSchema, and @response_schema validators
  • Handles validation retries and PromptedSchema for providers without native structured output

Ag2 Structured Output by the numbers

  • 33 all-time installs (skills.sh)
  • Ranked #8,968 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
  • Data as of Aug 1, 2026 (Skillselion catalog sync)
At a glance

ag2-structured-output capabilities & compatibility

Free skill; requires an LLM provider API key (e.g. OpenAI) to run the agent.

Capabilities
structured output · schema validation · data extraction · classification
Use cases
data analysis
Pricing
Bring your own API key
From the docs

What ag2-structured-output says it does

Get a typed Python value back from an AG2 beta `Agent` instead of free text.
SKILL.md
reply.body` is still the raw model text; `await reply.content()` runs validation and returns the parsed value.
SKILL.md
npx skills add https://github.com/ag2ai/ag2-skills --skill ag2-structured-output

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs33
repo stars8
Last updatedJuly 27, 2026
Repositoryag2ai/ag2-skills

What it does

Configure an AG2 beta agent to return a validated Pydantic model or typed value for classification, extraction, or scoring.

Who is it for?

Developers building AG2 beta agents that need validated structured output (classification, extraction, scoring).

Skip if: Multi-agent orchestration or plain string replies.

When should I use this skill?

The user wants a Pydantic model, dataclass, dict, primitive, or union back from an AG2 agent rather than a string.

What you get

The agent returns a typed, validation-checked value with automatic retry on failure.

  • AG2 Agent configured with response_schema
  • typed parsed reply via reply.content()

By the numbers

  • 8 schema types listed in the schema-types table

Files

SKILL.mdMarkdownGitHub ↗

Structured output

When to use

  • The user wants a Pydantic model, dataclass, dict, primitive, or union back — not a string.
  • They're doing classification, extraction, scoring, normalisation, or anything where downstream code parses the reply.
  • They want automatic retry on validation failure.

60-second recipe

from pydantic import BaseModel, Field
from typing import Annotated

from autogen.beta import Agent
from autogen.beta.config import OpenAIConfig

class TicketTriage(BaseModel):
    category: Annotated[str, Field(description="e.g. billing, bug, account_access")]
    urgency: Annotated[str, Field(description="low, medium, or high")]
    summary_one_line: Annotated[str, Field(description="Max 120 characters", max_length=120)]

agent = Agent(
    "triage",
    prompt="You triage support messages. Be conservative with urgency.",
    config=OpenAIConfig(model="gpt-4o-mini"),
    response_schema=TicketTriage,
)

reply = await agent.ask("I was charged twice and can't export reports. Quarter close blocked.")
triage = await reply.content()      # → typed TicketTriage
print(triage.category, triage.urgency)

reply.body is still the raw model text; await reply.content() runs validation and returns the parsed value. If validation fails, content() raises (e.g. pydantic.ValidationError).

Schema types you can pass

TypeWhat you get
Primitive (int, float, bool)Bare value, framework wraps in {"data": ...} for the API
dataclassInstance of the dataclass
Pydantic BaseModelInstance of the model
Union (`int \str, (int, str)`)
dict[K, V], TypedDictValidated dict
ResponseSchema(...)Same as above, with explicit name / description for the provider
@response_schema callableCustom validation/parsing logic
PromptedSchema(inner)Schema injected into the system prompt for providers without native structured output

ResponseSchema — name your payload

Helps the provider treat the structured output as a named contract:

from autogen.beta import Agent, ResponseSchema

schema = ResponseSchema(int | str, name="ByteWidth", description="Number of bits in one byte.")
agent = Agent("assistant", config=config, response_schema=schema)

@response_schema — custom validation

For clamping, regex cleanup, decoding wrapped JSON, or combining fields:

from autogen.beta import Agent, response_schema

@response_schema
def parse_rating(content: str) -> int:
    """Parse a rating and clamp to 1–5."""
    return max(1, min(5, int(content)))

agent = Agent("assistant", config=config, response_schema=parse_rating)

Multi-parameter form synthesises a JSON object schema from the parameter names:

from typing import Annotated
from pydantic import Field
from autogen.beta import response_schema

@response_schema
def extract_listing(
    title: Annotated[str, Field(description="Product name")],
    price_usd: Annotated[float, Field(description="Price in USD", ge=0)],
    in_stock: Annotated[bool, Field(description="True if it ships now")],
) -> dict:
    return {"title": title, "price_usd": price_usd, "in_stock": in_stock}

The function also participates in dependency injection — Context, Variable, Inject, Depends work the same way as in tools (and don't appear in the JSON schema).

Async validators are supported:

import json

@response_schema
async def fetch_and_validate(content: str) -> dict:
    data = json.loads(content)
    data["validated"] = True
    return data

PromptedSchema — for providers without native structured output

Injects the JSON schema into the system prompt instead of using response_format:

from autogen.beta import Agent, PromptedSchema

agent = Agent("assistant", config=config, response_schema=PromptedSchema(int))

Wraps any inner schema (type, ResponseSchema, @response_schema callable). The validation logic stays the same; only the wire format changes.

Custom prompt template:

PromptedSchema(int, prompt_template="Reply with JSON matching this schema:\n{schema}")

Per-turn override

agent = Agent("assistant", config=config)

turn = await agent.ask("How many seconds in a minute?", response_schema=int)
print(await turn.content())   # 60

turn2 = await turn.ask("Say hello.")     # back to default (no schema)

Pass response_schema=None to drop a schema set on the agent for one call.

Retries

When validation fails, automatically re-ask the model:

result = await reply.content(retries=3)   # initial + up to 3 re-asks
result = await reply.content(retries=math.inf)   # interactive only — could loop forever

The validation error is sent back to the model as a follow-up so it can correct itself.

Primitive embedding (embed)

Bare primitives (int, float, bool, list[T], primitive unions) get wrapped in {"data": ...} by default — most structured-output APIs handle objects more reliably than bare values. content() transparently unwraps. Opt out:

ResponseSchema(int, name="RawInt", embed=False)              # model must produce a bare 42
@response_schema(embed=False)
def parse_rating(value: int) -> int: ...

Going deeper

  • Working starter: assets/recipe_builder.py (mirrors code_examples/02) — Pydantic model + @tool + response_schema=.
  • Full reference: website/docs/beta/structured_output.mdx — covers every schema type, multi-param @response_schema, Field constraints, PromptedSchema, retries, embedding semantics.

Common pitfalls

  • Reading `reply.body` when you wanted typed outputreply.body is the raw text. await reply.content() does the parsing.
  • Forgetting `await` on `content()` — it's async; you'll get a coroutine, not the value.
  • No `description` in the Pydantic field — the LLM may guess what to put in each field. Add a Field(description=...) for every non-obvious key.
  • Provider doesn't support native structured output — wrap with PromptedSchema(...) rather than fighting the API.
  • `retries=math.inf` in production — will loop forever on a model that can't comply. Use a finite count.
  • Per-turn override is single-turn — passing response_schema=int to one ask() doesn't change the agent's default. The next turn returns to whatever was set on the constructor.

Related skills

FAQ

How do I get a typed value from an AG2 agent?

Pass response_schema= (a Pydantic model, dataclass, primitive, union, ResponseSchema, or @response_schema validator) and read the parsed result via await reply.content().

What happens if validation fails?

content() raises (e.g. pydantic.ValidationError); you can pass retries= to automatically re-ask the model with the validation error as a follow-up.

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.