LangChain快速入门-03Retrieval(上)

📅 2026/7/5 3:47:53
LangChain快速入门-03Retrieval(上)
文章目录1.RAG介绍1.1 大模型的局限1知识滞后2知识缺失3幻觉1.2 什么是RAG1.3 RAG优缺点1RAG的优点2RAG的缺点1.4 RAG流程1典型的RAG有两个主要流程2索引阶段整体流程如下3检索生成阶段2.文档加载2.1 加载 Markdown2.2 加载Docx2.3 加载 PDF1.RAG介绍1.1 大模型的局限1知识滞后LLM 因其具有海量参数需要花费相当的物力与时间成本进行预训练和微调同时商用 LLM 还需要进行各种安全测试与风险评估等。因此 LLM 会存在知识滞后的问题。2知识缺失在专有领域LLM 无法学习到所有的专业知识细节因此在面向专业领域知识的提问时无法给出可靠准确的回答。3幻觉LLM 在生成回答时可能会“胡言乱语”这种现象称之为 LLM 的“幻觉”。“幻觉”可以体现为错误陈述、编造事实、错误的复杂推理或者复杂语境下理解能力不足等。“幻觉”产生的原因训练知识存在偏差这些错误信息被 LLM 学习后在输出中复现LLM 训练时过度泛化将普通的模式应用在特定场合导致不准确输出LLM 本身没有真正学习到训练数据中深层次的含义导致在一些需要深入理解或复杂推理的任务中出错LLM 缺乏某些领域的相关知识在面临这些领域的相关问题时编造不存在的信息大模型生成内容的不可控尤其是在金融和医疗领域等领域一次金额评估的错误一次医疗诊断的失误哪怕只出现一次都是致命的。但这些错误对于非专业人士来说难以辨识。目前还没有能够百分之百解决这种情况的方案。1.2 什么是RAG为了改善大模型在时效性、可靠性与准确性方面的不足各种针对 LLM 优化的方法应运而生。RAGRetrieval-Augmented Generation检索增强生成就是其中一种被广泛研究和应用的优化架构。RAG 的基本思想为将传统的生成式大模型和实时信息检索技术相结合为大模型补充来自外部的相关数据和上下文来帮助大模型生成更加准确可靠的内容。这使得大模型在生成内容时可以依赖实时与个性化的数据和知识而非仅仅依赖训练知识。就相当于在大模型回答时给它一本参考书。可以说当应用需求集中在利用大模型去回答特定私有领域的知识且知识库足够大时那么除了微调大模型外RAG 就是非常有效的一种解决方案。LangChain 对这一流程提供了解决方案。1.3 RAG优缺点1RAG的优点相比提示词工程RAG 有更丰富的上下文和数据样本可以不需要用户提供过多的背景描述就能生成比较符合用户预期的答案。相比于模型微调RAG 可以提升问答内容的时效性和可靠性。在一定程度上保护了业务数据的隐私性。2RAG的缺点由于每次问答都涉及外部系统数据检索因此 RAG 的响应时延相对较高。引用的外部知识数据会消耗大量的模型 Token 资源。1.4 RAG流程1典型的RAG有两个主要流程索引从数据源提取数据构建索引。检索生成接受用户查询并从索引中检索相关数据然后将其传递给模型。2索引阶段整体流程如下从各种数据源加载数据将文档切分为小块对文本块进行嵌入存储嵌入向量。3检索生成阶段根据用户输入使用检索器从存储中检索相关文本块大模型使用包含问题和检索结果的提示生成回答。2.文档加载数据源可能包含多种格式的文件如文本文档、MarkdownPDF 等。因此我们首先需要对各种格式的文件进行处理。LangChain 实现和集成了众多文档加载器方便从不同格式的文件中加载数据。可在 https://docs.langchain.com/oss/python/integrations/document_loaders 查看所有集成的文档加载器。LangChain 所有文档加载器都实现了 BaseLoader 接口接口提供了通用的 load一次加载所有文档 与 lazy_load以延迟方式加载文档 方法用于从数据源加载数据并处理为 Document 对象。LangChain 实现了 Document 抽象用于表示文本单元及其元数据它包含三个属性page_content文本内容字符串。metadata包含元数据的字典如文档的来源等。id可选文档标识符。下面通过Markdown和Docx以及PDF作为例子来了解下如何对文件进行相关加载和解析。2.1 加载 MarkdownMarkDown形式一种半结构化的数据其原始文本通过特定语法标记出了标题、段落、有序列表、无序列表等相关信息如下所示不同的层级的文本在markdown当中表示的形式不一致可以使用 Unstructured 文档加载器来加载多种类型的文件关于如何在 LangChain 中使用 unstructured 生态系统可参考这里。Unstructured.io对Markdown的解析流程如下所示按照Markdown结构进行切分标题等会被切分成单独的element对于同一个标题下的文本再按照段落进行切分不同的段落通过\n标识会被切分成多个element。可使用 langchain集成的UnstructuredMarkdownLoader 来加载 Markdown 文件。2.2 加载Docx现代的 Word 文档.docx 格式本质上也是一种半结构化Semi-structured且机器可读Machine-readable的文件。.docx 的本质上是XML 的容器XML 标签严格规定了文档的层级比如 w:p 代表段落w:r 代表文本运行块。机器可以利用这些标签精确地提取信息。但是由于Word文档对于层级的定义相较于Markdown又更加灵活我们可以自定义不同层级标题的样式而这些样式通常只是正文样式加了手动格式使得解析库无法按照统一的标准格式将层级进行解析这个特点给Word解析又带来了难点。同样可以使用LangChain封装的Unstructured.io的Loader对.docx进行解析。在使用Unstructured.io对Word进行解析时仅会按照换行对文件进行解析无法识别出文档标题。加载 Markdown、Docx示例代码加载 Markdown、Docx示例代码# 加载MarkDown文件的函数fromlangchain_community.document_loadersimportUnstructuredMarkdownLoader,UnstructuredWordDocumentLoader# from langdetect import detectdefload_markdown():# 创建非结构化的MarkDown的加载器一次性加载整个文件file_loaderUnstructuredMarkdownLoader(files/LangChain.md)# 讲文件切分成多个文档file_loader2UnstructuredMarkdownLoader(file_pathfiles/LangChain.md,modeelements)# 加载文件docsfile_loader.load()docs2file_loader2.load()# 打印print(type(docs))# class list# 打印文档中的page_contentprint(docs[0].page_content)print(*60)print(type(docs2))# class list# 遍历fordocindocs2:print(doc.page_content)# 加载word文件的函数defload_word():# 创建加载器file_loadUnstructuredWordDocumentLoader(file_pathfiles/LangChain.docx,modeelements)# 加载文件得到多个文档docsfile_load.load()# 遍历fordocindocs:print(doc.page_content)if__name____main__:# 调用加载md文件的函数# load_markdown()# 调用加载word文件的函数load_word()这里需要自行创建LangChain.md和LangChain.docx2.3 加载 PDFPDF 存在多种来源格式包括扫描版图片 PDF、电子文本版、混合版。并且布局格式也多种多样包括单列布局、双列布局甚至竖排文本布局。并且包含段落、标题、页眉页脚、表格、数学公式、化学式、特殊符号、图片等各种元素。因此PDF 解析存在很多挑战。对于复杂 PDF需要进行文本提取、布局检测、表格解析、公式识别等处理。在此处我们介绍一个开源的专门用于解析PDF的工具Mineru。MinerU是一款将PDF转化为机器可读格式的工具如markdown、json可以很方便地抽取为任意格式。Mineru可以配置使用VLM模型进行文档解析。其开源的opendatalab/MinerU2.5-2509-1.2B(https://huggingface.co/opendatalab/MinerU2.5-2509-1.2B))模型在各项基础测试当中都达到了SOTA水平下图展示了MinerU2-VLM在多项基准测试当中得分排名MinerU2.5采用两阶段解析策略首先对下采样图像进行高效的全局布局分析然后对文本、公式和表格的原生分辨率裁剪图像进行细粒度内容识别。在大规模、多样化的数据引擎支持下进行预训练和微调MinerU2.5 在多个基准测试中始终优于通用模型和特定领域模型同时保持较低的计算开销。MinerU 提供了 PDF、Word、PPT、图片等文件的解析支持图像提取、OCR、公式、表格解析等功能。另外Mineru开源所有代码支持本地通过Docker方式进行部署其项目仓库链接https://github.com/opendatalab/MinerU。Mineru官网也提供了直接调用API的方式上传文件进行解析。首先需要在官网申请API_KEY并将其放到环境变量当中示例代码如下先去官网拿到免费使用的tokenhttps://mineru.net/# 测试使用MinerU解析PDF、图片等文件# 上传文件的函数defmineru_upload_file_demo():importrequests tokenmineru_tokenurlhttps://mineru.net/api/v4/file-urls/batchheader{Content-Type:application/json,Authorization:fBearer{token}}data{files:[{name:demo.pdf,data_id:abcd}],model_version:vlm}file_path[rfiles/img.png]try:responserequests.post(url,headersheader,jsondata)ifresponse.status_code200:resultresponse.json()print(上传成功:{}.format(result))batch_idresult[data][batch_id]ifresult[code]0:batch_idresult[data][batch_id]urlsresult[data][file_urls]print(batch_id:{},urls:{}.format(batch_id,urls))foriinrange(0,len(urls)):withopen(file_path[i],rb)asf:res_uploadrequests.put(urls[i],dataf)ifres_upload.status_code200:print(f{urls[i]}上传成功)else:print(f{urls[i]}上传失败)else:print(apply upload url failed,reason:{}.format(result.msg))returnbatch_idelse:print(f请求失败状态码{response.status_code}响应内容{response.text})exceptExceptionaserr:print(err)# 获取解析结果的函数defmineru_check_result_demo(batch_id):importrequestsimporttime tokenmineru_tokenurlfhttps://mineru.net/api/v4/extract-results/batch/{batch_id}header{Content-Type:application/json,Authorization:fBearer{token}}resrequests.get(url,headersheader)whileres.json()[data][extract_result][0][state]!done:print(当前状态为running等待3秒后重试)time.sleep(3)resrequests.get(url,headersheader)print(res.status_code)print(res.json()[data][extract_result][0][state],end\n\n\n\n)print(提取结果为:,res.json()[data][extract_result][0][full_zip_url])if__name____main__:# 调用上传文件的函数batch_idmineru_upload_file_demo()# 调用获取解析结果的函数mineru_check_result_demo(batch_id)Mineru解析之后有多种不同的输出格式具体可参见Mineru官方文档https://opendatalab.github.io/MinerU/zh/reference/output_files/。要进行下一步处理最简单的方式是通过解析之后得到的一个MarkDown文件再利用MarkDown解析器进行进一步的解析即可。相关文章LangChain快速入门-01概述LangChain快速入门-02Model I/OLangChain快速入门-03Retrieval(上)