|
|
|
|
|
using AI.Interface;
|
|
|
|
|
|
using AI.Models;
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
using System.Threading;
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
|
|
namespace AI.Workflow
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 执行结果
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class ExecutionResult
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 是否成功
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public bool IsSuccess { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 执行结果内容
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public string Content { get; set; } = string.Empty;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 错误信息(如果失败)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public string? ErrorMessage { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 是否需要重试
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public bool ShouldRetry { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 观察信息(ReAct 模式)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public string? Observation { get; set; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 步骤执行器 - 使用 ReAct 模式执行步骤:推理-行动-观察
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class Executor
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly IChatBackend _chatBackend;
|
|
|
|
|
|
private readonly ChatSession _executionSession;
|
|
|
|
|
|
private readonly WorkflowState _state;
|
|
|
|
|
|
private readonly List<ReActStep> _reactHistory = new();
|
|
|
|
|
|
private readonly Action<string, string>? _onThoughtUpdated;
|
|
|
|
|
|
|
|
|
|
|
|
public Executor(IChatBackend chatBackend, WorkflowState state, Action<string, string>? onThoughtUpdated = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_chatBackend = chatBackend;
|
|
|
|
|
|
_state = state;
|
|
|
|
|
|
_executionSession = new ChatSession();
|
|
|
|
|
|
_onThoughtUpdated = onThoughtUpdated;
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化 ReAct 提示词
|
|
|
|
|
|
_executionSession.AddSystemMessage(GetReActPrompt());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 使用 ReAct 模式执行单个步骤
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="step">要执行的步骤</param>
|
|
|
|
|
|
/// <param name="context">上下文信息(之前的步骤结果)</param>
|
|
|
|
|
|
/// <param name="maxIterations">最大迭代次数(默认3次)</param>
|
|
|
|
|
|
/// <param name="cancellationToken">取消令牌</param>
|
|
|
|
|
|
/// <returns>执行结果</returns>
|
|
|
|
|
|
public async Task<ExecutionResult> ExecuteStepWithReActAsync(PlanStep step, string? context = null, int maxIterations = 3, CancellationToken cancellationToken = default)
|
|
|
|
|
|
{
|
|
|
|
|
|
step.Status = PlanStepStatus.Running;
|
|
|
|
|
|
step.StartedAt = DateTime.Now;
|
|
|
|
|
|
step.ErrorMessage = null;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.WriteLine($"ReAct 模式执行步骤 {step.Order}: {step.Description}");
|
|
|
|
|
|
|
|
|
|
|
|
var reactStep = new ReActStep
|
|
|
|
|
|
{
|
|
|
|
|
|
StepId = step.Id,
|
|
|
|
|
|
StepDescription = step.Description,
|
|
|
|
|
|
Context = context
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// ReAct 循环:推理 -> 行动 -> 观察
|
|
|
|
|
|
for (int iteration = 0; iteration < maxIterations; iteration++)
|
|
|
|
|
|
{
|
|
|
|
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
|
|
|
|
|
|
|
|
|
|
Debug.WriteLine($"ReAct 迭代 {iteration + 1}/{maxIterations}");
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 推理(Think)
|
|
|
|
|
|
string thought = await ThinkAsync(step, context, reactStep, cancellationToken);
|
|
|
|
|
|
reactStep.Thoughts.Add(thought);
|
|
|
|
|
|
Debug.WriteLine($"推理: {thought}");
|
|
|
|
|
|
|
|
|
|
|
|
// 通知 Thought 更新
|
|
|
|
|
|
_onThoughtUpdated?.Invoke(step.Id, thought);
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 行动(Act)
|
|
|
|
|
|
string action = await ActAsync(step, thought, context, reactStep, cancellationToken);
|
|
|
|
|
|
reactStep.Actions.Add(action);
|
|
|
|
|
|
Debug.WriteLine($"行动: {action}");
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 观察(Observe)
|
|
|
|
|
|
string observation = await ObserveAsync(action, reactStep, cancellationToken);
|
|
|
|
|
|
reactStep.Observations.Add(observation);
|
|
|
|
|
|
Debug.WriteLine($"观察: {observation}");
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否完成
|
|
|
|
|
|
if (IsTaskComplete(observation, reactStep))
|
|
|
|
|
|
{
|
|
|
|
|
|
step.Status = PlanStepStatus.Completed;
|
|
|
|
|
|
step.Result = BuildFinalResult(reactStep);
|
|
|
|
|
|
step.CompletedAt = DateTime.Now;
|
|
|
|
|
|
|
|
|
|
|
|
_reactHistory.Add(reactStep);
|
|
|
|
|
|
|
|
|
|
|
|
Debug.WriteLine($"步骤 {step.Order} 执行完成");
|
|
|
|
|
|
|
|
|
|
|
|
return new ExecutionResult
|
|
|
|
|
|
{
|
|
|
|
|
|
IsSuccess = true,
|
|
|
|
|
|
Content = step.Result,
|
|
|
|
|
|
Observation = observation
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 达到最大迭代次数,返回当前结果
|
|
|
|
|
|
step.Status = PlanStepStatus.Completed;
|
|
|
|
|
|
step.Result = BuildFinalResult(reactStep);
|
|
|
|
|
|
step.CompletedAt = DateTime.Now;
|
|
|
|
|
|
|
|
|
|
|
|
_reactHistory.Add(reactStep);
|
|
|
|
|
|
|
|
|
|
|
|
return new ExecutionResult
|
|
|
|
|
|
{
|
|
|
|
|
|
IsSuccess = true,
|
|
|
|
|
|
Content = step.Result,
|
|
|
|
|
|
Observation = "达到最大迭代次数"
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
step.Status = PlanStepStatus.Failed;
|
|
|
|
|
|
step.ErrorMessage = ex.Message;
|
|
|
|
|
|
step.CompletedAt = DateTime.Now;
|
|
|
|
|
|
|
|
|
|
|
|
Debug.WriteLine($"步骤 {step.Order} 执行失败: {ex.Message}");
|
|
|
|
|
|
|
|
|
|
|
|
return new ExecutionResult
|
|
|
|
|
|
{
|
|
|
|
|
|
IsSuccess = false,
|
|
|
|
|
|
ErrorMessage = ex.Message,
|
|
|
|
|
|
ShouldRetry = true
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 推理阶段:分析当前情况和需要采取的行动
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private async Task<string> ThinkAsync(PlanStep step, string? context, ReActStep reactStep, CancellationToken cancellationToken)
|
|
|
|
|
|
{
|
|
|
|
|
|
var prompt = new StringBuilder();
|
|
|
|
|
|
prompt.AppendLine("【推理阶段】");
|
|
|
|
|
|
prompt.AppendLine($"当前步骤:{step.Description}");
|
|
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(context))
|
|
|
|
|
|
{
|
|
|
|
|
|
prompt.AppendLine($"\n上下文信息:");
|
|
|
|
|
|
prompt.AppendLine(context);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (reactStep.Thoughts.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
prompt.AppendLine($"\n之前的推理:");
|
|
|
|
|
|
for (int i = 0; i < reactStep.Thoughts.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
prompt.AppendLine($"{i + 1}. {reactStep.Thoughts[i]}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (reactStep.Observations.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
prompt.AppendLine($"\n之前的观察结果:");
|
|
|
|
|
|
for (int i = 0; i < reactStep.Observations.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
prompt.AppendLine($"{i + 1}. {reactStep.Observations[i]}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
prompt.AppendLine($"\n请分析当前情况,思考需要采取什么行动来完成这个步骤。");
|
|
|
|
|
|
|
|
|
|
|
|
string thought = await _chatBackend.AskAsync(prompt.ToString(), _executionSession, null, cancellationToken);
|
|
|
|
|
|
return thought;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 行动阶段:执行具体的操作
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private async Task<string> ActAsync(PlanStep step, string thought, string? context, ReActStep reactStep, CancellationToken cancellationToken)
|
|
|
|
|
|
{
|
|
|
|
|
|
var prompt = new StringBuilder();
|
|
|
|
|
|
prompt.AppendLine("【行动阶段】");
|
|
|
|
|
|
prompt.AppendLine($"步骤描述:{step.Description}");
|
|
|
|
|
|
prompt.AppendLine($"\n推理结果:{thought}");
|
|
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(context))
|
|
|
|
|
|
{
|
|
|
|
|
|
prompt.AppendLine($"\n上下文信息:");
|
|
|
|
|
|
prompt.AppendLine(context);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (reactStep.Actions.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
prompt.AppendLine($"\n之前的行动:");
|
|
|
|
|
|
for (int i = 0; i < reactStep.Actions.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
prompt.AppendLine($"{i + 1}. {reactStep.Actions[i]}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
prompt.AppendLine($"\n请根据推理结果,执行具体的行动来完成这个步骤。");
|
|
|
|
|
|
|
|
|
|
|
|
string action = await _chatBackend.AskAsync(prompt.ToString(), _executionSession, null, cancellationToken);
|
|
|
|
|
|
return action;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 观察阶段:观察行动的结果
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private async Task<string> ObserveAsync(string action, ReActStep reactStep, CancellationToken cancellationToken)
|
|
|
|
|
|
{
|
|
|
|
|
|
var prompt = new StringBuilder();
|
|
|
|
|
|
prompt.AppendLine("【观察阶段】");
|
|
|
|
|
|
prompt.AppendLine($"刚才的行动:{action}");
|
|
|
|
|
|
prompt.AppendLine($"\n请观察行动的结果,评估是否完成了步骤目标。如果未完成,说明还需要做什么。");
|
|
|
|
|
|
|
|
|
|
|
|
string observation = await _chatBackend.AskAsync(prompt.ToString(), _executionSession, null, cancellationToken);
|
|
|
|
|
|
return observation;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 判断任务是否完成
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private bool IsTaskComplete(string observation, ReActStep reactStep)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 简单的完成判断:如果观察结果包含完成相关的关键词
|
|
|
|
|
|
var completionKeywords = new[] { "完成", "成功", "已达成", "已完成", "done", "completed", "success" };
|
|
|
|
|
|
var lowerObservation = observation.ToLower();
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var keyword in completionKeywords)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (lowerObservation.Contains(keyword.ToLower()))
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 构建最终结果
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private string BuildFinalResult(ReActStep reactStep)
|
|
|
|
|
|
{
|
|
|
|
|
|
var result = new StringBuilder();
|
|
|
|
|
|
result.AppendLine("执行过程:");
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < reactStep.Thoughts.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
result.AppendLine($"\n迭代 {i + 1}:");
|
|
|
|
|
|
result.AppendLine($"推理: {reactStep.Thoughts[i]}");
|
|
|
|
|
|
if (i < reactStep.Actions.Count)
|
|
|
|
|
|
{
|
|
|
|
|
|
result.AppendLine($"行动: {reactStep.Actions[i]}");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (i < reactStep.Observations.Count)
|
|
|
|
|
|
{
|
|
|
|
|
|
result.AppendLine($"观察: {reactStep.Observations[i]}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return result.ToString();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取 ReAct 提示词
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private string GetReActPrompt()
|
|
|
|
|
|
{
|
|
|
|
|
|
return @"你是一个使用 ReAct(推理-行动-观察)模式执行任务的智能助手。
|
|
|
|
|
|
|
|
|
|
|
|
【ReAct 工作模式】
|
|
|
|
|
|
ReAct 是一种迭代式的问题解决方法,通过不断循环以下三个步骤来完成任务:
|
|
|
|
|
|
|
|
|
|
|
|
1. **推理(Think)**:深入分析当前情况
|
|
|
|
|
|
- 理解当前步骤的目标和要求
|
|
|
|
|
|
- 分析已有的上下文信息和历史记录
|
|
|
|
|
|
- 识别需要解决的问题和可能的障碍
|
|
|
|
|
|
- 制定具体的行动计划
|
|
|
|
|
|
- 推理过程要逻辑清晰、条理分明
|
|
|
|
|
|
|
|
|
|
|
|
2. **行动(Act)**:执行具体的操作
|
|
|
|
|
|
- 根据推理结果,采取明确的行动
|
|
|
|
|
|
- 行动要具体、可执行、有针对性
|
|
|
|
|
|
- 如果涉及工具调用,确保参数正确
|
|
|
|
|
|
- 行动描述要清晰,便于后续观察
|
|
|
|
|
|
|
|
|
|
|
|
3. **观察(Observe)**:评估行动结果
|
|
|
|
|
|
- 仔细分析行动产生的结果
|
|
|
|
|
|
- 判断是否达到了预期目标
|
|
|
|
|
|
- 识别成功点和失败点
|
|
|
|
|
|
- 评估是否需要继续迭代
|
|
|
|
|
|
- 观察要客观、准确、全面
|
|
|
|
|
|
|
|
|
|
|
|
【执行原则】
|
|
|
|
|
|
- **迭代优化**:如果任务未完成,基于观察结果进行下一轮推理,不断优化策略
|
|
|
|
|
|
- **目标导向**:始终牢记当前步骤的最终目标,不要偏离方向
|
|
|
|
|
|
- **充分利用上下文**:仔细分析之前步骤的结果和观察,避免重复工作
|
|
|
|
|
|
- **明确完成标准**:当任务完成时,明确说明已完成,并总结关键成果
|
|
|
|
|
|
|
|
|
|
|
|
【推理质量要求】
|
|
|
|
|
|
- 推理要深入,不能停留在表面
|
|
|
|
|
|
- 要分析问题的根本原因,而不仅仅是症状
|
|
|
|
|
|
- 要考虑多种可能的解决方案,选择最优的
|
|
|
|
|
|
- 要预测行动可能的结果,提前规避风险
|
|
|
|
|
|
|
|
|
|
|
|
【行动执行要求】
|
|
|
|
|
|
- 行动要具体,避免模糊的描述
|
|
|
|
|
|
- 要充分利用可用的工具和资源
|
|
|
|
|
|
- 要确保行动的可执行性和有效性
|
|
|
|
|
|
- 如果遇到障碍,要灵活调整策略
|
|
|
|
|
|
|
|
|
|
|
|
【观察评估要求】
|
|
|
|
|
|
- 要全面评估结果,不能只看表面
|
|
|
|
|
|
- 要识别成功的关键因素和失败的根因
|
|
|
|
|
|
- 要判断是否真正完成了目标
|
|
|
|
|
|
- 要为下一轮迭代提供有价值的反馈
|
|
|
|
|
|
|
|
|
|
|
|
请严格按照 ReAct 模式执行任务,确保推理深入、行动有效、观察准确。";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// ReAct 步骤记录
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
internal class ReActStep
|
|
|
|
|
|
{
|
|
|
|
|
|
public string StepId { get; set; } = string.Empty;
|
|
|
|
|
|
public string StepDescription { get; set; } = string.Empty;
|
|
|
|
|
|
public string? Context { get; set; }
|
|
|
|
|
|
public List<string> Thoughts { get; } = new List<string>();
|
|
|
|
|
|
public List<string> Actions { get; } = new List<string>();
|
|
|
|
|
|
public List<string> Observations { get; } = new List<string>();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|