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