找回密码
 立即注册
首页 业界区 业界 WPF/C#:使用Microsoft Agent Framework框架创建一个带 ...

WPF/C#:使用Microsoft Agent Framework框架创建一个带有审批功能的终端Agent

谅潭好 昨天 10:30
前言

最近新出了一个Microsoft Agent Framework框架,我感觉还挺有意思的,就通过它的那个Using function tools with human in the loop approvals例子,做了一个终端助手Agent。我觉得使用这个作为学习人在环上这个例子蛮合适的,因为对于需要执行敏感操作(如系统命令)的场景,人工审批机制显得尤为重要。本文以Rouyan为例,说明如何使用Microsoft Agent Framework创建一个能够执行终端命令并具备人工审批功能的WPF应用。
在详细介绍之前,先来看看它的效果。
1、比如获取当前时间
会先弹出一个人工审批窗口:
1.png

然后你点击同意了才会执行:
2.png

如果你拒绝了就是这样:
3.png

实际上你可以利用终端做很多事情,我再举一个例子。
2、新建一个文件,写入你好:
4.png

选择同意,结果如图所示:
5.png

6.png

在介绍如何具体实现之前,先来介绍一下Microsoft Agent Framework。
Microsoft Agent Framework介绍

GitHub上的简介是:“一个用于构建、编排和部署AI代理及多代理工作流程的框架,支持Python和.NET。”
GitHub地址:https://github.com/microsoft/agent-framework
7.png

Microsoft Agent Framework 是一个开源开发工具包,用于为 .NET 和 Python 构建 AI 代理和多代理工作流。它整合并扩展了 Semantic Kernel 和 AutoGen 项目的思想,融合了两者的优点,并新增了多项功能。该框架由同一团队开发,将成为未来构建 AI 代理的统一基础。
Agent Framework 提供了两大主要功能类别:
AI 代理:单个代理利用大语言模型(LLM)处理用户输入,调用工具和 MCP 服务器执行操作,并生成响应。代理支持的模型提供商包括 Azure OpenAI、OpenAI 和 Azure AI。
工作流:基于图形的工作流,用于连接多个代理和功能,以执行复杂的多步骤任务。工作流支持基于类型的路由、嵌套、检查点以及适用于人工干预场景的请求/响应模式。
该框架还提供了基础构建模块,包括模型客户端(聊天补全和响应)、用于状态管理的代理线程、用于代理记忆的上下文提供程序、用于拦截代理操作的中间件,以及用于工具集成的MCP客户端。这些组件共同为您提供灵活性和强大功能,以构建交互性强、稳健且安全的AI应用程序。
8.png

具体实现

1、安装Nuget包:
9.png

2、编写运行脚本的函数
  1. [Description("Execute a Windows cmd.exe script and return its output.")]
  2. static string ExecuteCmd([Description("The script content to run via 'cmd.exe /c'.")] string script)
  3. {
  4.     try
  5.     {
  6.         var psi = new ProcessStartInfo("cmd.exe", "/c " + script)
  7.         {
  8.             UseShellExecute = false,
  9.             RedirectStandardOutput = true,
  10.             RedirectStandardError = true,
  11.             CreateNoWindow = true
  12.         };
  13.         using (var process = new Process())
  14.         {
  15.             process.StartInfo = psi;
  16.             process.Start();
  17.             string output = process.StandardOutput.ReadToEnd();
  18.             string error = process.StandardError.ReadToEnd();
  19.             process.WaitForExit();
  20.             if (!string.IsNullOrWhiteSpace(error))
  21.             {
  22.                 return $"错误: {error.Trim()}";
  23.             }
  24.             return output.Trim();
  25.         }
  26.     }
  27.     catch (Exception ex)
  28.     {
  29.         return $"执行失败: {ex.Message}";
  30.     }
  31. }
复制代码
3、配置AI Agent
文档中只写了Azure中怎么使用,兼容OpenAI格式的可以这样写:
  1. // 配置AI Agent
  2. DotEnv.Load();
  3. var envVars = DotEnv.Read();
  4. var apiKey = envVars["OPENAI_API_KEY"];
  5. var model = envVars["OPENAI_CHAT_MODEL"];
  6. var baseUrl = new Uri(envVars["OPENAI_BASE_URL"]);
  7. ApiKeyCredential apiKeyCredential = new ApiKeyCredential(apiKey);
  8. OpenAIClientOptions openAIClientOptions = new OpenAIClientOptions();
  9. openAIClientOptions.Endpoint = baseUrl;
  10. AIAgent agent = new OpenAIClient(apiKeyCredential, openAIClientOptions)
  11.      .GetChatClient(model)
  12.      .CreateAIAgent(instructions: "你是一个乐于助人的助手,可以执行命令行脚本。请使用中文回答。", tools: [new ApprovalRequiredAIFunction(AIFunctionFactory.Create(ExecuteCmd))]);
复制代码
这里有一个新东西就是ApprovalRequiredAIFunction。
这说明如果调用这个函数需要经过人工审批。
4、审批流程
  1. // Call the agent and check if there are any user input requests to handle.
  2. AgentThread thread = agent.GetNewThread();
  3. var response = await agent.RunAsync(InputText, thread);
  4. var userInputRequests = response.UserInputRequests.ToList();
复制代码
我们先来看看这个是什么,运行起来打个断点看看:
10.png

这就是一个Agent想要执行的函数,那么现在来看看如何审批:
  1. while (userInputRequests.Count > 0)
  2. {
  3.     var userInputResponses = new List<ChatMessage>();
  4.     foreach (var functionApprovalRequest in userInputRequests.OfType<FunctionApprovalRequestContent>())
  5.     {
  6.         var scriptContent = functionApprovalRequest.FunctionCall.Arguments?["script"]?.ToString() ?? "未知脚本";
  7.         var functionName = functionApprovalRequest.FunctionCall.Name;
  8.         var dialogVm = new HumanApprovalDialogViewModel
  9.         {
  10.             Title = "命令执行审批",
  11.             Message = $"是否同意执行以下命令?\n\n函数名称: {functionName}\n脚本内容: {scriptContent}"
  12.         };
  13.         bool? result = _windowManager.ShowDialog(dialogVm);
  14.         bool approved = result == true;
  15.         userInputResponses.Add(new ChatMessage(ChatRole.User, [functionApprovalRequest.CreateResponse(approved)]));
  16.     }
  17.     // Pass the user input responses back to the agent for further processing.
  18.     response = await agent.RunAsync(userInputResponses, thread);
  19.     userInputRequests = response.UserInputRequests.ToList();
  20. }
复制代码
根据这个地方userInputResponses.Add(new ChatMessage(ChatRole.User, [functionApprovalRequest.CreateResponse(approved)]));中的approved传入的是true还是false表示用户是同意还是拒绝。
然后发送请求获取新的回复,直到没有需要人工审批的函数为止。
5、流式响应
最后再获取一个流式响应:
  1. await foreach (var update in agent.RunStreamingAsync("输出最终答案", thread))
  2. {
  3.     OutputText += update.Text;
  4. }
复制代码
最后

以上就是本期的全部内容,希望对你有所帮助。
全部代码已上传至GitHub,地址:https://github.com/Ming-jiayou/Rouyan。
终端助手的代码主要在src/Rouyan/Pages/ViewModel/TerminalAgentViewModel.cs中。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册