1. AI Agent开发实战:用C#构建智能任务执行系统
最近在开发一个能自动处理公司内部事务的AI助手时,我发现市面上大多数教程都停留在基础聊天机器人层面。实际上,真正的AI Agent应该像一位专业的办公室助理——不仅能回答问题,还能主动调用工具、处理复杂任务。下面分享我用C#实现的一个企业级AI Agent案例,它能查询公司机密文档并执行精确计算。
这个Agent的核心能力包括:
- 理解自然语言指令
- 访问公司内部知识库(RAG实现)
- 调用Python计算引擎处理数学问题
- 通过多轮对话完成复杂任务
2. 核心架构设计
2.1 Agent四大核心组件
现代AI Agent的架构通常包含四个关键部分:
csharp复制public class AIAgent
{
public LLMService Brain { get; set; } // 大语言模型推理引擎
public MemorySystem Memory { get; set; } // 记忆系统
public Planner Planner { get; set; } // 任务规划器
public ToolKit Tools { get; set; } // 工具集合
}
LLM(大语言模型):我选用阿里云的通义千问作为基础模型,相比直接使用OpenAI API,本地化部署的方案更符合企业安全要求。在C#中可以通过HttpClient封装REST调用:
csharp复制public class TongyiClient
{
private readonly HttpClient _httpClient;
private const string ApiUrl = "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation";
public async Task<string> GenerateResponse(string prompt)
{
var request = new
{
model = "qwen-plus",
input = new { messages = new[] { new { role = "user", content = prompt } } }
};
var response = await _httpClient.PostAsJsonAsync(ApiUrl, request);
return await response.Content.ReadAsStringAsync();
}
}
记忆系统:分为短期记忆(对话历史)和长期记忆(RAG知识库)。我采用FAISS向量数据库存储公司文档,用SQLite管理对话上下文:
csharp复制public class RAGService
{
private readonly FaissIndex _index;
public void Initialize(string documentsPath)
{
// 加载并分割文档
var documents = Directory.GetFiles(documentsPath)
.SelectMany(file => TextSplitter.Split(File.ReadAllText(file)));
// 构建向量索引
_index = new FaissIndex();
_index.BuildIndex(documents);
}
public string Search(string query)
{
return _index.Search(query, topK: 3);
}
}
2.2 工具调用机制
Agent的强大之处在于能调用外部工具。我设计了以下工具接口规范:
csharp复制public interface IAgentTool
{
string Name { get; }
string Description { get; }
Task<string> ExecuteAsync(string parameters);
}
// 计算器工具实现
public class CalculatorTool : IAgentTool
{
public string Name => "calculator";
public string Description => "计算数学表达式。需要精确计算时使用。示例:'500*0.8'";
public async Task<string> ExecuteAsync(string expression)
{
// 使用安全的计算库替代eval
try {
var result = new DataTable().Compute(expression, null);
return result.ToString();
}
catch (Exception e) {
return $"计算错误: {e.Message}";
}
}
}
重要安全提示:绝对不要直接使用eval执行用户输入!我改用DataTable.Compute方法,它支持基本运算但会过滤危险代码。
3. 完整实现流程
3.1 环境准备
-
安装必要NuGet包:
Microsoft.SemanticKernel(AI编排框架)Faiss.Net(向量搜索)Python.Runtime(调用Python计算器)
-
配置通义千问API密钥:
csharp复制Environment.SetEnvironmentVariable("DASHSCOPE_API_KEY", "your-api-key");
3.2 核心执行逻辑
csharp复制public class AgentRunner
{
private readonly List<IAgentTool> _tools;
private readonly int _maxIterations = 5;
public async Task<string> ExecuteTaskAsync(string userQuery)
{
var messages = new List<ChatMessage>
{
new ChatMessage("user", userQuery)
};
for (int i = 0; i < _maxIterations; i++)
{
var llmResponse = await GetLLMResponse(messages);
messages.Add(new ChatMessage("assistant", llmResponse.Content));
if (!llmResponse.ToolCalls.Any())
return llmResponse.Content;
foreach (var toolCall in llmResponse.ToolCalls)
{
var tool = _tools.FirstOrDefault(t => t.Name == toolCall.Name);
var result = tool != null
? await tool.ExecuteAsync(toolCall.Arguments)
: "错误: 工具不存在";
messages.Add(new ChatMessage("tool", result, toolCall.Id));
}
}
return "超过最大迭代次数";
}
}
3.3 多轮对话示例
当用户询问"公司经费预算提高46%后是多少"时,Agent的执行流程:
-
第一轮:识别需要查询预算原始值
json复制{ "tool_calls": [{ "name": "rag_search", "arguments": "经费预算" }] } -
第二轮:获取到原始值"50元"后,自动触发计算器
json复制{ "tool_calls": [{ "name": "calculator", "arguments": "50 * 1.46" }] } -
返回最终结果:"预算提高46%后是73元"
4. 安全加固方案
4.1 输入过滤层
在工具调用前添加安全校验:
csharp复制public class SafeCalculator : IAgentTool
{
public async Task<string> ExecuteAsync(string input)
{
if (ContainsMaliciousCode(input))
throw new SecurityException("检测到危险输入");
// 安全计算逻辑...
}
private bool ContainsMaliciousCode(string code)
{
var forbiddenPatterns = new[] { "import", "exec", "open", "system" };
return forbiddenPatterns.Any(p => code.Contains(p));
}
}
4.2 权限控制系统
为不同工具设置访问级别:
csharp复制[AttributeUsage(AttributeTargets.Class)]
public class ToolPermissionAttribute : Attribute
{
public AccessLevel RequiredLevel { get; }
public ToolPermissionAttribute(AccessLevel level)
{
RequiredLevel = level;
}
}
// 在工具调用前检查权限
if (!User.HasPermission(tool.GetType().GetCustomAttribute<ToolPermissionAttribute>()?.RequiredLevel))
{
return "错误: 权限不足";
}
5. 性能优化技巧
5.1 缓存策略
对频繁查询的RAG结果进行缓存:
csharp复制public class CachedRAGService : RAGService
{
private readonly MemoryCache _cache = new MemoryCache(new MemoryCacheOptions());
public override string Search(string query)
{
return _cache.GetOrCreate(query, entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30);
return base.Search(query);
});
}
}
5.2 并行工具调用
当多个工具可独立运行时:
csharp复制var toolTasks = llmResponse.ToolCalls
.Select(async toolCall =>
{
var tool = _tools.FirstOrDefault(t => t.Name == toolCall.Name);
return tool != null
? await tool.ExecuteAsync(toolCall.Arguments).ConfigureAwait(false)
: "错误: 工具不存在";
});
var results = await Task.WhenAll(toolTasks);
6. 调试与监控
6.1 日志记录
使用结构化日志记录每次工具调用:
csharp复制public class LoggingToolProxy : IAgentTool
{
private readonly IAgentTool _innerTool;
private readonly ILogger _logger;
public async Task<string> ExecuteAsync(string parameters)
{
_logger.LogInformation("工具调用开始 {@ToolName} {@Parameters}",
_innerTool.Name, parameters);
try {
var result = await _innerTool.ExecuteAsync(parameters);
_logger.LogInformation("工具调用成功 {@Result}", result);
return result;
}
catch (Exception ex) {
_logger.LogError(ex, "工具调用失败");
throw;
}
}
}
6.2 可视化追踪
用ASP.NET Core开发监控面板:
csharp复制app.MapGet("/conversations/{id}", (string id) =>
{
var conversation = _storage.GetConversation(id);
return Results.Json(new {
Steps = conversation.Messages.Select(m => new {
Type = m.Role,
Content = m.Content
})
});
});
在实际部署时,我建议采用渐进式开发策略:先从单个工具开始验证,逐步增加复杂度。对于关键业务工具,一定要实现完善的单元测试和沙箱环境。这个框架已经成功应用在我们公司的财务报告自动生成系统中,将人工处理时间减少了70%。