0

0

优化Langchain RAG检索:解决PDF文档信息不匹配问题

花韻仙語

花韻仙語

发布时间:2025-10-27 09:11:22

|

147人浏览过

|

来源于php中文网

原创

优化Langchain RAG检索:解决PDF文档信息不匹配问题

本文深入探讨了在使用langchain和rag(检索增强生成)处理pdf格式faq文档时,检索结果不准确的问题。核心在于优化嵌入模型和文档分块策略。通过采用huggingface的预训练嵌入模型,并结合合适的文本分割方法,可以显著提升rag系统的检索精度,确保llm能够获取到与查询高度相关的文档片段,从而生成更准确的答案。

Langchain RAG检索不准确问题分析与优化

在使用Langchain构建基于RAG的问答系统时,尤其是在处理PDF格式的FAQ文档时,可能会遇到检索到的信息与用户查询不匹配的问题。即使查询的问题直接存在于文档中,系统也可能返回看似相似但实际无关的文档片段。这通常是由于嵌入模型选择不当或文档分块策略不合理导致的。本教程将详细解析这些问题,并提供一套优化的解决方案。

1. RAG系统核心组件回顾

一个典型的Langchain RAG系统主要包含以下几个步骤:

  1. 文档加载 (Document Loading):从各种来源(如PDF、文本文件)加载原始文档。
  2. 文本分割 (Text Splitting):将长文档分割成更小的、可管理的文本块(chunks)。
  3. 文本嵌入 (Text Embedding):将文本块转换为数值向量( embeddings),捕捉其语义信息。
  4. 向量存储 (Vector Store):将嵌入向量存储在向量数据库中,以便快速检索。
  5. 检索 (Retrieval):根据用户查询的嵌入向量,在向量数据库中查找最相似的文本块。
  6. 生成 (Generation):将检索到的文本块作为上下文,结合用户查询,输入给大型语言模型(LLM)生成答案。

检索不准确的问题,往往发生在第3步(文本嵌入)和第2步(文本分割)上。

2. 优化嵌入模型选择

嵌入模型是RAG系统准确性的基石。它负责将文本转换为能够有效代表其语义的向量。如果嵌入模型无法准确捕捉文档片段和查询之间的语义相似性,那么即使文档中存在正确答案,也可能无法被检索到。

原先的代码可能使用了如 GPT4AllEmbeddings 或 OllamaEmbeddings 等本地模型。虽然这些模型易于部署,但在某些场景下,其语义理解能力可能不如更专业的预训练模型。

推荐方案:使用HuggingFace嵌入模型

HuggingFace提供了大量高质量的预训练嵌入模型,它们在各种文本理解任务上表现出色。这些模型通常经过大规模语料库的训练,能够更好地理解文本的语义细微差别。

以下是使用 HuggingFaceEmbeddings 的示例代码:

星辰Agent
星辰Agent

科大讯飞推出的智能体Agent开发平台,助力开发者快速搭建生产级智能体

下载
from langchain.document_loaders import PyPDFLoader, DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.chains import RetrievalQA
from langchain.llms import OpenAI # 示例,也可替换为其他LLM

# 1. 文档加载
# 如果是单个PDF文件,可以使用PyPDFLoader
# loader = PyPDFLoader("doc.pdf")
# documents = loader.load()

# 如果是目录下的所有PDF文件
loader = DirectoryLoader('./docs/', glob="./*.pdf", loader_cls=PyPDFLoader) # 假设PDF文件在当前目录的'docs'文件夹
documents = loader.load()

# 2. 文本分割
# 针对FAQ文档,chunk_size和chunk_overlap的设置尤为关键
# 确保一个完整的问答对尽可能在一个chunk中,或跨越少量chunk
text_splitter = RecursiveCharacterTextSplitter(chunk_size=700, # 适当调整大小
                                               chunk_overlap=70) # 适当的重叠有助于保持上下文
texts = text_splitter.split_documents(documents)

# 3. 文本嵌入
# 推荐使用HuggingFace的预训练模型
# "bert-base-multilingual-cased" 适用于多语言,效果较好
# "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2" 也是一个不错的选择
embeddings = HuggingFaceEmbeddings(
    model_name="bert-base-multilingual-cased"
    # 或者 model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
)

