Skip to content

Add quickstart for structured output #45979

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 2, 2025
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/ai/quickstarts/evaluate-ai-response.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ To provision an Azure OpenAI service and model using the Azure portal, complete

## Create the test app

Complete the following steps to create an MSTest project that connects to your local `phi3:mini` AI model.
Complete the following steps to create an MSTest project that connects to the `gpt-4o` AI model.

1. In a terminal window, navigate to the directory where you want to create your app, and create a new MSTest app with the `dotnet new` command:

Expand Down
66 changes: 66 additions & 0 deletions docs/ai/quickstarts/snippets/structured-output/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Configuration;

// <SnippetGetChatClient>
IConfigurationRoot config = new ConfigurationBuilder()
.AddUserSecrets<Program>()
.Build();

string endpoint = config["AZURE_OPENAI_ENDPOINT"];
string model = config["AZURE_OPENAI_GPT_NAME"];
string tenantId = config["AZURE_TENANT_ID"];

// Get a chat client for the Azure OpenAI endpoint.
AzureOpenAIClient azureClient =
new(
new Uri(endpoint),
new DefaultAzureCredential(new DefaultAzureCredentialOptions() { TenantId = tenantId }));
IChatClient chatClient = azureClient
.GetChatClient(deploymentName: model)
.AsIChatClient();
// </SnippetGetChatClient>

// <SnippetSimpleRequest>
string review = "I'm happy with the product!";
var response = await chatClient.GetResponseAsync<Sentiment>($"What's the sentiment of this review? {review}");
Console.WriteLine($"Sentiment: {response.Result}");
// </SnippetSimpleRequest>

// <SnippetMultipleReviews>
string[] inputs = [
"Best purchase ever!",
"Returned it immediately.",
"Hello",
"It works as advertised.",
"The packaging was damaged but otherwise okay."
];

foreach (var i in inputs)
{
var response2 = await chatClient.GetResponseAsync<Sentiment>($"What's the sentiment of this review? {i}");
Console.WriteLine($"Review: {i} | Sentiment: {response2.Result}");
}
// </SnippetMultipleReviews>

// <SnippetRecordRequest>
var review3 = "This product worked okay.";
var response3 = await chatClient.GetResponseAsync<SentimentRecord>($"What's the sentiment of this review? {review3}");

Console.WriteLine($"Response text: {response3.Result.ResponseText}");
Console.WriteLine($"Sentiment: {response3.Result.ReviewSentiment}");
// </SnippetRecordRequest>

// <SnippetInputOutputRecord>
record SentimentRecord(string ResponseText, Sentiment ReviewSentiment);
// </SnippetInputOutputRecord>

// <SnippetSentimentEnum>
public enum Sentiment
{
Positive,
Negative,
Neutral
}
// </SnippetSentimentEnum>
20 changes: 20 additions & 0 deletions docs/ai/quickstarts/snippets/structured-output/SOChat.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UserSecretsId>f28ec9ea-e017-46d7-9865-73550c9ec06b</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Azure.AI.OpenAI" Version="2.1.0" />
<PackageReference Include="Azure.Identity" Version="1.13.2" />
<PackageReference Include="Microsoft.Extensions.AI" Version="9.4.0-preview.1.25207.5" />
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="9.4.0-preview.1.25207.5" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.4" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.4" />
</ItemGroup>

</Project>
111 changes: 111 additions & 0 deletions docs/ai/quickstarts/structured-output.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
title: Quickstart - Request a response with structured output
description: Learn how to create a chat app that responds with structured output, that is, output that conforms to a type that you specify.
ms.date: 04/30/2025
ms.topic: quickstart
ms.custom: devx-track-dotnet, devx-track-dotnet-ai
---

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other AI quickstarts have a zone pivot for Azure OpenAI and OpenAI - is this something we want here as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a question for Jordan?

# Request a response with structured output

In this quickstart, you create a chat app that requests a response with *structured output*. A structured output response is a chat response that's of a type you specify instead of just plain text. The chat app you create in this quickstart analyzes sentiment of various product reviews, categorizing each review according to the values of a custom enumeration.

## Prerequisites

