在 RAG 系统中,文本分块(Chunking)是至关重要的一步,直接影响最终检索和生成的质量:
因此,恰当地实施文本分块不仅能够提升文本的整体品质和可读性,还能够预防由于信息丢失或不当分块引起的问题。这就是为何在处理长篇文档时,采用文本分块而非直接处理整个文档至关重要。
常见的文本分块方法可以分为以下几类:
最简单的分块方法,按照固定长度切割文本:
1# 简单固定长度切分示例
2chunk_size = 128
3chunks = []
4for i in range(0, len(text), chunk_size):
5 chunk = text[i:i + chunk_size]
6 chunks.append(chunk)优点:实现简单,速度快。 缺点:可能在句子中间切开,破坏语义完整性;无法处理不同语义单元的差异。
利用标点符号、换行符等分隔符进行切割:
1import re
2
3def split_sentences(text):
4 # 使用正则表达式匹配中文句子结束标点
5 sentence_delimiters = re.compile(u'[。?!;]|\n')
6 sentences = sentence_delimiters.split(text)
7 sentences = [s.strip() for s in sentences if s.strip()]
8 return sentences特点:
这是 LangChain 中最常用的分块方法,采用分而治之的思想:
1from langchain.text_splitter import RecursiveCharacterTextSplitter
2
3text_splitter = RecursiveCharacterTextSplitter(
4 chunk_size=100, # 设置目标块大小
5 chunk_overlap=20 # 块间重叠大小
6)
7chunks = text_splitter.create_documents([input_text])工作原理:
["\n\n", "\n", " ", ""]优点:
基于内容语义相似度进行分块,目标是让每个块包含完整语义单元:
常见方法:
1def is_nextsent(sent, next_sent, model, tokenizer, threshold=0.5):
2 with torch.no_grad():
3 encoding = tokenizer(sent, next_sent,
4 return_tensors="pt",
5 truncation=True,
6 padding=False)
7 outputs = model(**encoding)
8 logits = outputs.logits
9 probs = torch.softmax(logits/TEMPERATURE, dim=1)
10 next_sentence_prob = probs[:, 0].item()
11 return next_sentence_prob > MERGE_RATIO二级索引优化方案: 为了同时满足细粒度知识点和跨段落粗粒度知识的需求,可以构建二级索引:
针对特定格式的文档,LangChain 提供了专门的分块器:
代码示例:Python 代码拆分
1from langchain.text_splitter import PythonCodeTextSplitter
2
3python_splitter = PythonCodeTextSplitter(chunk_size=100, chunk_overlap=0)
4chunks = python_splitter.create_documents([python_text])对于代码分块,通常将重叠设置为 0,因为重叠可能改变代码原有含义。
Embedding 的作用是将文本转换为向量表示,以便进行相似度计算和检索。选择合适的 embedding 模型对 RAG 效果至关重要。
微调 embedding 模型:在特定领域数据上微调 embedding 模型,可以显著提高该领域的检索效果。
负样本挖掘:通过难负例采样优化对比学习,提高模型对语义相似度的判断能力:
动态嵌入:不同于静态嵌入,动态嵌入根据单词出现的上下文调整单词的向量表示,捕捉多义词。
查询与文档对齐:传统方法是对文档段落直接 embedding,但更好的方式是用"文档能回答什么问题"来做 embedding,这样能让查询(问题)和文档的语义空间更对齐。
HYDE 是一种利用大模型辅助召回的技术:
工作流程:
原理:融合向量既有用户问题的信息,也有答案模式的信息,可以增强召回效果。
缺点:效果非常依赖 LLM 能力,对于已经微调好的 embedding 模型提升有限,在 zero-shot 场景下更有用。
不直接对原始段落 embedding,而是先抽取关键信息(实体、关键词、核心谓词),只对关键信息 embedding,减少噪声干扰。
将文档(用于答案合成)和检索(用于匹配查询)分离,对不同部分分别生成 embedding:
回答要点:
回答要点:
回答要点:
回答要点: