插件系统 #
概述 #
插件(Plugin)是 Semantic Kernel 中封装可复用功能的基本单元。每个插件可以包含多个函数,这些函数可以是原生代码实现的,也可以是基于提示词的语义函数。
插件架构 #
text
┌─────────────────────────────────────────────────────────────┐
│ 插件架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Kernel │
│ │ │
│ ├── Plugin: "MathPlugin" │
│ │ ├── Function: "Add" (Native) │
│ │ ├── Function: "Subtract" (Native) │
│ │ └── Function: "Solve" (Semantic) │
│ │ │
│ ├── Plugin: "TextPlugin" │
│ │ ├── Function: "Summarize" (Semantic) │
│ │ ├── Function: "Translate" (Semantic) │
│ │ └── Function: "CountWords" (Native) │
│ │ │
│ └── Plugin: "FilePlugin" │ │ ├── Function: "Read" (Native) │
│ │ └── Function: "Write" (Native) │
│ │
└─────────────────────────────────────────────────────────────┘
原生插件 #
创建原生插件 #
csharp
using System.ComponentModel;
using Microsoft.SemanticKernel;
public class MathPlugin
{
[KernelFunction("add")]
[Description("将两个数字相加并返回结果")]
public double Add(
[Description("第一个数字")] double a,
[Description("第二个数字")] double b)
{
return a + b;
}
[KernelFunction("subtract")]
[Description("将两个数字相减并返回结果")]
public double Subtract(
[Description("被减数")] double a,
[Description("减数")] double b)
{
return a - b;
}
[KernelFunction("multiply")]
[Description("将两个数字相乘并返回结果")]
public double Multiply(
[Description("第一个数字")] double a,
[Description("第二个数字")] double b)
{
return a * b;
}
[KernelFunction("divide")]
[Description("将两个数字相除并返回结果")]
public double Divide(
[Description("被除数")] double a,
[Description("除数")] double b)
{
if (b == 0)
throw new ArgumentException("除数不能为零");
return a / b;
}
}
注册原生插件 #
csharp
var kernel = Kernel.CreateBuilder()
.AddOpenAIChatCompletion("gpt-4", "api-key")
.Build();
// 方式 1:从类型注册
kernel.Plugins.AddFromType<MathPlugin>("Math");
// 方式 2:从实例注册
var mathPlugin = new MathPlugin();
kernel.Plugins.AddFromObject(mathPlugin, "Math");
// 方式 3:使用 KernelPluginFactory
var plugin = KernelPluginFactory.CreateFromType<MathPlugin>("Math");
kernel.Plugins.Add(plugin);
带依赖注入的插件 #
csharp
public class DatabasePlugin
{
private readonly IDatabaseService _db;
public DatabasePlugin(IDatabaseService db)
{
_db = db;
}
[KernelFunction("query")]
[Description("执行数据库查询")]
public async Task<string> QueryAsync(
[Description("SQL 查询语句")] string sql)
{
return await _db.ExecuteQueryAsync(sql);
}
}
// 注册时注入依赖
var dbService = new DatabaseService();
kernel.Plugins.AddFromObject(new DatabasePlugin(dbService), "Database");
复杂参数类型 #
csharp
public class User
{
public string Name { get; set; }
public int Age { get; set; }
public string[] Interests { get; set; }
}
public class UserPlugin
{
[KernelFunction("create_user")]
[Description("创建新用户")]
public User CreateUser(
[Description("用户信息")] User user)
{
return user;
}
[KernelFunction("get_users")]
[Description("获取用户列表")]
public User[] GetUsers()
{
return new[]
{
new User { Name = "Alice", Age = 25, Interests = new[] { "Reading", "Music" } },
new User { Name = "Bob", Age = 30, Interests = new[] { "Sports", "Travel" } }
};
}
}
语义插件 #
从提示词创建 #
csharp
var summarizeFunction = kernel.CreateFunctionFromPrompt(
promptTemplate: """
请总结以下文本的主要内容:
文本:
{{$input}}
总结:
""",
functionName: "Summarize",
description: "总结文本内容"
);
var plugin = KernelPluginFactory.CreateFromFunctions(
"TextPlugin",
"文本处理插件",
new[] { summarizeFunction }
);
kernel.Plugins.Add(plugin);
从文件加载 #
text
Prompts/
└── TextPlugin/
├── Summarize/
│ ├── config.json
│ └── skprompt.txt
└── Translate/
├── config.json
└── skprompt.txt
config.json:
json
{
"schema": 1,
"description": "总结文本内容",
"execution_settings": {
"default": {
"max_tokens": 500,
"temperature": 0.3
}
},
"input_variables": [
{
"name": "input",
"description": "需要总结的文本",
"required": true
}
]
}
skprompt.txt:
text
请总结以下文本的主要内容:
文本:
{{$input}}
总结:
加载插件:
csharp
var plugin = kernel.ImportPluginFromPromptDirectory("./Prompts", "TextPlugin");
使用 Handlebars 模板 #
csharp
using Microsoft.SemanticKernel.PromptTemplates.Handlebars;
var function = kernel.CreateFunctionFromPrompt(
promptTemplate: """
请为以下产品写一段描述:
产品名称:{{name}}
产品类型:{{type}}
主要特点:
{{#each features}}
- {{this}}
{{/each}}
描述:
""",
templateFormat: "handlebars",
promptTemplateFactory: new HandlebarsPromptTemplateFactory()
);
kernel.Plugins.Add(KernelPluginFactory.CreateFromFunctions(
"ProductPlugin",
new[] { function }
));
内置插件 #
ConversationSummaryPlugin #
csharp
using Microsoft.SemanticKernel.Plugins.Core;
kernel.ImportPluginFromType<ConversationSummaryPlugin>();
var summary = await kernel.InvokeAsync(
"ConversationSummaryPlugin",
"SummarizeConversation",
new KernelArguments
{
["input"] = "长对话内容..."
}
);
FileIOPlugin #
csharp
using Microsoft.SemanticKernel.Plugins.Core;
kernel.ImportPluginFromType<FileIOPlugin>();
// 读取文件
var content = await kernel.InvokeAsync(
"FileIOPlugin",
"ReadAsync",
new KernelArguments { ["path"] = "/path/to/file.txt" }
);
// 写入文件
await kernel.InvokeAsync(
"FileIOPlugin",
"WriteAsync",
new KernelArguments
{
["path"] = "/path/to/output.txt",
["content"] = "要写入的内容"
}
);
HttpPlugin #
csharp
using Microsoft.SemanticKernel.Plugins.Core;
kernel.ImportPluginFromType<HttpPlugin>();
var response = await kernel.InvokeAsync(
"HttpPlugin",
"GetAsync",
new KernelArguments { ["uri"] = "https://api.example.com/data" }
);
TimePlugin #
csharp
using Microsoft.SemanticKernel.Plugins.Core;
kernel.ImportPluginFromType<TimePlugin>();
var now = await kernel.InvokeAsync("TimePlugin", "Now");
var date = await kernel.InvokeAsync("TimePlugin", "Date");
var time = await kernel.InvokeAsync("TimePlugin", "Time");
插件组合 #
链式调用 #
csharp
// 步骤 1:获取数据
var data = await kernel.InvokeAsync(
"DatabasePlugin",
"Query",
new KernelArguments { ["sql"] = "SELECT * FROM products" }
);
// 步骤 2:处理数据
var processed = await kernel.InvokeAsync(
"TextPlugin",
"Summarize",
new KernelArguments { ["input"] = data.ToString() }
);
// 步骤 3:翻译
var translated = await kernel.InvokeAsync(
"TranslatePlugin",
"ToChinese",
new KernelArguments { ["input"] = processed.ToString() }
);
使用 Planner 自动编排 #
csharp
using Microsoft.SemanticKernel.Planning;
var planner = new FunctionCallingStepwisePlanner();
var result = await planner.ExecuteAsync(
kernel,
"查询数据库中的产品信息,然后生成一份中文报告"
);
OpenAPI 插件 #
从 OpenAPI 规范导入 #
csharp
var plugin = await kernel.ImportPluginFromOpenApiAsync(
pluginName: "WeatherApi",
filePath: "openapi.json",
executionParameters: new OpenApiFunctionExecutionParameters
{
ServerUrlOverride = new Uri("https://api.weather.com")
}
);
var weather = await kernel.InvokeAsync(
"WeatherApi",
"GetCurrentWeather",
new KernelArguments
{
["city"] = "北京"
}
);
配置认证 #
csharp
var authCallback = async (HttpRequestMessage request, CancellationToken cancellationToken) =>
{
request.Headers.Authorization = new AuthenticationHeaderValue(
"Bearer",
"your-access-token"
);
};
var plugin = await kernel.ImportPluginFromOpenApiAsync(
"MyApi",
"openapi.json",
new OpenApiFunctionExecutionParameters
{
AuthCallback = authCallback
}
);
插件最佳实践 #
1. 清晰的命名和描述 #
csharp
public class GoodPlugin
{
[KernelFunction("calculate_discount")]
[Description("根据购买金额和会员等级计算折扣价格")]
public double CalculateDiscount(
[Description("原始购买金额,必须大于0")] double amount,
[Description("会员等级:Bronze, Silver, Gold, Platinum")] string memberLevel)
{
// 实现
}
}
2. 参数验证 #
csharp
[KernelFunction("divide")]
public double Divide(double a, double b)
{
if (b == 0)
{
throw new KernelException("除数不能为零");
}
return a / b;
}
3. 异步操作 #
csharp
public class AsyncPlugin
{
[KernelFunction("fetch_data")]
public async Task<string> FetchDataAsync(string url)
{
using var client = new HttpClient();
return await client.GetStringAsync(url);
}
}
4. 错误处理 #
csharp
[KernelFunction("process_file")]
public async Task<string> ProcessFileAsync(string path)
{
try
{
var content = await File.ReadAllTextAsync(path);
return content;
}
catch (FileNotFoundException)
{
return $"文件未找到: {path}";
}
catch (Exception ex)
{
return $"处理文件时出错: {ex.Message}";
}
}
5. 日志记录 #
csharp
public class LoggingPlugin
{
private readonly ILogger<LoggingPlugin> _logger;
public LoggingPlugin(ILogger<LoggingPlugin> logger)
{
_logger = logger;
}
[KernelFunction("important_operation")]
public async Task<string> ImportantOperationAsync(string input)
{
_logger.LogInformation("开始执行重要操作: {Input}", input);
try
{
var result = await DoWorkAsync(input);
_logger.LogInformation("操作成功完成");
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "操作执行失败");
throw;
}
}
}
下一步 #
现在你已经掌握了插件系统,接下来学习 函数,深入了解函数的创建和调用!
最后更新:2026-04-04