π¦ Structured Output
Get strongly-typed C# objects directly from the LLM β no manual JSON parsing required.
LLMs are excellent at extracting and transforming data. Structured output takes this further by constraining the model to return valid JSON that matches a specific schema β which Agent Framework automatically deserialises into a C# type.
The generic overload RunAsync<T>() accepts any class or C# record as the
type parameter. Agent Framework generates a JSON Schema from the type and passes it to the
model as a response format constraint. The model's output is then deserialised and returned
as a strongly-typed instance of T.
This pattern is ideal for data extraction, classification, entity recognition, content generation in structured form, and any scenario where you need predictable, parse-safe output.
Key Concepts
- RunAsync<T>() β generic overload that returns a deserialised
T - C# records β concise syntax for defining the output schema
- JSON Schema generation β Agent Framework generates the schema from your type automatically
- Model constraints β the model is instructed to return only valid JSON matching the schema
- [Description] attribute β annotate properties to improve model accuracy
NuGet Packages
dotnet add package Microsoft.Agents.AI.OpenAI --prerelease
dotnet add package Azure.AI.OpenAI --prerelease
dotnet add package Azure.Identity
Code Sample β Weather Forecast
using System.ComponentModel;
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
// 1. Define the output schema using a C# record.
// Use [Description] attributes to guide the model for each property.
record WeatherForecast(
[property: Description("The city name")]
string City,
[property: Description("The forecast high temperature in Celsius")]
int HighCelsius,
[property: Description("Short description of conditions, e.g. 'Sunny', 'Partly cloudy'")]
string Conditions,
[property: Description("Chance of rain as a percentage, 0-100")]
int RainChancePercent
);
AIAgent agent = new AzureOpenAIClient(
new Uri(Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")!),
new AzureCliCredential())
.GetChatClient("gpt-4o-mini")
.AsAIAgent(instructions: "You are a weather data assistant. Always respond in valid JSON.");
// 2. Use the generic RunAsync<T> to get a strongly-typed result.
WeatherForecast forecast = await agent.RunAsync<WeatherForecast>(
"What is the typical weather forecast for Seattle in July?");
// 3. Use the result like any other C# object β no JSON parsing needed.
Console.WriteLine($"City: {forecast.City}");
Console.WriteLine($"High: {forecast.HighCelsius}Β°C");
Console.WriteLine($"Conditions: {forecast.Conditions}");
Console.WriteLine($"Rain chance: {forecast.RainChancePercent}%");
Code Sample β Data Extraction
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
// Extract structured data from unstructured text.
record PersonInfo(string Name, int? Age, string? Email, string? Company);
AIAgent agent = new AzureOpenAIClient(
new Uri(Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")!),
new AzureCliCredential())
.GetChatClient("gpt-4o-mini")
.AsAIAgent(instructions: "Extract the requested information from the provided text. " +
"Use null for any fields not present in the text.");
string emailText = """
Hi, I'm Sarah Johnson, 34 years old, and I work at Contoso Ltd.
You can reach me at sarah.johnson@contoso.com for further details.
""";
PersonInfo person = await agent.RunAsync<PersonInfo>(
$"Extract person information from this text:\n\n{emailText}");
Console.WriteLine($"Name: {person.Name}");
Console.WriteLine($"Age: {person.Age}");
Console.WriteLine($"Email: {person.Email}");
Console.WriteLine($"Company: {person.Company}");
Step-by-Step Explanation
-
Define a C# record (or class) β Each property maps to a field in the JSON
output. C# records are ideal because they are concise and immutable. Use nullable types
(
string?,int?) for optional fields. -
Annotate with
[Description]β Adding descriptions to properties helps the model understand what each field represents, improving accuracy. -
Call
RunAsync<T>()β Agent Framework generates a JSON Schema from your type, constrains the model's output format, and deserialises the JSON response. - Use the result β The returned object is a fully deserialised instance of your type. Access properties directly with full IntelliSense and type checking.
Next Steps
All Examples
- π€ Hello Agent
- π§ Function Tools
- π¬ Multi-Turn Conversations
- β‘ Streaming Responses
- π¦ Structured Output
- π Sequential Workflows
- πΈοΈ Multi-Agent Orchestration
- π¦ Ollama β Local AI
- π₯οΈ LM Studio β Local AI
- π§ Agent Memory
- π RAG
- π MCP Tools
- π OpenTelemetry
- π§ Customer Support Triage
- π¬ Research Pipeline
- π€ Tools vs Sub-Agents
Concepts Used
π Running Agents Docs