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.

366 lines
13 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.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>();
}
}
}