LLM RAG|攻克切片难题

今日AI资讯
1.通义听悟升级,超长音视频自由问
2.多位专家签署《北京AI安全国际共识》
3.百川智能、北大成立“通用AI联合实验室”
4.实在Agent智能体公测招募
5.Stability AI推出3D视频生成模型
6.英伟达:发布AI旗舰芯片Blackwell GPU
7.OpenAI CEO:GPT-5能力提升将超乎想象

欢迎关注➕【小贾探AI】,一起进步一起成长

今天主要针对Langchain的文档切分中4个难点进行展开

文本切片

Langchain的文档切分存在哪些难点问题?

  1. 切片策略:固定长度分割文本,且分割窗口之间留一定重叠比例,以避免损失上下文语义信息。虽然简单便捷,但缺点也很明显。比如以下文本结构:

如果分片长度设置得太小,会导致一级标题下的段落二、三失去了与一级标题相关的重要信息。文档问答过程中,“系统主要的内容构成是什么?”,可能RAG只会检索到组件1,因为组件2和3由于分片长度的限制未能归入同一文本块内。然而,增加文本分片的长度又会增加LLM带来的冗余噪声信息,从而影响模型的回答准确性,尤其是对于一些开源LLM,其对上下文长度的支持和语义理解相对较弱。

  1. 使用RAG+LLM进行知识问答时,当知识内容较多时检索成本高,需要遍历所有文本块。

  2. 使用关键字提问时,RAG可能检索不到相关文本,需要补全问题描述。

  3. 如何将多模态知识(如包含图表的pdf、ppt等)加入知识库并进行知识问答?

那么如何做好文本切片?

答案:语义切分。语义切分方法主要包括以下两种:

  1. 篇章分析:利用自然语言处理的篇章分析工具(discourse parsing),提取段落间的主从关系,并将所有相关段落合并成一段,确保每个文本分块都在表达相同的事情。

  2. BERT判断段落相似度:除了 discourse parsing 的工具外,BERT-base-Chinese模型在预训练中采用了NSP(next sentence prediction)任务,因此可以完全判断两个句子(段落)是否具有语义上的衔接关系。可以设置相似度阈值,依次判断相邻两个段落的相似度分数是否大于阈值,若大于则合并,否则断开,本质上就是段落分割。推荐:阿里的SeqModel模型,可直接用modelscope调用。

切片后,会存在难点1:大块切片的噪声问题 和 难点2:检索成本高的问题,解决方案如下:

利用层次检索树形检索的方式,对应方式如下图所示:

篇章分析获取的文本块具有层次依存关系,检索时可以按照上至下的顺序进行,并配合剪枝策略。对于BERT段落相似判断,由于没有依存关系,需要使用LLM进行总结和摘要。2024年斯坦福大学提出的RAPTOR方法,是对固定长度分割后的文本块进行语义聚类,然后使用LLM总结摘要,生成摘要embedding作为树的节点。

在这三种层次结构中,由于语义切分后的文本块可能很长,所以采用固定长度分割可以避免引入冗余文本。如果检索成本不是问题(例如并行检索),那么可以将层次结构压平后进行检索。

难点(3):关键字提问,RAG检索不到相关文本,往往需要补全问题信息。

对此公开资料有一些解决方案:

  1. 引入追问机制:在Prompt中加入"如果无法从背景知识回答用户的问题,则根据背景知识内容,对用户进行追问,问题限制在3个以内"。这个机制主要依靠大模型的能力。不过可以改善了问答体验,用户在多轮引导中逐步明确了自己的问题,一般都能得到合适的答案。如果多轮引导后还是回答不出来,兜底:结合猜你所想给出已知的高频QA推荐。

  2. 关键词抽取:利用NLP技术(句法分析、NER、依存分析、语义角色标注、关键词提取等)抽取关键信息,将其加入到层次检索的顶部。先检索关键信息,再检索相应内容。缺点是如果用户提问的信息未被提前抽取,就无法检索到。

  3. RAG-Fusion:使用LLM优化用户查询,改写输入查询,并丰富召回结果。将召回内容通过倒排融合(Reciprocal rank fusion, RRF)得到统一得分,然后重排取 TOP k 检索结果。RAG-Fusion的缺点耗时,因为需要多次提问。

  1. 混合搜索:这是一种值得尝试的低成本高收益方案,将字面相似的传统搜索算法(Best Matching 25, BM25)与向量相似性检索相结合,实现混合搜索。可以采用加权融合分数、取各自top k检索后并集 或 RRF+Rerank等方法。

