构建生产级RAG系统:从数据处理到智能体的全流程实践

构建生产级RAG系统:从数据处理到智能体的全流程实践

检索增强生成(RAG)技术已成为打造高级知识问答系统的核心,但从原型到稳定高效的生产级系统,需突破数据处理、检索优化、智能决策等多重挑战。本文以某型号工业设备故障维修手册为知识源,结合LangChain、LangGraph、RAGAS等工具,详细拆解生产级RAG系统的全链路构建过程,为技术落地提供可复用的实践方案。

本文较长,建议点赞收藏,以免遗失。更多AI大模型开发 学习视频/籽料/面试题 都在这>>Github<< >>Gitee<<

一、整体架构:打造Agent驱动的智能RAG系统

生产级RAG绝非简单的“检索+生成”,而是具备自我规划、决策与反思能力的智能体系。基于Agent的RAG架构,核心是将复杂问题拆解为可执行子任务,通过工具调用与循环优化,确保回答的准确性与完整性。

1.1 核心工作流

系统以“问题匿名化-规划-任务执行-重新规划-答案生成与评估”为核心链路,具体步骤如下:

  • 问题匿名化:替换问题中的具体实体(如“V12型发动机”→“设备X”),消除大模型预训练知识偏见,避免“知识污染”。
  • 规划:Agent根据匿名化问题生成高层次解决计划,例如“先明确故障代码含义→检索对应诊断流程→提取安全操作指令”。
  • 计划分解与反匿名化:将高层计划拆分为工具可执行的子任务,并恢复原始实体名称,确保任务与实际知识源匹配。
  • 任务处理与工具执行:任务处理器根据子任务类型,选择合适工具(如故障摘要检索、维修流程检索),从不同向量数据库获取信息。
  • 重新规划:Agent评估新获取的信息是否充足,若存在缺口则调整计划(如补充检索相关安全警告),形成“执行-反思-优化”的闭环。
  • 答案生成与评估:信息充足时,结合思维链(CoT)推理生成答案,再通过RAGAS框架量化评估答案质量,确保无幻觉、高准确。

二、数据预处理:构建高质量知识库的基石

高质量知识库是RAG系统性能的核心保障。以《V12型涡轮增压柴油发动机维修手册》(PDF格式)为例,需经过“加载提取-多策略分块-清洗-重构-向量化存储”五步流程,构建多维度知识索引。

2.1 数据加载与初步提取

使用PyPDF2库提取PDF文本,处理加密文件、文本断裂等异常情况,确保原始数据完整性。核心代码逻辑如下:

import PyPDF2
from pathlib import Pathdef load_and_extract_text_from_pdf(pdf_path: Path):if not pdf_path.is_file():print(f"文件未找到: {pdf_path}")return Nonetry:with open(pdf_path, 'rb') as f:reader = PyPDF2.PdfReader(f)if reader.is_encrypted:  # 处理加密文件print(f"PDF {pdf_path.name} 已加密,无法提取")return None# 提取所有页面文本,过滤空内容pages_text = [page.extract_text() for page in reader.pages if page.extract_text()]return " ".join(pages_text)except Exception as e:print(f"提取错误: {e}")return None

2.2 多策略分块:适配不同查询需求

单一分块策略无法应对多样化查询(如“故障代码含义”“维修步骤细节”“安全警告”),需采用三种分块方式并行处理:

  • 逻辑分块:基于文本结构(如故障代码章节、关键指令)分块,保留完整语义。例如用正则表达式匹配“FAULT CODE XXX”格式,拆分故障代码章节,并提取故障代码作为元数据:
    import re
    from langchain.docstore.document import Documentdef chunk_by_fault_code(text: str) -> list[Document]:# 匹配“FAULT CODE 字母数字组合”格式sections = re.split(r'(FAULT CODE\s[A-Z0-9]+.*)', text)chapters = []for i in range(1, len(sections), 2):title = sections[i].strip()content = sections[i+1].strip()# 提取故障代码作为元数据fault_code = re.search(r'FAULT CODE\s([A-Z0-9]+)', title).group(1) if re.search(r'FAULT CODE\s([A-Z0-9]+)', title) else "UNKNOWN"chapters.append(Document(page_content=title+"\n"+content, metadata={"source": "fault_code", "fault_code": fault_code}))return chapters
    
  • 关键指令提取:针对“WARNING”“NOTE”等关键字,提取安全操作、注意事项等核心信息,满足紧急查询需求。
  • 传统分块:用RecursiveCharacterTextSplitter对无结构文本进行固定大小分块(如1000字符/块,200字符重叠),适配常规细节查询。

