AI Agent 开发 #

项目概述 #

本节将构建一个具有自主决策能力的 AI Agent,具备以下功能:

  • 任务理解与分解
  • 自动工具选择
  • 多步骤任务执行
  • 结果验证与修正
  • 学习与记忆

Agent 架构 #

text
┌─────────────────────────────────────────────────────────────┐
│                    AI Agent 架构                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│                    ┌─────────────┐                          │
│                    │   用户任务   │                          │
│                    └──────┬──────┘                          │
│                           │                                  │
│                    ┌──────▼──────┐                          │
│                    │  任务理解    │                          │
│                    └──────┬──────┘                          │
│                           │                                  │
│                    ┌──────▼──────┐                          │
│                    │  任务分解    │                          │
│                    └──────┬──────┘                          │
│                           │                                  │
│         ┌─────────────────┼─────────────────┐               │
│         │                 │                 │               │
│    ┌────▼────┐      ┌────▼────┐      ┌────▼────┐          │
│    │ 工具选择 │      │ 工具选择 │      │ 工具选择 │          │
│    └────┬────┘      └────┬────┘      └────┬────┘          │
│         │                 │                 │               │
│    ┌────▼────┐      ┌────▼────┐      ┌────▼────┐          │
│    │ 执行工具 │      │ 执行工具 │      │ 执行工具 │          │
│    └────┬────┘      └────┬────┘      └────┬────┘          │
│         │                 │                 │               │
│         └─────────────────┼─────────────────┘               │
│                           │                                  │
│                    ┌──────▼──────┐                          │
│                    │  结果验证    │                          │
│                    └──────┬──────┘                          │
│                           │                                  │
│                    ┌──────▼──────┐                          │
│                    │  输出结果    │                          │
│                    └─────────────┘                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

项目结构 #

text
AIAgent/
├── Agents/
│   ├── IAgent.cs
│   ├── BaseAgent.cs
│   └── TaskAgent.cs
├── Tools/
│   ├── ITool.cs
│   ├── WebSearchTool.cs
│   ├── CalculatorTool.cs
│   ├── EmailTool.cs
│   └── DatabaseTool.cs
├── Memory/
│   ├── AgentMemory.cs
│   └── ExperienceStore.cs
├── Services/
│   ├── ITaskPlanner.cs
│   ├── TaskPlanner.cs
│   └── ExecutionEngine.cs
├── Models/
│   ├── Task.cs
│   ├── Plan.cs
│   └── ExecutionResult.cs
└── Program.cs

核心代码实现 #

1. Agent 基类 #

csharp
public interface IAgent
{
    string Name { get; }
    string Description { get; }
    Task<AgentResponse> ExecuteAsync(string task);
    void AddTool(ITool tool);
}

public abstract class BaseAgent : IAgent
{
    protected readonly Kernel _kernel;
    protected readonly IChatCompletionService _chatService;
    protected readonly AgentMemory _memory;
    protected readonly List<ITool> _tools = new();

    public string Name { get; }
    public string Description { get; }

    protected BaseAgent(
        string name,
        string description,
        Kernel kernel,
        AgentMemory memory)
    {
        Name = name;
        Description = description;
        _kernel = kernel;
        _chatService = kernel.GetRequiredService<IChatCompletionService>();
        _memory = memory;
    }

    public void AddTool(ITool tool)
    {
        _tools.Add(tool);
        _kernel.Plugins.AddFromObject(tool, tool.Name);
    }

    public abstract Task<AgentResponse> ExecuteAsync(string task);
}

2. 任务 Agent #

csharp
public class TaskAgent : BaseAgent
{
    private readonly ITaskPlanner _planner;
    private readonly ExecutionEngine _engine;
    private readonly ILogger<TaskAgent> _logger;

    public TaskAgent(
        Kernel kernel,
        AgentMemory memory,
        ITaskPlanner planner,
        ILogger<TaskAgent> logger)
        : base("TaskAgent", "执行复杂任务的智能代理", kernel, memory)
    {
        _planner = planner;
        _engine = new ExecutionEngine(kernel, logger);
        _logger = logger;
    }