# 4. 向量存储
# persist_directory 用于将向量数据库持久化到磁盘,避免每次运行时重新生成
persist_directory = "./chromadb"
vectordb = Chroma.from_documents(documents=texts, embedding=embeddings, persist_directory=persist_directory)
vectordb.persist() # 确保数据被写入磁盘

print(f"成功加载并嵌入 {len(texts)} 个文本块。")

# 5. LLM集成与检索QA链
# 替换为你的LLM实例,这里以OpenAI为例
# llm = OpenAI(temperature=0, model_name="gpt-3.5-turbo-instruct")
# 如果使用HuggingFaceHub作为LLM
from langchain.llms import HuggingFaceHub
llm = HuggingFaceHub(repo_id="google/flan-t5-base",
                     model_kwargs={"temperature":0.1, "max_length": 500, "max_new_tokens": 200})

qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    retriever=vectordb.as_retriever(search_kwargs={"k": 3}), # k表示检索前k个最相关的文档
    chain_type="stuff", # "stuff"链类型将所有检索到的文档塞入LLM的上下文
    return_source_documents=True # 返回检索到的源文档
)

# 6. 执行查询
question = "How do I reset my password?" # 替换为你的实际问题
response = qa_chain({"query": question})

print("\n--- 回答 ---")
print(response["result"])
print("\n--- 来源文档 ---")
for doc in response["source_documents"]:
    print(f"内容: {doc.page_content[:200]}...") # 打印前200字
    print(f"来源: {doc.metadata.get('source')}, 页码: {doc.metadata.get('page')}")

3. 优化文档分块策略

对于FAQ(常见问题解答)文档,文本分割策略至关重要。如果一个问答对被分割到不同的块中,或者一个块包含了太多不相关的问答对,都会影响检索的准确性。

RecursiveCharacterTextSplitter 是一种常用的文本分割器,它会尝试根据一系列分隔符(如换行符、空格)递归地分割文本。

  • chunk_size:每个文本块的最大字符数。对于FAQ文档,应尝试将一个完整的问答对(或其核心部分)包含在一个块中。过大可能导致无关信息过多,过小可能导致一个问答对被切断。
  • chunk_overlap:相邻文本块之间的重叠字符数。适当的重叠有助于在分割点处保持上下文,避免语义信息丢失。

调整建议:

  • 仔细检查你的FAQ文档结构。如果每个问答对都有明确的编号或标题,可以尝试编写自定义的分割逻辑,确保每个问答对(或几个紧密相关的问答对)形成一个独立的块。
  • 对于通用PDF,RecursiveCharacterTextSplitter 仍是好的选择。根据你的文档平均问答对长度,调整 chunk_size。例如,如果一个问答对通常在200-500字符之间,那么 chunk_size 可以设置为700-1000,并设置适当的 chunk_overlap(如70-100)。

4. LLM选择与配置

除了OpenAI的LLM,你也可以选择其他开源的LLM,例如HuggingFace Hub上托管的模型。

from langchain.llms import HuggingFaceHub

# 使用Google的Flan-T5-base模型
llm_flan_t5 = HuggingFaceHub(
    repo_id="google/flan-t5-base",
    model_kwargs={"temperature": 0.6, "max_length": 500, "max_new_tokens": 200}
)

# 或者使用EleutherAI的GPT-Neo-2.7B模型
llm_gpt_neo = HuggingFaceHub(
    repo_id="EleutherAI/gpt-neo-2.7B",
    model_kwargs={"temperature": 0.7, "max_length": 500, "max_new_tokens": 200}
)

# 在RetrievalQA链中替换llm参数即可
# qa_chain = RetrievalQA.from_chain_type(llm=llm_flan_t5, ...)

配置 model_kwargs 中的 temperature(控制生成文本的随机性)、max_length 和 max_new_tokens(控制生成文本的最大长度)可以影响LLM的输出行为。

5. 注意事项与总结

  • 迭代优化:RAG系统的性能优化是一个迭代过程。在更换嵌入模型和调整分块策略后,务必进行测试和评估,根据实际效果进一步调整参数。
  • Prompt工程:虽然本文主要关注检索,但传递给LLM的 PromptTemplate 同样重要。清晰、明确的指令可以帮助LLM更好地利用检索到的信息。
  • 领域适应性:如果你的FAQ文档涉及特定领域,可以尝试寻找在该领域表现更好的嵌入模型,或者考虑对通用模型进行微调。
  • k 值设置:vectordb.as_retriever(search_kwargs={"k": 3}) 中的 k 参数决定了检索器返回多少个最相关的文档块。根据你的文档结构和LLM的上下文窗口大小,调整 k 值。