2.3 数据清洗:消除格式噪声

PDF提取文本常存在多余空格、换行符、单词断裂(如“ma- nual”)等问题,需通过正则表达式标准化:

def clean_text(text: str) -> str:# 合并多换行符为单个,修复断裂单词,统一空格text = re.sub(r'\n\s*\n', '\n', text)  # 合并空行text = re.sub(r'(\w)-\n(\w)', r'\1\2', text)  # 修复“ma- nual”→“manual”text = text.replace('\n', ' ')  # 换行符转空格text = re.sub(r' +', ' ', text)  # 多空格转单个return text.strip()

2.4 数据重构:生成章节摘要

对故障章节等长文本,用LLM生成浓缩摘要,减少向量化噪声。以Ollama(qwen2:1.5b模型)为例,核心逻辑如下:

from langchain.chains.summarize import load_summarize_chain
from langchain_community.chat_models.ollama import ChatOllamadef generate_chapter_summaries(documents: list[Document]):llm = ChatOllama(model="qwen2:1.5b", temperature=0)# 定义摘要Prompt,聚焦症状、诊断步骤、操作动作prompt = """请总结以下维修章节,重点包含故障症状、诊断步骤、执行动作,供技术人员直接使用:章节内容:{text}详细摘要:"""chain = load_summarize_chain(llm, chain_type="stuff", prompt=prompt)summaries = []for doc in documents:result = chain.invoke([doc])summaries.append(Document(page_content=result["output_text"], metadata=doc.metadata))return summaries

2.5 向量化与存储:构建多源向量库

将“传统分块文本”“章节摘要”“关键指令”分别向量化,用FAISS存储为三个独立向量库,供Agent按需检索。以HuggingFace的BAAI/bge-small-en-v1.5模型为例:

from langchain_community.vectorstores import FAISS
from langchain_community.embeddings.huggingface import HuggingFaceEmbeddingsdef build_vector_stores(data_dict: dict):# 初始化嵌入模型embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-small-en-v1.5",model_kwargs={"device": "cpu"},encode_kwargs={"normalize_embeddings": True})# 为每种数据类型创建FAISS库vector_stores = {}for name, docs in data_dict.items():vector_store = FAISS.from_documents(docs, embeddings)vector_store.save_local(f"./vector_stores/{name}")vector_stores[name] = vector_storereturn vector_stores# 示例:构建三个向量库
data = {"manual_splits": 传统分块文档列表,"chapter_summaries": 章节摘要文档列表,"key_instructions": 关键指令文档列表
}
vector_stores = build_vector_stores(data)

三、核心RAG流程:构建LangGraph智能体

基于LangGraph构建Agent,实现“规划-执行-反思”的闭环逻辑,核心包括规划器、任务处理器、检索子图、幻觉抑制四大模块。

3.1 规划与任务处理:Agent的决策核心

  • 规划器(Planner):根据问题生成初始计划,例如针对“如何处理故障代码P0128”,生成计划“1. 检索P0128含义→2. 提取诊断步骤→3. 确认安全操作”。
  • 重新规划器(Re-planner):根据检索结果调整计划,若未找到安全操作指令,则补充“检索WARNING类型文档”步骤。
  • 任务处理器(Task Handler):将子任务映射到具体工具,例如“检索P0128含义”→调用“chapter_summaries”向量库,核心代码逻辑如下:
from pydantic import BaseModel
from langchain_core.prompts import ChatPromptTemplate# 定义任务处理器输出结构
class TaskOutput(BaseModel):query: str  # 检索查询词tool: str  # 工具类型(如retrieve_summaries)curr_context: str  # 当前上下文def task_handler(question: str, curr_task: str, aggregated_context: str):llm = ChatOllama(model="qwen2:1.5b", temperature=0, format="json")# Prompt定义工具映射规则prompt = """你是工业维修RAG的任务处理器,需选择工具执行当前任务:可用工具:- retrieve_summaries:查询故障摘要(如故障代码含义)- retrieve_chunks:查询详细步骤(如维修流程)- retrieve_instructions:查询安全指令(如WARNING)- answer_question:信息充足时直接生成答案原始问题:{question}当前上下文:{aggregated_context}当前任务:{curr_task}请返回JSON格式:{{"query": "检索词", "tool": "工具名", "curr_context": "当前上下文"}}"""prompt_template = ChatPromptTemplate.from_template(prompt)chain = prompt_template | llm.with_structured_output(TaskOutput)return chain.invoke({"question": question, "curr_task": curr_task, "aggregated_context": aggregated_context})

