函数 #
概述 #
函数(Function)是 Semantic Kernel 中最小的执行单元。每个函数都属于一个插件,可以是语义函数(基于提示词)或原生函数(代码实现)。
函数类型 #
text
┌─────────────────────────────────────────────────────────────┐
│ 函数类型 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Semantic Function(语义函数) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 特点: │ │
│ │ - 基于 LLM 执行 │ │
│ │ - 使用提示词模板 │ │
│ │ - 支持变量替换 │ │
│ │ - 可配置执行参数 │ │
│ │ │ │
│ │ 示例: │ │
│ │ - 文本摘要 │ │
│ │ - 翻译 │ │
│ │ - 内容生成 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Native Function(原生函数) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 特点: │ │
│ │ - 使用代码实现 │ │
│ │ - 直接执行 │ │
│ │ - 不消耗 LLM tokens │ │
│ │ - 可访问外部资源 │ │
│ │ │ │
│ │ 示例: │ │
│ │ - 数学计算 │ │
│ │ - 文件操作 │ │
│ │ - API 调用 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
创建语义函数 #
从提示词创建 #
csharp
var summarizeFunction = kernel.CreateFunctionFromPrompt(
promptTemplate: "请总结以下文本:{{$input}}",
functionName: "Summarize",
description: "总结文本内容"
);
带执行设置 #
csharp
using Microsoft.SemanticKernel.Connectors.OpenAI;
var function = kernel.CreateFunctionFromPrompt(
promptTemplate: "写一首关于{{$topic}}的诗",
functionName: "WritePoem",
description: "根据主题写诗",
executionSettings: new OpenAIPromptExecutionSettings
{
MaxTokens = 500,
Temperature = 0.8
}
);
带输入变量定义 #
csharp
var function = kernel.CreateFunctionFromPrompt(
promptTemplate: """
你是一个{{$role}}。
请回答以下问题:{{$question}}
回答:
""",
functionName: "AskExpert",
description: "以专家身份回答问题",
inputVariables: new[]
{
new InputVariable
{
Name = "role",
Description = "专家角色",
IsRequired = true
},
new InputVariable
{
Name = "question",
Description = "用户问题",
IsRequired = true
}
}
);
从文件加载 #
text
Prompts/
└── Summarize/
├── config.json
└── skprompt.txt
config.json:
json
{
"schema": 1,
"description": "总结文本内容",
"execution_settings": {
"default": {
"max_tokens": 300,
"temperature": 0.3
}
},
"input_variables": [
{
"name": "input",
"description": "需要总结的文本",
"required": true
},
{
"name": "language",
"description": "输出语言",
"required": false,
"default": "中文"
}
]
}
skprompt.txt:
text
请用{{$language}}总结以下文本:
{{$input}}
总结:
加载函数:
csharp
var plugin = kernel.ImportPluginFromPromptDirectory("./Prompts");
var function = plugin["Summarize"];
创建原生函数 #
基本方法 #
csharp
using System.ComponentModel;
using Microsoft.SemanticKernel;
public class MathPlugin
{
[KernelFunction]
[Description("计算两个数的和")]
public double Add(
[Description("第一个数")] double a,
[Description("第二个数")] double b)
{
return a + b;
}
}
从方法创建 #
csharp
public static class HelperFunctions
{
public static string FormatDate(DateTime date)
{
return date.ToString("yyyy-MM-dd");
}
public static int CalculateAge(DateTime birthDate)
{
return DateTime.Now.Year - birthDate.Year;
}
}
var formatDate = kernel.CreateFunctionFromMethod(
method: HelperFunctions.FormatDate,
functionName: "FormatDate",
description: "格式化日期"
);
var calculateAge = kernel.CreateFunctionFromMethod(
method: HelperFunctions.CalculateAge,
functionName: "CalculateAge",
description: "计算年龄"
);
异步函数 #
csharp
public class AsyncPlugin
{
[KernelFunction("fetch_url")]
[Description("获取 URL 内容")]
public async Task<string> FetchUrlAsync(
[Description("URL 地址")] string url)
{
using var client = new HttpClient();
return await client.GetStringAsync(url);
}
}
返回复杂类型 #
csharp
public class SearchResult
{
public string Title { get; set; }
public string Url { get; set; }
public string Snippet { get; set; }
}
public class SearchPlugin
{
[KernelFunction("search")]
[Description("搜索网络内容")]
public async Task<SearchResult[]> SearchAsync(
[Description("搜索关键词")] string query)
{
// 实现搜索逻辑
return new[]
{
new SearchResult
{
Title = "结果1",
Url = "https://example.com/1",
Snippet = "摘要..."
}
};
}
}
调用函数 #
通过 Kernel 调用 #
csharp
// 调用语义函数
var result = await kernel.InvokePromptAsync("你好");
// 调用插件中的函数
var result = await kernel.InvokeAsync(
pluginName: "Math",
functionName: "Add",
arguments: new KernelArguments
{
["a"] = 5,
["b"] = 3
}
);
通过函数引用调用 #
csharp
var function = kernel.Plugins["Math"]["Add"];
var result = await kernel.InvokeAsync(
function,
new KernelArguments { ["a"] = 5, ["b"] = 3 }
);
链式调用 #
csharp
var result = await kernel.Plugins["Math"]["Add"]
.InvokeAsync(kernel, new KernelArguments { ["a"] = 5, ["b"] = 3 });
参数传递 #
KernelArguments 基本用法 #
csharp
var arguments = new KernelArguments
{
["name"] = "小明",
["age"] = 25,
["interests"] = new[] { "编程", "阅读" }
};
var result = await kernel.InvokePromptAsync(
"你好{{$name}},你今年{{$age}}岁",
arguments
);
结合执行设置 #
csharp
var settings = new OpenAIPromptExecutionSettings
{
Temperature = 0.7,
MaxTokens = 500
};
var arguments = new KernelArguments(settings)
{
["topic"] = "人工智能"
};
动态构建参数 #
csharp
var arguments = new KernelArguments();
// 根据条件添加参数
if (includeDetails)
{
arguments["details"] = "详细信息";
}
// 从字典构建
var dict = new Dictionary<string, object?>
{
["key1"] = "value1",
["key2"] = "value2"
};
foreach (var kvp in dict)
{
arguments[kvp.Key] = kvp.Value;
}
函数结果 #
获取字符串结果 #
csharp
var result = await kernel.InvokeAsync("Plugin", "Function", arguments);
string text = result.ToString();
获取类型化结果 #
csharp
var result = await kernel.InvokeAsync<SearchResult[]>("Search", "Search", arguments);
var searchResults = result.GetValue<SearchResult[]>();
获取元数据 #
csharp
var result = await kernel.InvokePromptAsync("问题");
var metadata = result.Metadata;
if (metadata != null)
{
var usage = metadata["Usage"] as Dictionary<string, object>;
Console.WriteLine($"Prompt Tokens: {usage?["PromptTokens"]}");
Console.WriteLine($"Completion Tokens: {usage?["CompletionTokens"]}");
}
流式执行 #
流式提示词 #
csharp
await foreach (var chunk in kernel.InvokePromptStreamingAsync("写一首诗"))
{
Console.Write(chunk);
}
流式函数调用 #
csharp
var function = kernel.Plugins["Text"]["WriteStory"];
await foreach (var chunk in kernel.InvokeStreamingAsync(function, arguments))
{
Console.Write(chunk);
}
完整流式示例 #
csharp
var function = kernel.CreateFunctionFromPrompt(
"写一篇关于{{$topic}}的长文章",
functionName: "WriteArticle"
);
var fullContent = new StringBuilder();
await foreach (var streamingContent in kernel.InvokeStreamingAsync<StreamingChatMessageContent>(
function,
new KernelArguments { ["topic"] = "人工智能" }))
{
var content = streamingContent.Content;
if (content != null)
{
Console.Write(content);
fullContent.Append(content);
}
}
Console.WriteLine("\n--- 完整内容 ---");
Console.WriteLine(fullContent.ToString());
函数组合 #
手动组合 #
csharp
// 步骤 1:翻译
var translated = await kernel.InvokeAsync(
"Translate", "ToEnglish",
new KernelArguments { ["input"] = chineseText }
);
// 步骤 2:摘要
var summarized = await kernel.InvokeAsync(
"Text", "Summarize",
new KernelArguments { ["input"] = translated.ToString() }
);
// 步骤 3:翻译回中文
var result = await kernel.InvokeAsync(
"Translate", "ToChinese",
new KernelArguments { ["input"] = summarized.ToString() }
);
使用管道模式 #
csharp
public static class FunctionPipeline
{
public static async Task<FunctionResult> PipelineAsync(
this Kernel kernel,
params (string Plugin, string Function, KernelArguments Arguments)[] steps)
{
FunctionResult? result = null;
foreach (var (plugin, function, args) in steps)
{
if (result != null)
{
args["input"] = result.ToString();
}
result = await kernel.InvokeAsync(plugin, function, args);
}
return result!;
}
}
// 使用
var result = await kernel.PipelineAsync(
("Translate", "ToEnglish", new KernelArguments { ["input"] = chineseText }),
("Text", "Summarize", new KernelArguments()),
("Translate", "ToChinese", new KernelArguments())
);
函数调用上下文 #
访问 Kernel #
csharp
[KernelFunction("process")]
public async Task<string> ProcessAsync(string input, Kernel kernel)
{
// 可以在函数内调用其他函数
var summary = await kernel.InvokeAsync("Text", "Summarize",
new KernelArguments { ["input"] = input });
return summary.ToString();
}
使用 KernelFunctionAttribute #
csharp
public class ContextAwarePlugin
{
[KernelFunction("analyze")]
public async Task<string> AnalyzeAsync(
string input,
Kernel kernel,
CancellationToken cancellationToken = default)
{
// 访问服务
var chatService = kernel.GetRequiredService<IChatCompletionService>();
// 调用其他函数
var related = await kernel.InvokeAsync(
"Search", "FindRelated",
new KernelArguments { ["query"] = input },
cancellationToken: cancellationToken
);
return $"分析结果: {related}";
}
}
最佳实践 #
1. 清晰的函数描述 #
csharp
[KernelFunction("calculate_mortgage")]
[Description("""
计算房屋贷款月供。
输入:
- principal: 贷款本金(元)
- rate: 年利率(如 0.05 表示 5%)
- years: 贷款年限
输出:
- 每月还款金额(元)
""")]
public double CalculateMortgage(
[Description("贷款本金")] double principal,
[Description("年利率")] double rate,
[Description("贷款年限")] int years)
{
// 实现
}
2. 参数验证 #
csharp
[KernelFunction("divide")]
public double Divide(double a, double b)
{
if (b == 0)
{
throw new KernelException("除数不能为零");
}
return a / b;
}
3. 异常处理 #
csharp
[KernelFunction("safe_operation")]
public async Task<string> SafeOperationAsync(string input)
{
try
{
// 执行操作
return await DoWorkAsync(input);
}
catch (Exception ex)
{
return $"操作失败: {ex.Message}";
}
}
4. 使用 CancellationToken #
csharp
[KernelFunction("long_operation")]
public async Task<string> LongOperationAsync(
string input,
CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
// 长时间操作
await Task.Delay(5000, cancellationToken);
return "完成";
}
下一步 #
现在你已经掌握了函数系统,接下来学习 规划器,了解如何自动编排函数执行!
最后更新:2026-04-04