规划器 #

概述 #

规划器(Planner)是 Semantic Kernel 的智能编排组件,能够自动将复杂的用户请求分解为一系列可执行的步骤,并协调执行这些步骤。

规划器架构 #

text
┌─────────────────────────────────────────────────────────────┐
│                    规划器工作流程                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  用户请求                                                    │
│  "帮我查询北京的天气,然后写一首关于天气的诗"                │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  1. 理解意图                                         │   │
│  │     分析用户想要完成的任务                          │   │
│  └─────────────────────────────────────────────────────┘   │
│                            │                                │
│                            ▼                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  2. 生成计划                                         │   │
│  │     Step 1: WeatherPlugin.GetWeather("北京")        │   │
│  │     Step 2: PoemPlugin.WritePoem(weather_info)      │   │
│  └─────────────────────────────────────────────────────┘   │
│                            │                                │
│                            ▼                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  3. 执行计划                                         │   │
│  │     按顺序执行每个步骤                              │   │
│  │     将上一步输出传递给下一步                        │   │
│  └─────────────────────────────────────────────────────┘   │
│                            │                                │
│                            ▼                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  4. 返回结果                                         │   │
│  │     最终生成的诗歌                                  │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

规划器类型 #

FunctionCallingStepwisePlanner #

这是推荐的规划器,使用 LLM 的函数调用能力来规划和执行任务。

csharp
using Microsoft.SemanticKernel.Planning;

var planner = new FunctionCallingStepwisePlanner();

var result = await planner.ExecuteAsync(
    kernel,
    "帮我查询北京的天气,然后写一首关于天气的诗"
);

Console.WriteLine(result);

配置选项 #

csharp
var options = new FunctionCallingStepwisePlannerOptions
{
    MaxIterations = 10,
    MaxTokens = 4000
};

var planner = new FunctionCallingStepwisePlanner(options);

使用规划器 #

基本使用 #

csharp
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Planning;

var builder = Kernel.CreateBuilder();
builder.AddOpenAIChatCompletion("gpt-4", "api-key");
var kernel = builder.Build();

// 注册插件
kernel.Plugins.AddFromType<WeatherPlugin>("Weather");
kernel.Plugins.AddFromType<PoemPlugin>("Poem");

// 创建规划器
var planner = new FunctionCallingStepwisePlanner();

// 执行任务
var result = await planner.ExecuteAsync(
    kernel,
    "查询北京今天的天气,如果天气晴朗就写一首阳光的诗,否则写一首雨天的诗"
);

Console.WriteLine(result);

带初始参数 #

csharp
var arguments = new KernelArguments
{
    ["city"] = "北京",
    ["style"] = "现代诗"
};

var result = await planner.ExecuteAsync(
    kernel,
    "根据指定的城市和风格写诗",
    arguments
);

指定可用插件 #

csharp
var options = new FunctionCallingStepwisePlannerOptions
{
    // 只使用指定的插件
    GetAvailableFunctionsAsync = (kernel) => Task.FromResult(
        kernel.Plugins.GetFunctionsMetadata()
            .Where(f => f.PluginName == "Weather" || f.PluginName == "Poem")
    )
};

var planner = new FunctionCallingStepwisePlanner(options);

规划器执行流程 #

详细执行过程 #

csharp
var planner = new FunctionCallingStepwisePlanner();

// 执行并获取详细结果
var result = await planner.ExecuteAsync(
    kernel,
    "计算 5 加 3,然后乘以 2"
);

// 查看执行步骤
if (result.Iterations != null)
{
    foreach (var iteration in result.Iterations)
    {
        Console.WriteLine($"步骤: {iteration.FunctionName}");
        Console.WriteLine($"参数: {string.Join(", ", iteration.Arguments)}");
        Console.WriteLine($"结果: {iteration.Result}");
    }
}

获取中间结果 #

csharp
public class StepResult
{
    public string FunctionName { get; set; }
    public string PluginName { get; set; }
    public Dictionary<string, object> Arguments { get; set; }
    public string Result { get; set; }
}

// 自定义规划器以捕获中间结果
public class ObservablePlanner
{
    private readonly FunctionCallingStepwisePlanner _planner;
    public List<StepResult> Steps { get; } = new();

    public ObservablePlanner()
    {
        _planner = new FunctionCallingStepwisePlanner();
    }

    public async Task<string> ExecuteAsync(Kernel kernel, string goal)
    {
        // 添加事件监听
        kernel.FunctionInvoking += (s, e) =>
        {
            Console.WriteLine($"[调用] {e.Function.PluginName}.{e.Function.Name}");
        };

        kernel.FunctionInvoked += (s, e) =>
        {
            Steps.Add(new StepResult
            {
                PluginName = e.Function.PluginName,
                FunctionName = e.Function.Name,
                Result = e.Result.ToString()
            });
        };

        return await _planner.ExecuteAsync(kernel, goal);
    }
}

高级配置 #

配置最大迭代次数 #

csharp
var options = new FunctionCallingStepwisePlannerOptions
{
    MaxIterations = 5  // 限制最大执行步骤数
};

var planner = new FunctionCallingStepwisePlanner(options);

配置系统提示词 #

csharp
var options = new FunctionCallingStepwisePlannerOptions
{
    SystemPrompt = """
        你是一个智能助手,可以帮助用户完成各种任务。
        
        可用的工具:
        {{$available_functions}}
        
        请根据用户的请求,选择合适的工具来完成任务。
        """
};

