AutoGen Tutorial (Python): parsing structured output for advanced developers

By Cyprian AaronsUpdated 2026-04-21
autogenparsing-structured-output-for-advanced-developerspython

This tutorial shows you how to get AutoGen agents to return structured data in Python and parse it reliably into typed objects. You need this when free-form LLM text is too brittle for downstream code, especially if you’re feeding results into workflows, validation layers, or databases.

What You'll Need

  • Python 3.10+
  • pyautogen installed
  • A valid OpenAI API key
  • Basic familiarity with AutoGen AssistantAgent and UserProxyAgent
  • Optional but useful:
    • pydantic for schema validation
    • python-dotenv for local environment variables

Install the packages:

pip install pyautogen pydantic python-dotenv

Set your API key:

export OPENAI_API_KEY="your-key-here"

Step-by-Step

  1. Start by defining the structure you want back from the model. For production work, a Pydantic model is the cleanest way to enforce field names, types, and defaults.
from pydantic import BaseModel, Field
from typing import Literal

class ClaimSummary(BaseModel):
    claim_id: str = Field(..., description="Unique claim identifier")
    status: Literal["approved", "denied", "needs_review"]
    amount_usd: float
    risk_notes: list[str]
  1. Next, configure an AutoGen assistant that is explicitly instructed to return JSON matching your schema. Keep the prompt strict; parsing becomes much easier when the model is told not to add extra prose.
import os
from autogen import AssistantAgent

llm_config = {
    "model": "gpt-4o-mini",
    "api_key": os.environ["OPENAI_API_KEY"],
    "temperature": 0,
}

assistant = AssistantAgent(
    name="claims_assistant",
    llm_config=llm_config,
    system_message=(
        "You extract insurance claim summaries.\n"
        "Return only valid JSON.\n"
        "Do not wrap output in markdown.\n"
        "Use keys: claim_id, status, amount_usd, risk_notes."
    ),
)
  1. Send a task that asks for structured output and capture the raw response. In real systems, this raw string is what you validate before allowing anything downstream to consume it.
from autogen import UserProxyAgent

user = UserProxyAgent(
    name="user",
    human_input_mode="NEVER",
    code_execution_config=False,
)

message = (
    "Summarize this claim:\n"
    "Claim ID: CLM-1042\n"
    "Amount: 1250.50 USD\n"
    "Decision: approved\n"
    "Notes: Minor windshield damage; no prior incidents."
)

response = user.initiate_chat(
    assistant,
    message=message,
)
print(response.chat_history[-1]["content"])
  1. Parse the assistant response into your Pydantic model. If the model output drifts from the schema, this is where you catch it before bad data enters your pipeline.
import json

raw_output = response.chat_history[-1]["content"]
data = json.loads(raw_output)
claim = ClaimSummary.model_validate(data)

print(claim)
print(claim.status)
print(claim.model_dump())
  1. Add a retry path for malformed JSON. In production, you should assume some percentage of responses will be invalid and recover by sending the parser error back to the agent with a stricter correction prompt.
def parse_claim(raw_text: str) -> ClaimSummary:
    try:
        return ClaimSummary.model_validate(json.loads(raw_text))
    except Exception as e:
        raise ValueError(f"Invalid structured output: {e}") from e

try:
    parsed = parse_claim(raw_output)
except ValueError as err:
    repair_prompt = (
        f"Your previous output was invalid JSON or did not match schema.\n"
        f"Error: {err}\n"
        f"Return only valid JSON with keys claim_id, status, amount_usd, risk_notes."
    )
    repaired = user.initiate_chat(assistant, message=repair_prompt)
    parsed = parse_claim(repaired.chat_history[-1]["content"])

print(parsed.claim_id)
  1. If you want a stronger contract, make the agent emit a minimal JSON object and validate every field before use. This pattern is what you want in banking or insurance workflows where downstream systems expect deterministic inputs.
def process_claim(claim_data: ClaimSummary) -> dict:
    return {
        "claim_id": claim_data.claim_id,
        "decision": claim_data.status,
        "reserve_amount": round(claim_data.amount_usd * 0.8, 2),
        "flags": claim_data.risk_notes,
    }

result = process_claim(parsed)
print(result)

Testing It

Run the script against a few different claim descriptions and inspect both valid and invalid outputs. You want to verify that clean cases parse directly and that malformed responses trigger your repair path instead of crashing later in the workflow.

Also test edge cases like missing fields, numeric values returned as strings, or extra commentary outside JSON. If you’re using this in production, log both the raw response and validation errors so you can measure failure rates over time.

A good final check is to feed the parsed object into a downstream function that expects typed data only. If that function runs without defensive string handling or ad hoc cleanup logic, your structured-output layer is doing its job.

Next Steps

  • Learn AutoGen tool calling so agents can produce structured outputs through function execution instead of plain text.
  • Add JSON Schema validation if you need stricter interoperability across services.
  • Build a retry-and-repair wrapper around AssistantAgent for high-volume extraction pipelines.

Keep learning

By Cyprian Aarons, AI Consultant at Topiax.

Want the complete 8-step roadmap?

Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.

Get the Starter Kit

Related Guides