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
{
///
/// Planner - 负责规划任务,将任务分解成步骤
///
public class Planner
{
private readonly IChatBackend _chatBackend;
private readonly ChatSession _planningSession;
public Planner(IChatBackend chatBackend)
{
_chatBackend = chatBackend;
_planningSession = new ChatSession();
// 初始化规划提示词
_planningSession.AddSystemMessage(GetPlanningPrompt());
}
///
/// 规划任务
///
/// 任务目标
/// 取消令牌
/// 规划结果
public async Task 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;
}
///
/// 从响应中解析规划步骤
///
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()
});
}
///
/// 尝试解析 JSON 格式的规划
///
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;
}
///
/// 尝试解析列表格式的规划
///
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;
}
///
/// 获取规划提示词
///
private string GetPlanningPrompt()
{
return @"你是一个专业的任务规划专家,擅长将复杂任务分解为清晰、可执行的步骤序列。
【核心职责】
将用户提出的任务目标分解为一系列有序、可执行的步骤,确保每个步骤都有明确的目标和可衡量的结果。
【规划原则】
1. **原子性**:每个步骤应该是独立的、可单独执行的最小任务单元
2. **顺序性**:步骤之间必须有清晰的逻辑顺序和依赖关系
3. **可执行性**:每个步骤的描述应该具体、明确,能够直接指导执行
4. **完整性**:确保所有必要的步骤都被包含,不遗漏关键环节
5. **可验证性**:每个步骤完成后应该有明确的验证标准
【步骤描述要求】
- 使用动词开头,明确表达要执行的动作(如:""加载文件""、""验证数据""、""生成报告"")
- 包含必要的上下文信息(如:""从指定路径加载 XYZ 文件"")
- 避免模糊表述,使用具体、可操作的语言
- 每个步骤描述控制在 20-50 字之间
【输出格式】
优先使用 JSON 格式,结构如下:
{
""steps"": [
{""description"": ""步骤1的详细描述""},
{""description"": ""步骤2的详细描述""},
...
]
}
如果无法返回 JSON,请使用编号列表格式:
1. 步骤1的详细描述
2. 步骤2的详细描述
...
【注意事项】
- 不要创建过于细碎的步骤,也不要创建过于宏大的步骤
- 考虑步骤之间的依赖关系,确保顺序合理
- 如果任务涉及多个阶段,可以按阶段组织步骤
- 对于需要用户输入或确认的步骤,明确标注";
}
}
}