Semantic Kernel:OpenAPI的Plugin
SK的插件,能让AI功能如虎添翼。Plugin能让AI与本地功能和数据互动,使AI与应用的结合,并起到了很好的粘合剂作用。
怎么能让Plugin本身和功能分离呢?调用API是一个很好的办法,比如下面是一个查询订单的功能,是一个mini API项目。
using System.Text.Json.Serialization;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/orders", () =>
{
app.Logger.LogInformation("查询orders");
var orders = Enumerable.Range(1, 5).Select(index =>
new Order(Guid.NewGuid().ToString(),$"Product {index}",index,index * 10))
.ToArray();
return orders;
})
.WithName("orders").WithDescription("获取订单列表");
app.Run();
class Order
{
public Order(string id, string product, int quantity, decimal price)
{
Id = id;
Product = product;
Quantity = quantity;
Price = price;
}
[JsonPropertyName("编号")]
public string Id { get; set; }
[JsonPropertyName("产品名称")]
public string Product { get; set; }
[JsonPropertyName("订单数量")]
public int Quantity { get; set; }
[JsonPropertyName("订单金额")]
public decimal Price { get; set; }
}
这个API的OpenAPI的框架是这样的:http://localhost:5000/openapi/v1.json
{
"openapi": "3.0.1",
"info": {
"title": "OpenAPIDemoForAI | v1",
"version": "1.0.0"
},
"servers": [
{
"url": "http://localhost:5000"
}
],
"paths": {
"/orders": {
"get": {
"tags": [
"OpenAPIDemoForAI"
],
"description": "获取订单列表",
"operationId": "orders",
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Order"
}
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"Order": {
"required": [
"编号",
"产品名称",
"订单数量",
"订单金额"
],
"type": "object",
"properties": {
"编号": {
"type": "string"
},
"产品名称": {
"type": "string"
},
"订单数量": {
"type": "integer",
"format": "int32"
},
"订单金额": {
"type": "number",
"format": "double"
}
}
}
}
},
"tags": [
{
"name": "OpenAPIDemoForAI"
}
]
}
现在调用一下接口,查询一下订单:http://localhost:5000/orders
[
{
"编号": "c82bd2f1-25d1-4a17-bb40-7cfe9fd35f71",
"产品名称": "Product 1",
"订单数量": 1,
"订单金额": 10
},
{
"编号": "bc6f1eef-4ea9-426c-a446-1cff12d963ac",
"产品名称": "Product 2",
"订单数量": 2,
"订单金额": 20
},
{
"编号": "b7b27a33-db1f-4c7c-99c6-064d330d8893",
"产品名称": "Product 3",
"订单数量": 3,
"订单金额": 30
},
{
"编号": "c58f6e36-4363-441d-b54f-50c99970d07a",
"产品名称": "Product 4",
"订单数量": 4,
"订单金额": 40
},
{
"编号": "2789ac41-0d90-4da8-8041-b2e3cd3f7859",
"产品名称": "Product 5",
"订单数量": 5,
"订单金额": 50
}
]
SK本身是支持把符合OpenAPI(这里不是OpenAI)规范的API导入成为SK的插件的,主要借助OpenApiKernelPluginFactory来完成,具体实现如下:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Microsoft.SemanticKernel.Plugins.OpenApi;
using System.IO;
using System.Text.Json;
#pragma warning disable
var apikey = File.ReadAllText("c:/gpt/key.txt");
using HttpClient httpClient = new();
var kernelBuilder = Kernel.CreateBuilder();
kernelBuilder.AddOpenAIChatCompletion("gpt-4o", apiKey: apikey);
var kernel = kernelBuilder.Build();
var pluginArr = new List<PluginSetting>
{
new PluginSetting{PluginName="OrderService",UriString="http://localhost:5000/openapi/v1.json"}
};
foreach (var pluginItem in pluginArr)
{
var plugin = await OpenApiKernelPluginFactory.CreateFromOpenApiAsync(pluginName: pluginItem.PluginName,
uri: new Uri(pluginItem.UriString),
executionParameters: new OpenApiFunctionExecutionParameters(httpClient)
{
IgnoreNonCompliantErrors = true,
EnableDynamicPayload = true,
});
kernel.Plugins.Add(plugin);
}
var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
var openAIPromptExecutionSettings = new OpenAIPromptExecutionSettings()
{
ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
};
ChatHistory history = [];
while (true)
{
Console.WriteLine("回车开始");
Console.ReadLine();
Console.WriteLine("用户 > 查询一下订单,然后总汇订单的总金额 ");
history.AddUserMessage("总汇一下订单的总金额");
var result = await chatCompletionService.GetChatMessageContentAsync(
history,
executionSettings: openAIPromptExecutionSettings,
kernel: kernel);
Console.WriteLine("助理 > " + result);
history.AddMessage(result.Role, result.Content!);
}
public class PluginSetting
{
public string PluginName { get; set; }
public string UriString { get; set; }
}
运行结果如下:
文章来源微信公众号
想要更快更方便的了解相关知识,可以关注微信公众号
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下