Files
EmailBill/Service/AgentFramework/BaseAgent.cs
2026-01-12 14:34:03 +08:00

218 lines
6.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
};
}
}