3.2 检索子图:模块化检索与蒸馏

为每种检索工具构建独立LangGraph子图,包含“检索-蒸馏-验证”三步,确保检索结果准确。以“摘要检索”为例,子图逻辑如下:

  1. 检索节点:调用“chapter_summaries”向量库,获取相关文档。
  2. 蒸馏节点:过滤无关信息(如排除与故障代码无关的摘要)。
  3. 验证节点:检查蒸馏后内容是否忠于原文,若存在偏差则重新过滤。

核心代码框架如下:

from langgraph.graph import StateGraph, END
from typing import TypedDict# 定义子图状态
class RetrievalState(TypedDict):query: strretrieved_docs: list[Document]distilled_docs: list[Document]# 构建检索子图的高阶函数
def build_retrieval_subgraph(retriever):graph = StateGraph(RetrievalState)# 1. 检索节点:调用向量库def retrieve_node(state):docs = retriever.invoke(state["query"])return {"retrieved_docs": docs}# 2. 蒸馏节点:过滤无关文档def distill_node(state):# 模拟:保留与query匹配度高的文档(实际用LLM判断)distilled = [doc for doc in state["retrieved_docs"] if state["query"] in doc.page_content]return {"distilled_docs": distilled}# 3. 验证节点:判断是否忠于原文(实际用LLM评估)def is_grounded(state):return "grounded" if len(state["distilled_docs"]) > 0 else "not_grounded"# 组装子图graph.add_node("retrieve", retrieve_node)graph.add_node("distill", distill_node)graph.set_entry_point("retrieve")graph.add_edge("retrieve", "distill")# 条件边:验证通过则结束,否则重新蒸馏graph.add_conditional_edges("distill", is_grounded, {"grounded": END, "not_grounded": "distill"})return graph.compile()

3.3 思维链与幻觉抑制:提升答案可信度

  • 思维链(CoT)推理:在答案生成阶段,引导LLM输出“推理过程+最终答案”,例如:“1. 故障代码P0128表示冷却液节温器故障→2. 诊断步骤:先检查温度传感器读数→3. 维修动作:若读数异常,更换节温器”。
  • 幻觉抑制子图:生成答案后,用LLM评估“答案是否基于检索上下文”,若存在幻觉(如编造未提及的工具),则回退至“重新检索”步骤。核心逻辑如下:
def hallucination_check(answer: str, context: list[Document]) -> bool:llm = ChatOllama(model="qwen2:1.5b", temperature=0)prompt = """判断以下答案是否完全基于提供的上下文,无编造信息:答案:{answer}上下文:{context}若完全基于上下文,返回True;否则返回False。"""result = llm.invoke(prompt.format(answer=answer, context="\n".join([c.page_content for c in context])))return "true" in result.lower()

四、实战测试与评估:验证系统性能

通过“案例测试+RAGAS量化评估”,确保系统在准确性、抗幻觉性、实用性上达标。

4.1 案例测试:验证核心能力

  • 信息不存在测试:提问“如何更换V12发动机火花塞?”(柴油发动机无火花塞)。系统应检索后返回“未找到相关信息,且该设备为柴油机,无需更换火花塞”,验证抗幻觉能力。
  • 复杂推理测试:提问“发动机过热且冷却液位正常,应检查哪些部件?”。系统需推理:“1. 排除冷却液泄漏→2. 检索过热相关故障→3. 确定冷却风扇、节温器为关键部件”,验证多步推理能力。
  • CoT生成测试:提问“如何处理故障代码P0128?”。系统需输出“推理过程+步骤”,例如:“1. P0128含义:冷却液节温器故障→2. 诊断:检查温度传感器读数→3. 维修:更换节温器→4. 安全警告:需冷却发动机后操作”,验证深度解释能力。

4.2 RAGAS量化评估:多维度打分

使用RAGAS框架,从5个核心指标评估系统性能,示例代码如下:

from ragas import evaluate
from ragas.metrics import answer_correctness, faithfulness, answer_relevancy# 准备评估数据集(问题、生成答案、检索上下文、标准答案)
data = {"question": ["V12发动机燃油喷射系统标准压力是多少?", "拆卸机油滤清器需什么工具?"],"answer": ["燃油喷射系统标准压力为2000 bar", "需36mm套筒扳手"],"contexts": [["5.2节:燃油喷射系统标准压力2000 bar,高压易致损坏"],["3章12页:拆卸机油滤清器需36mm套筒扳手、接油盘"]],"ground_truth": ["标准压力2000 bar", "需36mm套筒扳手"]
}
dataset = Dataset.from_dict(data)# 配置RAGAS评估模型
ragas_llm = LangchainLLM(llm=ChatOllama(model="qwen2:1.5b"))
faithfulness.llm = ragas_llm
answer_correctness.llm = ragas_llm# 运行评估
results = evaluate(dataset=dataset,metrics=[answer_correctness, faithfulness, answer_relevancy]
)
# 输出结果(DataFrame格式)
print(results.to_pandas())

