如何实现RAG与MCP集成
<h1>1.概述</h1><p>在人工智能的创新浪潮中,检索增强生成(RAG)技术以其高效调用外部知识、提升生成内容准确性的能力备受瞩目,而模型上下文协议(MCP)则为不同模型间的交互与协同提供了标准框架。当 RAG 的知识检索优势与 MCP 的灵活交互能力相遇,不仅能大幅提升 AI 系统的实用性与智能水平,还能为复杂场景下的应用开发开辟新路径。那么,如何实现 RAG 与 MCP 的深度集成,充分释放二者潜力?笔者将为大家来一一介绍。</p>
<h1>2.内容</h1>
<div class="ace-line" dir="auto" data-node="true">
<p>在人工智能技术不断迭代的背景下,检索增强生成(Retrieval-Augmented Generation,简称 RAG)作为一项突破性技术,打破了传统语言模型依赖静态训练数据的局限。它创造性地将语言模型的生成能力与外部知识检索系统深度融合,使模型输出的答案不再局限于训练阶段获取的历史数据,而是能实时关联最新事实依据。<br>RAG 的运行机制依托于一套精密的知识调用管道:当用户输入查询指令后,系统会即刻启动知识库检索程序,借助嵌入矢量数据库的高效匹配算法,从海量信息中精准筛选出与问题最相关的文档片段。这些高关联度的文档内容会被巧妙地融入模型提示词中,形成增强型输入,辅助语言模型生成更具事实性、准确性的回答。<br>这一创新架构带来双重显著优势:一方面,通过引入实时权威知识源,有效降低了模型产生 “幻觉”(即生成无事实依据内容)的概率;另一方面,企业或机构能够将特定领域的专业数据、私有业务知识纳入检索范围,使模型输出贴合行业特性与个性化需求,极大提升了 AI 在垂直领域的应用价值 。</p>
<p><img src="https://img2024.cnblogs.com/blog/666745/202506/666745-20250602130609650-285252887.png" alt="" loading="lazy"></p>
<p> </p>
<p>尽管检索增强生成(RAG)显著提升了 AI 的事实性与准确性,但传统 RAG 架构仍存在难以忽视的技术瓶颈。其核心局限在于信息检索的单一性与被动性:多数传统 RAG 系统仅能对接单个数据源,且采用 “单次检索 - 直接应用” 的简单逻辑 —— 一旦初始检索结果不佳,或用户查询表述模糊、偏离常规语义模式,模型生成的答案质量将严重下滑,难以满足复杂场景下的精准需求。<br>从系统架构层面来看,传统 RAG 缺乏智能检索策略优化机制。它既无法基于初始检索结果主动推理、调整检索策略(如更换关键词、扩大检索范围),也不具备动态调用外部工具(如知识图谱、实时数据接口)的能力。这种 “静态检索 + 被动响应” 的模式,使得系统在面对交叉领域知识需求、模糊语义理解任务时,难以实现深度知识整合与灵活应对,限制了 RAG 技术在复杂业务场景中的应用潜力。</p>
<h2>2.1 Agentic RAG</h2>
<p>针对传统检索增强生成(RAG)在信息检索单一性与策略被动性上的固有局限,Agentic RAG 以AI 代理驱动的智能架构实现技术突破。该模式将智能代理深度嵌入 RAG 工作流,打破 “单次检索 - 直接生成” 的固定链路,通过代理的动态协调能力,使检索与生成过程升级为具备自主规划、灵活适配特性的智能循环。<br>在 Agentic RAG 系统中,由大语言模型(LLM)赋能的智能代理充当 “决策中枢”,依托三大核心能力重塑 RAG 应用边界:</p>
<ul>
<li>记忆管理能力:借助短期记忆实时保存对话上下文,结合长期记忆调用历史知识储备,确保信息处理的连贯性与针对性;</li>
<li>规划推理能力:基于用户查询意图与中间检索结果,自主分析并动态调整策略,如重构查询关键词、优化检索路径或切换数据源;</li>
<li>工具集成能力:无缝对接搜索引擎、专业数据库、计算接口等外部工具,突破单一数据源限制,实现多模态信息的高效调用与交叉验证。</li>
</ul>
<p>这些能力赋予 Agentic RAG 系统强大的自主决策力 —— 代理可基于实时需求灵活判断检索时机、智能选择数据来源,并在答案生成前主动校验信息准确性,彻底扭转传统 RAG 的被动响应模式,显著提升复杂场景下 AI 输出的可靠性与灵活性,为 RAG 技术在多领域深度应用开辟全新路径。</p>
<p><img src="https://img2024.cnblogs.com/blog/666745/202506/666745-20250602135709765-501319009.png" alt="" loading="lazy"></p>
<h2> 2.2 RAG系统中AI代理的分类</h2>
<p>在 Agentic RAG 系统的智能生态中,不同类型的 AI 代理各司其职、协同运作,共同构建起高效灵活的知识处理体系:</p>
<ul>
<li><strong>路由代理</strong>:作为系统的 “智能导航员”,路由代理通过深度语义分析用户查询,精准识别问题核心要素,进而从多元知识源与工具库中筛选最优解决方案。在基础 RAG 场景中,它能快速定位最匹配的数据源,确保信息检索的高效性与针对性。</li>
<li><strong>查询计划代理</strong>:扮演 “项目统筹者” 角色,专注于复杂任务拆解与流程管理。面对复杂查询,它会将问题解构为多个逻辑子任务,动态分配给适配的代理模块执行,并最终整合碎片化结果,输出结构完整、逻辑连贯的最终答案,显著提升复杂问题的处理能力。</li>
<li><strong>ReAct 代理</strong>:以 “推理 - 行动” 双轮驱动为核心,ReAct 代理擅长制定分步骤解决方案。它会基于问题特性规划执行路径,智能调用外部工具辅助推理,并依据中间结果实时调整策略。这种动态自适应机制,使其在应对模糊或开放性问题时,能灵活迭代解决方案,增强系统的应变能力。</li>
<li><strong>计划和执行代理</strong>:作为 ReAct 代理的进阶形态,计划和执行代理进一步强化自主性与闭环处理能力。它能够独立规划完整工作流,在无人干预的情况下自主完成从任务解析到结果输出的全流程操作,不仅大幅降低运营成本,还通过深度推理确保任务高完成率与优质输出,成为复杂场景下的核心驱动力量。</li>
</ul>
<p>多种代理类型的有机结合,让 Agentic RAG 系统突破传统框架限制,实现知识检索、任务处理与答案生成的全链路智能化升级,为用户提供更智能、更高效的交互体验。</p>
<p><img src="https://img2024.cnblogs.com/blog/666745/202506/666745-20250602140237216-19589059.png" alt="" loading="lazy"></p>
<h2> 2.3 主动与数据交互</h2>
<p>Agentic RAG 彻底颠覆传统检索增强生成模式的被动属性,通过智能代理的深度介入,构建起具备主动学习与动态优化能力的 AI 交互体系。该系统突破单次检索的局限,以 “主动参与式” 数据处理策略,实现结果准确性与场景适配性的双重跃升:智能代理可同时调用多源知识库与 API 接口,灵活应对多元查询需求;通过实时分析用户意图与上下文,动态调整检索策略,精准匹配复杂情境下的答案生成需求;并借助迭代优化机制,持续打磨检索结果,显著提升答案的事实准确性与语义相关性。<br>在推理能力层面,Agentic RAG 展现出卓越的自主性与灵活性。面对复杂或模糊的用户提问,代理能够主动执行多步推理:通过自我查询与查询重构技术,将模糊问题拆解为精准子任务;若首次检索未达预期,系统可自动触发二次检索或切换数据源,确保信息获取的全面性。此外,代理还集成了智能验证模块,在答案生成前对检索数据进行交叉核验与冗余过滤,有效规避错误信息干扰,为用户输出更可靠、更具权威性的回答。<br>这种 “自适应、智能解决问题” 的革新架构,赋予大语言模型(LLM)主动调用外部工具、深度参与问题解决全流程的能力,真正实现从 “信息查找者” 到 “智能决策助手” 的角色蜕变,为 AI 应用场景的拓展与深化提供了全新可能。</p>
<p><img src="https://img2024.cnblogs.com/blog/666745/202506/666745-20250602140825703-92387204.png" alt="" loading="lazy"></p>
<h1>3.模型上下文协议(MCP)服务器:下一代AI服务引擎</h1>
<p>随着人工智能代理向更自主化、工具化的方向演进,如何高效连接海量外部数据源与工具,成为制约其发展的关键瓶颈。就像电子设备需要统一接口适配不同配件,AI 领域也亟需一个通用标准来打通数据交互壁垒,<strong>模型上下文协议(MCP)</strong> 正是为此而生的 “AI 通用接口”。作为 Anthropic 于 2024 年提出的开放标准,MCP 通过规范应用程序向大语言模型(LLM)传递上下文的方式,为 AI 系统连接外部服务构建了如 “USB-C 端口” 般便捷、统一的交互通道。<br>MCP 的核心架构基于客户端 - 服务器模式:AI 助手作为客户端,可通过标准化协议与各类 MCP 服务器通信。这些轻量级服务器如同 “功能中转站”,将特定数据源(如企业知识库)或工具(邮件、数据库接口)的能力,以统一规则对外开放。例如,企业可部署文档库 MCP 服务器供 AI 检索内部资料,或搭建数据库 MCP 服务器实现数据实时调取,不同功能的服务器遵循同一交互语言,确保 AI 代理能无缝对接。<br>相较于传统自定义集成模式的零散与低效,MCP 彻底革新了 AI 工具连接方式。它打破 “一源一适配” 的开发困境,使 AI 代理只需遵循 MCP 标准,即可像 “即插即用” 般快速集成任意数据源与工具,极大提升了 AI 系统的扩展性与开发效率,为智能体迈向更复杂、多元的应用场景奠定基础。<br>MCP 官方介绍 为深入了解其技术细节与应用案例提供了权威入口。若想直观对比技术演进路径,下图将呈现 LLM 连接外部工具的三种进阶方案,揭示 MCP 带来的变革性突破。</p>
<p><img src="https://img2024.cnblogs.com/blog/666745/202506/666745-20250602141540378-569012245.png" alt="" loading="lazy"></p>
<p> </p>
<p>为直观展现 AI 工具集成的技术演进,我们从左至右剖析三种不同架构模式的核心差异:</p>
<ul>
<li><strong>左侧</strong>:独立运行的 LLM作为基础形态,独立的大语言模型(LLM)如同 “信息孤岛”,仅依赖预训练数据储备进行响应。由于缺乏外部数据源的实时连接,它无法获取训练完成后的新知识,在处理动态信息或特定领域数据时,表现出显著的局限性,答案的时效性与准确性大打折扣。</li>
<li><strong>中间</strong>:典型的 RAG 应用检索增强生成(RAG)架构的出现,为 LLM 搭建了与外部世界沟通的桥梁。通过连接矢量数据库、定制应用或网页搜索 API,LLM 能够获取实时上下文信息,提升回答的事实性。然而,这种集成模式如同 “定制化拼图”—— 每个工具需单独开发适配接口,AI 应用需针对不同工具编写特定交互逻辑,导致系统扩展性差、开发成本高,难以快速适应多样化的工具迭代需求。</li>
<li><strong>右侧</strong>:基于 MCP 的 LLM 应用模型上下文协议(MCP)的引入,彻底改写了 AI 工具集成规则。它在 LLM 与外部工具间构建了一层标准化 “智能中介”:LLM 无需直接对接复杂多样的数据源或应用,仅需向 MCP 发送标准化请求(如 “检索关键词 X”),MCP 便能自动识别需求,将指令精准路由至对应的工具(数据库、搜索引擎等),并以统一格式回传结果。这一架构将 AI 逻辑与底层数据细节解耦,赋予系统 “即插即用” 的灵活性 —— 开发者只需遵循 MCP 标准开发一次连接器,即可无缝集成至不同 LLM 应用,大幅降低开发复杂度,显著提升系统的可扩展性与互操作性。</li>
</ul>
<p>MCP 的出现,让 AI 工具集成从 “手工定制” 迈向 “标准化工业生产” 时代,不仅简化了技术架构,更为 Agentic RAG 等复杂智能系统的高效运行提供了坚实底座,推动 AI 应用向更广阔的场景延伸。</p>
<h2>3.1 MCP与上下文记忆系统</h2>
<p>大语言模型(LLM)的原生上下文窗口通常限制在数千 Token 以内,难以处理长对话历史或大规模知识库的持续调用。MCP 服务器通过构建外部持久化记忆层,为 AI 代理提供了可扩展的 “记忆仓储”:</p>
<ul>
<li><strong>技术实现</strong>:MCP 服务器可对接矢量数据库(如 Milvus、Pinecone)或文档存储系统,将对话历史、用户偏好、领域知识等信息编码为高维向量,实现高效存储与检索。例如,通过嵌入技术将用户过往交互中的关键信息(如身份标签、需求偏好)转化为数字指纹,存储于专用向量库中。</li>
<li><strong>应用场景</strong>:在客服场景中,MCP 服务器可存储用户历史工单、咨询记录及解决方案,使代理在新对话中快速调取相关上下文,避免重复询问用户信息;在企业知识库场景中,服务器可索引数万页技术文档,当代理处理复杂技术问题时,实时检索匹配的历史案例或操作手册片段。</li>
</ul>
<h2>3.2 双向交互赋能:MCP 服务器的记忆增强与个性化应用</h2>
<p>MCP 服务器不仅是信息的 “存储仓库”,更是实现双向上下文交互的智能枢纽。一方面,AI 代理可主动查询服务器,获取定制化上下文数据。以智能客服场景为例,MCP 服务器能存储客户历史咨询记录、购买偏好等信息,当用户再次咨询时,代理迅速调用这些数据,提供针对性解决方案,大幅提升服务效率与用户体验。<br>另一方面,MCP 支持 AI 代理反向写入信息,构建动态更新的知识体系。以开源工具 mem0 为例,其作为 MCP 内存服务器,允许编码助手实时存储代码片段、项目配置参数及技术文档。在后续编程任务中,AI 不仅能调用这些资源辅助代码生成,还可根据新需求迭代更新存储内容,形成 “学习 - 应用 - 优化” 的闭环。这种双向数据流动,使 AI 代理能够在复杂场景下持续积累经验,实现跨会话的上下文延续与个性化响应,真正将外部记忆转化为智能决策的 “强大后盾”。</p>
<h1>4.RAG与MCP相结合的系统架构</h1>
<p>在 AI 技术向复杂化、场景化演进的趋势下,将 Agentic RAG 的智能决策能力与 MCP 的标准化连接优势相结合,成为释放 AI 系统潜力的关键路径。其集成架构通过模块化设计与标准化协议,构建起高效的知识检索 - 生成闭环,核心包含四大组件:</p>
<ul>
<li><strong>智能决策中枢</strong>:由大语言模型(LLM)驱动的智能代理,具备规划与推理能力,负责解析用户查询意图,动态制定检索策略;</li>
<li><strong>标准化连接层</strong>:MCP 服务器作为 “智能网关”,将各类知识源(如专业数据库、文档库)与工具(API 接口、计算服务)转化为统一格式,供代理调用;</li>
<li><strong>长期记忆仓库</strong>:向量数据库或知识库作为信息存储核心,借助 MCP 服务器实现与代理的实时交互,存储并快速检索历史对话、专业知识等数据;</li>
<li><strong>交互桥梁</strong>:MCP 客户端接口遵循统一协议,确保代理与 MCP 服务器间的请求发送、数据传输流畅无阻。</li>
</ul>
<p>在实际运行中,代理作为流程核心,依据用户查询智能调度资源:先通过语义分析锁定关键信息,再利用 MCP 客户端向对应服务器发送检索指令;MCP 服务器接收到请求后,从知识库中筛选匹配数据并回传,代理将获取的上下文精准嵌入 LLM 提示词,最终生成贴合需求的答案。<br>以单代理 RAG 架构为例,其 “一站式路由” 特性将集成优势发挥到极致。面对用户提问,单一代理可快速判断知识源:如处理学术问题时,灵活选择索引不同学科文献的向量数据库 A 或 B;遇到数值计算需求,则立即调用计算器工具;若需实时资讯,自动触发 Web 搜索功能。通过 MCP 协议的标准化适配,代理无需针对每个工具开发复杂接口,仅需一次请求即可实现多源数据整合,显著提升响应效率与答案准确性,为复杂场景下的 AI 应用提供了兼具灵活性与扩展性的解决方案。</p>
<p>在 Agentic RAG 与 MCP 的集成架构中,MCP 服务器通过标准化封装,将多元异构的数据源与工具转化为可插拔的 “智能组件”,形成代理的动态工具集合。这种模块化设计使系统能够根据业务需求灵活扩展能力边界,典型的服务器类型包括:</p>
<ul>
<li><strong>企业知识库服务器</strong>:基于矢量数据库构建,存储企业内部文档、流程手册、技术报告等核心数据,通过语义索引实现高效检索,满足合规性要求高的场景需求;</li>
<li><strong>动态搜索服务器</strong>:对接实时搜索引擎或垂直领域数据接口(如财经资讯、医疗指南),使代理能够获取训练数据外的最新信息,应对时效性问题;</li>
<li><strong>记忆管理服务器</strong>:专门存储对话历史、用户画像、偏好设置等状态数据,支持跨会话的上下文延续,例如在客服场景中持续记录客户沟通轨迹;</li>
<li><strong>功能扩展服务器</strong>:集成计算器、代码执行引擎、API 网关等工具,处理数值计算、脚本运行、系统对接等特定任务,增强代理的实操能力。</li>
</ul>
<p>MCP 客户端作为代理与服务器间的 “通信适配器”,基于 MCP 规范实现轻量化连接。通过 JSON 格式的远程过程调用(RPC)协议,结合 STDIO 流或 HTTP/SSE 长连接,确保数据传输的可靠性与实时性。这种通信机制使代理能够像调用本地函数一样触发服务器操作,例如通过searchDocuments("Q3销售额对比")指令激活知识库服务器的检索功能,或通过calculate("(本季度-上季度)/上季度*100%")调用计算工具完成数据处理。<br>以 “跨季度销售数据对比” 查询为例,代理的执行链路展现出标准化交互的高效性:</p>
<ul>
<li><strong>意图解析</strong>:通过语义理解识别问题需要企业内部财务数据支撑;</li>
<li><strong>工具调用</strong>:通过 MCP 客户端向数据库服务器发送结构化查询请求,服务器执行 SQL 或矢量检索后返回格式化结果(如 “上季度销售额 X 万元,本季度 Y 万元”);</li>
<li><strong>逻辑处理</strong>:代理自动调用计算服务器完成环比增长率计算,或触发可视化工具生成趋势图表;</li>
<li><strong>答案生成</strong>:将整合后的数据分析结果嵌入 LLM 提示词,生成包含数据对比、原因分析的自然语言回答。</li>
</ul>
<p>这种基于 MCP API 的标准化操作,使代理无需关心底层数据库类型(如 SQL、NoSQL 或矢量库)、工具接口差异或网络协议细节,仅通过统一的函数调用语法即可完成复杂任务。它不仅降低了多工具集成的技术门槛,更通过 “热插拔” 式的服务器扩展机制,让 AI 应用能够快速适应业务需求变化,推动智能系统从定制化开发迈向工业化组装的新范式。</p>
<h2>4.1 数据流</h2>
<p>为清晰呈现 Agentic RAG 与 MCP 集成系统的运作逻辑,以下通过一个典型业务场景的查询往返流程,拆解从用户提问到答案生成的全链条技术交互:</p>
<h3>1.用户查询解析与代理规划</h3>
<p>当用户提出复杂请求 —— 例如 “生成一份关于未结支持工单的报告,并包含所有近期相关的客户反馈”—— 代理(由 LLM 驱动)首先通过自然语言理解(NLU)模块拆解需求核心:</p>
<ul>
<li><strong>关键信息提取</strong>:识别 “未结工单”“近期客户反馈”“报告生成” 等核心要素;</li>
<li><strong>多源数据定位</strong>:判断需调用两类数据源 —— 支持工单数据库(结构化数据)与客户反馈语料库(非结构化文本);</li>
<li><strong>执行流程规划</strong>:制定分阶段任务链:① 检索未结工单列表 → ② 检索关联客户反馈 → ③ 数据清洗与整合 → ④ 报告生成与格式化。</li>
</ul>
<p>此阶段代理通过 “思维链”(Chain of Thought)推理,明确工具调用顺序与数据依赖关系,为后续 MCP 交互奠定基础。</p>
<h3>2.MCP 协议驱动的多源数据检索</h3>
<p>代理通过 MCP 客户端发起标准化工具调用,依托 MCP 协议的统一接口与不同服务器交互:</p>
<ul>
<li><strong>工单数据库检索</strong>
<ul>
<li>请求发送:代理向工单数据库 MCP 服务器发送find_tickets方法调用,附带查询参数status="open";</li>
<li>执行与响应:服务器对接企业工单系统执行 SQL 查询,返回结构化 JSON 数据(包含工单 ID、创建时间、所属部门等字段)。</li>
</ul>
</li>
<li><strong>客户反馈检索</strong>
<ul>
<li>向量搜索触发:代理向反馈 MCP 服务器发送vector_search请求,指定搜索条件 “过去 3 个月内产品 X 的反馈”;</li>
<li>语义匹配与返回:服务器通过嵌入模型将查询转换为向量,在反馈语料库中检索余弦相似度>0.7 的文档片段,返回包含情感倾向的文本摘要。</li>
</ul>
</li>
</ul>
<p><strong>技术关键点:</strong><br>所有工具调用遵循 JSON-RPC 协议,请求格式统一为 <strong>{"method":"searchDocuments","params":{"query":"...","filters":{"time_range":"last_3_months"}}} </strong>;<br>MCP 服务器屏蔽底层数据源差异(如 SQL 数据库与矢量数据库的交互细节),代理仅需关注业务逻辑。</p>
<h3>3.上下文整合与 LLM 生成</h3>
<p>代理将多源检索结果整合成 LLM 可理解的上下文格式,触发答案生成:</p>
<ul>
<li>数据清洗与结构化
<ul>
<li>解析工单 JSON 数据,提取关键指标(未结工单总数、平均处理时长);</li>
<li>对客户反馈进行情感分析,统计正面 / 负面评价占比。</li>
</ul>
</li>
<li>提示词工程构建包含背景指令与数据块的复合提示:</li>
</ul>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">任务:生成未结支持工单分析报告
数据输入:
[工单统计]:未结工单总计235单,平均处理时长48小时,Top3部门为客服部(112单)、技术部(67单)、运维部(56单)
[反馈摘要]:近3个月产品X相关反馈共187条,其中45</span>%提及功能缺陷,<span style="color: rgba(128, 0, 128, 1)">28</span>%<span style="color: rgba(0, 0, 0, 1)">反映操作复杂,典型评价:“工单处理进度更新不及时,影响问题解决效率”
输出要求:包含数据概览、问题分类、改进建议,字数500字以内 </span></pre>
</div>
<ul>
<li>LLM 生成执行
<ul>
<li>同一 LLM 实例或独立模型(如 GPT-4 Turbo)基于上下文生成报告,结合实时数据与领域知识输出结构化内容。</li>
</ul>
</li>
</ul>
<h3>4.结果存储与持续优化</h3>
<p>查询闭环完成后,代理通过 MCP 协议实现知识沉淀与系统进化:</p>
<ul>
<li><strong>中间结果存储</strong>:将工单统计数据与反馈分析结果写入向量内存服务器,生成唯一标识符report_v1.0;</li>
<li><strong>索引构建</strong>:为存储内容添加元数据标签(如 “报告类型 = 工单分析”“时间范围 = 2024Q4”),便于后续快速检索;</li>
<li><strong>迭代调用示例</strong>:当用户后续提问 “对比上一季度的工单处理效率” 时,代理可直接通过 MCP 服务器调取历史报告report_v1.0,避免重复计算。</li>
<li><strong>架构扩展</strong>:从单代理到多代理协同</li>
<li><strong>单代理模式</strong>:适用于轻量级场景,单个代理通过 MCP 客户端统一管理所有工具接口,如同时调用工单数据库与 Web 搜索 API;</li>
<li><strong>多代理模式</strong>:复杂场景下引入职责分工:</li>
<li><strong>研究代理</strong>:专职处理互联网公开数据检索(如市场趋势分析);</li>
<li><strong>数据库代理</strong>:负责企业内部敏感数据访问(如财务报表查询);</li>
<li><strong>主代理</strong>:作为协调中枢,分配子任务并整合多源结果。</li>
</ul>
<p>此架构通过 MCP 协议的标准化接口,实现代理模块的 “即插即用”,既降低系统耦合度,又支持按需扩展工具生态,为企业级 AI 应用提供了灵活可演进的技术底座。</p>
<p><img src="https://img2024.cnblogs.com/blog/666745/202506/666745-20250602145547359-1779432542.png" alt="" loading="lazy"></p>
<p>将 Agentic RAG 系统与 MCP 服务器集成,需按序完成数据处理、服务器部署、功能测试及环境适配等关键环节。以下从六大核心步骤展开,助您高效构建稳定智能的 AI 应用架构。<br><strong>知识库数据预处理与索引构建</strong></p>
<ul>
<li><strong>数据清洗与分块</strong>:整合企业内部文档、数据库记录、行业报告等结构化与非结构化数据,利用 Python 脚本或专用工具(如 OpenRefine)去除重复项、修正格式错误并统一编码。将长文本分割为 200-500 字的逻辑片段,便于后续向量处理。</li>
<li><strong>向量嵌入与存储</strong>:选用 OpenAI Embeddings、Hugging Face 的 SentenceTransformer 等模型,将文本块转化为高维向量。根据业务规模与需求,选择适配的向量数据库:轻量场景可使用本地部署的 FAISS;需云端扩展则优先考虑 Weaviate 或 Pinecone,完成向量数据的高效存储。</li>
<li><strong>多源数据管理</strong>:针对不同数据源(如产品手册、客服工单),创建独立索引分区。为每个数据块添加元数据标签(如文档类型、创建时间、所属部门),支持 “2024 年产品 A 更新日志” 等精准检索,例如将企业 FAQ 按业务线分类索引,提升查询效率。</li>
</ul>
<p><strong>MCP 服务器部署与接口开发</strong></p>
<ul>
<li><strong>服务器快速搭建</strong>:优先复用 Anthropic 开源的 MCP 服务器模板(如适配 Google Drive、Slack、SQL 数据库版本),或基于业务需求定制开发。采用 Docker 容器化部署,确保服务在不同环境下的便捷迁移与稳定运行。</li>
<li><strong>接口协议适配</strong>:根据知识库类型开发对应接口逻辑。若对接向量数据库,需实现search_documents方法,将用户查询转换为向量后执行余弦相似度检索,返回 Top-N 匹配结果;若连接关系型数据库,则需封装 SQL 查询语句。所有接口严格遵循 JSON-RPC 协议规范,保障数据交互的可靠性。</li>
<li><strong>功能声明配置</strong>:在 MCP 服务器配置文件中明确列出支持的功能,如resources: ["document_retrieval", "data_aggregation"],方便客户端(代理)识别可用服务。可扩展记忆型 MCP 服务器,对接 Redis 键值存储或专用向量库,用于存储对话历史与用户画像数据。</li>
</ul>
<p><strong>MCP 服务器功能测试与验证</strong></p>
<ul>
<li><strong>单元测试执行</strong>:使用 Postman 或官方 MCP 测试工具,发送模拟请求{"method":"search_documents","params":{"query":"系统故障排查"}},验证服务器能否按预期返回结构化数据结果集,确保基础检索功能正常。</li>
<li><strong>性能压力测试</strong>:通过 JMeter 等工具模拟高并发场景,监测服务器在大量请求下的响应时间、吞吐量及稳定性。分析日志定位性能瓶颈,优化检索算法与资源分配策略,保障服务高可用性。</li>
</ul>
<p><strong>MCP 客户端环境适配与集成</strong></p>
<ul>
<li><strong>平台对接配置</strong>:在 Claude 等桌面应用中,通过设置面板添加 MCP 服务器地址、认证密钥;若基于 Cursor 等 IDE 开发,需在插件配置页输入服务器端点 URL,并选择 SSE(Server-Sent Events)或 WebSocket 通信协议,实现客户端与服务器的无缝连接。</li>
<li><strong>安全机制强化</strong>:启用 TLS 加密传输,防止数据泄露;配置 API 密钥、JWT 令牌等认证机制,限制非法访问。针对企业敏感数据,部署基于角色的访问控制(RBAC),确保代理仅能调用授权范围内的 MCP 服务。</li>
</ul>
<p><strong>端到端全链路联调测试</strong><br>在代理代码中编写调用逻辑,输入 “查询 2024 年 Q3 销售报表” 等实际业务指令,验证从用户请求发起、MCP 服务器数据调取,到代理生成响应的完整流程。通过日志记录与分析,排查数据传输、接口调用等环节的潜在问题,优化交互性能与响应准确性。</p>
<p><strong>系统维护与功能扩展</strong><br>建立定期数据更新机制,确保知识库内容时效性;监控 MCP 服务器运行状态,及时处理异常告警。根据业务发展需求,灵活添加新的 MCP 服务器或数据源,通过标准化接口实现系统功能的平滑迭代升级。</p>
<div class="ace-line" dir="auto" data-node="true">
<h2><span class="am">4.2 实现查询扩展或多步检索</span></h2>
</div>
<div class="ace-line" dir="auto" data-node="true">
<p>在 Agentic RAG 与 MCP 服务器的集成架构中,释放代理的多步检索与智能决策能力,是应对复杂查询、提升系统响应质量的关键。以下从动态检索策略、客户端优化、资源管控等维度,详述强化代理功能的核心方法。</p>
<h3>1.构建智能多步检索机制</h3>
<ul>
<li><strong>LLM 驱动的自主决策</strong>:借助大语言模型的推理能力,赋予代理动态规划检索步骤的能力。例如,当用户提问 “分析某新能源车型销量波动与政策补贴的关联” 时,代理可先从行业数据库中检索车型销量数据,发现缺乏政策时间线信息后,自动触发二次检索,调取政府公告文档库,补充关键上下文。</li>
<li><strong>ReAct 模式深度应用</strong>:基于 “推理 - 行动 - 观察” 循环,将代理的思维过程显性化。当首次检索结果不足时,LLM 生成推理结论(如 “需补充竞品同期数据对比”),驱动系统执行对应检索动作,并根据返回结果调整后续策略,形成闭环迭代。</li>
</ul>
<h3>2.优化 MCP 客户端交互性能</h3>
<ul>
<li><strong>长连接管理与请求队列优化</strong>:配置 MCP 客户端保持与服务器的持久连接,减少频繁握手开销。通过异步请求队列设计,实现连续检索任务的有序调度,避免并发过载。例如,在处理多轮检索时,客户端可缓存未执行请求,按优先级依次发送。</li>
<li><strong>智能重试与策略调整</strong>:内置检索失败处理逻辑,当首次查询无有效结果时,自动触发关键词重构或检索范围扩展。可利用 LLM 生成近义词组(如将 “新能源车” 扩展为 “电动汽车、插混车型”),或切换数据源(从企业知识库转向公开学术数据库),提升检索成功率。</li>
</ul>
<h3>3. 实施动态查询迭代策略</h3>
<ul>
<li><strong>多源数据协同检索</strong>:建立数据源优先级矩阵,指导代理在检索失效时快速切换资源。例如,若企业内部系统未命中数据,自动调用 Web 搜索 MCP 服务器获取行业报告;若需专业解读,再转向学术文献库,实现数据互补。</li>
<li><strong>上下文感知的查询优化</strong>:代理在每次检索后,基于新获取的信息动态修正后续查询。如在分析市场趋势时,根据初步检索结果中的关键事件,生成更聚焦的子查询(如 “该事件后 3 个月内的市场份额变化”),逐步逼近精准答案。</li>
</ul>
<h3>4. 资源使用监控与管控</h3>
<ul>
<li><strong>令牌消耗精细化管理</strong>:设置单轮查询的令牌使用阈值(如限制每次对话检索调用不超过 3 次),结合成本预估模型,动态调整检索策略。当接近阈值时,优先选择高相关性数据源,避免无效调用。</li>
<li><strong>异常流程熔断机制</strong>:针对可能出现的无限循环(如错误关键词导致重复检索),部署超时中断与回溯逻辑。一旦检索步骤超出预设次数或耗时过长,强制终止当前流程,提示用户修正问题或切换检索方向。</li>
</ul>
<h3>5. 全面测试与功能验证</h3>
<ul>
<li><strong>复杂场景模拟测试</strong>:设计涵盖多数据源整合、多轮检索的测试用例,如 “结合公司财报、行业白皮书与社交媒体舆情,评估某产品市场竞争力”,验证代理能否协调多个 MCP 服务器完成任务。</li>
<li><strong>边界条件压力测试</strong>:模拟高并发请求、低质量查询等极端场景,监测系统资源消耗与响应稳定性。通过日志分析检索路径效率,优化代理决策逻辑,确保在复杂环境下仍能高效运行。</li>
</ul>
</div>
<h2 class="ace-line" dir="auto" data-node="true">4.3 数据更新与存储</h2>
<div class="ace-line" dir="auto" data-node="true">
<h3>1. 动态知识更新体系构建</h3>
<p>针对数据的不同特性,需采用差异化的更新策略。对于相对稳定的文档集(如经典学术著作、企业标准手册),可设定周期性任务(如每周 / 每月),通过脚本重新分割文本、生成向量并更新索引,确保知识储备的完整性;而对于高频变动的数据(如实时工单系统、政策法规库),则需构建实时更新管道。以数据库场景为例,可配置 MCP 服务器采用轮询或事件触发机制,当检测到数据变更时,立即调用最新记录,确保每次检索结果均为最新状态。<br>在向量存储环境下,需开发具备增删改查功能的更新 API。例如,通过upsert_document(id, content)方法,系统可自动对新文档进行向量化处理,并替换或新增对应记录;同时支持版本管理,记录文档的修改历史。更灵活的是,代理可在对话交互中实时捕捉关键信息,如用户反馈的产品新功能细节,通过 MCP 协议即时调用更新接口,将新知识 “写入” 记忆层,实现 “边对话边学习”。此外,记忆型 MCP 服务器可构建分层存储结构:短期记忆缓存当前会话的关键数据,长期记忆则归档重要问答、用户画像等信息,通过时间戳与访问频率动态调整数据优先级,加速检索效率。</p>
<h3>2. 智能化知识库维护机制</h3>
<p>建立自动化与人工审核结合的知识库清洗流程。一方面,利用自然语言处理技术自动识别过时内容,如通过语义分析对比新旧政策文档,标记差异部分;或根据元数据中的时间戳,自动淘汰超期数据。另一方面,预留人工审核入口,由领域专家对复杂内容进行确认,确保知识准确性。同时,为每条数据添加丰富元数据标签,除时间戳外,还可包含数据来源可信度评分、适用场景分类、关联知识点图谱等信息,帮助代理在检索时优先选择权威、时效的内容。例如,当处理医疗咨询时,代理可根据 “三甲医院最新研究” 标签筛选数据,提升答案权威性。</p>
<h3>3. 全维度系统测试优化策略</h3>
<p>系统测试需覆盖功能、性能与可靠性多维度。功能测试阶段,设计包含单步检索、多步联动、跨源数据整合的多样化测试用例,如模拟 “结合企业财报与行业舆情分析产品市场表现” 的复杂查询,验证代理能否正确调用 MCP 服务器、筛选数据并生成逻辑清晰的答案。性能测试则聚焦响应速度与资源消耗,通过 JMeter 等工具模拟高并发请求,监控 MCP 调用延迟、LLM 推理耗时及令牌使用量。若出现响应迟缓,可从三方面优化:一是检查代理的检索策略,剔除重复或低效的搜索步骤;二是调整提示工程,通过实验确定最优文档嵌入数量(通常 3-5 个高相关片段既能提供充足信息,又避免因数据过载导致模型性能下降);三是优化 MCP 服务器与向量数据库的交互链路,采用批量查询、缓存热点数据等技术减少 IO 开销。<br>可靠性测试需模拟极端场景,如数据源故障、网络中断等,验证系统的容错能力与自动降级策略。例如,当内部数据库异常时,代理能否及时切换至备用数据源或触发人工介入流程。同时,建立日志追踪体系,详细记录每次查询的处理路径、数据调用记录及中间结果,便于问题回溯与性能分析,确保 Agentic RAG 系统在复杂业务场景中持续稳定运行。</p>
<h2>4.4 技术优化</h2>
<p>在 Agentic RAG 与 MCP 的集成架构中,通过多维度优化策略可显著提升系统响应速度与答案准确性。以下从缓存机制构建、向量数据库调优到动态监控迭代,提供系统化的性能优化方案。</p>
<h3>1. 多级缓存策略构建高效数据复用体系</h3>
<p>构建包含客户端、服务器与对话层的三级缓存架构:在客户端侧,对高频检索请求(如 “退款政策”“产品使用说明”)的结果或检索文档进行持久化缓存,避免重复向量搜索;服务器端针对频繁访问的资源(如 MCP 文件服务器的特定文档),将内容常驻内存以降低 IO 开销;对话层则缓存最近 N 次查询的向量搜索结果,当用户调整提问措辞时,可快速复用上下文数据。同时建立智能缓存失效机制,基于文档 ID 版本号或时间戳触发更新,例如当知识库中政策文档修订后,自动清除相关缓存条目,确保数据时效性。</p>
<h3>2. 向量数据库深度调优提升检索精度</h3>
<p>模型适配与参数优化:根据业务领域特性选择嵌入模型,如法律场景采用 LegalBERT、医疗领域使用 BioBERT,提升语义表征准确性;精细调整相似度阈值与 Top-K 参数,平衡检索速度与召回率,通常将返回文档数控制在 3-5 篇以聚焦核心信息。<br>混合检索与元数据过滤:启用向量数据库的混合检索功能,对包含特定关键词(如产品型号、日期)的查询,结合语义匹配与关键字检索,既捕获模糊关联又保证精准匹配;利用元数据标签(如时间范围、文档类型)进行前置过滤,例如用户询问 “2024 年 Q3 财务报告” 时,优先筛选对应时间区间的文档,减少搜索空间。<br>索引维护与数据清洗:定期归档历史数据、删除失效文档,避免冗余信息干扰检索排序;通过聚类分析等手段识别并合并重复或高度相似的向量记录,保持索引轻量化。</p>
<h3>3. 提示工程与代理指令的精细化设计</h3>
<p>行为引导与示例教学:在系统提示中明确代理决策逻辑,如 “若问题涉及具体数据或事实,优先调用 MCP 工具检索;若无可靠信息源,如实告知用户”,降低幻觉风险;通过小样本示例展示完整推理链(问题解析→工具选择→检索执行→答案生成),帮助模型快速适应集成系统的运行模式。<br>上下文格式化与分步推理:采用结构化标记(如### 参考资料:)清晰分隔检索上下文与用户输入,防止模型混淆;要求代理输出分步推理过程,先记录检索依据与中间结论(可隐藏不展示给用户),再生成最终答案,便于追溯信息使用逻辑;针对需要增强可信度的场景,指令代理添加来源引用(如 “根据《2024 年产品手册》第 3 章...”)。</p>
<h3>4. 智能工具调度与故障容错机制</h3>
<p>前置路由与批量操作:部署轻量级查询分类器,基于关键词匹配、意图识别等启发式算法,预判最优数据源并优先调用,减少代理推理消耗;对支持批量处理的工具(如数据计算、代码执行),将同类任务打包提交,例如将多个数值计算需求合并为一次 API 调用。<br>异常处理与资源管控:设置检索超时与重试上限,当 MCP 服务器响应异常时,自动切换至备用数据源或执行降级策略(如返回通用解释);通过设置推理步骤上限、令牌使用阈值,防止因复杂查询导致资源耗尽或长时间等待。</p>
<h3>5. 全链路监控与持续优化闭环</h3>
<p>建立覆盖调用频率、响应时长、答案质量的多维监控体系:分析各 MCP 服务器的调用数据,对高频慢速接口进行缓存优化或服务升级;通过用户反馈与答案质量评估,追溯问题根源(如检索遗漏、LLM 生成错误),针对性调整提示策略、优化数据源或改进 MCP 服务器功能。定期评估工具使用率,淘汰低效或冗余服务,逐步构建动态进化的智能系统架构。</p>
<h1>5.代码实践</h1>
<p>为了巩固概念,以下是一些简化的代码片段,演示了集成的关键部分。我们假设我们的知识库有一个 MCP 服务器正在运行,它暴露了一个search方法。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">from</span> mcp <span style="color: rgba(0, 0, 255, 1)">import</span> Client <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 假设的 MCP 客户端库</span>
<span style="color: rgba(0, 0, 255, 1)">from</span> langchain.agents <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> Tool, initialize_agent
</span><span style="color: rgba(0, 0, 255, 1)">from</span> langchain.llms <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> OpenAI
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> logging
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 配置日志记录</span>
logging.basicConfig(level=logging.INFO, format=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">%(asctime)s - %(name)s - %(levelname)s - %(message)s</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
logger </span>= logging.getLogger(<span style="color: rgba(128, 0, 128, 1)">__name__</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> MCPSearchAgent:
</span><span style="color: rgba(0, 0, 255, 1)">def</span> <span style="color: rgba(128, 0, 128, 1)">__init__</span>(self, server_url=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">http://localhost:8080</span><span style="color: rgba(128, 0, 0, 1)">"</span>, model_name=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">o3-mini</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">):
</span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">初始化MCP搜索代理</span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(0, 0, 0, 1)">
self.mcp_client </span>= Client(server_url=<span style="color: rgba(0, 0, 0, 1)">server_url)
self.llm </span>= OpenAI(model=model_name, temperature=<span style="color: rgba(0, 0, 0, 1)">0)
self.search_tool </span>=<span style="color: rgba(0, 0, 0, 1)"> None
self.agent </span>=<span style="color: rgba(0, 0, 0, 1)"> None
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> initialize(self):
</span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">初始化MCP连接和代理</span><span style="color: rgba(128, 0, 0, 1)">"""</span>
<span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">:
logger.info(f</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">正在连接到MCP服务器: {self.mcp_client.server_url}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
self.mcp_client.initialize()</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 执行MCP握手</span>
logger.info(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">MCP连接初始化成功</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 初始化搜索工具</span>
self.search_tool =<span style="color: rgba(0, 0, 0, 1)"> Tool(
name</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">KnowledgeBaseSearch</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
func</span>=<span style="color: rgba(0, 0, 0, 1)">self.search_knowledge,
description</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">在知识库中搜索相关文档。输入:查询;输出:相关片段。</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 初始化代理</span>
self.agent =<span style="color: rgba(0, 0, 0, 1)"> initialize_agent(
,
self.llm,
agent</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">zero-shot-react-description</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
verbose</span>=False<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 可设置为True以查看详细推理过程</span>
<span style="color: rgba(0, 0, 0, 1)"> )
logger.info(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">代理初始化成功</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">except</span><span style="color: rgba(0, 0, 0, 1)"> Exception as e:
logger.error(f</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">初始化失败: {str(e)}</span><span style="color: rgba(128, 0, 0, 1)">"</span>, exc_info=<span style="color: rgba(0, 0, 0, 1)">True)
</span><span style="color: rgba(0, 0, 255, 1)">raise</span>
<span style="color: rgba(0, 0, 255, 1)">def</span> search_knowledge(self, query: str) -><span style="color: rgba(0, 0, 0, 1)"> str:
</span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">搜索知识库并返回相关内容</span><span style="color: rgba(128, 0, 0, 1)">"""</span>
<span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(0, 0, 255, 1)">not</span><span style="color: rgba(0, 0, 0, 1)"> query:
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">错误: 查询不能为空</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
logger.info(f</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">搜索查询: {query}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
response </span>= self.mcp_client.request(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">search</span><span style="color: rgba(128, 0, 0, 1)">"</span>, params={<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">query</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: query})
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 验证响应格式</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(0, 0, 255, 1)">not</span><span style="color: rgba(0, 0, 0, 1)"> isinstance(response, dict):
logger.warning(f</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">收到非字典格式的响应: {type(response)}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">错误: 服务器响应格式不正确</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
docs </span>= response.get(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">results</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, [])
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 处理空结果</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(0, 0, 255, 1)">not</span><span style="color: rgba(0, 0, 0, 1)"> docs:
logger.info(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">未找到匹配的文档</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">未找到相关信息</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 合并并截断文档内容</span>
combined_text = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\n</span><span style="color: rgba(128, 0, 0, 1)">"</span>.join(doc.get(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">""</span>) <span style="color: rgba(0, 0, 255, 1)">for</span> doc <span style="color: rgba(0, 0, 255, 1)">in</span> docs[:3<span style="color: rgba(0, 0, 0, 1)">])
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 限制最大长度,防止LLM输入过载</span>
max_length = 4000
<span style="color: rgba(0, 0, 255, 1)">if</span> len(combined_text) ><span style="color: rgba(0, 0, 0, 1)"> max_length:
logger.info(f</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">截断搜索结果从{len(combined_text)}到{max_length}字符</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
combined_text </span>= combined_text[:max_length] + <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">...</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> combined_text
</span><span style="color: rgba(0, 0, 255, 1)">except</span><span style="color: rgba(0, 0, 0, 1)"> Exception as e:
logger.error(f</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">搜索失败: {str(e)}</span><span style="color: rgba(128, 0, 0, 1)">"</span>, exc_info=<span style="color: rgba(0, 0, 0, 1)">True)
</span><span style="color: rgba(0, 0, 255, 1)">return</span> f<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">搜索过程中发生错误: {str(e)}</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 0, 255, 1)">def</span> run(self, user_query: str) -><span style="color: rgba(0, 0, 0, 1)"> str:
</span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">使用代理执行用户查询</span><span style="color: rgba(128, 0, 0, 1)">"""</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(0, 0, 255, 1)">not</span><span style="color: rgba(0, 0, 0, 1)"> self.agent:
</span><span style="color: rgba(0, 0, 255, 1)">raise</span> RuntimeError(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">代理未初始化,请先调用initialize()方法</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">:
logger.info(f</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">用户查询: {user_query}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
result </span>=<span style="color: rgba(0, 0, 0, 1)"> self.agent.run(user_query)
logger.info(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">查询执行成功</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> result
</span><span style="color: rgba(0, 0, 255, 1)">except</span><span style="color: rgba(0, 0, 0, 1)"> Exception as e:
logger.error(f</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">查询执行失败: {str(e)}</span><span style="color: rgba(128, 0, 0, 1)">"</span>, exc_info=<span style="color: rgba(0, 0, 0, 1)">True)
</span><span style="color: rgba(0, 0, 255, 1)">return</span> f<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">查询执行失败: {str(e)}</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 使用示例</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(128, 0, 128, 1)">__name__</span> == <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">__main__</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 初始化代理</span>
agent = MCPSearchAgent(server_url=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">http://localhost:8080</span><span style="color: rgba(128, 0, 0, 1)">"</span>, model_name=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">o3-mini</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
agent.initialize()
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 执行查询</span>
user_query = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">请解释量子计算的基本原理</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
response </span>=<span style="color: rgba(0, 0, 0, 1)"> agent.run(user_query)
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(f<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">用户查询: {user_query}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(f<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">AI回答: {response}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">except</span><span style="color: rgba(0, 0, 0, 1)"> Exception as e:
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(f<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">程序运行出错: {str(e)}</span><span style="color: rgba(128, 0, 0, 1)">"</span>)</pre>
</div>
<p>在这个代码实现中,我们首先实例化了一个 MCP 客户端,然后创建了一个名为 search_knowledge 的包装函数,该函数封装了客户端的 search 方法。接着,我们将这个函数作为一个名为 KnowledgeBaseSearch 的工具注册到智能体的工具列表中。</p>
<p>这里使用的智能体采用了 ReAct 框架下的零样本推理机制,它能够在运行时动态决定是否需要调用外部工具来满足用户需求。当智能体处理用户提示时,如果通过分析发现需要访问外部知识库获取相关信息,就会自动调用 KnowledgeBaseSearch 工具进行知识检索,并将检索结果整合到后续的推理过程中。</p>
<p>使用代理通过 RAG 回答查询,代码如下所示:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> logging
</span><span style="color: rgba(0, 0, 255, 1)">from</span> typing <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> Optional
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 配置日志记录</span>
<span style="color: rgba(0, 0, 0, 1)">logging.basicConfig(
level</span>=<span style="color: rgba(0, 0, 0, 1)">logging.INFO,
format</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%(asctime)s - %(levelname)s - %(message)s</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
)
logger </span>= logging.getLogger(<span style="color: rgba(128, 0, 128, 1)">__name__</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span> fetch_rag_comparison_details(query_text: str) -><span style="color: rgba(0, 0, 0, 1)"> Optional:
</span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">
向智能代理提交查询,获取关于 Agentic RAG 和传统 RAG 对比的详细信息
参数:
query_text: 要提交的查询字符串
返回:
智能代理返回的结果,如果出错则返回 None
</span><span style="color: rgba(128, 0, 0, 1)">"""</span>
<span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 导入智能代理(实际使用时需要根据具体的代理实现进行导入)</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 这里假设 agent 是某个智能代理库的实例</span>
<span style="color: rgba(0, 0, 255, 1)">from</span> your_agent_library <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> Agent
agent </span>=<span style="color: rgba(0, 0, 0, 1)"> Agent()
logger.info(f</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">正在提交查询: {query_text}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 显示进度提示</span>
<span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">正在处理您的请求,请稍候...</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 执行查询</span>
response =<span style="color: rgba(0, 0, 0, 1)"> agent.run(query_text)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 验证响应是否有效</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(0, 0, 255, 1)">not</span><span style="color: rgba(0, 0, 0, 1)"> response:
logger.warning(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">收到空响应</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> None
logger.info(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">查询成功完成</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> response
</span><span style="color: rgba(0, 0, 255, 1)">except</span><span style="color: rgba(0, 0, 0, 1)"> Exception as e:
logger.error(f</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">查询执行失败: {str(e)}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(f<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">抱歉,处理您的请求时出错: {str(e)}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> None
</span><span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(128, 0, 128, 1)">__name__</span> == <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">__main__</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 定义要查询的问题</span>
comparison_query = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Agentic RAG 相对于传统 RAG 有哪些优势?</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 获取查询结果</span>
response_data =<span style="color: rgba(0, 0, 0, 1)"> fetch_rag_comparison_details(comparison_query)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 显示结果</span>
<span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> response_data:
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\n查询结果:</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">-</span><span style="color: rgba(128, 0, 0, 1)">"</span> * 50<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">print</span><span style="color: rgba(0, 0, 0, 1)">(response_data)
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">-</span><span style="color: rgba(128, 0, 0, 1)">"</span> * 50<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">未能获取到查询结果,请检查输入或稍后重试。</span><span style="color: rgba(128, 0, 0, 1)">"</span>)</pre>
</div>
<p>当调用 agent.run(query) 时,LLM 会执行以下结构化推理流程:</p>
<ul>
<li><strong>意图解析</strong>:LLM 首先分析查询语义,识别关键实体(如 "Agentic RAG")和用户意图(如 "优势")</li>
<li><strong>检索规划</strong>:基于解析结果生成检索指令,构造优化后的查询:</li>
</ul>
<div class="cnblogs_code">
<pre>retrieval_query = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Agentic RAG 相比传统 RAG 的核心优势及应用场景分析</span><span style="color: rgba(128, 0, 0, 1)">"</span></pre>
</div>
<ul>
<li>知识检索:调用 MCP 客户端发送检索请求,触发向量数据库混合检索:
<ul>
<li>基于语义相似度获取 top-k 相关文档</li>
<li>执行关键词过滤和文档质量评估</li>
<li>应用段落级重排序算法优化结果</li>
</ul>
</li>
<li>结果处理:
<ul>
<li>提取关键片段并生成内容摘要</li>
<li>构建包含元数据的引用结构:</li>
</ul>
</li>
</ul>
<div class="cnblogs_code">
<pre>{
"content": "Agentic RAG 通过动态查询重构实现...",
"source": "Advances in Retrieval Augmented Generation, 2024",
"page": 12,
"relevance_score": 0.92
}</pre>
</div>
<ul>
<li>结果整合:LLM 将检索内容与内部知识结合,执行多轮推理:
<ul>
<li>优势提取与分类(灵活性、适应性、准确性等)</li>
<li>对比分析与实例验证</li>
<li>逻辑连贯性检查</li>
</ul>
</li>
<li>响应生成:基于结构化证据生成最终回答,并自动插入格式化引用标记:</li>
</ul>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">Agentic RAG 相比传统方法具有三大核心优势:
</span><span style="color: rgba(128, 0, 128, 1)">1</span>. **动态查询构建**:能够根据中间结果调整检索策略[<span style="color: rgba(128, 0, 128, 1)">1</span>, p.<span style="color: rgba(128, 0, 128, 1)">12</span><span style="color: rgba(0, 0, 0, 1)">]
</span><span style="color: rgba(128, 0, 128, 1)">2</span>. **迭代结果收集**:支持多轮检索直至满足置信度阈值[<span style="color: rgba(128, 0, 128, 1)">2</span>, §<span style="color: rgba(128, 0, 128, 1)">3.2</span><span style="color: rgba(0, 0, 0, 1)">]
</span><span style="color: rgba(128, 0, 128, 1)">3</span>. **语境感知整合**:通过上下文理解优化信息融合过程[<span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">]
[</span><span style="color: rgba(128, 0, 128, 1)">1</span>] Advances <span style="color: rgba(0, 0, 255, 1)">in</span> Retrieval Augmented Generation, <span style="color: rgba(128, 0, 128, 1)">2024</span><span style="color: rgba(0, 0, 0, 1)">
[</span><span style="color: rgba(128, 0, 128, 1)">2</span>] Agentic Learning Systems, NeurIPS <span style="color: rgba(128, 0, 128, 1)">2023</span><span style="color: rgba(0, 0, 0, 1)">
[</span><span style="color: rgba(128, 0, 128, 1)">3</span>] Dynamic RAG Architectures, ACL <span style="color: rgba(128, 0, 128, 1)">2024</span></pre>
</div>
<p>假设我们正在设置一个简单的文件系统 MCP 服务器,允许代理读取文件(这可以用于长期记忆或文本文件的本地知识库)。配置可能如下所示(JSON 或 YAML 格式),指定服务器的功能:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">server</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">FileExplorer</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">port</span><span style="color: rgba(128, 0, 0, 1)">"</span>: 8090<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">resources</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: [
{
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">name</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">file</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">description</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">访问本地文本文件</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">endpoints</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: [
{
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">name</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">read_file</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">method</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">GET</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">path</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/files/{path}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">parameters</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">path</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">type</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">string</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">description</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">相对于allowed_paths的文件路径</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
}
},
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">responses</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">200</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">content</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">type</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">string</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">description</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">文件内容</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
}
},
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">400</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">error</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">type</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">string</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">description</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">无效路径</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
}
},
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">403</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">error</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">type</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">string</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">description</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">权限不足</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
}
},
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">404</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">error</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">type</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">string</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">description</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">文件不存在</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
}
}
}
},
{
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">name</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">search_files</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">method</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">GET</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">path</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/search</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">parameters</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">query</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">type</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">string</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">description</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">搜索关键词</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
},
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">limit</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">type</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">integer</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">description</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">返回结果数量限制</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">default</span><span style="color: rgba(128, 0, 0, 1)">"</span>: 10<span style="color: rgba(0, 0, 0, 1)">
}
},
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">responses</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">200</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">results</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">type</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">array</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">items</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">type</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">object</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">properties</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">name</span><span style="color: rgba(128, 0, 0, 1)">"</span>: { <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">type</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">string</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> },
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">path</span><span style="color: rgba(128, 0, 0, 1)">"</span>: { <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">type</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">string</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> },
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">size</span><span style="color: rgba(128, 0, 0, 1)">"</span>: { <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">type</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">integer</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> },
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">modified</span><span style="color: rgba(128, 0, 0, 1)">"</span>: { <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">type</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">string</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">format</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">date-time</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> }
}
},
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">description</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">匹配的文件列表</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
}
},
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">400</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">error</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">type</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">string</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">description</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">无效查询参数</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
}
}
}
}
]
}
],
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">security</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">allowed_paths</span><span style="color: rgba(128, 0, 0, 1)">"</span>: [<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/home/agent/docs/</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">],
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">max_file_size</span><span style="color: rgba(128, 0, 0, 1)">"</span>: 10485760, //<span style="color: rgba(0, 0, 0, 1)"> 10MB
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">allowed_extensions</span><span style="color: rgba(128, 0, 0, 1)">"</span>: [<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">txt</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">md</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">json</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">csv</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">],
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">rate_limit</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">requests</span><span style="color: rgba(128, 0, 0, 1)">"</span>: 100<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">period</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">hour</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
}
}
}</span></pre>
</div>
<p>本假设配置定义了一个基于 MCP(Machine Communication Protocol) 的文件资源服务,运行于 8090 端口,服务名称为 FileExplorer。该服务通过标准化接口暴露文件操作能力,同时实施目录级访问控制以增强安全性。服务包含单一资源 Files,封装以下两类文件操作接口:</p>
<ul>
<li>read_file
<ul>
<li>功能:读取指定路径文件的内容</li>
<li>参数:file_path(文件绝对路径,需在授权目录内)</li>
<li>返回:文件内容字符串或二进制流</li>
</ul>
</li>
<li>search_files
<ul>
<li>功能:在指定目录树中搜索包含特定文本的文件</li>
<li>参数:
<ul>
<li>query:搜索关键词(支持正则表达式)</li>
<li>directory:搜索范围根目录(默认受限目录)</li>
</ul>
</li>
<li>返回:匹配文件路径列表</li>
</ul>
</li>
</ul>
<h1>6.总结</h1>
<p>在人工智能技术不断发展的当下,RAG 与 MCP 的集成成为提升 AI 性能的关键路径。Agentic RAG 与 MCP 服务器的深度融合,通过知识检索为 AI 代理提供精准信息支撑,借助记忆与数据集成增强其情境感知能力,使 AI 系统从被动应答迈向主动决策。这一创新架构赋予 AI 研究员般的探索力、助手级的执行力与分析师的洞察力,不仅实现海量信息的高效调用,更能智能判断知识应用场景与时机,让 AI 真正成为兼具专业性与实用性的智能伙伴,开启智能交互的全新可能。</p>
<h1>7.结束语</h1>
<p>这篇博客就和大家分享到这里,如果大家在研究学习的过程当中有什么问题,可以加群进行讨论或发送邮件给我,我会尽我所能为您解答,与君共勉!</p>
<p>另外,博主出新书了《<span style="color: rgba(255, 0, 0, 1)"><strong><span style="color: rgba(255, 0, 0, 1)">Hadoop与Spark大数据全景解析</span></strong></span>》、同时已出版的《<span style="color: rgba(0, 0, 255, 1)"><strong><span style="color: rgba(0, 0, 255, 1)">深入理解Hive</span></strong></span>》、《<span style="color: rgba(0, 0, 255, 1)"><strong><span style="color: rgba(0, 0, 255, 1)">Kafka并不难学</span></strong></span>》和《<span style="color: rgba(0, 0, 255, 1)"><strong><span style="color: rgba(0, 0, 255, 1)">Hadoop大数据挖掘从入门到进阶实战</span></strong></span>》也可以和新书配套使用,喜欢的朋友或同学, 可以<span style="color: rgba(255, 0, 0, 1)"><strong>在公告栏那里点击购买链接购买博主的书</strong></span>进行学习,在此感谢大家的支持。关注下面公众号,根据提示,可免费获取书籍的教学视频。</p>
</div>
</div>
</div>
<div id="MySignature" role="contentinfo">
<div>
<b class="b1"></b><b class="b2 d1"></b><b class="b3 d1"></b><b class="b4 d1"></b>
<div class="b d1 k">
联系方式:
<br/>
邮箱:smartloli.org@gmail.com
<br/>
<strong style="color: green">QQ群(Hive与AI实战【新群】):935396818</strong>
<br/>
QQ群(Hadoop - 交流社区1):424769183
<br/>
QQ群(Kafka并不难学):825943084
<br/>
温馨提示:请大家加群的时候写上加群理由(姓名+公司/学校),方便管理员审核,谢谢!
<br/>
<h3>热爱生活,享受编程,与君共勉!</h3>
</div>
<b class="b4b d1"></b><b class="b3b d1"></b><b class="b2b d1"></b><b class="b1b"></b>
</div>
<br>
<div>
<b class="b1"></b><b class="b2 d1"></b><b class="b3 d1"></b><b class="b4 d1"></b>
<div class="b d1 k">
<h3>公众号:</h3>
<h3><img style="width: 8%; margin-left: 10px" src="https://www.cnblogs.com/images/cnblogs_com/smartloli/1324636/t_qr.png"></h3>
</div>
<b class="b4b d1"></b><b class="b3b d1"></b><b class="b2b d1"></b><b class="b1b"></b>
</div>
<br>
<div>
<b class="b1"></b><b class="b2 d1"></b><b class="b3 d1"></b><b class="b4 d1"></b>
<div class="b d1 k">
<h3>作者:哥不是小萝莉 [关于我][犒赏]</h3>
<h3>出处:http://www.cnblogs.com/smartloli/</h3>
<h3>转载请注明出处,谢谢合作!</h3>
</div>
<b class="b4b d1"></b><b class="b3b d1"></b><b class="b2b d1"></b><b class="b1b"></b>
</div><br><br>
来源:https://www.cnblogs.com/smartloli/p/18907145
頁:
[1]