var planner = new FunctionCallingStepwisePlanner(options);

自定义函数选择 #

csharp
var options = new FunctionCallingStepwisePlannerOptions
{
    GetAvailableFunctionsAsync = async (kernel) =>
    {
        var allFunctions = kernel.Plugins.GetFunctionsMetadata();
        
        // 过滤敏感函数
        return allFunctions.Where(f => 
            !f.Name.Contains("Delete") && 
            !f.Name.Contains("Remove"));
    }
};

实战示例 #

示例 1:数据处理流程 #

csharp
// 注册插件
kernel.Plugins.AddFromType<DataPlugin>("Data");
kernel.Plugins.AddFromType<AnalysisPlugin>("Analysis");
kernel.Plugins.AddFromType<ReportPlugin>("Report");

var planner = new FunctionCallingStepwisePlanner();

var result = await planner.ExecuteAsync(
    kernel,
    "从数据库获取销售数据,分析趋势,然后生成一份中文报告"
);

示例 2:多步骤工作流 #

csharp
kernel.Plugins.AddFromType<EmailPlugin>("Email");
kernel.Plugins.AddFromType<CalendarPlugin>("Calendar");
kernel.Plugins.AddFromType<TaskPlugin>("Task");

var planner = new FunctionCallingStepwisePlanner();

var result = await planner.ExecuteAsync(
    kernel,
    """
    执行以下任务:
    1. 查找明天下午空闲的时间段
    2. 创建一个会议邀请
    3. 发送邮件通知所有参会者
    """
);

示例 3:条件执行 #

csharp
kernel.Plugins.AddFromType<WeatherPlugin>("Weather");
kernel.Plugins.AddFromType<NotificationPlugin>("Notification");
kernel.Plugins.AddFromType<CalendarPlugin>("Calendar");

var planner = new FunctionCallingStepwisePlanner();

var result = await planner.ExecuteAsync(
    kernel,
    """
    检查明天的天气预报:
    - 如果下雨,发送提醒带伞的通知
    - 如果晴天,安排户外活动
    """
);

规划器最佳实践 #

1. 提供清晰的函数描述 #

csharp
public class WeatherPlugin
{
    [KernelFunction("get_weather")]
    [Description("""
        获取指定城市的天气信息。
        
        参数:
        - city: 城市名称,如"北京"、"上海"
        
        返回:
        - 天气信息,包括温度、天气状况、湿度等
        """)]
    public async Task<string> GetWeather(
        [Description("城市名称")] string city)
    {
        // 实现
    }
}

2. 限制可用函数 #

csharp
// 只暴露必要的函数给规划器
var options = new FunctionCallingStepwisePlannerOptions
{
    GetAvailableFunctionsAsync = (kernel) => Task.FromResult(
        kernel.Plugins.GetFunctionsMetadata()
            .Where(f => f.PluginName is "Weather" or "Email" or "Calendar")
    )
};

3. 设置合理的迭代限制 #

csharp
var options = new FunctionCallingStepwisePlannerOptions
{
    MaxIterations = 10  // 防止无限循环
};

4. 处理执行失败 #

csharp
try
{
    var result = await planner.ExecuteAsync(kernel, goal);
}
catch (KernelException ex)
{
    Console.WriteLine($"规划执行失败: {ex.Message}");
    // 回退方案
}

5. 监控执行过程 #

csharp
kernel.FunctionInvoking += (s, e) =>
{
    Console.WriteLine($"[开始] {e.Function.PluginName}.{e.Function.Name}");
};

kernel.FunctionInvoked += (s, e) =>
{
    Console.WriteLine($"[完成] {e.Function.Name}");
    Console.WriteLine($"[结果] {e.Result}");
};

var result = await planner.ExecuteAsync(kernel, goal);

规划器与其他组件协作 #

与记忆系统协作 #

csharp
// 保存规划结果到记忆
var result = await planner.ExecuteAsync(kernel, goal);

await kernel.Memory.SaveInformationAsync(
    "planning_history",
    text: $"目标: {goal}\n结果: {result}",
    id: Guid.NewGuid().ToString()
);

与过滤器协作 #

csharp
public class PlanningFilter : IFunctionFilter
{
    public async Task OnFunctionInvocationAsync(
        FunctionInvocationContext context,
        Func<FunctionInvocationContext, Task> next)
    {
        // 记录规划步骤
        LogStep(context);
        
        await next(context);
        
        // 验证结果
        ValidateResult(context);
    }
}

kernel.FunctionFilters.Add(new PlanningFilter());

调试规划器 #

启用详细日志 #

csharp
using Microsoft.Extensions.Logging;

var loggerFactory = LoggerFactory.Create(builder =>
{
    builder.AddConsole();
    builder.SetMinimumLevel(LogLevel.Debug);
});

var kernel = Kernel.CreateBuilder()
    .AddOpenAIChatCompletion("gpt-4", "api-key")
    .Build();

kernel.LoggerFactory = loggerFactory;

查看生成的计划 #

csharp
// 使用事件查看规划决策
kernel.FunctionInvoking += (s, e) =>
{
    Console.WriteLine($"调用: {e.Function.PluginName}.{e.Function.Name}");
    foreach (var arg in e.Arguments)
    {
        Console.WriteLine($"  {arg.Key}: {arg.Value}");
    }
};

下一步 #

现在你已经掌握了规划器,接下来学习 提示词模板,了解如何设计高效的提示词!

最后更新:2026-04-04