Files
semantic-kernel/dotnet/samples/KernelSyntaxExamples/Example54_AzureChatCompletionWithData.cs
T
Dmytro Struk 4d23e16d13 .Net: Fixed Azure Chat Completion with data example (#2663)
### 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.
-->

Problem: 
In case of using `AzureChatCompletion` directly, `ChatHistory` object
should be maintained on developers' side (`AddUserMessage` ->
`AddAssistantMessage` -> `AddUserMessage`).

In case of `AzureChatCompletionWithData`, Azure OpenAI API is different,
so `ChatHistory` should also contain message from `Tool`, which is the
new chat role, that contains information from data source of chat
response. The flow of `ChatHistory` maintenance should look like this -
`AddUserMessage` -> `AddToolMessage` -> `AddAssistantMessage` ->
`AddUserMessage`).

More information here:

https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/use-your-data#conversation-history-for-better-results

This PR contains changes to provide `Tool` content as part of model
result and update code example to maintain chat history, when using
`AzureChatCompletionWithData` directly.

### Description

<!-- Describe your changes, the overall approach, the underlying design.
These notes will help understanding how your code works. Thanks! -->
1. Added `Tool` content as part of model result.
2. Updated code example to maintain chat history and improve console
output.

### 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 😄
2023-09-01 13:17:17 +00:00

138 lines
5.3 KiB
C#

// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Threading.Tasks;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.AI.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.AI.OpenAI.ChatCompletionWithData;
/**
* This example shows how to use Azure OpenAI Chat Completion with data.
* More information: <see href="https://learn.microsoft.com/en-us/azure/ai-services/openai/use-your-data-quickstart"/>
*/
// ReSharper disable once InconsistentNaming
public static class Example54_AzureChatCompletionWithData
{
public static async Task RunAsync()
{
// Uploaded content in Azure Blob Storage in .txt file:
// Emily and David, two passionate scientists, met during a research expedition to Antarctica.
// Bonded by their love for the natural world and shared curiosity,
// they uncovered a groundbreaking phenomenon in glaciology that could
// potentially reshape our understanding of climate change.
await ExampleWithChatCompletion();
await ExampleWithKernel();
}
private static async Task ExampleWithChatCompletion()
{
Console.WriteLine("=== Example with Chat Completion ===");
var chatCompletion = new AzureChatCompletionWithData(GetCompletionWithDataConfig());
var chatHistory = chatCompletion.CreateNewChat();
// First question without previous context based on uploaded content.
var ask = "How did Emily and David meet?";
chatHistory.AddUserMessage(ask);
// Chat Completion example
var chatResult = (await chatCompletion.GetChatCompletionsAsync(chatHistory))[0];
var chatMessage = await chatResult.GetChatMessageAsync();
var response = chatMessage.Content;
var toolResponse = chatResult.ModelResult.GetResult<ChatWithDataModelResult>().ToolContent;
// Output
// Ask: How did Emily and David meet?
// Response: Emily and David, both passionate scientists, met during a research expedition to Antarctica.
Console.WriteLine($"Ask: {ask}");
Console.WriteLine($"Response: {response}");
Console.WriteLine();
// Chat history maintenance
if (!string.IsNullOrEmpty(toolResponse))
{
chatHistory.AddMessage(AuthorRole.Tool, toolResponse);
}
chatHistory.AddAssistantMessage(response);
// Second question based on uploaded content.
ask = "What are Emily and David studying?";
chatHistory.AddUserMessage(ask);
// Chat Completion Streaming example
Console.WriteLine($"Ask: {ask}");
Console.WriteLine("Response: ");
await foreach (var result in chatCompletion.GetStreamingChatCompletionsAsync(chatHistory))
{
await foreach (var message in result.GetStreamingChatMessageAsync())
{
// Output
// Ask: What are Emily and David studying?
// Response: They are passionate scientists who study glaciology,
// a branch of geology that deals with the study of ice and its effects.
Console.Write(message.Content);
}
}
Console.WriteLine(Environment.NewLine);
}
private static async Task ExampleWithKernel()
{
Console.WriteLine("=== Example with Kernel ===");
var ask = "How did Emily and David meet?";
var completionWithDataConfig = GetCompletionWithDataConfig();
IKernel kernel = new KernelBuilder()
.WithAzureChatCompletionService(config: completionWithDataConfig)
.Build();
var semanticFunction = kernel.CreateSemanticFunction("Question: {{$input}}");
// First question without previous context based on uploaded content.
var response = await kernel.RunAsync(ask, semanticFunction);
// Output
// Ask: How did Emily and David meet?
// Response: Emily and David, both passionate scientists, met during a research expedition to Antarctica.
Console.WriteLine($"Ask: {ask}");
Console.WriteLine($"Response: {response}");
Console.WriteLine();
// Second question based on uploaded content.
ask = "What are Emily and David studying?";
response = await kernel.RunAsync(ask, semanticFunction);
// Output
// Ask: What are Emily and David studying?
// Response: They are passionate scientists who study glaciology,
// a branch of geology that deals with the study of ice and its effects.
Console.WriteLine($"Ask: {ask}");
Console.WriteLine($"Response: {response}");
Console.WriteLine();
}
/// <summary>
/// Initializes a new instance of the <see cref="AzureChatCompletionWithDataConfig"/> class.
/// </summary>
private static AzureChatCompletionWithDataConfig GetCompletionWithDataConfig()
{
return new AzureChatCompletionWithDataConfig
{
CompletionModelId = TestConfiguration.AzureOpenAI.ChatDeploymentName,
CompletionEndpoint = TestConfiguration.AzureOpenAI.Endpoint,
CompletionApiKey = TestConfiguration.AzureOpenAI.ApiKey,
DataSourceEndpoint = TestConfiguration.ACS.Endpoint,
DataSourceApiKey = TestConfiguration.ACS.ApiKey,
DataSourceIndex = TestConfiguration.ACS.IndexName
};
}
}