    public override async Task<AgentResponse> ExecuteAsync(string task)
    {
        _logger.LogInformation("Agent 开始执行任务: {Task}", task);

        var relevantExperiences = await _memory.GetRelevantExperiencesAsync(task);
        
        var plan = await _planner.CreatePlanAsync(task, _tools, relevantExperiences);
        
        _logger.LogInformation("生成执行计划: {Steps} 个步骤", plan.Steps.Count);

        var results = new List<StepResult>();
        
        foreach (var step in plan.Steps)
        {
            var result = await ExecuteStepAsync(step, results);
            results.Add(result);
            
            if (!result.Success)
            {
                var recoveryPlan = await _planner.CreateRecoveryPlanAsync(
                    task, step, result.Error, results);
                
                if (recoveryPlan != null)
                {
                    var recoveryResult = await ExecuteStepAsync(recoveryPlan.Steps[0], results);
                    if (recoveryResult.Success)
                    {
                        continue;
                    }
                }
                
                return new AgentResponse
                {
                    Success = false,
                    Message = $"任务执行失败: {result.Error}",
                    Results = results
                };
            }
        }

        await _memory.SaveExperienceAsync(task, plan, results);

        var finalResult = await SummarizeResultsAsync(task, results);

        return new AgentResponse
        {
            Success = true,
            Message = finalResult,
            Results = results
        };
    }

    private async Task<StepResult> ExecuteStepAsync(
        PlanStep step,
        List<StepResult> previousResults)
    {
        _logger.LogInformation("执行步骤: {Step}", step.Description);

        try
        {
            var arguments = await ResolveArgumentsAsync(step, previousResults);
            
            var result = await _kernel.InvokeAsync(
                step.PluginName,
                step.FunctionName,
                arguments
            );

            return new StepResult
            {
                StepId = step.Id,
                Success = true,
                Output = result.ToString(),
                Metadata = result.Metadata
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "步骤执行失败: {Step}", step.Description);
            
            return new StepResult
            {
                StepId = step.Id,
                Success = false,
                Error = ex.Message
            };
        }
    }

    private async Task<KernelArguments> ResolveArgumentsAsync(
        PlanStep step,
        List<StepResult> previousResults)
    {
        var arguments = new KernelArguments();

        foreach (var param in step.Parameters)
        {
            if (param.Source == "previous_step" && param.StepIndex.HasValue)
            {
                var previousResult = previousResults[param.StepIndex.Value];
                arguments[param.Name] = previousResult.Output;
            }
            else if (param.Source == "user_input")
            {
                arguments[param.Name] = param.Value;
            }
            else
            {
                arguments[param.Name] = param.Value;
            }
        }

        return arguments;
    }

    private async Task<string> SummarizeResultsAsync(
        string task,
        List<StepResult> results)
    {
        var summaryPrompt = $"""
            任务: {task}
            
            执行结果:
            {string.Join("\n", results.Select((r, i) => $"步骤{i + 1}: {r.Output}"))}
            
            请总结任务执行结果:
            """;

        var summary = await _kernel.InvokePromptAsync(summaryPrompt);
        return summary.ToString();
    }
}

3. 任务规划器 #

csharp
public class TaskPlanner : ITaskPlanner
{
    private readonly Kernel _kernel;
    private readonly ILogger<TaskPlanner> _logger;

    public async Task<Plan> CreatePlanAsync(
        string task,
        List<ITool> tools,
        List<Experience> experiences)
    {
        var toolsDescription = string.Join("\n", tools.Select(t => 
            $"- {t.Name}: {t.Description}"));

        var experienceContext = experiences.Any()
            ? $"\n\n相关经验:\n{string.Join("\n", experiences.Select(e => $"- {e.Task}: {e.Summary}"))}"
            : "";

        var planningPrompt = $"""
            你是一个任务规划专家。请为以下任务创建执行计划。
            
            可用工具:
            {toolsDescription}
            {experienceContext}
            
            任务: {task}
            
            请按以下 JSON 格式返回计划:
            {{
                "steps": [
                    {{
                        "id": "step-1",
                        "description": "步骤描述",
                        "pluginName": "插件名",
                        "functionName": "函数名",
                        "parameters": [
                            {{
                                "name": "参数名",
                                "source": "user_input/previous_step",
                                "value": "值",
                                "stepIndex": null 或 步骤索引
                            }}
                        ]
                    }}
                ]
            }}
            """;

        var result = await _kernel.InvokePromptAsync(planningPrompt);
        var planJson = ExtractJson(result.ToString());
        
        return JsonSerializer.Deserialize<Plan>(planJson) ?? new Plan();
    }

    public async Task<Plan?> CreateRecoveryPlanAsync(
        string task,
        PlanStep failedStep,
        string error,
        List<StepResult> previousResults)
    {
        var recoveryPrompt = $"""
            任务执行失败,请创建恢复计划。
            
            原任务: {task}
            失败步骤: {failedStep.Description}
            错误信息: {error}
            
            已完成步骤:
            {string.Join("\n", previousResults.Select((r, i) => $"步骤{i + 1}: {r.Output}"))}
            
            请提供替代方案或返回 null 表示无法恢复。
            """;

        var result = await _kernel.InvokePromptAsync(recoveryPrompt);
        
        if (result.ToString().Contains("无法恢复"))
        {
            return null;
        }

        var planJson = ExtractJson(result.ToString());
        return JsonSerializer.Deserialize<Plan>(planJson);
    }