- [.NET 8 or a later version](https://dotnet.microsoft.com/download)
- [Visual Studio Code](https://code.visualstudio.com/) (optional)

## Configure the AI service

To provision an Azure OpenAI service and model using the Azure portal, complete the steps in the [Create and deploy an Azure OpenAI Service resource](/azure/ai-services/openai/how-to/create-resource?pivots=web-portal) article. In the "Deploy a model" step, select the `gpt-4o` model.

## Create the chat app

Complete the following steps to create a console app that connects to the `gpt-4o` AI model.

1. In a terminal window, navigate to the directory where you want to create your app, and create a new console app with the `dotnet new` command:

```dotnetcli
dotnet new console -o SOChat
```

1. Navigate to the `SOChat` directory, and add the necessary packages to your app:

```dotnetcli
dotnet add package Azure.AI.OpenAI
dotnet add package Azure.Identity
dotnet add package Microsoft.Extensions.AI --prerelease
dotnet add package Microsoft.Extensions.AI.OpenAI --prerelease
dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.UserSecrets
```

1. Run the following commands to add [app secrets](/aspnet/core/security/app-secrets) for your Azure OpenAI endpoint, model name, and tenant ID:

```bash
dotnet user-secrets init
dotnet user-secrets set AZURE_OPENAI_ENDPOINT <your-azure-openai-endpoint>
dotnet user-secrets set AZURE_OPENAI_GPT_NAME gpt-4o
dotnet user-secrets set AZURE_TENANT_ID <your-tenant-id>
```

(Depending on your environment, the tenant ID might not be needed. In that case, remove it from the code that instantiates the <xref:Azure.Identity.DefaultAzureCredential>.)

1. Open the new app in your editor of choice.

## Add the code

1. Define the enumeration that describes the different sentiments.

:::code language="csharp" source="./snippets/structured-output/Program.cs" id="SentimentEnum":::

1. Create the <xref:Microsoft.Extensions.AI.IChatClient> that will communicate with the model.

:::code language="csharp" source="./snippets/structured-output/Program.cs" id="GetChatClient":::

1. Send a request to the model with a single product review, and then print the analyzed sentiment to the console. You declare the requested structured output type by passing it as the type argument to the <xref:Microsoft.Extensions.AI.ChatClientStructuredOutputExtensions.GetResponseAsync``1(Microsoft.Extensions.AI.IChatClient,System.String,Microsoft.Extensions.AI.ChatOptions,System.Nullable{System.Boolean},System.Threading.CancellationToken)?displayProperty=nameWithType> extension method.

:::code language="csharp" source="./snippets/structured-output/Program.cs" id="SimpleRequest":::

This code produces output similar to:

```output
Sentiment: Positive
```

1. Instead of just analyzing a single review, you can analyze a collection of reviews.

:::code language="csharp" source="./snippets/structured-output/Program.cs" id="MultipleReviews":::

This code produces output similar to:

```output
Review: Best purchase ever! | Sentiment: Positive
Review: Returned it immediately. | Sentiment: Negative
Review: Hello | Sentiment: Neutral
Review: It works as advertised. | Sentiment: Neutral
Review: The packaging was damaged but otherwise okay. | Sentiment: Neutral
```

1. And instead of requesting just the analyzed enumeration value, you can request the text response along with the analyzed value.

Define a record type to contain the text response and analyzed sentiment:

:::code language="csharp" source="./snippets/structured-output/Program.cs" id="InputOutputRecord":::

Send the request using the record type as the type argument to `GetResponseAsync<T>`:

:::code language="csharp" source="./snippets/structured-output/Program.cs" id="RecordRequest":::

This code produces output similar to:

```output
Response text: Certainly, I have analyzed the sentiment of the review you provided.
Sentiment: Neutral
```

## See also

- [Structured outputs (Azure OpenAI Service)](/azure/ai-services/openai/how-to/structured-outputs)
- [Using JSON schema for structured output in .NET for OpenAI models](https://devblogs.microsoft.com/semantic-kernel/using-json-schema-for-structured-output-in-net-for-openai-models)
- [Introducing Structured Outputs in the API (OpenAI)](https://openai.com/index/introducing-structured-outputs-in-the-api/)
2 changes: 2 additions & 0 deletions docs/ai/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ items:
items:
- name: Build a chat app
href: quickstarts/build-chat-app.md
- name: Request structured output
href: quickstarts/structured-output.md
- name: Build a .NET AI vector search app
href: quickstarts/build-vector-search-app.md
- name: Execute a local .NET function
Expand Down