I was learning about the planner capabilities by going through the Book creator sample and the Example12_SequentialPlanner
I thought it was odd that this type of code
|
private static async Task<Plan> ExecutePlanAsync( |
|
IKernel kernel, |
|
Plan plan, |
|
string input = "", |
|
int maxSteps = 10) |
|
{ |
|
Stopwatch sw = new(); |
|
sw.Start(); |
|
|
|
// loop until complete or at most N steps |
|
try |
|
{ |
|
for (int step = 1; plan.HasNextStep && step < maxSteps; step++) |
|
{ |
|
if (string.IsNullOrEmpty(input)) |
|
{ |
|
await plan.InvokeNextStepAsync(kernel.CreateNewContext()); |
|
// or await kernel.StepAsync(plan); |
|
} |
|
else |
|
{ |
|
plan = await kernel.StepAsync(input, plan); |
|
input = string.Empty; |
|
} |
|
|
|
if (!plan.HasNextStep) |
|
{ |
|
Console.WriteLine($"Step {step} - COMPLETE!"); |
|
Console.WriteLine(plan.State.ToString()); |
|
break; |
|
} |
|
|
|
Console.WriteLine($"Step {step} - Results so far:"); |
|
Console.WriteLine(plan.State.ToString()); |
|
} |
|
} |
|
catch (KernelException e) |
|
{ |
|
Console.WriteLine("Step - Execution failed:"); |
|
Console.WriteLine(e.Message); |
|
} |
was not part of the library. I expected these common use cases to be abstracted.
I actually expected the first PoetrySamplesAsync which uses a different method of running the plan to run it to completion, but from what I saw it only ran the first step of the plan.
|
var result = await kernel.RunAsync(plan); |
The other EmailSamplesAsync and BookSamplesAsync using a different method of calling ExecutePlanAsync
ExecutePlanAsync mixes stopwatch timing, step counting, and printing of log messages which can distract from the core purpose of the example which is to teach developers how to sequentially execute a plan.
I would propose the library has a built in sequential execution implemented as a generator like so
async IAsyncEnumerable<(ContextVariables, Plan, int)> ExecutePlanSequentiallyAsync(
IKernel kernel,
Plan plan,
string input = "")
{
// for each plan step, invoke step and yield state
for (int stepIndex = 0; plan.HasNextStep; stepIndex = +1)
{
if (string.IsNullOrEmpty(input))
{
plan = await kernel.StepAsync(plan);
}
else
{
plan = await kernel.StepAsync(input, plan);
}
yield return (plan.State, plan.Steps.ElementAt(stepIndex), stepIndex);
}
}
You can then separate the SK responsibility of plan execution from the Application responsibilities (in the case of example) such as writing logs before and after, or breaking after desired step max
PrintStep("Execute Plan:");
var planExecutor = ExecutePlanSequentiallyAsync(kernel, plan);
await foreach (var (state, step, stepIndex) in planExecutor)
{
PrintStep($"Step {stepIndex + 1}: {plan.Name} {step.Name}");
Console.WriteLine(state.ToString());
Console.WriteLine();
}
PrintStep($"Plan Complete");
What do you think about an approach like this?
I was learning about the planner capabilities by going through the Book creator sample and the Example12_SequentialPlanner
I thought it was odd that this type of code
semantic-kernel/samples/dotnet/kernel-syntax-examples/Example12_SequentialPlanner.cs
Lines 194 to 234 in f31c58b
was not part of the library. I expected these common use cases to be abstracted.
I actually expected the first
PoetrySamplesAsyncwhich uses a different method of running the plan to run it to completion, but from what I saw it only ran the first step of the plan.semantic-kernel/samples/dotnet/kernel-syntax-examples/Example12_SequentialPlanner.cs
Line 55 in f31c58b
The other EmailSamplesAsync and BookSamplesAsync using a different method of calling
ExecutePlanAsyncExecutePlanAsync mixes stopwatch timing, step counting, and printing of log messages which can distract from the core purpose of the example which is to teach developers how to sequentially execute a plan.
I would propose the library has a built in sequential execution implemented as a generator like so
You can then separate the SK responsibility of plan execution from the Application responsibilities (in the case of example) such as writing logs before and after, or breaking after desired step max
What do you think about an approach like this?