4.3 评估结果示例

问题答案正确性忠实度答案相关性
燃油喷射系统压力1.0001.0000.985
机油滤清器工具1.0001.0000.991

结果显示,系统在核心指标上得分均接近满分,无幻觉、高准确,满足生产级需求。

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

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

相关文章

Java-代理

在 Java 开发中&#xff0c;代理模式是一种非常重要的设计模式&#xff0c;它通过引入代理对象来控制对目标对象的访问&#xff0c;从而实现额外功能的增强。一、代理模式的基本概念代理模式的核心思想是&#xff1a;通过一个代理对象来间接访问目标对象&#xff0c;在不修改目…

【基础知识】互斥锁、读写锁、自旋锁的区别

从定义、工作原理、适用场景和性能开销四个维度来剖析这三种锁的区别 核心结论 这三种锁的核心区别在于它们应对“锁已被占用”情况时的行为策略不同,而这直接决定了它们的性能和适用场景。 锁类型 核心策略 适用场景 互斥锁 (Mutex) 等不到,就睡 通用的独占访问,临界区执行…

智慧清洁革新者:有鹿机器人自述

晨曦微露&#xff0c;当城市还未完全苏醒&#xff0c;我已悄然完成数万平方米的清洁工作。作为有鹿智能巡扫机器人&#xff0c;我很荣幸能与您分享如何以科技之力重塑清洁行业的标准与体验。卓越技术&#xff1a;重新定义清洁新标准我搭载的聪明大脑是基于Master2000通用具身智…

python学习打卡day48

知识点回顾&#xff1a; 随机张量的生成&#xff1a;torch.randn函数卷积和池化的计算公式&#xff08;可以不掌握&#xff0c;会自动计算的&#xff09;pytorch的广播机制&#xff1a;加法和乘法的广播机制 ps&#xff1a;numpy运算也有类似的广播机制&#xff0c;基本一致 im…

记一次雪花算法 ID 精度丢失的Bug:前端接收到的 Long 被“四舍五入”了?

后端生成的 ID&#xff1a;1961005746230337538 前端收到的 ID&#xff1a;1961005746230337500 —— 少了 38&#xff1f;&#xff01;这不是 Bug&#xff0c;是 JavaScript 的“安全整数”陷阱&#xff01;本文记录一次真实项目中因 雪花算法 ID 精度丢失 导致的线上问题&…

零知开源——基于STM32F407VET6和ADXL345三轴加速度计的精准运动姿态检测系统

✔零知IDE 是一个真正属于国人自己的开源软件平台&#xff0c;在开发效率上超越了Arduino平台并且更加容易上手&#xff0c;大大降低了开发难度。零知开源在软件方面提供了完整的学习教程和丰富示例代码&#xff0c;让不懂程序的工程师也能非常轻而易举的搭建电路来创作产品&am…

Android14 init.qcom.usb.rc详解

本文以高通平台为例&#xff0c;介绍其USB子系统启动以及USB各种配置动态切换的逻辑&#xff0c;它是以configfs架构实现动态配置USB。 相关文档 1. USB子系统的启动 1.1 on boot阶段 1.1.1 重启恢复用户选择的USB配置 当设备重启时恢复用户选择的USB配置&#xff0c;避免每…

Docker的常用命令及简单使用

1、docker的常用命令 1.1、帮助命令 docker version # 显示docker的版本信息 docker info # 显示docker的系统信息&#xff0c;包括镜像和容器的数量 docker 指令 --help # 查看某个指令的帮助命令可以通过docker --help查看docker常用命…

HGDB全文检索/中文分词的使用

文章目录文档用途详细信息文档用途 本文用于HGDB全文检索/中文分词的介绍&#xff0c;其介绍内容在附件&#xff0c;使用案例见正文 详细信息 一、创建扩展 highgo# create extension zhparser;CREATE EXTENSION highgo# \dFp List of text search parsers Schema…

baijian xiaomaodawang