    private string ExtractJson(string text)
    {
        var start = text.IndexOf('{');
        var end = text.LastIndexOf('}');
        
        if (start >= 0 && end > start)
        {
            return text.Substring(start, end - start + 1);
        }
        
        return "{}";
    }
}

4. 工具定义 #

csharp
public interface ITool
{
    string Name { get; }
    string Description { get; }
}

public class WebSearchTool : ITool
{
    private readonly ISearchService _searchService;

    public string Name => "WebSearch";
    public string Description => "搜索网络获取信息";

    public WebSearchTool(ISearchService searchService)
    {
        _searchService = searchService;
    }

    [KernelFunction("search")]
    [Description("搜索网络信息")]
    public async Task<string> SearchAsync(
        [Description("搜索关键词")] string query)
    {
        var results = await _searchService.SearchAsync(query);
        return string.Join("\n", results.Select(r => $"- {r.Title}: {r.Snippet}"));
    }
}

public class EmailTool : ITool
{
    private readonly IEmailService _emailService;

    public string Name => "Email";
    public string Description => "发送邮件";

    public EmailTool(IEmailService emailService)
    {
        _emailService = emailService;
    }

    [KernelFunction("send_email")]
    [Description("发送邮件")]
    public async Task<string> SendEmailAsync(
        [Description("收件人")] string to,
        [Description("主题")] string subject,
        [Description("内容")] string body)
    {
        await _emailService.SendAsync(to, subject, body);
        return $"邮件已发送给 {to}";
    }
}

public class DatabaseTool : ITool
{
    private readonly IDatabaseService _dbService;

    public string Name => "Database";
    public string Description => "查询数据库";

    public DatabaseTool(IDatabaseService dbService)
    {
        _dbService = dbService;
    }

    [KernelFunction("query")]
    [Description("执行数据库查询")]
    public async Task<string> QueryAsync(
        [Description("SQL 查询语句")] string sql)
    {
        return await _dbService.ExecuteQueryAsync(sql);
    }
}

5. Agent 记忆 #

csharp
public class AgentMemory
{
    private readonly SemanticTextMemory _memory;
    private readonly ITextEmbeddingGenerationService _embeddingService;

    public async Task SaveExperienceAsync(
        string task,
        Plan plan,
        List<StepResult> results)
    {
        var summary = await SummarizeExperienceAsync(task, plan, results);
        
        await _memory.SaveInformationAsync(
            "agent_experiences",
            text: $"任务: {task}\n总结: {summary}",
            id: Guid.NewGuid().ToString()
        );
    }

    public async Task<List<Experience>> GetRelevantExperiencesAsync(string task)
    {
        var experiences = new List<Experience>();
        
        var results = _memory.SearchAsync(
            "agent_experiences",
            query: task,
            limit: 3
        );

        await foreach (var result in results)
        {
            experiences.Add(new Experience
            {
                Task = result.Metadata.Text,
                Summary = result.Metadata.Description
            });
        }

        return experiences;
    }

    private async Task<string> SummarizeExperienceAsync(
        string task,
        Plan plan,
        List<StepResult> results)
    {
        var summaryPrompt = $"""
            总结以下任务执行经验:
            
            任务: {task}
            计划步骤: {plan.Steps.Count}
            执行结果: {results.Count(r => r.Success)}/{results.Count} 成功
            
            请用一句话总结关键经验:
            """;

        var summary = await _kernel.InvokePromptAsync(summaryPrompt);
        return summary.ToString();
    }
}

6. 使用示例 #

csharp
var builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion(...);
var kernel = builder.Build();

var memory = new AgentMemory(...);
var planner = new TaskPlanner(kernel, logger);
var agent = new TaskAgent(kernel, memory, planner, logger);

agent.AddTool(new WebSearchTool(searchService));
agent.AddTool(new EmailTool(emailService));
agent.AddTool(new DatabaseTool(dbService));

var result = await agent.ExecuteAsync(
    "搜索最新的 AI 新闻,总结要点,然后发送到 my@email.com"
);

Console.WriteLine($"成功: {result.Success}");
Console.WriteLine($"结果: {result.Message}");

最佳实践 #

1. 工具设计 #

csharp
// 好的做法:单一职责
public class EmailTool : ITool { }
public class CalendarTool : ITool { }

// 避免:功能过多
public class EverythingTool : ITool { }

2. 错误处理 #

csharp
public async Task<StepResult> ExecuteStepAsync(PlanStep step)
{
    try
    {
        // 执行
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "步骤失败");
        return new StepResult { Success = false, Error = ex.Message };
    }
}

下一步 #

现在你已经掌握了 AI Agent 开发,接下来学习 工作流自动化,构建自动化工作流系统!

最后更新:2026-04-04