1. 理解AI Agent的核心价值
在.NET生态中构建智能代理系统,首先要明确AI Agent与传统聊天机器人的本质区别。普通聊天模型像是一个知识丰富的顾问,能够回答问题却无法采取行动;而AI Agent更像是一位具备执行力的助手,能够规划、决策并完成实际任务。
1.1 Agent系统的三大支柱
一个完整的Agent系统建立在三个核心组件之上:
-
目标导向的任务理解:Agent需要明确识别用户意图并将其转化为可执行的目标。例如"安排下周会议"这个模糊需求,Agent应能分解为"查询参与者空闲时间→预定会议室→发送邀请"等具体步骤。
-
工具调用能力:通过Semantic Kernel等框架,我们可以将.NET应用中的方法暴露为Agent可调用的工具。这些工具需要满足:
- 单一职责原则(每个工具只做一件事)
- 清晰的输入输出定义
- 完善的错误处理机制
-
状态持久化:Agent需要维护任务执行的上下文,包括:
- 已完成的操作记录
- 中间结果缓存
- 下一步行动计划
1.2 执行循环:Agent的核心工作机制
Agent的执行流程遵循"感知-思考-行动"循环:
mermaid复制graph TD
A[接收用户目标] --> B[分析任务需求]
B --> C{需要工具?}
C -->|是| D[选择合适工具]
C -->|否| E[直接响应]
D --> F[执行工具调用]
F --> G[评估结果]
G --> H{任务完成?}
H -->|否| B
H -->|是| I[返回最终结果]
这个循环的关键在于Agent能够根据执行结果动态调整策略,而不是简单地按预定流程机械执行。例如当预定会议室失败时,Agent应该能够自动尝试调整时间或寻找替代场地。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 构建.NET Agent开发环境
2.1 开发环境准备
在开始Agent开发前,需要配置以下环境:
-
安装.NET 8 SDK:
bash复制
winget install Microsoft.DotNet.SDK.8 -
创建项目结构:
bash复制dotnet new console -n SmartAgentDemo cd SmartAgentDemo dotnet add package Microsoft.SemanticKernel -
配置API密钥:
建议使用.NET用户机密存储敏感信息:bash复制dotnet user-secrets init dotnet user-secrets set "OpenAI:ApiKey" "your-api-key"
2.2 基础架构设计
典型的.NET Agent项目应包含以下核心模块:
code复制SmartAgentDemo/
├── Agents/
│ ├── Core/ # 基础Agent实现
│ ├── Orchestrator/ # 任务编排
│ └── Roles/ # 不同角色Agent
├── Plugins/
│ ├── Tools/ # 工具函数集合
│ └── Skills/ # 复杂技能
├── Models/
│ ├── State/ # 状态模型
│ └── Messages/ # 消息协议
└── Services/
├── Memory/ # 记忆服务
└── Logging/ # 执行日志
3. 实现核心Agent功能
3.1 工具插件开发
在Semantic Kernel中,工具通过插件形式暴露给Agent。以下是增强版的待办管理插件:
csharp复制using System.ComponentModel;
using Microsoft.SemanticKernel;
public sealed class EnhancedTodoPlugin
{
private readonly List<TodoItem> _todos = new();
public record TodoItem(string Content, DateTime? DueDate, string Category);
[KernelFunction("add_todo")]
[Description("添加带有分类和截止日期的待办事项")]
public string AddTodo(
[Description("待办内容")] string content,
[Description("截止日期,格式yyyy-MM-dd")] string? dueDate = null,
[Description("分类标签")] string? category = null)
{
var item = new TodoItem(
content,
dueDate != null ? DateTime.Parse(dueDate) : null,
category);
_todos.Add(item);
return $"已添加待办:{content}";
}
[KernelFunction("get_urgent_todos")]
[Description("获取今天到期的待办事项")]
public string GetUrgentTodos()
{
var today = DateTime.Today;
var urgent = _todos
.Where(t => t.DueDate.HasValue && t.DueDate.Value.Date == today)
.ToList();
if (!urgent.Any()) return "今天没有到期待办";
return string.Join("\n", urgent.Select((t, i) =>
$"{i+1}. {t.Content} (分类: {t.Category ?? "无"})"));
}
[KernelFunction("complete_todo")]
[Description("完成指定待办事项")]
public string CompleteTodo(
[Description("待办编号,从1开始")] int index)
{
if (index < 1 || index > _todos.Count)
return "无效的待办编号";
var completed = _todos[index-1];
_todos.RemoveAt(index-1);
return $"已完成:{completed.Content}";
}
}
这个增强版插件展示了几个重要实践:
- 使用强类型模型(TodoItem)而非原始字符串
- 支持更丰富的参数(截止日期、分类)
- 提供专门的查询方法(GetUrgentTodos)
- 每个方法都有详细的参数描述
3.2 任务编排实现
下面是增强版的任务编排器实现,支持多步骤执行和状态持久化:
csharp复制public class TaskOrchestrator
{
private readonly IKernel _kernel;
private readonly ILogger _logger;
public TaskOrchestrator(IKernel kernel, ILogger logger)
{
_kernel = kernel;
_logger = logger;
}
public async Task<AgentResult> ExecuteAsync(
AgentTask task,
CancellationToken ct = default)
{
var state = task.InitialState ?? new AgentState();
var maxSteps = task.MaxSteps ?? 10;
for (int step = 1; step <= maxSteps; step++)
{
try
{
_logger.LogInformation($"开始执行第 {step} 步");
var result = await ExecuteStepAsync(state, ct);
if (result.IsComplete)
{
_logger.LogInformation("任务成功完成");
return new AgentResult(
true, result.FinalOutput, state);
}
state = result.NextState;
}
catch (Exception ex)
{
_logger.LogError(ex, $"第 {step} 步执行失败");
state.RecordError(ex.Message);
if (task.RetryPolicy.ShouldRetry(step, ex))
{
_logger.LogWarning("准备重试...");
continue;
}
return new AgentResult(
false, $"执行失败: {ex.Message}", state);
}
}
return new AgentResult(
false, "达到最大执行步数仍未完成", state);
}
private async Task<StepResult> ExecuteStepAsync(
AgentState state,
CancellationToken ct)
{
var prompt = BuildStepPrompt(state);
var settings = new OpenAIPromptExecutionSettings
{
ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions,
Temperature = 0.3 // 降低随机性
};
var result = await _kernel.InvokePromptAsync(
prompt, new(settings), ct);
var isComplete = result.Metadata?
.GetValueOrDefault("is_complete", false) ?? false;
state.UpdateWith(result);
return new StepResult(
