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.

573 lines
19 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
}
}