Structured Output for Teams
Get a validated Pydantic object from a team instead of raw text.
Set output_schema on a team to constrain its final response to a Pydantic model. The team leader synthesizes member outputs into a validated object.
Setup
Install the dependencies in your Python environment and set your OpenAI API key:
pip install agno openai yfinance
export OPENAI_API_KEY="your-api-key"The later examples reuse the imports and members defined in Basic Usage.
Basic Usage
from pydantic import BaseModel, Field
from agno.agent import Agent
from agno.models.openai import OpenAIResponses
from agno.team import Team
from agno.tools.hackernews import HackerNewsTools
from agno.tools.yfinance import YFinanceTools
class ResearchReport(BaseModel):
title: str
summary: str = Field(description="Executive summary of findings")
key_insights: list[str] = Field(description="Top 3-5 insights")
recommendation: str
news_agent = Agent(
name="News Researcher",
role="Research tech news and trends",
tools=[HackerNewsTools()]
)
finance_agent = Agent(
name="Finance Analyst",
role="Analyze financial data and stocks",
tools=[YFinanceTools()]
)
team = Team(
name="Research Team",
model=OpenAIResponses(id="gpt-5.2"),
members=[news_agent, finance_agent],
output_schema=ResearchReport,
)
response = team.run("Research NVIDIA - analyze stock performance and recent news")
# Check that a structured result was returned before accessing fields
if not isinstance(response.content, ResearchReport):
raise ValueError(f"Expected ResearchReport, got: {response.content!r}")
report: ResearchReport = response.content
print(report.title)
print(report.summary)
print(report.recommendation)How It Works
In the default coordinate mode used above, a team with output_schema can:
- The team leader delegates tasks to members
- Members execute and return their results
- The leader synthesizes all member outputs
- The final response is structured according to your schema
In coordinate mode, the team's schema applies to its final output. Individual members use their own output_schema, if configured. In route mode (respond_directly=True), Agno passes the team's output schema to a selected member that has no schema, since that member supplies the final response directly.
Fallback parsing failures are logged and can leave response.content as a string. Check its type before accessing schema fields, including when you force JSON mode.
Control output_schema Per-Run
Override or set the schema at run time:
class MarketReport(BaseModel):
summary: str
trends: list[str]
class StockComparison(BaseModel):
symbols: list[str]
comparison: str
team = Team(
model=OpenAIResponses(id="gpt-5.2"),
members=[news_agent, finance_agent],
)
# Different schemas for different requests
report = team.run("Analyze AI market", output_schema=MarketReport)
comparison = team.run("Compare NVDA vs AMD", output_schema=StockComparison)Control output_schema Per Member/Team
You can set output_schema on both individual members and the team:
from pydantic import BaseModel, Field
from agno.agent import Agent
from agno.models.openai import OpenAIResponses
from agno.team import Team
from agno.tools.hackernews import HackerNewsTools
from agno.tools.yfinance import YFinanceTools
# Member schemas
class NewsInsights(BaseModel):
headlines: list[str]
sentiment: str = Field(description="positive, negative, or neutral")
class FinanceInsights(BaseModel):
price: float
change_percent: float
recommendation: str
# Team schema
class CombinedReport(BaseModel):
summary: str
market_sentiment: str
stock_outlook: str
final_recommendation: str
news_agent = Agent(
name="News Analyst",
role="Research news",
tools=[HackerNewsTools()],
output_schema=NewsInsights,
)
finance_agent = Agent(
name="Finance Analyst",
role="Analyze stocks",
tools=[YFinanceTools()],
output_schema=FinanceInsights,
)
team = Team(
model=OpenAIResponses(id="gpt-5.2"),
members=[news_agent, finance_agent],
output_schema=CombinedReport,
)
response = team.run("Full analysis of NVDA")
report: CombinedReport = response.contentMember schemas ensure consistent intermediate outputs. The team schema controls the final synthesized response.
Schema Design Tips
Aggregate Multiple Perspectives
Design schemas that capture synthesized insights:
class CompetitiveAnalysis(BaseModel):
company: str
market_position: str = Field(description="Leader, challenger, or follower")
technical_strengths: list[str] = Field(description="From technical research")
financial_strengths: list[str] = Field(description="From financial analysis")
combined_outlook: strInclude Confidence and Reasoning
class InvestmentRecommendation(BaseModel):
ticker: str
action: str = Field(description="buy, hold, or sell")
price_target: float | None = None
reasoning: str = Field(description="Synthesized reasoning from all analysts")
risk_factors: list[str]
confidence: float = Field(ge=0, le=1)Structured Comparisons
class CompanyComparison(BaseModel):
companies: list[str]
winner: str
comparison_criteria: list[str]
scores: dict[str, dict[str, int]] # company -> criterion -> score
summary: strJSON Mode
Agno uses a JSON fallback automatically when the model lacks native schema support. Set use_json_mode=True to force JSON mode for a model that supports native structured output:
team = Team(
model=OpenAIResponses(id="gpt-5.2"),
members=[news_agent, finance_agent],
output_schema=ResearchReport,
use_json_mode=True,
)JSON mode instructs the model to respond in JSON but doesn't guarantee schema compliance. Prefer models with native structured output support.
Related
- Agent Structured Output: Configure structured output for agents
- Team Structured Input: Validate input for teams
- Output Model: Use a separate model to structure output