218 lines
6.1 KiB
C#
218 lines
6.1 KiB
C#
|
|
using System.Diagnostics;
|
|||
|
|
using Microsoft.Extensions.Logging;
|
|||
|
|
|
|||
|
|
namespace Service.AgentFramework;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Agent 基类 - 提供通用的工作流编排能力
|
|||
|
|
/// </summary>
|
|||
|
|
public abstract class BaseAgent
|
|||
|
|
{
|
|||
|
|
protected readonly IToolRegistry _toolRegistry;
|
|||
|
|
protected readonly ILogger<BaseAgent> _logger;
|
|||
|
|
protected readonly List<ExecutionStep> _steps = new();
|
|||
|
|
protected readonly Dictionary<string, object?> _metadata = new();
|
|||
|
|
|
|||
|
|
// 定义 ActivitySource 供 DevUI 捕获
|
|||
|
|
private static readonly ActivitySource _activitySource = new("Microsoft.Agents.Workflows");
|
|||
|
|
|
|||
|
|
protected BaseAgent(
|
|||
|
|
IToolRegistry toolRegistry,
|
|||
|
|
ILogger<BaseAgent> logger)
|
|||
|
|
{
|
|||
|
|
_toolRegistry = toolRegistry;
|
|||
|
|
_logger = logger;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 记录执行步骤
|
|||
|
|
/// </summary>
|
|||
|
|
protected void RecordStep(
|
|||
|
|
string name,
|
|||
|
|
string description,
|
|||
|
|
object? output = null,
|
|||
|
|
long durationMs = 0)
|
|||
|
|
{
|
|||
|
|
var step = new ExecutionStep
|
|||
|
|
{
|
|||
|
|
Name = name,
|
|||
|
|
Description = description,
|
|||
|
|
Status = "Completed",
|
|||
|
|
Output = output,
|
|||
|
|
DurationMs = durationMs
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
_steps.Add(step);
|
|||
|
|
|
|||
|
|
// 使用 Activity 进行埋点,将被 DevUI 自动捕获
|
|||
|
|
using var activity = _activitySource.StartActivity(name);
|
|||
|
|
activity?.SetTag("agent.step.description", description);
|
|||
|
|
if (output != null) activity?.SetTag("agent.step.output", output.ToString());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 记录失败的步骤
|
|||
|
|
/// </summary>
|
|||
|
|
protected void RecordFailedStep(
|
|||
|
|
string name,
|
|||
|
|
string description,
|
|||
|
|
string error,
|
|||
|
|
long durationMs = 0)
|
|||
|
|
{
|
|||
|
|
var step = new ExecutionStep
|
|||
|
|
{
|
|||
|
|
Name = name,
|
|||
|
|
Description = description,
|
|||
|
|
Status = "Failed",
|
|||
|
|
Error = error,
|
|||
|
|
DurationMs = durationMs
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
_steps.Add(step);
|
|||
|
|
|
|||
|
|
using var activity = _activitySource.StartActivity($"{name} (Failed)");
|
|||
|
|
activity?.SetTag("agent.step.error", error);
|
|||
|
|
_logger.LogError("[Agent步骤失败] {StepName}: {Error}", name, error);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 设置元数据
|
|||
|
|
/// </summary>
|
|||
|
|
protected void SetMetadata(string key, object? value)
|
|||
|
|
{
|
|||
|
|
_metadata[key] = value;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 获取执行日志
|
|||
|
|
/// </summary>
|
|||
|
|
protected List<ExecutionStep> GetExecutionLog()
|
|||
|
|
{
|
|||
|
|
return _steps.ToList();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 生成多轮总结
|
|||
|
|
/// </summary>
|
|||
|
|
protected virtual async Task<string> GenerateSummaryAsync(
|
|||
|
|
string[] phases,
|
|||
|
|
Dictionary<string, object?> phaseResults)
|
|||
|
|
{
|
|||
|
|
var summaryParts = new List<string>();
|
|||
|
|
|
|||
|
|
// 简单的总结生成逻辑
|
|||
|
|
// 实际项目中可以集成 AI 生成更复杂的总结
|
|||
|
|
foreach (var phase in phases)
|
|||
|
|
{
|
|||
|
|
if (phaseResults.TryGetValue(phase, out var result))
|
|||
|
|
{
|
|||
|
|
summaryParts.Add($"{phase}:已完成");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return await Task.FromResult(string.Join(";", summaryParts) + "。");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 调用 Tool(简化接口)
|
|||
|
|
/// </summary>
|
|||
|
|
protected async Task<TResult> CallToolAsync<TResult>(
|
|||
|
|
string toolName,
|
|||
|
|
string stepName,
|
|||
|
|
string stepDescription)
|
|||
|
|
{
|
|||
|
|
var sw = System.Diagnostics.Stopwatch.StartNew();
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
_logger.LogInformation("开始执行 Tool: {ToolName}", toolName);
|
|||
|
|
var result = await _toolRegistry.InvokeToolAsync<TResult>(toolName);
|
|||
|
|
sw.Stop();
|
|||
|
|
|
|||
|
|
RecordStep(stepName, stepDescription, result, sw.ElapsedMilliseconds);
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
sw.Stop();
|
|||
|
|
RecordFailedStep(stepName, stepDescription, ex.Message, sw.ElapsedMilliseconds);
|
|||
|
|
throw;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 调用带参数的 Tool
|
|||
|
|
/// </summary>
|
|||
|
|
protected async Task<TResult> CallToolAsync<TParam, TResult>(
|
|||
|
|
string toolName,
|
|||
|
|
TParam param,
|
|||
|
|
string stepName,
|
|||
|
|
string stepDescription)
|
|||
|
|
{
|
|||
|
|
var sw = System.Diagnostics.Stopwatch.StartNew();
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
_logger.LogInformation("开始执行 Tool: {ToolName},参数: {Param}", toolName, param);
|
|||
|
|
var result = await _toolRegistry.InvokeToolAsync<TParam, TResult>(toolName, param);
|
|||
|
|
sw.Stop();
|
|||
|
|
|
|||
|
|
RecordStep(stepName, stepDescription, result, sw.ElapsedMilliseconds);
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
sw.Stop();
|
|||
|
|
RecordFailedStep(stepName, stepDescription, ex.Message, sw.ElapsedMilliseconds);
|
|||
|
|
throw;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 调用带多参数的 Tool
|
|||
|
|
/// </summary>
|
|||
|
|
protected async Task<TResult> CallToolAsync<TParam1, TParam2, TResult>(
|
|||
|
|
string toolName,
|
|||
|
|
TParam1 param1,
|
|||
|
|
TParam2 param2,
|
|||
|
|
string stepName,
|
|||
|
|
string stepDescription)
|
|||
|
|
{
|
|||
|
|
var sw = System.Diagnostics.Stopwatch.StartNew();
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
_logger.LogInformation("开始执行 Tool: {ToolName},参数: {Param1}, {Param2}", toolName, param1, param2);
|
|||
|
|
var result = await _toolRegistry.InvokeToolAsync<TParam1, TParam2, TResult>(
|
|||
|
|
toolName, param1, param2);
|
|||
|
|
sw.Stop();
|
|||
|
|
|
|||
|
|
RecordStep(stepName, stepDescription, result, sw.ElapsedMilliseconds);
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
sw.Stop();
|
|||
|
|
RecordFailedStep(stepName, stepDescription, ex.Message, sw.ElapsedMilliseconds);
|
|||
|
|
throw;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 获取 Agent 执行结果
|
|||
|
|
/// </summary>
|
|||
|
|
protected AgentResult<T> CreateResult<T>(
|
|||
|
|
T data,
|
|||
|
|
string summary,
|
|||
|
|
bool success = true,
|
|||
|
|
string? error = null)
|
|||
|
|
{
|
|||
|
|
return new AgentResult<T>
|
|||
|
|
{
|
|||
|
|
Data = data,
|
|||
|
|
Summary = summary,
|
|||
|
|
Steps = _steps,
|
|||
|
|
Metadata = _metadata,
|
|||
|
|
Success = success,
|
|||
|
|
Error = error
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
}
|