You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

216 lines
7.1 KiB
C#

1 month ago
using AI.Interface;
using AI.Models;
using System;
using System.Diagnostics;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace AI.Workflow
{
/// <summary>
/// Planner - 负责规划任务,将任务分解成步骤
/// </summary>
public class Planner
{
private readonly IChatBackend _chatBackend;
private readonly ChatSession _planningSession;
public Planner(IChatBackend chatBackend)
{
_chatBackend = chatBackend;
_planningSession = new ChatSession();
// 初始化规划提示词
_planningSession.AddSystemMessage(GetPlanningPrompt());
}
/// <summary>
/// 规划任务
/// </summary>
/// <param name="goal">任务目标</param>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>规划结果</returns>
public async Task<Plan> PlanAsync(string goal, CancellationToken cancellationToken = default)
{
var plan = new Plan
{
Goal = goal
};
try
{
// 请求 Planner 生成规划
string planningPrompt = $"请为以下任务制定详细的执行计划:\n\n任务{goal}\n\n请将任务分解为具体的步骤每个步骤应该是可执行的、明确的。";
string response = await _chatBackend.AskAsync(planningPrompt, _planningSession, null, cancellationToken);
// 解析规划结果
ParsePlanFromResponse(response, plan);
Debug.WriteLine($"Planner 生成了 {plan.Steps.Count} 个步骤");
}
catch (Exception ex)
{
Debug.WriteLine($"Planner 规划失败: {ex.Message}");
throw;
}
return plan;
}
/// <summary>
/// 从响应中解析规划步骤
/// </summary>
private void ParsePlanFromResponse(string response, Plan plan)
{
// 尝试解析 JSON 格式
if (TryParseJsonPlan(response, plan))
{
return;
}
// 尝试解析列表格式1. 步骤1 2. 步骤2 ...
if (TryParseListPlan(response, plan))
{
return;
}
// 如果都解析失败,将整个响应作为单个步骤
plan.Steps.Add(new PlanStep
{
Order = 1,
Description = response.Trim()
});
}
/// <summary>
/// 尝试解析 JSON 格式的规划
/// </summary>
private bool TryParseJsonPlan(string response, Plan plan)
{
try
{
// 尝试提取 JSON 部分
var jsonMatch = Regex.Match(response, @"\{[\s\S]*\}");
if (!jsonMatch.Success)
{
return false;
}
var json = jsonMatch.Value;
var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
if (root.TryGetProperty("steps", out var stepsElement) && stepsElement.ValueKind == JsonValueKind.Array)
{
int order = 1;
foreach (var stepElement in stepsElement.EnumerateArray())
{
var step = new PlanStep
{
Order = order++,
Description = stepElement.GetProperty("description").GetString() ?? string.Empty
};
plan.Steps.Add(step);
}
return true;
}
}
catch
{
// JSON 解析失败,继续尝试其他格式
}
return false;
}
/// <summary>
/// 尝试解析列表格式的规划
/// </summary>
private bool TryParseListPlan(string response, Plan plan)
{
// 匹配各种列表格式1. 2. 3. 或 - 或 * 等
var patterns = new[]
{
@"^\s*(\d+)\.\s+(.+)$", // 1. 步骤
@"^\s*[-*]\s+(.+)$", // - 步骤 或 * 步骤
@"^\s*(\d+)\)\s+(.+)$" // 1) 步骤
};
var lines = response.Split('\n', StringSplitOptions.RemoveEmptyEntries);
int order = 1;
foreach (var line in lines)
{
var trimmedLine = line.Trim();
if (string.IsNullOrWhiteSpace(trimmedLine))
continue;
foreach (var pattern in patterns)
{
var match = Regex.Match(trimmedLine, pattern);
if (match.Success)
{
string description = match.Groups.Count > 2 ? match.Groups[2].Value : match.Groups[1].Value;
plan.Steps.Add(new PlanStep
{
Order = order++,
Description = description.Trim()
});
break;
}
}
}
return plan.Steps.Count > 0;
}
/// <summary>
/// 获取规划提示词
/// </summary>
private string GetPlanningPrompt()
{
return @"你是一个专业的任务规划专家,擅长将复杂任务分解为清晰、可执行的步骤序列。
1. ****
2. ****
3. ****
4. ****
5. ****
- 使""""""""""""
- "" XYZ ""
- 使
- 20-50
使 JSON
{
""steps"": [
{""description"": ""1""},
{""description"": ""2""},
...
]
}
JSON使
1. 1
2. 2
...
-
-
-
- ";
}
}
}