Agent Framework 中为 Agent Skill 接入依赖注入 DI

news2026/5/4 15:47:01
在前面的文章中我们介绍过 FileBased、CodeBased 和 ClassBased 等不同的 Skill 实现方式也演示了如何通过 AgentSkillsProvider 或 AgentSkillsProviderBuilder 将多个 Skill 组合起来让一个 Agent 同时具备多种能力。在实际项目中Skill 通常不只是简单的本地函数它往往需要依赖应用中的各种服务例如数据库访问HTTP API 调用缓存或配置服务如果每个 Skill 都自行创建和管理这些依赖不仅会导致代码重复还会增加测试和维护的成本。因此在 Agent Framework 中可以将 Skill 与 .NET 的依赖注入机制结合使用。下面通过一个单位换算的例子来看一下如何在 Skill 中使用 DI。1. 核心设计思想在 Agent 架构中用户 → Agent → Skill → DI → Service → 业务逻辑分层层级职责Agent理解用户意图Skill能力入口AI 可调用Service业务实现DI生命周期与依赖管理Skill 不承载业务逻辑只负责能力编排。2. 示例场景构建一个“单位换算 Agent”支持距离换算英里 ⇄ 千米重量换算磅 ⇄ 千克实现方式Skill类型功能distance-converterInline距离weight-converterClass重量两者共用同一个业务服务ConversionService2. 创建项目并安装依赖包首先创建一个控制台项目然后安装相关依赖包dotnet add package Azure.AI.OpenAI dotnet add package Azure.Identity dotnet add package Microsoft.Agents.AI.OpenAI dotnet add package Microsoft.Extensions.DependencyInjection3. 环境准备安装依赖dotnet add package Azure.AI.OpenAI --version 2.9.0-beta.1 dotnet add package Azure.Identity dotnet add package Microsoft.Agents.AI.OpenAI dotnet add package Microsoft.Extensions.DependencyInjection版本说明GetResponsesClient()需要Azure.AI.OpenAI 2.9.0-beta.1否则可能出现404或 API 不兼容问题。4. 配置 Azure OpenAI示例中通过环境变量读取 Azure OpenAI 的终结点和模型部署名称string endpoint Environment.GetEnvironmentVariable(AZURE_OPENAI_ENDPOINT) ?? throw new InvalidOperationException(AZURE_OPENAI_ENDPOINT is not set.); string deploymentName Environment.GetEnvironmentVariable(AZURE_OPENAI_DEPLOYMENT_NAME) ?? gpt-5.4-mini;这里需要提前配置环境变量在Windows中可以使用setx AZURE_OPENAI_ENDPOINT https://你的资源名.openai.azure.com/ setx AZURE_OPENAI_DEPLOYMENT_NAME 你的模型部署名在 Linux 或 macOS 中可以使用export AZURE_OPENAI_ENDPOINThttps://你的资源名.openai.azure.com/ export AZURE_OPENAI_DEPLOYMENT_NAME你的模型部署名5. 创建 DI 容器在.NET 中依赖注入通常从 ServiceCollection 开始。示例中注册了一个 ConversionServiceServiceCollection services new(); services.AddSingletonConversionService(); IServiceProvider serviceProvider services.BuildServiceProvider();6. 定义业务服务 ConversionServiceConversionService 是一个普通的 C# 服务类用于提供单位换算能力。它主要包含三个方法internal sealedclassConversionService { public string GetDistanceTable() # 距离转换 公式**结果 值 × 系数** | 从 | 到 | 系数 | |-------------|-------------|----------| | 英里 | 千米 | 1.60934 | | 千米 | 英里 | 0.621371 | ; public string GetWeightTable() # 重量转换 公式**结果 值 × 系数** | 从 | 到 | 系数 | |-------------|-------------|----------| | 磅 | 千克 | 0.453592 | | 千克 | 磅 | 2.20462 | ; public string Convert(double value, double factor) { double result Math.Round(value * factor, 4); return JsonSerializer.Serialize(new { value, factor, result }); } }这里的设计思路很清晰GetDistanceTable()提供距离换算表。GetWeightTable()提供重量换算表。Convert()根据传入的值和换算系数返回计算结果。7. 使用 AgentInlineSkill 实现距离换算第一个 Skill 使用 AgentInlineSkill 实现。它适合比较简单、轻量的场景直接在代码中定义 Skill 的资源和脚本。var distanceSkill new AgentInlineSkill( name: distance-converter, description: 在距离单位之间转换。当要求将英里转换为千米或将千米转换为英里时使用。, instructions: 当用户要求在距离单位英里和千米之间转换时请使用此技能。 1. 查看 distance-table 资源找到所请求转换的系数。 2. 使用 convert 脚本传入值和表中的系数。 ) .AddResource(distance-table, (IServiceProvider serviceProvider) { var service serviceProvider.GetRequiredServiceConversionService(); return service.GetDistanceTable(); }) .AddScript(convert, (double value, double factor, IServiceProvider serviceProvider) { var service serviceProvider.GetRequiredServiceConversionService(); return service.Convert(value, factor); });这里有一个关键点资源和脚本方法中都声明了IServiceProvider参数。例如.AddResource(distance-table, (IServiceProvider serviceProvider) { var service serviceProvider.GetRequiredServiceConversionService(); return service.GetDistanceTable(); })Agent Framework 会自动注入IServiceProvider。然后我们就可以通过var service serviceProvider.GetRequiredServiceConversionService();距离换算的执行过程大致如下用户提出距离换算问题。Agent 判断需要使用distance-converter。Skill 读取distance-table资源。Agent 根据换算表选择正确的系数。调用convert脚本完成计算。返回最终结果。8. 使用 AgentClassSkill 实现重量换算第二个 Skill 使用基于类的方式实现也就是 AgentClassSkill。 这种方式更适合结构稍复杂的 Skill因为可以把资源、脚本、说明信息都封装在一个类中。internal sealedclassWeightConverterSkill : AgentClassSkillWeightConverterSkill { publicoverride AgentSkillFrontmatter Frontmatter { get; } new( weight-converter, 在重量单位之间转换。当要求将磅转换为千克或将千克转换为磅时使用。); protectedoverridestring Instructions 当用户要求在重量单位磅和千克之间转换时请使用此技能。 1. 查看 weight-table 资源找到所请求转换的系数。 2. 使用 convert 脚本传入值和表中的系数。 3. 使用两个单位清晰呈现结果。 ; [AgentSkillResource(weight-table)] [Description(重量转换乘法系数的查找表。)] private static string GetWeightTable(IServiceProvider serviceProvider) { var service serviceProvider.GetRequiredServiceConversionService(); return service.GetWeightTable(); } [AgentSkillScript(convert)] [Description(将值乘以转换系数并以 JSON 形式返回结果。)] private static string Convert(double value, double factor, IServiceProvider serviceProvider) { var service serviceProvider.GetRequiredServiceConversionService(); return service.Convert(value, factor); } }基于ClassBased的 Skill里面属性和方法的作用我们在前面的文章中已经介绍过了这里不再赘述。在类形式的 Skill 中同样可以通过IServiceProvider使用 DI。例如资源方法[AgentSkillResource(weight-table)] [Description(重量转换乘法系数的查找表。)] private static string GetWeightTable(IServiceProvider serviceProvider) { var service serviceProvider.GetRequiredServiceConversionService(); return service.GetWeightTable(); }脚本方法[AgentSkillScript(convert)] [Description(将值乘以转换系数并以 JSON 形式返回结果。)] private static string Convert(double value, double factor, IServiceProvider serviceProvider) { var service serviceProvider.GetRequiredServiceConversionService(); return service.Convert(value, factor); }只要方法参数中声明了IServiceProvider, Agent Framework 就会在执行时自动注入它。这样ClassBased Skill 也可以和普通 ASP.NET Core 或 Worker Service 一样通过 DI 使用应用中的业务服务。9. 注册多个 Skill定义好距离 Skill 和重量 Skill 后需要把它们注册到统一的技能提供者中。var weightSkill new WeightConverterSkill(); var skillsProvider new AgentSkillsProvider(distanceSkill, weightSkill);它们分别负责不同的领域Skill实现方式能力distance-converterAgentInlineSkill英里和千米转换weight-converterAgentClassSkill磅和千克转换这意味着同一个 Agent 可以根据用户问题自动选择合适的 Skill。如果用户问26.2 英里是多少千米Agent 会倾向于使用distance-converter。如果用户问75 千克是多少磅Agent 会倾向于使用weight-converter。如果用户同时问两个问题Agent 也可以分别调用不同的 Skill 来完成任务。10. 创建 Agent 并注入AgentSkillsProvider和IServiceProvider接下来创建 AgentAIAgent agent new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()) .GetResponsesClient() .AsAIAgent( options: new ChatClientAgentOptions { Name UnitConverterAgent, ChatOptions new() { Instructions 你是一个可以转换单位的实用助手。, }, AIContextProviders [skillsProvider], }, model: deploymentName, services: serviceProvider);这里有两个地方非常重要。第一个是AIContextProviders [skillsProvider]这表示把前面定义的 Skill 提供给 Agent。第二个是services: serviceProvider这表示把 DI 容器传递给 Agent。 正因为传入了serviceProvider所以 Skill 在执行资源和脚本时才能自动获得IServiceProvider然后解析出ConversionService。 如果没有传入这个服务提供者Skill 中依赖 DI 的代码就无法正常解析服务。11. 运行示例最后我们向 Agent 提出一个同时包含距离和重量换算的问题AgentResponse response await agent.RunAsync( 一场马拉松26.2 英里是多少千米75 千克是多少磅); Console.WriteLine($智能体{response.Text});根据示例中的转换系数计算结果如下为12. 为什么要在 Skill 中使用 DI把 DI 引入 Agent Skill最大的好处是让 Skill 不再直接依赖具体实现。 比如在当前示例中Skill 并不负责保存换算表也不直接维护业务规则而是通过ConversionService来完成具体业务。这样做有几个好处。1. 业务逻辑可以复用ConversionService 不只可以被 Agent Skill 使用也可以被普通 API、后台任务、命令行工具或测试代码使用。 Skill 只是业务能力的一种入口。2. 更容易测试如果未来要测试 Skill可以替换掉真实的服务实现注入 Mock 服务或测试服务。 例如可以把ConversionService抽象成接口IConversionService然后在测试中注入假的实现。3. 更容易扩展如果以后换算规则不再写死在代码中而是来自数据库只需要修改服务层即可。 Skill 的调用方式可以保持不变。4. 更符合 .NET 应用架构在 ASP.NET Core、Worker Service 和现代 .NET 应用中DI 是非常核心的基础设施。 Agent Skill 支持 DI意味着它可以自然融入现有 .NET 应用架构。13. Agent Skill 和传统服务的关系可以把 Agent Skill 理解成一层“AI 可调用的能力入口”。 传统代码中我们可能这样调用服务var result conversionService.Convert(value, factor);而在 Agent Framework 中用户通过自然语言提出问题 26.2 英里是多少千米Agent 会根据问题自动选择 Skill然后 Skill 再调用服务var service serviceProvider.GetRequiredServiceConversionService(); return service.Convert(value, factor);所以它们的关系可以理解为用户自然语言 ↓ Agent ↓ Skill ↓ DI 服务 ↓ 业务逻辑Skill 并不是替代业务服务而是把业务服务包装成 Agent 可以理解和调用的能力。总结本文演示了如何在 Agent Framework 中结合依赖注入使用 Agent Skill。 示例中包含两种 SkillAgentInlineSkill用于距离换算。AgentClassSkill用于重量换算。这两个 Skill 都没有直接维护复杂业务逻辑而是通过 IServiceProvider 从 DI 容器中解析同一个 ConversionService。通过这种方式Agent Skill 可以像普通 .NET 组件一样使用应用中的服务。 这让 Skill 的设计更加清晰也让 Agent 更容易接入真实业务系统。 随着 Skill 接入的服务越来越多Agent 的能力也会不断增强。从简单的单位换算到数据库查询、HTTP API 调用、企业系统集成最终都可以通过同样的方式扩展出来。源代码地址https://github.com/bingbing-gui/dotnet-platform/tree/master/src/09-AI-Agent/Agent-Framework/32-AgentSkill-Integration-DI

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2578654.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…