我将为你创建一个基于Go 1.20.8和Gin框架的博客系统项目。以下是完整的实现方案&#xff1a; 项目创建流程 打开Goland&#xff0c;创建新项目选择Go项目&#xff0c;设置GOROOT为Go 1.20.8项目名称&#xff1a;blog-system启用Go Modules 项目结构 blog-system/ ├── cmd/ │…

Node.js的特性

Node.js的特性 Node.js具有几个显著特性&#xff1a; 事件驱动&#xff1a;Node.js采用事件驱动机制来处理请求和响应&#xff0c;这种机制可以帮助开发者处理大量并发请求&#xff0c;提高系统的性能和可靠性。 非阻塞I/O&#xff1a;Node.js使用异步I/O原语来实现非阻塞I/O操…

交叉编译linux-arm32位程序

目标平台rv1126 芯片 arm32位架构 在ubuntu22.04上交叉编译&#xff1a; 编译器下载地址&#xff1a; Linaro Releases 或者&#xff1a; wget http://releases.linaro.org/components/toolchain/binaries/6.4-2017.11/arm-linux-gnueabihf/gcc-linaro-6.4.1-2017.11-x86_6…

S 3.1深度学习--卷积神经网络

卷积层 图像原理 卷积神经网络&#xff08;Convolutional Neural Network, CNN&#xff09; 图像在计算机中是一堆按顺序排列的数字&#xff0c;数值为 0 到 255。0 表示最暗&#xff0c;255 表示最亮。 图像识别 上图是只有黑白颜色的灰度图&#xff0c;而更普遍的图片表达…

【7】SQL 语句基础应用

SQL 语句基础应用where (筛选)where 子句可使用到运算符查询表中所有的数据查询表中的数据&#xff0c;必须满足 11&#xff08;相当于恒成立&#xff09;查询表中的 分数(score) 大于 80 分的学生查询表中 名称(name) 是 赵六 的数据查询表中 名称(name) 不等于 哈哈 的数据.查…

android 嵌套webview 全屏展示 页面延伸到状态栏且不被底部导航栏遮挡

我的项目是使用webview嵌套了一个uniapp打包出的h5 本来展示很正常&#xff0c;某天突然发现uniapp的底部导航被手机底部的导航栏挡住了&#xff0c;离奇&#xff0c;某天突然出现的 有些手机会设置展示底部导航按钮&#xff0c;有些手机会关闭底部导航 以下代码对这两种情况通…

【大前端】React Native 调用 Android、iOS 原生能力封装

&#x1f4d6; React Native 调用 Android、iOS 原生能力封装 1. 原理 React Native 的 核心思想&#xff1a;JS 层&#xff08;React 代码&#xff09;不能直接调用 Android/iOS 的 API。RN 提供了 Native Module 机制&#xff1a; Android&#xff1a;Java/Kotlin → 继承 Re…

HOOK安卓木马重大升级,勒索功能扩展至107项

勒索覆盖屏成新特征网络安全研究人员发现名为HOOK的安卓银行木马新变种&#xff0c;该恶意软件新增勒索软件式覆盖屏功能用于显示勒索信息。Zimperium zLabs研究员Vishnu Pratapagiri表示&#xff1a;"最新变种的显著特征是能够部署全屏勒索覆盖界面&#xff0c;旨在胁迫受…

GeoScene Maps 完整入门指南:从安装到实战

什么是GeoScene MapsGeoScene Maps是一套功能强大的Web地图开发平台&#xff0c;它基于现代Web技术构建&#xff0c;为开发者提供了丰富的地图服务和开发工具。与其他地图API相比&#xff0c;GeoScene Maps具有以下特点&#xff1a;核心优势全面的地图服务&#xff1a;支持2D/3…

本地大模型部署:Ollama 部署与 Python 接口调用全攻略

本地大语言模型实践&#xff1a;Ollama 部署与 Python 接口调用全攻略 一、引言 过去我们使用大语言模型&#xff08;LLM&#xff09;&#xff0c;更多依赖于 OpenAI API、Claude API 等云端服务。它们虽然强大&#xff0c;但存在两大问题&#xff1a; 隐私与数据安全&#xff…

OpenFeign:让微服务间调用像本地方法一样简单

引言&#xff1a;微服务通信的演进之路什么是OpenFeign&#xff1f;核心特性概览快速开始&#xff1a;搭建OpenFeign环境环境准备与依赖配置启用OpenFeign功能基础用法&#xff1a;从简单示例开始定义第一个Feign客户端在服务中调用Feign客户端进阶配置&#xff1a;深度定制Ope…