|
|
using AI.Interface;
|
|
|
using AI.Models;
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Collections.ObjectModel;
|
|
|
using System.Diagnostics;
|
|
|
using System.Linq;
|
|
|
using System.Text;
|
|
|
using System.Threading;
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
namespace AI.Workflow
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// 步骤状态更新事件参数
|
|
|
/// </summary>
|
|
|
public class StepStatusUpdatedEventArgs : EventArgs
|
|
|
{
|
|
|
public PlanStep Step { get; set; } = null!;
|
|
|
public int StepIndex { get; set; }
|
|
|
public int TotalSteps { get; set; }
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 规划完成事件参数
|
|
|
/// </summary>
|
|
|
public class PlanCompletedEventArgs : EventArgs
|
|
|
{
|
|
|
public Plan Plan { get; set; } = null!;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 步骤思考更新事件参数
|
|
|
/// </summary>
|
|
|
public class StepThoughtUpdatedEventArgs : EventArgs
|
|
|
{
|
|
|
public PlanStep Step { get; set; } = null!;
|
|
|
public int StepIndex { get; set; }
|
|
|
public string Thought { get; set; } = string.Empty;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// ReAct 工作流 Agent 配置
|
|
|
/// </summary>
|
|
|
public class AgentConfig
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// 每个步骤最大重试次数(默认2次)
|
|
|
/// </summary>
|
|
|
public int MaxRetries { get; set; } = 2;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 遇到错误是否继续执行(默认false)
|
|
|
/// </summary>
|
|
|
public bool ContinueOnError { get; set; } = false;
|
|
|
|
|
|
/// <summary>
|
|
|
/// ReAct 模式最大迭代次数(默认3次)
|
|
|
/// </summary>
|
|
|
public int MaxReActIterations { get; set; } = 3;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 重试前等待时间(毫秒,默认1000ms)
|
|
|
/// </summary>
|
|
|
public int RetryDelayMs { get; set; } = 1000;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// ReAct 工作流 Agent - 使用 Planner + ReAct 模式执行任务
|
|
|
/// </summary>
|
|
|
public class Agent
|
|
|
{
|
|
|
#region 事件定义
|
|
|
|
|
|
/// <summary>
|
|
|
/// 步骤状态更新事件
|
|
|
/// </summary>
|
|
|
public event EventHandler<StepStatusUpdatedEventArgs>? StepStatusUpdated;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 规划完成事件
|
|
|
/// </summary>
|
|
|
public event EventHandler<PlanCompletedEventArgs>? PlanCompleted;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 步骤思考更新事件
|
|
|
/// </summary>
|
|
|
public event EventHandler<StepThoughtUpdatedEventArgs>? StepThoughtUpdated;
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region 属性
|
|
|
|
|
|
/// <summary>
|
|
|
/// Agent 配置
|
|
|
/// </summary>
|
|
|
public AgentConfig Config { get; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// Agent 唯一标识符
|
|
|
/// </summary>
|
|
|
public string Id { get; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// Agent 名称
|
|
|
/// </summary>
|
|
|
public string Name { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// Agent 描述
|
|
|
/// </summary>
|
|
|
public string Description { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// Agent 状态
|
|
|
/// </summary>
|
|
|
public WorkflowStatus Status { get; private set; } = WorkflowStatus.NotStarted;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 创建时间
|
|
|
/// </summary>
|
|
|
public DateTime CreatedAt { get; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 更新时间
|
|
|
/// </summary>
|
|
|
public DateTime UpdatedAt { get; private set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 开始执行时间
|
|
|
/// </summary>
|
|
|
public DateTime? StartedAt { get; private set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 完成时间
|
|
|
/// </summary>
|
|
|
public DateTime? CompletedAt { get; private set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 错误信息(如果执行失败)
|
|
|
/// </summary>
|
|
|
public string? ErrorMessage { get; private set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 执行快照(用于回溯和调试)
|
|
|
/// </summary>
|
|
|
public List<WorkflowState> StateSnapshots { get; } = new List<WorkflowState>();
|
|
|
|
|
|
/// <summary>
|
|
|
/// 规划结果
|
|
|
/// </summary>
|
|
|
public Plan? Plan { get; private set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 工作流状态
|
|
|
/// </summary>
|
|
|
public WorkflowState? State { get; private set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 当前执行的步骤索引
|
|
|
/// </summary>
|
|
|
public int CurrentStepIndex { get; private set; } = -1;
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region 内部组件
|
|
|
|
|
|
/// <summary>
|
|
|
/// Planner - 规划组件
|
|
|
/// </summary>
|
|
|
private Planner? _planner;
|
|
|
|
|
|
/// <summary>
|
|
|
/// Executor - 执行组件
|
|
|
/// </summary>
|
|
|
private Executor? _executor;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 聊天后端
|
|
|
/// </summary>
|
|
|
private readonly IChatBackend _chatBackend;
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region 构造函数
|
|
|
|
|
|
/// <summary>
|
|
|
/// 创建 ReAct 工作流 Agent
|
|
|
/// </summary>
|
|
|
/// <param name="chatBackend">聊天后端</param>
|
|
|
/// <param name="config">配置(可选,使用默认配置)</param>
|
|
|
public Agent(IChatBackend chatBackend, AgentConfig? config = null)
|
|
|
{
|
|
|
_chatBackend = chatBackend ?? throw new ArgumentNullException(nameof(chatBackend));
|
|
|
Config = config ?? new AgentConfig();
|
|
|
Id = Guid.NewGuid().ToString();
|
|
|
CreatedAt = DateTime.Now;
|
|
|
UpdatedAt = DateTime.Now;
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region 公共方法
|
|
|
|
|
|
/// <summary>
|
|
|
/// 重置 Agent 状态
|
|
|
/// </summary>
|
|
|
public void Reset()
|
|
|
{
|
|
|
Status = WorkflowStatus.NotStarted;
|
|
|
StartedAt = null;
|
|
|
CompletedAt = null;
|
|
|
UpdatedAt = DateTime.Now;
|
|
|
ErrorMessage = null;
|
|
|
CurrentStepIndex = -1;
|
|
|
StateSnapshots.Clear();
|
|
|
Plan = null;
|
|
|
State = null;
|
|
|
_planner = null;
|
|
|
_executor = null;
|
|
|
|
|
|
Debug.WriteLine($"ReActWorkflowAgent '{Name}' has been reset");
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 获取当前执行的步骤
|
|
|
/// </summary>
|
|
|
/// <returns>当前步骤,如果未开始或已完成则返回 null</returns>
|
|
|
public PlanStep? GetCurrentStep()
|
|
|
{
|
|
|
if (Plan == null || CurrentStepIndex < 0 || CurrentStepIndex >= Plan.Steps.Count)
|
|
|
{
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
return Plan.Steps[CurrentStepIndex];
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 执行工作流(Planner + ReAct 模式,硬流程控制)
|
|
|
/// </summary>
|
|
|
/// <param name="goal">任务目标</param>
|
|
|
/// <param name="cancellationToken">取消令牌</param>
|
|
|
/// <param name="timeout">超时时间,为 null 表示不限制</param>
|
|
|
/// <returns>执行结果</returns>
|
|
|
public async Task<string> ExecuteAsync(string goal, CancellationToken cancellationToken = default, TimeSpan? timeout = null)
|
|
|
{
|
|
|
using var timeoutCts = timeout.HasValue ? new CancellationTokenSource(timeout.Value) : null;
|
|
|
var linkedCts = timeoutCts != null
|
|
|
? CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token)
|
|
|
: null;
|
|
|
var effectiveToken = linkedCts?.Token ?? cancellationToken;
|
|
|
|
|
|
try
|
|
|
{
|
|
|
Status = WorkflowStatus.Running;
|
|
|
StartedAt = DateTime.Now;
|
|
|
UpdatedAt = DateTime.Now;
|
|
|
ErrorMessage = null;
|
|
|
CurrentStepIndex = -1;
|
|
|
|
|
|
Debug.WriteLine($"开始 ReActWorkflowAgent 执行: {goal}");
|
|
|
|
|
|
// 初始化状态
|
|
|
State = new WorkflowState
|
|
|
{
|
|
|
WorkflowId = Id
|
|
|
};
|
|
|
|
|
|
// 初始化组件
|
|
|
InitializeComponents();
|
|
|
|
|
|
// 1. Planner 规划(LLM 负责)
|
|
|
Debug.WriteLine("【阶段1】Planner 规划中...");
|
|
|
Plan = await _planner!.PlanAsync(goal, effectiveToken);
|
|
|
|
|
|
Debug.WriteLine($"规划完成,共 {Plan.Steps.Count} 个步骤");
|
|
|
|
|
|
// 触发规划完成事件
|
|
|
PlanCompleted?.Invoke(this, new PlanCompletedEventArgs { Plan = Plan });
|
|
|
|
|
|
// 2. Runtime 执行循环:代码决定执行流程
|
|
|
string result = await ExecuteRuntimeLoop(effectiveToken);
|
|
|
|
|
|
// 代码控制:所有步骤执行完成
|
|
|
Status = WorkflowStatus.Completed;
|
|
|
CompletedAt = DateTime.Now;
|
|
|
CurrentStepIndex = -1;
|
|
|
|
|
|
Debug.WriteLine($"\nReActWorkflowAgent 执行完成");
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
catch (OperationCanceledException ex)
|
|
|
{
|
|
|
Status = WorkflowStatus.Cancelled;
|
|
|
CompletedAt = DateTime.Now;
|
|
|
UpdatedAt = DateTime.Now;
|
|
|
ErrorMessage = ex.CancellationToken.IsCancellationRequested ? "已取消" : "已超时";
|
|
|
|
|
|
Debug.WriteLine($"ReActWorkflowAgent 已取消或超时: {ErrorMessage}");
|
|
|
throw;
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
Status = WorkflowStatus.Failed;
|
|
|
CompletedAt = DateTime.Now;
|
|
|
UpdatedAt = DateTime.Now;
|
|
|
ErrorMessage = ex.Message;
|
|
|
|
|
|
Debug.WriteLine($"ReActWorkflowAgent 执行失败: {ex.Message}");
|
|
|
throw;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 将 PlanStep 转换为 WorkflowStepModel
|
|
|
/// </summary>
|
|
|
public static WorkflowStepModel ConvertToWorkflowStepModel(PlanStep planStep)
|
|
|
{
|
|
|
var model = new WorkflowStepModel
|
|
|
{
|
|
|
Id = planStep.Id,
|
|
|
DisplayName = planStep.Description,
|
|
|
Order = planStep.Order
|
|
|
};
|
|
|
|
|
|
// 转换状态
|
|
|
model.Status = planStep.Status switch
|
|
|
{
|
|
|
PlanStepStatus.Pending => WorkflowStepStatus.Pending,
|
|
|
PlanStepStatus.Running => WorkflowStepStatus.Running,
|
|
|
PlanStepStatus.Completed => WorkflowStepStatus.Completed,
|
|
|
PlanStepStatus.Failed => WorkflowStepStatus.Failed,
|
|
|
_ => WorkflowStepStatus.Pending
|
|
|
};
|
|
|
|
|
|
// 存储结果
|
|
|
if (!string.IsNullOrEmpty(planStep.Result))
|
|
|
{
|
|
|
model.OutputResult = planStep.Result;
|
|
|
}
|
|
|
|
|
|
return model;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 将 Plan 转换为 WorkflowStepModel 集合
|
|
|
/// </summary>
|
|
|
public static ObservableCollection<WorkflowStepModel> ConvertPlanToStepModels(Plan plan)
|
|
|
{
|
|
|
var models = new ObservableCollection<WorkflowStepModel>();
|
|
|
foreach (var step in plan.Steps.OrderBy(s => s.Order))
|
|
|
{
|
|
|
models.Add(ConvertToWorkflowStepModel(step));
|
|
|
}
|
|
|
return models;
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region 私有方法
|
|
|
|
|
|
/// <summary>
|
|
|
/// 初始化组件
|
|
|
/// </summary>
|
|
|
private void InitializeComponents()
|
|
|
{
|
|
|
// 初始化 Planner
|
|
|
_planner = new Planner(_chatBackend);
|
|
|
|
|
|
// 初始化 Executor
|
|
|
_executor = new Executor(_chatBackend, State!, (stepId, thought) =>
|
|
|
{
|
|
|
// 找到对应的步骤并触发 Thought 更新事件
|
|
|
if (Plan != null)
|
|
|
{
|
|
|
var step = Plan.Steps.FirstOrDefault(s => s.Id == stepId);
|
|
|
if (step != null)
|
|
|
{
|
|
|
var stepIndex = Plan.Steps.IndexOf(step);
|
|
|
OnStepThoughtUpdated(step, stepIndex, thought);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// Runtime 执行循环:控制步骤的执行流程
|
|
|
/// </summary>
|
|
|
private async Task<string> ExecuteRuntimeLoop(CancellationToken cancellationToken)
|
|
|
{
|
|
|
if (Plan == null || _executor == null)
|
|
|
{
|
|
|
throw new InvalidOperationException("Plan 或 Executor 未初始化");
|
|
|
}
|
|
|
|
|
|
var contextBuilder = new StringBuilder();
|
|
|
var executionResults = new List<ExecutionResult>();
|
|
|
|
|
|
// 代码控制:逐步执行每个步骤
|
|
|
for (int i = 0; i < Plan.Steps.Count; i++)
|
|
|
{
|
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
|
|
|
|
var step = Plan.Steps[i];
|
|
|
CurrentStepIndex = i;
|
|
|
State!.CurrentNodeId = step.Id;
|
|
|
|
|
|
Debug.WriteLine($"\n【代码控制】执行步骤 {i + 1}/{Plan.Steps.Count}: {step.Description}");
|
|
|
|
|
|
// 触发步骤开始事件
|
|
|
OnStepStatusUpdated(step, i, Plan.Steps.Count);
|
|
|
|
|
|
// 构建上下文(之前的步骤结果)
|
|
|
string? context = contextBuilder.Length > 0 ? contextBuilder.ToString() : null;
|
|
|
|
|
|
// 代码控制:重试机制
|
|
|
ExecutionResult? result = null;
|
|
|
int retryCount = 0;
|
|
|
bool stepSuccess = false;
|
|
|
|
|
|
while (retryCount <= Config.MaxRetries && !stepSuccess)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
// ReAct 模式执行(LLM 负责具体执行)
|
|
|
result = await _executor.ExecuteStepWithReActAsync(step, context, Config.MaxReActIterations, cancellationToken);
|
|
|
|
|
|
if (result.IsSuccess)
|
|
|
{
|
|
|
stepSuccess = true;
|
|
|
executionResults.Add(result);
|
|
|
|
|
|
// 更新上下文
|
|
|
contextBuilder.AppendLine($"步骤 {step.Order}: {step.Description}");
|
|
|
contextBuilder.AppendLine($"结果: {result.Content}");
|
|
|
if (!string.IsNullOrEmpty(result.Observation))
|
|
|
{
|
|
|
contextBuilder.AppendLine($"观察: {result.Observation}");
|
|
|
}
|
|
|
contextBuilder.AppendLine();
|
|
|
|
|
|
Debug.WriteLine($"步骤 {step.Order} 执行成功");
|
|
|
|
|
|
// 触发步骤完成事件
|
|
|
OnStepStatusUpdated(step, i, Plan.Steps.Count);
|
|
|
}
|
|
|
else if (result.ShouldRetry && retryCount < Config.MaxRetries)
|
|
|
{
|
|
|
retryCount++;
|
|
|
Debug.WriteLine($"步骤 {step.Order} 执行失败,重试 {retryCount}/{Config.MaxRetries}");
|
|
|
await Task.Delay(Config.RetryDelayMs, cancellationToken);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
stepSuccess = false;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
catch (OperationCanceledException)
|
|
|
{
|
|
|
throw;
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
Debug.WriteLine($"步骤 {step.Order} 执行异常: {ex.Message}");
|
|
|
|
|
|
if (retryCount < Config.MaxRetries)
|
|
|
{
|
|
|
retryCount++;
|
|
|
Debug.WriteLine($"异常重试 {retryCount}/{Config.MaxRetries}");
|
|
|
await Task.Delay(Config.RetryDelayMs, cancellationToken);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
result = new ExecutionResult
|
|
|
{
|
|
|
IsSuccess = false,
|
|
|
ErrorMessage = ex.Message,
|
|
|
ShouldRetry = false
|
|
|
};
|
|
|
stepSuccess = false;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 代码控制:错误处理决策
|
|
|
if (!stepSuccess)
|
|
|
{
|
|
|
if (Config.ContinueOnError)
|
|
|
{
|
|
|
Debug.WriteLine($"步骤 {step.Order} 执行失败,但继续执行后续步骤");
|
|
|
step.Status = PlanStepStatus.Failed;
|
|
|
step.ErrorMessage = result?.ErrorMessage ?? "执行失败";
|
|
|
|
|
|
// 即使失败也更新上下文
|
|
|
contextBuilder.AppendLine($"步骤 {step.Order}: {step.Description} [失败]");
|
|
|
contextBuilder.AppendLine($"错误: {result?.ErrorMessage ?? "未知错误"}");
|
|
|
contextBuilder.AppendLine();
|
|
|
|
|
|
// 触发步骤失败事件
|
|
|
OnStepStatusUpdated(step, i, Plan.Steps.Count);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
// 代码决定:失败时停止
|
|
|
Debug.WriteLine($"步骤 {step.Order} 执行失败,停止工作流");
|
|
|
Status = WorkflowStatus.Failed;
|
|
|
ErrorMessage = $"步骤 {step.Order} 执行失败: {result?.ErrorMessage ?? "未知错误"}";
|
|
|
throw new Exception(ErrorMessage);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 保存状态快照
|
|
|
StateSnapshots.Add((WorkflowState)State!.Clone());
|
|
|
UpdatedAt = DateTime.Now;
|
|
|
}
|
|
|
|
|
|
// 构建最终结果
|
|
|
return BuildFinalResult(contextBuilder, executionResults);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 构建最终结果
|
|
|
/// </summary>
|
|
|
private string BuildFinalResult(StringBuilder contextBuilder, List<ExecutionResult> executionResults)
|
|
|
{
|
|
|
var result = new StringBuilder();
|
|
|
result.AppendLine("=== 工作流执行结果 ===");
|
|
|
result.AppendLine();
|
|
|
result.AppendLine("执行摘要:");
|
|
|
result.AppendLine($"总步骤数: {Plan?.Steps.Count ?? 0}");
|
|
|
result.AppendLine($"成功步骤: {executionResults.Count(r => r.IsSuccess)}");
|
|
|
result.AppendLine($"失败步骤: {executionResults.Count(r => !r.IsSuccess)}");
|
|
|
result.AppendLine();
|
|
|
result.AppendLine("详细执行过程:");
|
|
|
result.Append(contextBuilder.ToString());
|
|
|
|
|
|
return result.ToString();
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 触发步骤状态更新事件
|
|
|
/// </summary>
|
|
|
protected virtual void OnStepStatusUpdated(PlanStep step, int stepIndex, int totalSteps)
|
|
|
{
|
|
|
StepStatusUpdated?.Invoke(this, new StepStatusUpdatedEventArgs
|
|
|
{
|
|
|
Step = step,
|
|
|
StepIndex = stepIndex,
|
|
|
TotalSteps = totalSteps
|
|
|
});
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 触发步骤思考更新事件
|
|
|
/// </summary>
|
|
|
protected virtual void OnStepThoughtUpdated(PlanStep step, int stepIndex, string thought)
|
|
|
{
|
|
|
StepThoughtUpdated?.Invoke(this, new StepThoughtUpdatedEventArgs
|
|
|
{
|
|
|
Step = step,
|
|
|
StepIndex = stepIndex,
|
|
|
Thought = thought
|
|
|
});
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
}
|
|
|
}
|