Microsoft Agent Framework:3 行代码给 Agent 加 RAG,秒对接外部知识库

B站影视 港台电影 2025-11-18 14:39 1

摘要:在《》中,已经了解了会话的持久化保存跟会话的缩减 。 AI Agent 光会聊天可不够!实际开发中,我们需要它能 “查资料”—— 比如对接产品手册、售后政策、企业内部文档,这就是 RAG(检索增强生成)的核心价值。

在《》中,已经了解了会话的持久化保存跟会话的缩减 。 AI Agent 光会聊天可不够!实际开发中,我们需要它能 “查资料”—— 比如对接产品手册、售后政策、企业内部文档,这就是 RAG(检索增强生成)的核心价值。

结合实战 Demo,快速给 Agent 集成 RAG,从模拟知识库到真实业务对接,一步到位解决 “Agent 知识有限、易瞎编” 的痛点。

很多开发者会混淆 “模型微调” 和 “RAG”,用一个通俗比喻就能分清:

模型微调

像大学生备考,把专业知识(训练数据)死记硬背在脑子里,回答问题时直接调用记忆 —— 反应快,但知识更新难(毕业后的新信息完全不知道);

RAG

像给普通人配了本《新华词典》,不用死记硬背所有知识,遇到不懂的问题(用户查询),先查词典(外部知识库)再回答 —— 知识更新快(换本新版词典就行),还能避免 “瞎编”。

简单说:微调适合沉淀核心固定知识(比如行业通用规则),RAG 适合灵活调用动态 / 私有知识(比如公司最新产品政策、临时活动规则)。而我们今天用的TextSearchProvider,就是给 Agent 配 “词典” 的最快方式。

纯大模型 Agent 有 3 个致命短板,光靠微调解决不了:

知识有保质期

大模型训练数据有时间窗口(比如 2025年5月1号之后的信息不知道),没法实时同步动态信息;

易 “幻觉”

对未知问题会凭空生成虚假信息,比如用户问 “你们的退货期限是多久”,Agent 可能瞎编 “7 天无理由”,但实际是 30 天;

私有知识难接入

企业内部文档、敏感数据(比如员工手册、客户资料),没法通过微调注入公域大模型,安全风险高。

而 RAG 能完美解决这些问题:让 Agent “有据可查”,回答准确率翻倍,还能低成本对接私有知识库。

是Microsoft Agent Framework 内置的RAG 适配神器,本质就是给 Agent 配的 “智能词典检索工具”,核心作用就 3 步:

拦截 Agent 的模型调用:用户发消息后,Agent 先判断是否需要查 “词典”;

触发检索:根据用户查询关键词,从外部知识库捞相关信息;

注入上下文:把检索结果自动拼接到 Agent 的对话上下文里,Agent 不用额外编码就能参考。

它的优势特别明显:

零侵入:不用改 Agent 的对话逻辑,只需配置检索函数;

高灵活:支持自定义检索时机、上下文记忆长度;

易扩展:检索函数能对接任何知识库(向量库、数据库、API、本地文件)。

我们的 Demo 里用模拟知识库检索,实际开发中直接替换成真实逻辑就行。1. 前置准备:依赖包安装

首先确保项目引用以下包(预览版需启用 NuGet 预览源):

PackageReference include="Microsoft.Agents.AI.OpenAI" Version="1.0.0-preview.251114.1" />2. 核心代码拆解:每一行都讲透

Demo 代码实现了 “模拟产品知识库检索 + Agent 自动参考回答”,下面逐部分拆解核心逻辑,重点看 RAG 怎么集成:

