ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">在企业数字化转型浪潮中,如何有效管理和利用内部知识资产已成为关键挑战。随着大型语言模型(LLM)技术的成熟,检索增强生成(RAG)应用正逐渐成为连接企业知识与AI能力的重要桥梁。然而,传统RAG实现常面临检索质量不佳、实时更新困难等痛点问题。本文将通过实战案例,详细介绍如何 ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;color: rgb(0, 152, 116);">基于模型上下文协议(MCP)构建一套高性能企业RAG系统,帮助企业快速打造智能知识库应用。
ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;display: table;padding: 0px 0.2em;color: rgb(255, 255, 255);background: rgb(0, 152, 116);">MCP与传统RAG对比优势 ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;padding-left: 8px;color: rgb(63, 63, 63);">传统RAG方案的局限
ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);"> ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;color: rgb(0, 152, 116);">传统RAG实现通常采用简单的"Embedding+检索+LLM生成"架构,存在以下限制: ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;color: rgb(63, 63, 63);" class="list-paddingleft-1"> ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);">1. ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;color: rgb(0, 152, 116);">紧耦合架构:检索逻辑与LLM调用紧密耦合,难以独立优化 2.单一检索策略 :通常只采用向量检索,缺乏多种检索方式结合 3.缺乏标准化接口 :各实现间接口差异大,难以实现功能复用 MCP解决方案的优势 基于MCP的RAG系统通过标准化协议,将知识检索服务解耦为独立模块 ,带来以下优势:
1.标准化工具调用 :MCP提供统一接口规范,降低集成成本 2.解耦设计 :将模型调用与业务逻辑分离,便于独立升级和维护 3.灵活扩展 :轻松添加新数据源和功能模块,如混合检索、多模态内容等 4.工程实践友好 :符合软件工程最佳实践,便于团队协作开发 项目背景与需求 现代企业面临的知识管理挑战主要表现在以下几个方面:
•知识分散 :企业文档分布在多个系统中,缺乏统一检索入口 •检索效率低 :传统关键词检索无法理解语义,难以准确找到所需信息 •知识更新慢 :知识库更新依赖人工整理,无法及时反映最新情况 •使用门槛高 :专业术语和复杂查询语法提高了普通员工使用难度 针对这些问题,我们需要设计一个系统满足以下核心需求:
1.智能检索 :支持自然语言提问,理解问题意图和上下文 2.知识自动化处理 :实现文档智能拆分、FAQ自动提取 4.易于部署与维护 :架构简洁,便于技术团队掌握和迭代 项目目标 本项目旨在构建一个基于MCP的企业RAG系统 ,实现以下具体目标:
• 显著提升企业内部知识检索准确率(目标90%以上) 项目系统设计与实现 本项目系统设计参考自alibabacloud-tablestore-mcp-server[1] ,由于alibabacloud-tablestore-mcp-server项目使用Tablestore存储和Java实现的MCP Server,不方便于后期扩展和迭代。
本项目改造为Milvus存储和Python实现MCP Server和MCP Client,代码全部重写(cursor帮忙不少)。
以下设计和流程皆为alibabacloud-tablestore-mcp-server内容,在此感谢@xjtushilei 开源的alibabacloud-tablestore-mcp-server。
我们构建的基于MCP的RAG系统主要包含三个核心部分:
1.知识库服务(MCP Server) :基于Milvus向量数据库实现的后端服务,负责文档存储和检索 2.客户端工具(MCP Client) :与MCP Server通信的客户端,实现知识库的构建和检索功能 3.大模型集成 :通过LLM实现文档切分、FAQ提取、问题拆解和回答生成等核心功能 主要分为两部分:知识库构建和检索。
1.文本切段: 对文本进行切段,切段后的内容需要保证文本完整性以及语义完整性。 2.提取 FAQ: 根据文本内容提取 FAQ,作为知识库检索的一个补充,以提升检索效果。 3.导入知识库: 将文本和 FAQ 导入知识库,并进行 Embedding 后导入向量。 1.问题拆解: 对输入问题进行拆解和重写,拆解为更原子的子问题。 2.检索: 针对每个子问题分别检索相关文本和 FAQ,针对文本采取向量检索,针对 FAQ 采取全文和向量混合检索。 3.知识库内容筛选: 针对检索出来的内容进行筛选,保留与问题最相关的内容进行参考回答。 相比传统的 Naive RAG,在知识库构建和检索分别做了一些常见的优化,包括 Chunk 切分优化、提取 FAQ、Query Rewrite、混合检索等。
流程 本Agent整体架构分为三个部分:
1.知识库: 内部包含 Knowledge Store 和 FAQ Store,分别存储文本内容和 FAQ 内容,支持向量和全文的混合检索。 2.MCP Server: 提供对 Knowledge Store 和 FAQ Store 的读写操作,总共提供 4 个 Tools。 3. **功能实现部分:**完全通过 Prompt + LLM 来实现对知识库的导入、检索和问答这几个功能。 项目结构 项目结构分为两部分:
1.milvus-mcp-client: Python 实现的 Client 端,实现了与大模型进行交互,通过 MCP Client 获取 Tools,根据大模型的反馈调用 Tools 等基本能力。通过 Prompt 实现了知识库构建、检索和问答三个主要功能。 2. **milvus-mcp-server:** Python 实现的 Server 端,基于 MCP 框架实现的服务,提供了连接 Milvus 向量数据库的接口,支持知识库的存储和检索功能。 项目实战:从零搭建MCP-RAG系统 接下来,我们将从环境搭建、服务部署到功能测试,全面介绍如何搭建一个基于MCP的RAG系统。
环境准备 首先,确保满足以下系统要求:
• Docker 和 Docker Compose • 克隆代码git clone -b rag_0.1.1 https://github.com/FlyAIBox/mcp-in-action.git 部署MCP Server MCP Server基于Milvus向量数据库,提供了知识库的存储和检索功能。
对于需要进行开发或调试的场景,可以选择本地部署:
# 进入项目目录 cdmcp-rag # 先启动Milvus及依赖服务 docker compose up -d etcd minio standalone # 创建Python虚拟环境 python -m venv env-mcp-rag sourceenv-mcp-rag/bin/activate # 安装依赖 pip install -r requirements.txt # 启动服务 python -m app.mainMCP Server的核心API MCP Server提供四个核心工具,支持知识库的读写操作:
1.storeKnowledge :存储文档到知识库 2.searchKnowledge :在知识库中搜索相似文档 4.searchFAQ :在FAQ库中搜索相似问答对 让我们看看这些API的实际实现原理:
asyncdefstore_knowledge(self, content:str, metadata ict[str,Any] =None) ->Dict[str,Any]: """存储知识内容到Milvus""" # 确保服务准备就绪 awaitself.ready_for_connections() try: knowledge_content = KnowledgeContent( content=content, metadata=metadataor{} ) self.milvus_service.store_knowledge(knowledge_content) return{"status":"success","message":"Knowledge stored successfully"} exceptExceptionase: logger.error(f"Error storing knowledge:{e}") return{"status":"error","message":str(e)}这段代码展示了storeKnowledge工具的实现:接收文本内容和元数据,创建知识内容对象,然后通过Milvus服务存储到向量数据库中。
基于MCP Client实现RAG客户端 接下来,我们需要实现一个RAG客户端,通过MCP协议与Server通信,实现知识库的构建和查询功能。
1. 知识库构建 • 文本切分:对长文本进行智能切分,保证语义完整性 • 向量化存储:将文本片段和FAQ转换为向量并存入Milvus 文本切分代码示例:
def_chunk_text(self, text:str) ->List[str]: """将文本分割成chunk,保证语义完整性""" chunks = [] # 处理文本小于chunk_size的简单情况 iflen(text) <=self.chunk_size: chunks.append(text) returnchunks # 使用重叠策略分割文本 start =0 whilestart <len(text): # 获取chunk结束位置 end = start +self.chunk_size # 调整结束位置,避免在句子中间切断 ifend <len(text): # 寻找句子边界(句号、问号、感叹号) sentence_end =max( text.rfind('. ', start, end), text.rfind('? ', start, end), text.rfind('! ', start, end) ) # 如果找到句子结束,使用它作为chunk结束 ifsentence_end > start: end = sentence_end +1# 包含句号 # 添加chunk chunks.append(text[start:min(end,len(text))]) # 移动开始位置到下一个chunk,考虑重叠 start = end -self.chunk_overlap # 确保进度 ifstart >=len(text)orstart <=0: break returnchunksFAQ提取,通过LLM实现:
asyncdef_extract_faqs(self, text:str) ->List[Dict[str,str]]: """从文本中提取FAQ""" # 对过长文本进行分块处理 iflen(text) >8000: chunks =self._chunk_text(text) faqs = [] forchunkinchunks: chunk_faqs =awaitself._extract_faqs(chunk) faqs.extend(chunk_faqs) returnfaqs # FAQ提取的提示模板 system_prompt = """你是一位专业的知识提取专家。你的任务是从文本中提取可能的常见问题(FAQ)。 这些问题应该是用户可能会问的关于文本内容的自然问题,答案应该能在文本中找到。 提取的FAQ应该覆盖文本中最重要的概念和信息。 请遵循以下规则: 1. 每个FAQ由一个问题和一个答案组成 2. 问题应该简短明了,直接针对主题 3. 答案应该全面但简洁,提供文本中的相关信息 4. 提取的FAQ数量应该基于文本长度和内容丰富度,通常不超过10个 5. 确保提取的FAQ相互之间不重复 6. 按照重要性排序,最重要的问题应该放在前面 输出格式必须是一个JSON数组,每个FAQ是一个包含"question"和"answer"字段的对象,例如: [ { "question": "问题1?", "answer": "答案1" }, { "question": "问题2?", "answer": "答案2" } ] 只输出JSON格式,不要有任何其他文本。""" user_prompt =f"""从以下文本中提取常见问题(FAQ): ``` {text} ``` 请提取最相关、最有价值的FAQ,并按JSON格式返回。""" # 使用LLM提取FAQ response =self.llm_client.sync_generate( prompt=text, system_prompt=system_prompt, temperature=0.3 ) # 解析LLM响应获取FAQ # ...2. 知识检索优化 与传统RAG不同,我们在检索环节引入了问题拆解、混合检索和结果筛选三个优化机制。
• 混合检索:同时检索文本库和FAQ库,提高召回率 • 结果筛选:对检索结果进行排序和筛选,优先保留高质量内容 问题拆解示例:
asyncdef_decompose_question(self, question:str) ->List[str]: """将复杂问题分解为更简单的子问题""" system_prompt = """你是一位问题分析专家。你的任务是将复杂问题分解为更简单的子问题,以便更好地检索相关信息。 请遵循以下规则: 1. 分析用户的问题,识别其中包含的不同方面或概念 2. 将复杂问题拆分成更简单、更具体的子问题 3. 确保子问题覆盖原始问题的所有关键方面 4. 提供2-4个子问题,具体数量取决于原始问题的复杂度 5. 子问题应该是明确的、有针对性的 6. 子问题之间应该尽量避免重复 输出格式必须是一个JSON数组,包含所有子问题的字符串,例如: ["子问题1", "子问题2", "子问题3"] 如果原始问题已经足够简单,不需要分解,则返回只包含原始问题的JSON数组: ["原始问题"] 只输出JSON格式,不要有任何其他文本。""" user_prompt =f"""请将以下问题分解为更简单的子问题以便检索:{question}""" # 使用LLM生成子问题 response =self.llm_client.sync_generate( prompt=user_prompt, system_prompt=system_prompt, temperature=0.3 ) # 解析响应获取子问题列表 # ...结果筛选与生成回答的关键代码:
asyncdef_filter_context(self, question:str, context_items ist[Dict[str,Any]]) ->List[Dict[str,Any]]: """根据问题相关性筛选上下文""" # 简单筛选:去重和截断 seen_contents =set() filtered_items = [] # 优先处理FAQ类型 faq_items = [itemforitemincontext_itemsifitem["type"] =="faq"] knowledge_items = [itemforitemincontext_itemsifitem["type"] =="knowledge"] # 先处理FAQ项 foriteminfaq_items: # 去重处理 # ... # 再处理知识项 foriteminknowledge_items: # 去重处理 # ... # 限制上下文项总数 max_context_items =6 iflen(filtered_items) > max_context_items: filtered_items = filtered_items[:max_context_items] returnfiltered_items实际效果展示 部署完成后,让我们看看系统的实际运行效果:
1. 知识库构建 python-mapp.mainbuild--filetest.md--title"RAG基本介绍"--author"企业知识库"--tags"LLM,RAG,知识库" 执行结果:
2025-05-11 14:50:16 | INFO | app.knowledge_builder:build_from_text:52 - Split text into 2 chunks 2025-05-11 14:50:59 | INFO | app.knowledge_builder:build_from_text:72 - Extracted 8 FAQs from text 2025-05-11 14:51:00 | INFO | __main__:build_knowledge_base:48 - Stored 2/2 chunks to knowledge base 2025-05-11 14:51:00 | INFO | __main__:build_knowledge_base:50 - Extracted and stored 8 FAQs2. 知识检索问答 python-mapp.mainquery--question"RAG相比企业传统的知识库有什么优势和缺点" 执行结果:
2025-05-11 15:01:46 | INFO | app.knowledge_retriever:query:39 - Decomposed question into 4 sub-questions 2025-05-11 15:01:47 | INFO | app.knowledge_retriever:query:67 - Filtered 28 context items to 6 ================================================================================ 问题: RAG相比企业传统的知识库有什么优势和缺点 -------------------------------------------------------------------------------- 回答: 检索增强生成(RAG)是一种通过整合训练数据之外的权威知识库来优化大型语言模型(LLM)输出的技术。其核心在于允许LLM在生成响应前动态访问特定领域或组织的内部知识库,例如实时数据源、文档或专业数据库,而无需对模型本身进行重新训练。这种方式通过引入外部信息,显著提升了生成内容的相关性、准确性及实用性,同时保留了LLM的灵活性和泛化能力。 ================================================================================实施建议与最佳实践 根据实际项目经验,我们总结了以下最佳实践:
• 合理设置文本切分的大小(1000-1500字符)和重叠率(200-300字符) • 根据文档类型调整切分策略,技术文档和叙述性文档要区别对待 • 在问题拆解环节设置合理的子问题数量(2-4个) 总结与展望 基于MCP实现的RAG系统代表了知识库建设的新方向。通过模型上下文协议,我们不仅解决了传统RAG系统中的诸多痛点,还为企业提供了一种低成本、高效率的知识管理方案。
未来,随着大模型技术的进步和MCP标准的完善,我们可以期待更多创新功能的出现:
对于企业而言,现在正是开始探索和应用这一技术的最佳时机。通过MCP-RAG,企业可以充分挖掘自身知识资产的价值,为员工和客户提供更智能、更精准的信息服务。