Skip to content

Commit a12b433

Browse files
authored
.Net: Added Structured Output example with Azure OpenAI and Function Calling (#11447)
### Motivation and Context <!-- Thank you for your contribution to the semantic-kernel repo! Please help reviewers and future users, providing the following information: 1. Why is this change required? 2. What problem does it solve? 3. What scenario does it contribute to? 4. If it fixes an open issue, please link to the issue here. --> Resolves: #9768 Added an example how to use Structured Outputs with Azure OpenAI and Function Calling. ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [x] The code builds clean without any errors or warnings - [x] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [x] All unit tests pass, and I have added new tests where possible - [x] I didn't break anyone 😄
1 parent 072c476 commit a12b433

File tree

1 file changed

+56
-6
lines changed

1 file changed

+56
-6
lines changed

dotnet/samples/Concepts/ChatCompletion/OpenAI_StructuredOutputs.cs

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Text.Json;
44
using Azure.Identity;
55
using Microsoft.SemanticKernel;
6+
using Microsoft.SemanticKernel.Connectors.AzureOpenAI;
67
using Microsoft.SemanticKernel.Connectors.OpenAI;
78
using OpenAI.Chat;
89

@@ -143,13 +144,13 @@ public async Task StructuredOutputsWithTypeInExecutionSettingsAsync()
143144
}
144145

145146
/// <summary>
146-
/// This method shows how to use Structured Outputs feature in combination with Function Calling.
147+
/// This method shows how to use Structured Outputs feature in combination with Function Calling and OpenAI models.
147148
/// <see cref="EmailPlugin.GetEmails"/> function returns a <see cref="List{T}"/> of email bodies.
148149
/// As for final result, the desired response format should be <see cref="Email"/>, which contains additional <see cref="Email.Category"/> property.
149150
/// This shows how the data can be transformed with AI using strong types without additional instructions in the prompt.
150151
/// </summary>
151152
[Fact]
152-
public async Task StructuredOutputsWithFunctionCallingAsync()
153+
public async Task StructuredOutputsWithFunctionCallingOpenAIAsync()
153154
{
154155
// Initialize kernel.
155156
Kernel kernel = Kernel.CreateBuilder()
@@ -164,7 +165,57 @@ public async Task StructuredOutputsWithFunctionCallingAsync()
164165
var executionSettings = new OpenAIPromptExecutionSettings
165166
{
166167
ResponseFormat = typeof(EmailResult),
167-
ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
168+
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
169+
};
170+
171+
// Send a request and pass prompt execution settings with desired response format.
172+
var result = await kernel.InvokePromptAsync("Process the emails.", new(executionSettings));
173+
174+
// Deserialize string response to a strong type to access type properties.
175+
// At this point, the deserialization logic won't fail, because EmailResult type was specified as desired response format.
176+
// This ensures that response string is a serialized version of EmailResult type.
177+
var emailResult = JsonSerializer.Deserialize<EmailResult>(result.ToString())!;
178+
179+
// Output the result.
180+
this.OutputResult(emailResult);
181+
182+
// Output:
183+
184+
// Email #1
185+
// Body: Let's catch up over coffee this Saturday. It's been too long!
186+
// Category: Social
187+
188+
// Email #2
189+
// Body: Please review the attached document and provide your feedback by EOD.
190+
// Category: Work
191+
192+
// ...and more...
193+
}
194+
195+
/// <summary>
196+
/// This method shows how to use Structured Outputs feature in combination with Function Calling and Azure OpenAI models.
197+
/// <see cref="EmailPlugin.GetEmails"/> function returns a <see cref="List{T}"/> of email bodies.
198+
/// As for final result, the desired response format should be <see cref="Email"/>, which contains additional <see cref="Email.Category"/> property.
199+
/// This shows how the data can be transformed with AI using strong types without additional instructions in the prompt.
200+
/// </summary>
201+
[Fact]
202+
public async Task StructuredOutputsWithFunctionCallingAzureOpenAIAsync()
203+
{
204+
// Initialize kernel.
205+
Kernel kernel = Kernel.CreateBuilder()
206+
.AddAzureOpenAIChatCompletion(
207+
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
208+
endpoint: TestConfiguration.AzureOpenAI.Endpoint,
209+
credentials: new AzureCliCredential())
210+
.Build();
211+
212+
kernel.ImportPluginFromType<EmailPlugin>();
213+
214+
// Specify response format by setting Type object in prompt execution settings and enable automatic function calling.
215+
var executionSettings = new AzureOpenAIPromptExecutionSettings
216+
{
217+
ResponseFormat = typeof(EmailResult),
218+
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
168219
};
169220

170221
// Send a request and pass prompt execution settings with desired response format.
@@ -204,12 +255,11 @@ public async Task StructuredOutputsWithAzureOpenAIAsync()
204255
.AddAzureOpenAIChatCompletion(
205256
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
206257
endpoint: TestConfiguration.AzureOpenAI.Endpoint,
207-
credentials: new AzureCliCredential(),
208-
apiVersion: "2024-08-01-preview")
258+
credentials: new AzureCliCredential())
209259
.Build();
210260

211261
// Specify response format by setting Type object in prompt execution settings.
212-
var executionSettings = new OpenAIPromptExecutionSettings
262+
var executionSettings = new AzureOpenAIPromptExecutionSettings
213263
{
214264
ResponseFormat = typeof(MovieResult)
215265
};

0 commit comments

Comments
 (0)