using Microsoft.Agents.AI;using Microsoft.Agents.AI.Data;using Microsoft.Extensions.AI;using OpenAI;using System.ClientModel;namespace AgentDemo{#pragma warning disable OPENAI001#pragma warning disable MEAI001 internal static class AgentContextProviderBase { public static async Task DemoAsnc(string apiKey, string endpoint, string modelName) { // 1. 创建OpenAI客户端,转换为通用IChatClient(适配不同模型) var clientOptions = new OpenAIClientOptions { Endpoint = new Uri(endpoint) }; IChatClient chatClient = new OpenAIClient(new ApiKeyCredential(apiKey), clientOptions) .GetOpenAIResponseClient(modelName) .AsIChatClient .AsBuilder .Build; // 2. 创建Agent,绑定TextSearchProvider(核心RAG配置) AIAgent agent = chatClient.CreateAIAgent(new ChatClientAgentOptions { // 给Agent的角色提示:优先参考搜索结果,注明来源 Instructions= "你是产品咨询客服,优先参考搜索结果回答,回答时注明信息来源", Name = "ProductConsultAgent", // 关键:注入RAG检索逻辑(相当于给Agent配词典) AIContextProviderFactory=ctx=>new TextSearchProvider( searchFunc: MockSearchAsync, // 自定义检索函数(核心) serializedState: ctx.SerializedState, jsonSerializerOptions: ctx.JsonSerializerOptions, new TextSearchProviderOptions { // 检索时机:每次AI调用前自动检索(用户无感知) SearchTime = TextSearchProviderOptions.TextSearchBehavior.BeforeAIInvoke, // 上下文记忆限制:保留最近6条消息,避免关键词提取混乱 RecentMessageMemoryLimit = 6 }) }); // 3. 创建对话线程,启动交互循环 AgentThread thread = agent.GetNewThread; while (true) { var userInput = Console.ReadLine; if (userInput == "Exit") break; var response = await agent.RunAsync(userInput, thread); Console.WriteLine($"Agent Output:{response}\n"); } // 4. 模拟检索函数(相当于“词典查询逻辑”,可替换为真实知识库) static Task { List // 逻辑:根据用户查询关键词,匹配对应的知识库信息 // 场景1:退货/退款相关查询 if (query.Contains("return", StringComparison.OrdinalIgnoreCase) || query.Contains("refund", StringComparison.OrdinalIgnoreCase)) { results.Add(new { SourceName = "Contoso Outdoors Return Policy", // 来源名称(比如“退货政策V2.0”) SourceLink = "https://contoso.com/policies/returns", // 来源链接(溯源用) Text = "Customers may return any item within 30 days of delivery. Items should be unused and include original packaging. Refunds are issued to the original payment method within 5 business days of inspection." // 核心检索内容 }); } // 场景2:物流相关查询 if (query.Contains("shipping", StringComparison.OrdinalIgnoreCase)) { results.Add(new { SourceName = "Contoso Outdoors Shipping Guide", SourceLink = "https://contoso.com/help/shipping", Text = "Standard shipping is free on orders over $50 and typically arrives in 3-5 business days within the continental United States. Expedited options are available at checkout." }); } // 场景3:帐篷/面料相关查询 if (query.Contains("tent", StringComparison.OrdinalIgnoreCase) || query.ContAIns("fabric", StringComparison.OrdinalIgnoreCase)) { results.Add(new { SourceName = "TrailRunner Tent Care Instructions", SourceLink = "https://contoso.com/manuals/trailrunner-tent", Text = "Clean the tent fabric with lukewarm water and a non-detergent soap. Allow it to air dry completely before storage and avoid prolonged UV exposure to extend the lifespan of the waterproof coating." }); } return Task.FromResult } } }#pragma warning restore OPENAI001#pragma warning restore MEAI001}关键代码解析(重点看这 3 处):searchFunc: MockSearchAsync

:指定检索函数,这是 RAG 的核心,后续替换为真实知识库对接;

SearchTime: BeforeAIInvoke

:检索时机 —— 每次 Agent 调用模型前自动检索,用户无感知(推荐客服、问答场景);

RecentMessageMemoryLimit: 6

:检索时参考最近 6 条消息,适配多轮对话(比如用户先问 “帐篷怎么洗”,再问 “洗后能退货吗”,Agent 会结合历史查询检索)。

检索结果格式:TextSearchProvider.TextSearchResult是固定格式,3 个字段缺一不可:SourceName

:来源名称(让用户知道信息来自哪里,增强可信度);

SourceLink

:来源链接(方便溯源验证,比如点击查看完整退货政策);

Text

:核心检索内容(Agent 回答时的 “参考资料”)。

MockSearchAsync 函数:模拟了 “关键词匹配知识库” 的逻辑,实际开发中可替换为:

向量库检索(如 Qdrant、Chroma):对接 PDF、Word 等非结构化文档;

数据库查询(如 SQL、MySQL):对接产品库存、订单等结构化数据;

企业 API 调用:对接物流状态、活动规则等实时数据。

3. 效果演示:Agent 自动 “查词典” 回答

运行 Demo 后,输入以下查询,看看 Agent 的表现 —— 它会自动触发检索,结合知识库信息生成回答:

场景 1:查询退货政策用户输入:Can I return a product I bought 20 days ago?Agent Output:Yes, you may return the item as it falls within the 30-day return window from delivery. Please ensure the item is unused and includes the original packaging. Refunds will be issued to your original payment method within 5 business days of inspection. (Source: Contoso Outdoors Return Policy)场景 2:查询物流信息用户输入:How long does shipping take?Agent Output:Standard shipping typically arrives in 3-5 business days within the continental United States, and it's free on orders over $50. Expedited shipping options are also available at checkout. (Source: Contoso Outdoors Shipping Guide)场景 3:查询帐篷护理(多轮对话)用户输入:How to clean the tent fabric?Agent Output:To clean the tent fabric, use lukewarm water and a non-detergent soap. Allow it to air dry completely before storage and avoid prolonged UV exposure to extend the lifespan of the waterproof coating. (Source: TrailRunner Tent Care Instructions)用户输入:Can I return the tent after cleaning it?Agent Output:According to the return policy, items should be unused and include original packaging to be eligible for a refund. Since you have cleaned the tent, it is no longer in an unused state, so it cannot be returned. (Source: Contoso Outdoors Return Policy)

亮点

无需手动触发检索:Agent 自动识别关键词,不用用户说 “查一下”;

回答有依据:明确标注来源,避免幻觉;

多轮对话连贯:能结合历史查询和检索结果,回答逻辑一致。

Demo 中的是模拟逻辑,下面以 “对接 Qdrant 向量库”(企业常用场景)为例,展示如何替换为真实检索:1. 安装向量库依赖 PackageReference Include="Microsoft.SemanticKernel.Connectors.Qdrant" />2. 实现真实检索函数// 真实检索函数:对接Qdrant向量库(替换原来的MockSearchAsync)static async Task{ // 1. 连接Qdrant向量库(提前把产品文档入库) var qdrantClient = new Qdrant.Client.QdrantClient("localhost"); var vectorStore = new QdrantVectorStore(qdrantClient, ownsClient: true, new { // 配置嵌入模型(与文档入库时一致) EmbeddingGenerator = new OpenAIEmbeddingClient( new ApiKeyCredential("你的OpenAI密钥"), new OpenAIClientOptions { Endpoint = new Uri("嵌入模型端点") }) .AsIEmbeddingGenerator }); var collection = vectorStore.GetCollection // 2. 向量检索(获取Top3相关文档) var searchResults = await collection.SearchAsync(query, limit: 3, cancellationToken: cancellationToken); // 3. 转换为TextSearchProvider所需格式 return searchResults.Select(result => new TextSearchProvider.TextSearchResult { SourceName = result.Record.SourceName, SourceLink = result.Record.SourceLink, Text = result.Record.Content });}// 向量库数据模型(定义文档存储结构)internal sealed class ProductDocChunk{ [VectorStoreKey] public Guid Key { get; set; } [VectorStoreData] public string SourceName { get; set; } = string.Empty; [VectorStoreData] public string SourceLink { get; set; } = string.Empty; [VectorStoreData] public string Content { get; set; } = string.Empty; [VectorStoreVector(Dimensions = 3072)] public string Embedding => this.Content;}3. 替换 Agent 配置中的检索函数AIContextProviderFactory=ctx=>new TextSearchProvider( searchFunc: QdrantSearchAsync, // 替换为真实检索函数 serializedState: ctx.SerializedState, jsonSerializerOptions: ctx.JsonSerializerOptions, new TextSearchProviderOptions { SearchTime = TextSearchProviderOptions.TextSearchBehavior.BeforeAIInvoke, RecentMessageMemoryLimit = 6 })

这样,Agent 就可以从真实的企业知识库中检索信息,完美适配生产环境。

用Microsoft Agent Framework 的集成 RAG,核心就是 “给 Agent 配词典”,3 个关键结论:

成本低:无需搭建复杂 RAG 架构,3 行核心配置 + 1 个检索函数,当天就能落地;

灵活高:检索函数可对接任何知识库,知识更新只需同步知识库(换 “词典”),不用改 Agent;

体验好:用户无感知检索,回答有依据,避免幻觉,多轮对话连贯。

微调是让 Agent “记住” 知识,RAG 是让 Agent “会查” 知识—— 大多数业务场景下,先做 RAG 快速落地,再根据高频问题补充微调,是性价比最高的方案。

using Microsoft.Agents.AI;using Microsoft.Agents.AI.Data;using Microsoft.Extensions.AI;using OpenAI;using System.ClientModel;namespace AgentDemo{#pragma warning disable OPENAI001#pragma warning disable MEAI001 /// /// 如何使用 TextSearchProvider 为 AI 代理添加检索增强生成(RAG)功能。这里展示了搜索函数的模拟实现,该实现可替换为任何自定义搜索逻辑,以查询任何外部知识库。 /// internal static class AgentContextProviderBase { public static async Task DemoAsnc(string apiKey, string endpoint, string modelName) { var clientOptions = new OpenAIClientOptions { Endpoint = new Uri(endpoint) }; IChatClient chatClient = new OpenAIClient(new ApiKeyCredential(apiKey), clientOptions) .GetOpenAIResponseClient(modelName).AsIChatClient.AsBuilder.Build; AIAgent agent = chatClient.CreateAIAgent(new ChatClientAgentOptions { Instructions= "你是产品咨询客服,优先参考搜索结果回答,回答时注明信息来源", // 给Agent的角色提示 Name = "ProductConsultAgent", AIContextProviderFactory=ctx=>new TextSearchProvider(MockSearchAsync,ctx.SerializedState,ctx.JsonSerializerOptions, new TextSearchProviderOptions { //在每次模型调用前调用自定义搜索函数,并将结果注入模型上下文中。 SearchTime = TextSearchProviderOptions.TextSearchBehavior.BeforeAIInvoke, RecentMessageMemoryLimit = 6,// // 上下文记忆限制:保留最近6条消息,避免关键词提取混乱 }) }); AgentThread thread = agent.GetNewThread; while (true) { var userInput = Console.ReadLine; if (userInput == "Exit") break; var response = await agent.RunAsync(userInput, thread); Console.WriteLine($"Agent Output:{response}\n"); } //模拟搜索函数(相当于“词典查询逻辑”,可替换为真实知识库对接) static Task { List if (query.Contains("return", StringComparison.OrdinalIgnoreCase) || query.Contains("refund", StringComparison.OrdinalIgnoreCase)) { results.Add(new { SourceName = "Contoso Outdoors Return Policy", SourceLink = "https://contoso.com/policies/returns", Text = "Customers may return any item within 30 days of delivery. Items should be unused and include original packaging. Refunds are issued to the original payment method within 5 business days of inspection." }); } if (query.Contains("shipping", StringComparison.OrdinalIgnoreCase)) { results.Add(new { SourceName = "Contoso Outdoors Shipping Guide", SourceLink = "https://contoso.com/help/shipping", Text = "Standard shipping is free on orders over $50 and typically arrives in 3-5 business days within the continental United States. Expedited options are available at checkout." }); } if (query.Contains("tent", StringComparison.OrdinalIgnoreCase) || query.Contains("fabric", StringComparison.OrdinalIgnoreCase)) { results.Add(new { SourceName = "TrailRunner Tent Care Instructions", SourceLink = "https://contoso.com/manuals/trailrunner-tent", Text = "Clean the tent fabric with lukewarm water and a non-detergent soap. Allow it to air dry completely before storage and avoid prolonged UV exposure to extend the lifespan of the waterproof coating." }); } return Task.FromResult } } }#pragma warning disable OPENAI001#pragma warning disable MEAI001}

来源:opendotnet

相关推荐