难点4:如何将多模态知识(如包含图表的pdf、ppt等)加入知识库并进行知识问答?

答案:多模态模型,通过prompt技术提取文档中图片的关键信息,形成摘要描述作为图片索引缺点是多模态模型对图片描述的细致程度可能影响索引的质量。实际上可以将图片、表格、ppt都视为图片,使用多模态模型OCR模型分别抽取摘要描述和源数据中的数据和文本要素,整理后作为源数据的知识分片。

期待

今天我们主要针对RAG中文本切片的难点进行了一一解答,后面我会从文本版式解析展开说一下相关关键技术。

引用

  • 基于LLM+向量库的文档对话痛点及解决方案:https://zhuanlan.zhihu.com/p/651179780
  • 斯坦福 | 提出PDFTriage,解决结构化文档的问题,提升「文档问答」准确率:https://zhuanlan.zhihu.com/p/657316158
  • pdf解析关键问题:https://zhuanlan.zhihu.com/p/652975673

关于我

欢迎关注➕【小贾探AI】,一起进步一起成长

### 关于LLMRAG的相关代码示例 #### 使用Hugging Face Transformers实现简单RAG模型 下面是一个基于Python的简单例子,展示了如何利用`transformers`库创建一个基本的RAG模型。此实例采用预训练的语言模型以及DPR(密集段落检索器),用于从给定的知识库中提取相关信息。 ```python from transformers import RagTokenizer, RagRetriever, RagSequenceForGeneration # 加载预训练的RAG-tokenizer 和 DPR retriever tokenizer = RagTokenizer.from_pretrained("facebook/rag-token-nq") retriever = RagRetriever.from_pretrained("facebook/dpr-question_encoder-single-nq-base", index_name="exact", indexed_dataset_path="./indexed_data") # 初始化带有检索组件的序列生成模型 model = RagSequenceForGeneration.from_pretrained("facebook/rag-token-nq", retriever=retriever) def rag_query(question): # 对问题进行编码 input_ids = tokenizer.question_encoder(question, return_tensors="pt").input_ids # 获取答案 with model.as_context(): generated = model.generate(input_ids) # 解码输出 answer = tokenizer.batch_decode(generated, skip_special_tokens=True)[0] return answer # 测试函数 if __name__ == "__main__": question = "What is the capital of France?" print(rag_query(question)) ``` 这段代码实现了简单的问答功能,其中涉及到加载必要的组件、定义查询函数,并最终测试该函数以获取特定问题的答案[^2]。 #### 构建自定义知识库索引并与RAG集成 对于更复杂的场景,比如拥有自己的专有数据集作为知识源时,则需要先建立相应的索引来支持高效的检索操作。这里展示的是如何使用Faiss库来构建向量数据库,并将其与上述提到的RAG架构相结合的方法: ```python import faiss from sentence_transformers import SentenceTransformer from typing import List class CustomKnowledgeBase: def __init__(self, documents: List[str]): self.documents = documents # 创建句子嵌入模型 embedder = SentenceTransformer('paraphrase-MiniLM-L6-v2') # 将文档转换成向量表示形式 corpus_embeddings = embedder.encode(documents, convert_to_tensor=True).cpu().numpy() # 定义FAISS索引参数 dimension = corpus_embeddings.shape[-1] nlist = 100 # 聚类中心数量 quantizer = faiss.IndexFlatIP(dimension) index = faiss.IndexIVFPQ(quantizer, dimension, nlist, m=8, bits_per_code=8) # 训练并添加向量至索引 index.train(corpus_embeddings.astype('float32')) index.add(corpus_embeddings.astype('float32')) self.index = index self.embedder = embedder def search(self, query: str, top_k: int = 5) -> List[int]: """执行近似最近邻搜索""" q_embedding = self.embedder.encode([query], show_progress_bar=False).astype('float32') _, I = self.index.search(q_embedding, k=top_k) return [self.documents[i] for i in list(I.flatten())] # 实际部署过程中可以根据需求调整这部分逻辑 knowledge_base = CustomKnowledgeBase(["Paris is the capital city of France.", ...]) relevant_docs = knowledge_base.search("capital cities in Europe", top_k=3) print(relevant_docs) ``` 在此部分代码里,首先初始化了一个名为`CustomKnowledgeBase`的类,用来封装整个过程——从读取原始文本文件直到完成向量化处理并将结果存入内存中的Faiss索引结构之中;接着提供了便捷接口供外部调用者发起查询请求,返回最接近询问内容的一组候选答案列表。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值