-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
.Net: Sample showing function calling using NexusRaven (#7256)
### Motivation and Context Closes #7190 ### Description <!-- Describe your changes, the overall approach, the underlying design. These notes will help understanding how your code works. Thanks! --> ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [ ] The code builds clean without any errors or warnings - [ ] 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 - [ ] All unit tests pass, and I have added new tests where possible - [ ] I didn't break anyone 😄
- Loading branch information
1 parent
f2bd420
commit a335d55
Showing
12 changed files
with
436 additions
and
32 deletions.
There are no files selected for viewing
146 changes: 146 additions & 0 deletions
146
dotnet/samples/Concepts/FunctionCalling/NexusRaven_FunctionCalling.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
using System.Text; | ||
using Microsoft.SemanticKernel; | ||
using Microsoft.SemanticKernel.Connectors.HuggingFace; | ||
using Microsoft.SemanticKernel.PromptTemplates.Handlebars; | ||
using Microsoft.SemanticKernel.TextGeneration; | ||
|
||
namespace FunctionCalling; | ||
|
||
/// <summary> | ||
/// The following example shows how to use Semantic Kernel with the HuggingFace <see cref="HuggingFaceTextGenerationService"/> | ||
/// to implement function calling with the Nexus Raven model. | ||
/// </summary> | ||
/// <param name="output">The test output helper.</param> | ||
public class NexusRaven_FunctionCalling(ITestOutputHelper output) : BaseTest(output) | ||
{ | ||
/// <summary> | ||
/// Nexus Raven endpoint | ||
/// </summary> | ||
private Uri RavenEndpoint => new("http://nexusraven.nexusflow.ai"); | ||
|
||
/// <summary> | ||
/// Invokes the Nexus Raven model using Text Generation. | ||
/// </summary> | ||
[Fact] | ||
public async Task InvokeTextGenerationAsync() | ||
{ | ||
Kernel kernel = Kernel.CreateBuilder() | ||
.AddHuggingFaceTextGeneration(endpoint: RavenEndpoint) | ||
.Build(); | ||
|
||
var textGeneration = kernel.GetRequiredService<ITextGenerationService>(); | ||
var prompt = "What is deep learning?"; | ||
|
||
var result = await textGeneration.GetTextContentsAsync(prompt); | ||
|
||
Console.WriteLine(result[0].ToString()); | ||
} | ||
|
||
/// <summary> | ||
/// Invokes the Nexus Raven model with Function Calling. | ||
/// </summary> | ||
[Fact] | ||
public async Task InvokeTextGenerationWithFunctionCallingAsync() | ||
{ | ||
using var handler = new LoggingHandler(new HttpClientHandler(), this.Output); | ||
using var httpClient = new HttpClient(handler); | ||
|
||
Kernel kernel = Kernel.CreateBuilder() | ||
.AddHuggingFaceTextGeneration( | ||
endpoint: RavenEndpoint, | ||
httpClient: httpClient) | ||
.Build(); | ||
var plugin = ImportFunctions(kernel); | ||
var textGeneration = kernel.GetRequiredService<ITextGenerationService>(); | ||
|
||
// This Handlebars template is used to format the available KernelFunctions so | ||
// they can be understood by the NexusRaven model. The function name, signature and | ||
// description must be provided. NexusRaven can reason over the list of functions and | ||
// determine which ones need to be called for the current query. | ||
var template = | ||
"""" | ||
{{#each (functions)}} | ||
Function: | ||
{{Name}}{{Signature}} | ||
""" | ||
{{Description}} | ||
""" | ||
{{/each}} | ||
User Query:{{prompt}}<human_end> | ||
""""; | ||
|
||
var prompt = "What is the weather like in Dublin?"; | ||
var functions = plugin.Select(f => new FunctionDefinition { Name = f.Name, Description = f.Description, Signature = CreateSignature(f) }).ToList(); | ||
var executionSettings = new HuggingFacePromptExecutionSettings { Temperature = 0.001F, MaxNewTokens = 1024, ReturnFullText = false, DoSample = false }; // , Stop = ["<bot_end>"] | ||
KernelArguments arguments = new(executionSettings) { { "prompt", prompt }, { "functions", functions } }; | ||
|
||
var factory = new HandlebarsPromptTemplateFactory(); | ||
var promptTemplate = factory.Create(new PromptTemplateConfig(template) { TemplateFormat = "handlebars" }); | ||
var rendered = await promptTemplate.RenderAsync(kernel, arguments); | ||
|
||
Console.WriteLine(" Prompt:\n===================="); | ||
Console.WriteLine(rendered); | ||
|
||
var function = kernel.CreateFunctionFromPrompt(template, templateFormat: "handlebars", promptTemplateFactory: new HandlebarsPromptTemplateFactory()); | ||
|
||
var result = await kernel.InvokeAsync(function, arguments); | ||
|
||
Console.WriteLine("\n Response:\n===================="); | ||
Console.WriteLine(result.ToString()); | ||
} | ||
|
||
// The signature must be Python compliant and currently only supports primitive values | ||
private static string CreateSignature(KernelFunction function) | ||
{ | ||
var signature = new StringBuilder(); | ||
var parameters = function.Metadata.Parameters; | ||
signature.Append('('); | ||
foreach (var parameter in parameters) | ||
{ | ||
signature.Append(parameter.Name).Append(':').Append(GetType(parameter)); | ||
} | ||
signature.Append(')'); | ||
return signature.ToString(); | ||
} | ||
|
||
private static string GetType(KernelParameterMetadata parameter) | ||
{ | ||
if (parameter.Schema is not null) | ||
{ | ||
var rootElement = parameter.Schema.RootElement; | ||
if (rootElement.TryGetProperty("type", out var type)) | ||
{ | ||
return type.GetString() ?? string.Empty; | ||
} | ||
} | ||
return string.Empty; | ||
} | ||
|
||
private static KernelPlugin ImportFunctions(Kernel kernel) | ||
{ | ||
return kernel.ImportPluginFromFunctions("WeatherPlugin", | ||
[ | ||
kernel.CreateFunctionFromMethod( | ||
(string cityName) => "12°C\nWind: 11 KMPH\nHumidity: 48%\nMostly cloudy", | ||
"GetWeatherForCity", | ||
"Gets the current weather for the specified city", | ||
new List<KernelParameterMetadata> | ||
{ | ||
new("cityName") { Description = "The city name", ParameterType = string.Empty.GetType() } | ||
}), | ||
]); | ||
} | ||
|
||
/// <summary> | ||
/// Function definition for use with Nexus Raven. | ||
/// </summary> | ||
private sealed class FunctionDefinition | ||
{ | ||
public string Name { get; init; } | ||
public string Signature { get; init; } | ||
public string Description { get; init; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.