通过上述优化,特别是选择一个更强大的嵌入模型(如HuggingFace提供的模型)并精细调整文本分块策略,你可以显著提升Langchain RAG系统在处理FAQ文档时的检索准确性,从而为用户提供更精准、更相关的答案。

相关专题

更多
数据库三范式
数据库三范式

数据库三范式是一种设计规范,用于规范化关系型数据库中的数据结构,它通过消除冗余数据、提高数据库性能和数据一致性,提供了一种有效的数据库设计方法。本专题提供数据库三范式相关的文章、下载和课程。

352

2023.06.29

如何删除数据库
如何删除数据库

删除数据库是指在MySQL中完全移除一个数据库及其所包含的所有数据和结构,作用包括:1、释放存储空间;2、确保数据的安全性;3、提高数据库的整体性能,加速查询和操作的执行速度。尽管删除数据库具有一些好处,但在执行任何删除操作之前,务必谨慎操作,并备份重要的数据。删除数据库将永久性地删除所有相关数据和结构,无法回滚。

2075

2023.08.14

vb怎么连接数据库
vb怎么连接数据库

在VB中,连接数据库通常使用ADO(ActiveX 数据对象)或 DAO(Data Access Objects)这两个技术来实现:1、引入ADO库;2、创建ADO连接对象;3、配置连接字符串;4、打开连接;5、执行SQL语句;6、处理查询结果;7、关闭连接即可。

347

2023.08.31

MySQL恢复数据库
MySQL恢复数据库

MySQL恢复数据库的方法有使用物理备份恢复、使用逻辑备份恢复、使用二进制日志恢复和使用数据库复制进行恢复等。本专题为大家提供MySQL数据库相关的文章、下载、课程内容,供大家免费下载体验。

255

2023.09.05

vb中怎么连接access数据库
vb中怎么连接access数据库

vb中连接access数据库的步骤包括引用必要的命名空间、创建连接字符串、创建连接对象、打开连接、执行SQL语句和关闭连接。本专题为大家提供连接access数据库相关的文章、下载、课程内容,供大家免费下载体验。

324

2023.10.09

数据库对象名无效怎么解决
数据库对象名无效怎么解决

数据库对象名无效解决办法:1、检查使用的对象名是否正确,确保没有拼写错误;2、检查数据库中是否已存在具有相同名称的对象,如果是,请更改对象名为一个不同的名称,然后重新创建;3、确保在连接数据库时使用了正确的用户名、密码和数据库名称;4、尝试重启数据库服务,然后再次尝试创建或使用对象;5、尝试更新驱动程序,然后再次尝试创建或使用对象。

410

2023.10.16

vb连接access数据库的方法
vb连接access数据库的方法

vb连接access数据库方法:1、使用ADO连接,首先导入System.Data.OleDb模块,然后定义一个连接字符串,接着创建一个OleDbConnection对象并使用Open() 方法打开连接;2、使用DAO连接,首先导入 Microsoft.Jet.OLEDB模块,然后定义一个连接字符串,接着创建一个JetConnection对象并使用Open()方法打开连接即可。

404

2023.10.16

vb连接数据库的方法
vb连接数据库的方法

vb连接数据库的方法有使用ADO对象库、使用OLEDB数据提供程序、使用ODBC数据源等。详细介绍:1、使用ADO对象库方法,ADO是一种用于访问数据库的COM组件,可以通过ADO连接数据库并执行SQL语句。可以使用ADODB.Connection对象来建立与数据库的连接,然后使用ADODB.Recordset对象来执行查询和操作数据;2、使用OLEDB数据提供程序方法等等。

221

2023.10.19

Golang 性能分析与pprof调优实战
Golang 性能分析与pprof调优实战

本专题系统讲解 Golang 应用的性能分析与调优方法,重点覆盖 pprof 的使用方式,包括 CPU、内存、阻塞与 goroutine 分析,火焰图解读,常见性能瓶颈定位思路,以及在真实项目中进行针对性优化的实践技巧。通过案例讲解,帮助开发者掌握 用数据驱动的方式持续提升 Go 程序性能与稳定性。

6

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 4万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号