在当今AI快速发展的背景下,函数调用功能为开发者提供了一种强大的方式,让聊天机器人能够与现有代码无缝交互。本文将深入探讨C#中如何利用Semantic Kernel实现高效的函数调用,帮助您构建能够自动化业务流程、生成代码片段等功能的智能应用。
函数调用是聊天完成功能中最强大的特性之一,它允许模型调用您预先定义的函数。通过Semantic Kernel框架,这一过程被大大简化 - 它自动为模型描述您的函数及其参数,并处理模型与代码之间的通信。
当您使用启用了函数调用的模型发送请求时,Semantic Kernel会执行以下步骤:
MarkdownMicrosoft.SemanticKernel Microsoft.Extensions.Hosting
让我们通过一个具体的Pizza订购插件示例来展示函数调用的工作原理:
C#using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Hosting;
using OpenAI;
using System.ClientModel;
namespace PizzaOrderingBot
{
class Program
{
static async Task Main(string[] args)
{
// 设置依赖注入容器
var services = new ServiceCollection();
// 注册服务
services.AddSingleton<IPizzaService, MockPizzaService>();
services.AddSingleton<IUserContext, MockUserContext>();
services.AddSingleton<IPaymentService, MockPaymentService>();
// 添加日志
services.AddLogging(builder =>
{
builder.AddConsole();
builder.SetMinimumLevel(LogLevel.Information);
});
var serviceProvider = services.BuildServiceProvider();
// 创建Semantic Kernel
var kernelBuilder = Kernel.CreateBuilder();
// 配置OpenAI客户端凭证
var openAIClientCredential = new ApiKeyCredential("sk-xxxx");
// 配置客户端选项,指向DeepSeek的API端点
var openAIClientOption = new OpenAIClientOptions
{
Endpoint = new Uri("https://api.deepseek.com/v1"),
};
// 创建OpenAI客户端实例
var openapiClient = new OpenAIClient(openAIClientCredential, openAIClientOption);
// 注册DeepSeek聊天完成服务
// 第一个参数是服务标识符,第二个是客户端实例,第三个是服务描述
kernelBuilder.Services.AddOpenAIChatCompletion("deepseek-chat", openapiClient, "对话服务ID");
// 添加日志服务
kernelBuilder.Services.AddLogging(builder => builder.AddConsole());
// 构建内核
var kernel = kernelBuilder.Build();
// 将披萨订购插件添加到内核
var pizzaPlugin = new OrderPizzaPlugin(
serviceProvider.GetRequiredService<IPizzaService>(),
serviceProvider.GetRequiredService<IUserContext>(),
serviceProvider.GetRequiredService<IPaymentService>()
);
kernel.Plugins.AddFromObject(pizzaPlugin, "OrderPizza");
// 运行聊天对话示例
await RunChatExampleAsync(kernel);
}
static async Task RunChatExampleAsync(Kernel kernel)
{
Console.WriteLine("===== 披萨订购聊天机器人示例 =====");
Console.WriteLine("输入'exit'退出对话\n");
// 创建聊天历史
var chatHistory = new ChatHistory();
// 获取聊天完成服务
var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
// 设置执行选项 - 启用函数调用
var executionSettings = new OpenAIPromptExecutionSettings
{
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(),
Temperature = 0.7,
TopP = 0.8
};
while (true)
{
// 获取用户输入
Console.Write("用户: ");
string userInput = Console.ReadLine() ?? string.Empty;
if (userInput.ToLower() == "exit")
break;
// 添加用户消息到聊天历史
chatHistory.AddUserMessage(userInput);
try
{
// 获取AI回复
var response = await chatCompletionService.GetChatMessageContentAsync(
chatHistory,
executionSettings: executionSettings,
kernel: kernel);
// 输出AI回复
Console.WriteLine($"AI: {response.Content}");
// 添加AI回复到聊天历史
chatHistory.AddAssistantMessage(response.Content);
}
catch (Exception ex)
{
Console.WriteLine($"错误: {ex.Message}");
}
}
}
}
#region 模型定义
// 枚举定义
public enum PizzaSize
{
Small,
Medium,
Large
}
public enum PizzaToppings
{
Cheese,
Pepperoni,
Mushrooms,
Olives,
Onions,
Bacon,
ExtraCheese,
GreenPeppers,
Pineapple,
Sausage
}
// 数据模型
public class Menu
{
public List<PizzaMenuItem> Pizzas { get; set; } = new();
public List<string> Sides { get; set; } = new();
public List<string> Drinks { get; set; } = new();
public override string ToString()
{
return $"菜单: {Pizzas.Count} 种披萨, {Sides.Count} 种配菜, {Drinks.Count} 种饮料";
}
}
public class PizzaMenuItem
{
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public decimal Price { get; set; }
public List<PizzaToppings> DefaultToppings { get; set; } = new();
}
public class PizzaItem
{
public int Id { get; set; }
public PizzaSize Size { get; set; }
public List<PizzaToppings> Toppings { get; set; } = new();
public int Quantity { get; set; }
public string SpecialInstructions { get; set; } = string.Empty;
public decimal Price { get; set; }
}
public class Cart
{
public Guid Id { get; set; }
public List<PizzaItem> Items { get; set; } = new();
public decimal Subtotal { get; set; }
public decimal Tax { get; set; }
public decimal Total { get; set; }
}
public class CartDelta
{
public List<PizzaItem> NewItems { get; set; } = new();
public Cart UpdatedCart { get; set; } = new();
public override string ToString()
{
return $"已添加 {NewItems.Count} 个商品,购物车总额: ${UpdatedCart.Total}";
}
}
public class CheckoutResponse
{
public string OrderId { get; set; } = string.Empty;
public decimal Total { get; set; }
public string EstimatedDeliveryTime { get; set; } = string.Empty;
public override string ToString()
{
return $"订单 {OrderId} 已确认, 总价: ${Total}, 预计送达时间: {EstimatedDeliveryTime}";
}
}
#endregion
#region 服务接口
// 服务接口
public interface IPizzaService
{
Task<Menu> GetMenu();
Task<CartDelta> AddPizzaToCart(Guid cartId, PizzaSize size, List<PizzaToppings> toppings, int quantity, string specialInstructions);
Task<Cart> GetCart(Guid cartId);
Task<Cart> RemoveItemFromCart(Guid cartId, int itemId);
Task<CheckoutResponse> Checkout(Guid cartId, Guid paymentId);
}
public interface IUserContext
{
Task<Guid> GetCartIdAsync();
Guid GetCartId();
Task<string> GetUserAddressAsync();
}
public interface IPaymentService
{
Task<Guid> RequestPaymentFromUserAsync(Guid cartId);
Task<bool> VerifyPaymentAsync(Guid paymentId);
}
#endregion
#region 模拟服务实现
// 模拟服务实现
public class MockPizzaService : IPizzaService
{
private readonly Dictionary<Guid, Cart> _carts = new();
private int _nextItemId = 1;
public Task<Menu> GetMenu()
{
var menu = new Menu
{
Pizzas = new List<PizzaMenuItem>
{
new() { Name = "经典芝士披萨", Description = "传统意式芝士披萨", Price = 9.99m, DefaultToppings = new List<PizzaToppings> { PizzaToppings.Cheese } },
new() { Name = "意式辣香肠披萨", Description = "经典辣香肠披萨", Price = 11.99m, DefaultToppings = new List<PizzaToppings> { PizzaToppings.Cheese, PizzaToppings.Pepperoni } },
new() { Name = "蔬菜至尊披萨", Description = "各类新鲜蔬菜", Price = 12.99m, DefaultToppings = new List<PizzaToppings> { PizzaToppings.Cheese, PizzaToppings.Mushrooms, PizzaToppings.Olives, PizzaToppings.GreenPeppers, PizzaToppings.Onions } }
},
Sides = new List<string> { "蒜香面包", "薯条", "鸡翅" },
Drinks = new List<string> { "可乐", "雪碧", "冰红茶", "矿泉水" }
};
return Task.FromResult(menu);
}
public Task<CartDelta> AddPizzaToCart(Guid cartId, PizzaSize size, List<PizzaToppings> toppings, int quantity, string specialInstructions)
{
// 获取或创建购物车
if (!_carts.TryGetValue(cartId, out var cart))
{
cart = new Cart { Id = cartId, Items = new List<PizzaItem>() };
_carts[cartId] = cart;
}
// 根据尺寸计算基础价格
decimal basePrice = size switch
{
PizzaSize.Small => 8.99m,
PizzaSize.Medium => 10.99m,
PizzaSize.Large => 13.99m,
_ => 10.99m
};
// 每种配料加0.75美元
decimal toppingsPrice = toppings.Count * 0.75m;
// 创建新披萨项
var newItem = new PizzaItem
{
Id = _nextItemId++,
Size = size,
Toppings = toppings,
Quantity = quantity,
SpecialInstructions = specialInstructions,
Price = (basePrice + toppingsPrice) * quantity
};
// 添加到购物车
cart.Items.Add(newItem);
// 计算小计、税和总计
cart.Subtotal = cart.Items.Sum(item => item.Price);
cart.Tax = Math.Round(cart.Subtotal * 0.08m, 2);
cart.Total = cart.Subtotal + cart.Tax;
// 返回购物车增量
return Task.FromResult(new CartDelta
{
NewItems = new List<PizzaItem> { newItem },
UpdatedCart = cart
});
}
public Task<Cart> GetCart(Guid cartId)
{
if (!_carts.TryGetValue(cartId, out var cart))
{
cart = new Cart { Id = cartId, Items = new List<PizzaItem>() };
_carts[cartId] = cart;
}
return Task.FromResult(cart);
}
public Task<Cart> RemoveItemFromCart(Guid cartId, int itemId)
{
if (!_carts.TryGetValue(cartId, out var cart))
{
throw new Exception("购物车不存在");
}
var itemToRemove = cart.Items.FirstOrDefault(item => item.Id == itemId);
if (itemToRemove == null)
{
throw new Exception("商品不存在");
}
cart.Items.Remove(itemToRemove);
// 重新计算购物车总额
cart.Subtotal = cart.Items.Sum(item => item.Price);
cart.Tax = Math.Round(cart.Subtotal * 0.08m, 2);
cart.Total = cart.Subtotal + cart.Tax;
return Task.FromResult(cart);
}
public Task<CheckoutResponse> Checkout(Guid cartId, Guid paymentId)
{
if (!_carts.TryGetValue(cartId, out var cart))
{
throw new Exception("购物车不存在");
}
// 生成订单ID
string orderId = Guid.NewGuid().ToString()[..8].ToUpper();
// 模拟送达时间(30-45分钟)
var now = DateTime.Now;
var deliveryTime = now.AddMinutes(new Random().Next(30, 46));
var response = new CheckoutResponse
{
OrderId = orderId,
Total = cart.Total,
EstimatedDeliveryTime = deliveryTime.ToString("HH:mm")
};
// 清空购物车
_carts.Remove(cartId);
return Task.FromResult(response);
}
}
public class MockUserContext : IUserContext
{
private readonly Guid _cartId = Guid.NewGuid();
public Task<Guid> GetCartIdAsync()
{
return Task.FromResult(_cartId);
}
public Guid GetCartId()
{
return _cartId;
}
public Task<string> GetUserAddressAsync()
{
return Task.FromResult("北京市朝阳区建国路88号");
}
}
public class MockPaymentService : IPaymentService
{
public Task<Guid> RequestPaymentFromUserAsync(Guid cartId)
{
// 模拟支付处理
return Task.FromResult(Guid.NewGuid());
}
public Task<bool> VerifyPaymentAsync(Guid paymentId)
{
// 假设所有付款都通过验证
return Task.FromResult(true);
}
}
#endregion
#region 披萨订购插件
// 披萨订购插件
public class OrderPizzaPlugin
{
private readonly IPizzaService _pizzaService;
private readonly IUserContext _userContext;
private readonly IPaymentService _paymentService;
public OrderPizzaPlugin(
IPizzaService pizzaService,
IUserContext userContext,
IPaymentService paymentService)
{
_pizzaService = pizzaService;
_userContext = userContext;
_paymentService = paymentService;
}
[KernelFunction("get_pizza_menu")]
[Description("获取披萨菜单,包括披萨种类、配菜和饮料")]
public async Task<Menu> GetPizzaMenuAsync()
{
return await _pizzaService.GetMenu();
}
[KernelFunction("add_pizza_to_cart")]
[Description("添加披萨到用户购物车,返回新添加的商品和更新后的购物车")]
public async Task<CartDelta> AddPizzaToCart(
[Description("披萨尺寸:小号、中号或大号")] PizzaSize size,
[Description("披萨配料列表,可选:芝士、意式辣香肠、蘑菇、橄榄、洋葱、培根、额外芝士、青椒、菠萝、香肠")] List<PizzaToppings> toppings,
[Description("披萨数量,默认为1")] int quantity = 1,
[Description("特殊制作说明,例如'少放盐',默认为空")] string specialInstructions = "")
{
try
{
Guid cartId = _userContext.GetCartId();
return await _pizzaService.AddPizzaToCart(
cartId: cartId,
size: size,
toppings: toppings,
quantity: quantity,
specialInstructions: specialInstructions);
}
catch (Exception ex)
{
throw new Exception($"添加披萨失败: {ex.Message}");
}
}
[KernelFunction("get_cart")]
[Description("获取用户当前购物车内容")]
public async Task<Cart> GetCart()
{
try
{
Guid cartId = _userContext.GetCartId();
return await _pizzaService.GetCart(cartId);
}
catch (Exception ex)
{
throw new Exception($"获取购物车失败: {ex.Message}");
}
}
[KernelFunction("remove_item_from_cart")]
[Description("从购物车中移除指定商品")]
public async Task<Cart> RemoveItemFromCart(
[Description("要移除的商品ID")] int itemId)
{
try
{
Guid cartId = _userContext.GetCartId();
return await _pizzaService.RemoveItemFromCart(cartId, itemId);
}
catch (Exception ex)
{
throw new Exception($"移除商品失败: {ex.Message}");
}
}
[KernelFunction("checkout")]
[Description("结算用户购物车,处理付款并完成订单")]
public async Task<CheckoutResponse> Checkout()
{
try
{
Guid cartId = await _userContext.GetCartIdAsync();
Guid paymentId = await _paymentService.RequestPaymentFromUserAsync(cartId);
// 确认付款成功
bool paymentVerified = await _paymentService.VerifyPaymentAsync(paymentId);
if (!paymentVerified)
{
throw new Exception("付款验证失败");
}
return await _pizzaService.Checkout(cartId, paymentId);
}
catch (Exception ex)
{
throw new Exception($"结算失败: {ex.Message}");
}
}
[KernelFunction("get_delivery_address")]
[Description("获取用户的送货地址")]
public async Task<string> GetDeliveryAddress()
{
try
{
return await _userContext.GetUserAddressAsync();
}
catch (Exception ex)
{
throw new Exception($"获取送货地址失败: {ex.Message}");
}
}
}
#endregion
}

函数调用为C#开发者提供了构建强大、交互式AI应用的能力。通过Semantic Kernel,您可以轻松集成现有代码与大型语言模型。掌握本文介绍的最佳实践,将帮助您开发出反应灵敏、用户友好的聊天机器人,能够处理从订购披萨到执行复杂业务逻辑的各种任务。
通过合理设计函数、优化参数和返回值,以及实现并行函数调用,您可以创建出更高效、更智能的交互式应用程序。
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!