mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
.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 😄
This commit is contained in:
@@ -34,25 +34,46 @@ public static class Example54_AzureChatCompletionWithData
|
||||
var chatHistory = chatCompletion.CreateNewChat();
|
||||
|
||||
// First question without previous context based on uploaded content.
|
||||
chatHistory.AddUserMessage("How did Emily and David meet?");
|
||||
var ask = "How did Emily and David meet?";
|
||||
chatHistory.AddUserMessage(ask);
|
||||
|
||||
// Chat Completion example
|
||||
string reply = await chatCompletion.GenerateMessageAsync(chatHistory);
|
||||
var chatResult = (await chatCompletion.GetChatCompletionsAsync(chatHistory))[0];
|
||||
var chatMessage = await chatResult.GetChatMessageAsync();
|
||||
|
||||
// Output: Emily and David, both passionate scientists, met during a research expedition to Antarctica.
|
||||
Console.WriteLine(reply);
|
||||
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.
|
||||
chatHistory.AddUserMessage("What are Emily and David studying?");
|
||||
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:
|
||||
// They are passionate scientists who study glaciology,
|
||||
// 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);
|
||||
}
|
||||
@@ -65,6 +86,8 @@ public static class Example54_AzureChatCompletionWithData
|
||||
{
|
||||
Console.WriteLine("=== Example with Kernel ===");
|
||||
|
||||
var ask = "How did Emily and David meet?";
|
||||
|
||||
var completionWithDataConfig = GetCompletionWithDataConfig();
|
||||
|
||||
IKernel kernel = new KernelBuilder()
|
||||
@@ -74,21 +97,26 @@ public static class Example54_AzureChatCompletionWithData
|
||||
var semanticFunction = kernel.CreateSemanticFunction("Question: {{$input}}");
|
||||
|
||||
// First question without previous context based on uploaded content.
|
||||
var result = await kernel.RunAsync("How did Emily and David meet?", semanticFunction);
|
||||
var response = await kernel.RunAsync(ask, semanticFunction);
|
||||
|
||||
// Output: Emily and David, both passionate scientists, met during a research expedition to Antarctica.
|
||||
Console.WriteLine(result);
|
||||
// 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.
|
||||
result = await kernel.RunAsync("What are Emily and David studying?", semanticFunction);
|
||||
ask = "What are Emily and David studying?";
|
||||
response = await kernel.RunAsync(ask, semanticFunction);
|
||||
|
||||
// Output:
|
||||
// They are passionate scientists who study glaciology,
|
||||
// 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(result);
|
||||
|
||||
Console.WriteLine(Environment.NewLine);
|
||||
Console.WriteLine($"Ask: {ask}");
|
||||
Console.WriteLine($"Response: {response}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
+6
@@ -20,6 +20,12 @@ public class ChatWithDataModelResult
|
||||
/// </summary>
|
||||
public DateTimeOffset Created { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Content from data source, including citations.
|
||||
/// For more information see <see href="https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/use-your-data#conversation-history-for-better-results"/>.
|
||||
/// </summary>
|
||||
public string? ToolContent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ChatWithDataModelResult"/> class.
|
||||
/// </summary>
|
||||
|
||||
+12
-1
@@ -21,7 +21,10 @@ internal sealed class ChatWithDataResult : IChatResult, ITextResult
|
||||
Verify.NotNull(response);
|
||||
Verify.NotNull(choice);
|
||||
|
||||
this.ModelResult = new(new ChatWithDataModelResult(response.Id, DateTimeOffset.FromUnixTimeSeconds(response.Created)));
|
||||
this.ModelResult = new(new ChatWithDataModelResult(response.Id, DateTimeOffset.FromUnixTimeSeconds(response.Created))
|
||||
{
|
||||
ToolContent = this.GetToolContent(choice)
|
||||
});
|
||||
|
||||
this._choice = choice;
|
||||
}
|
||||
@@ -45,5 +48,13 @@ internal sealed class ChatWithDataResult : IChatResult, ITextResult
|
||||
|
||||
private readonly ChatWithDataChoice _choice;
|
||||
|
||||
private string? GetToolContent(ChatWithDataChoice choice)
|
||||
{
|
||||
var message = choice.Messages
|
||||
.FirstOrDefault(message => message.Role.Equals(AuthorRole.Tool.Label, StringComparison.Ordinal));
|
||||
|
||||
return message?.Content;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
+12
-1
@@ -23,7 +23,10 @@ internal sealed class ChatWithDataStreamingResult : IChatStreamingResult, ITextS
|
||||
Verify.NotNull(response);
|
||||
Verify.NotNull(choice);
|
||||
|
||||
this.ModelResult = new(new ChatWithDataModelResult(response.Id, DateTimeOffset.FromUnixTimeSeconds(response.Created)));
|
||||
this.ModelResult = new(new ChatWithDataModelResult(response.Id, DateTimeOffset.FromUnixTimeSeconds(response.Created))
|
||||
{
|
||||
ToolContent = this.GetToolContent(choice)
|
||||
});
|
||||
|
||||
this._choice = choice;
|
||||
}
|
||||
@@ -72,5 +75,13 @@ internal sealed class ChatWithDataStreamingResult : IChatStreamingResult, ITextS
|
||||
(message.Delta.Role is null || !message.Delta.Role.Equals(AuthorRole.Tool.Label, StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
private string? GetToolContent(ChatWithDataStreamingChoice choice)
|
||||
{
|
||||
var message = choice.Messages
|
||||
.FirstOrDefault(message => message.Delta.Role is not null && message.Delta.Role.Equals(AuthorRole.Tool.Label, StringComparison.Ordinal));
|
||||
|
||||
return message?.Delta?.Content;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user