DevExpress Blazor UI组件使用了C#为Blazor Server和Blazor WebAssembly创建高影响力的用户体验,这个UI自建库提供了一套全面的原生Blazor UI组件(包括Pivot Grid、调度程序、图表、数据编辑器和报表等)。
现代AI驱动的应用程序需要与外部系统或内部应用程序组件无缝交互,许多AI服务提供商现在支持函数调用(也称为工具调用),这允许AI模型在运行时触发函数。这种功能对于AI需要执行诸如获取数据、调用API或在应用程序中启动任务(从安排约会和修改数据库信息到更新应用程序的外观)等操作的代理工作流/应用程序特别有价值。
获取DevExpress v24.2正式版下载
本文实例中的整个流程是这样的:模型不是回复用户消息,而是请求一个带有指定参数的函数调用,然后聊天客户端调用该函数并将结果返回给LLM。此时,LLM根据函数返回的值构造一个响应。
在本指南中,我们将探索如何在DevExpress Blazor DxAiChat组件中启用函数调用:
- 来自Microsoft.Extensions.AI库的IChatClient接口
- 来自Microsoft语义内核的插件
开始
要开始,您必须首先将DxAiChat组件集成到应用程序中(请参阅我们的官方指南以获取更多信息):Add AI Chat to a Project。
接下来注册您的AI服务,在这个例子中我们将使用Azure OpenAI。下面是一个示例Program.cs设置:
using Azure.AI.OpenAI;
using Microsoft.Extensions.AI;
...
var builder = WebApplication.CreateBuilder(args);
...
// Replace with your endpoint, API key, and deployed AI model name
string azureOpenAIEndpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT");
string azureOpenAIKey = Environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY");
string deploymentName = string.Empty;
...
var azureChatClient = new AzureOpenAIClient(
new Uri(azureOpenAIEndpoint),
new AzureKeyCredential(azureOpenAIKey));IChatClient chatClient = azureChatClient.AsChatClient(deploymentName);builder.Services.AddDevExpressBlazor();
builder.Services.AddChatClient(chatClient);
builder.Services.AddDevExpressAI();
运行项目来确认您可以发送消息和接收AI响应。
使用IChatClient调用工具
首先,定义一个简单的函数来检索指定城市的天气信息。在本例中,这是GetWeatherTool。为了帮助AI理解如何调用GetWeatherTool函数,请使用方法及其参数的System.ComponentModel.Description属性。LLM使用参数找出最合适的方法调用,并规划调用顺序:
using System.ComponentModel;
using Microsoft.Extensions.AI;public class CustomAIFunctions
{
public static AIFunction GetWeatherTool => AIFunctionFactory.Create(GetWeather);
[Description("Gets the current weather in the city")]
public static string GetWeather([Description("The name of the city")] string city)
{
switch (city)
{
case "Los Angeles":
case "LA":
return GetTemperatureValue(20);
case "London":
return GetTemperatureValue(15);
default:
return $"The information about the weather in {city} is not available.";
}
}
static string GetTemperatureValue(int value)
{
var valueInFahrenheits = value * 9 / 5 + 32;
return $"{valueInFahrenheits}\u00b0F ({value}\u00b0C)";
}
}
修改聊天客户端注册,如下所示,来提供可用函数列表,并允许客户端在回答用户问题时调用函数。确保首先配置聊天客户端选项,因为这里的方法调用顺序至关重要:
using Azure;
using Azure.AI.OpenAI;
using Microsoft.Extensions.AI;
...
IChatClient chatClient = new ChatClientBuilder(azureChatClient)
.ConfigureOptions(opt =>
{
opt.Tools = [CustomAIFunctions.GetWeatherTool];
})
.UseFunctionInvocation()
.Build();builder.Services.AddChatClient(chatClient);
此时当用户向AI服务询问天气时,该服务将自动触发GetWeatherTool函数并将结果添加到其响应中。
集成语义内核插件
Microsoft语义内核允许开发人员将高级AI功能整合到应用程序中(包括推理、工作流编排和动态提示工程),Microsoft的框架通过允许应用程序与插件交互和更有效地管理内存来增强AI解决方案。
首先,将以下NuGet包添加到项目中:
- Microsoft.SemanticKernel
- Microsoft.SemanticKernel.Plugins.Core
- Microsoft.SemanticKernel.Connectors.OpenAI (或为您的AI提供商提供适当的连接器)
如果您已经在应用程序中使用语义内核,并且熟悉插件的概念,可以很容易地将它连接到DevExpress Blazor DxAiChat控件。
由于DevExpress AI驱动的API使用IChatClient接口与llm一起操作,您需要手动实现接口并从语义内核调用IChatCompletionService方法:
using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
...
public class SemanticKernelPluginCallingChatClient : IChatClient {
private IChatCompletionService _chatCompletionService;
private Kernel _kernel;
private OpenAIPromptExecutionSettings _executionSettings;
public SemanticKernelPluginCallingChatClient(Kernel kernel)
{
_kernel = kernel;
_chatCompletionService = _kernel.GetRequiredService();
_executionSettings = new OpenAIPromptExecutionSettings() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions };
}public async Task GetResponseAsync(IEnumerable chatMessages, ChatOptions? options = null, CancellationToken cancellationToken = default)
{
var history = GetChatHistory(chatMessages);
ChatMessageContent message = await _chatCompletionService.GetChatMessageContentAsync(history, _executionSettings, _kernel, cancellationToken);
return new ChatResponse(new ChatMessage(ChatRole.Assistant, message.Content));
}public async IAsyncEnumerable GetStreamingResponseAsync(IEnumerable chatMessages, ChatOptions? options = null, CancellationToken cancellationToken = default)
{
var history = GetChatHistory(chatMessages);
await foreach(var item in _chatCompletionService.GetStreamingChatMessageContentsAsync(history, _executionSettings, _kernel, cancellationToken)) {
yield return new ChatResponseUpdate(ChatRole.Assistant, item.Content);
}
}AuthorRole GetRole(ChatRole chatRole) {
if(chatRole == ChatRole.User) return AuthorRole.User;
if(chatRole == ChatRole.System) return AuthorRole.System;
if(chatRole == ChatRole.Assistant) return AuthorRole.Assistant;
if(chatRole == ChatRole.Tool) return AuthorRole.Tool;
throw new Exception();
}private ChatHistory GetChatHistory(IEnumerable chatMessages)
{
var history = new ChatHistory(chatMessages.Select(x => new ChatMessageContent(GetRole(x.Role), x.Text)));
return history;
}
...
}
实现一个类似于前面函数的语义内核插件,但是用Microsoft.SemanticKernel.KernelFunction属性修饰main函数方法:
using Microsoft.SemanticKernel;
using System.ComponentModel;
...public class WeatherPlugin {
[KernelFunction]
[Description("Gets the current weather in the city")]
public static string GetWeather([Description("The name of the city")] string city) {
switch(city) {
case "Los Angeles":
case "LA":
return GetTemperatureValue(20);
case "London":
return GetTemperatureValue(15);
default:
return $"The information about the weather in {city} is not available.";
}
}
static string GetTemperatureValue(int value)
{
var valueInFahrenheits = value * 9 / 5 + 32;
return $"{valueInFahrenheits}\u00b0F ({value}\u00b0C)";
}
}
最后,在应用程序启动时注册语义内核和聊天客户端:
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Plugins.Core;
...var semanticKernelBuilder = Kernel.CreateBuilder();
semanticKernelBuilder.AddAzureOpenAIChatCompletion(
deploymentName,
azureOpenAIEndpoint,
azureOpenAIKey);// Add plugins from Microsoft.SemanticKernel.Plugins.Core
#pragma warning disable SKEXP0050
semanticKernelBuilder.Plugins.AddFromType<TimePlugin>(); // this is a built-in plugin
semanticKernelBuilder.Plugins.AddFromType<WeatherPlugin>(); // this is our custom plugin
#pragma warning restore SKEXP0050var globalKernel = semanticKernelBuilder.Build();
builder.Services.AddChatClient(new SemanticKernelPluginCallingChatClient(globalKernel));builder.Services.AddDevExpressAI();
一旦配置好,您的应用程序将使用Semantic Kernel插件来智能地处理请求: