RAG分块策略对比

RAG分块策略对比:找到知识切分的最优解

引言 RAG系统的第一步是将文档分块(Chunking)。这个看似简单的步骤,实际上对RAG质量有巨大影响——分块太大,检索不精确;分块太小,丢失上下文。 2026年,分块策略已经从简单的"按字数切分"发展出多种智能策略。本文将系统对比这些策略。 一、为什么分块很重要 1.1 检索精度 文档: "Python是一种解释型语言。它由Guido van Rossum于1991年创建。Python强调代码可读性..." 分块A(太大大): 整个文档作为一个块 → 检索时可能返回很多不相关的内容 分块B(太小): "Python是一种解释型语言。" → 缺少上下文,不知道在说什么 分块C(合适): "Python是一种解释型语言。它由Guido van Rossum于1991年创建。" → 信息完整且精确 1.2 上下文完整性 好的分块应该保持语义完整性——一个块应该表达一个完整的意思。 1.3 检索效率 块的大小直接影响向量索引的大小和检索速度。 二、分块策略分类 2.1 固定大小分块 class FixedSizeChunker: def __init__(self, chunk_size=500, overlap=50): self.chunk_size = chunk_size # 字符数或token数 self.overlap = overlap def chunk(self, text): chunks = [] start = 0 while start < len(text): end = start + self.chunk_size chunk = text[start:end] chunks.append(chunk) start = end - self.overlap # 重叠部分 return chunks 优势:简单、快速、可预测。 劣势:可能在句子中间截断,破坏语义。 最佳实践:设置50-100 token的重叠,减少截断影响。 2.2 句子分块 class SentenceChunker: def __init__(self, max_sentences=5, max_tokens=500): self.max_sentences = max_sentences self.max_tokens = max_tokens def chunk(self, text): sentences = self.split_sentences(text) chunks = [] current_chunk = [] current_tokens = 0 for sentence in sentences: sent_tokens = self.count_tokens(sentence) if current_tokens + sent_tokens > self.max_tokens or \ len(current_chunk) >= self.max_sentences: if current_chunk: chunks.append(" ".join(current_chunk)) current_chunk = [sentence] current_tokens = sent_tokens else: current_chunk.append(sentence) current_tokens += sent_tokens if current_chunk: chunks.append(" ".join(current_chunk)) return chunks 优势:保持句子完整,语义更好。 劣势:块大小不均匀。 ...

2026-07-02 · 4 min · 767 words · 硅基 AGI 探索者
RAG分块策略深度对比:语义分块 vs 文档感知 vs 层级分块

RAG分块策略深度对比:语义分块 vs 文档感知 vs 层级分块

为什么分块策略如此重要? 在RAG系统中,分块(Chunking)是影响检索质量的第一道关卡。同样的文档、同样的Embedding模型、同样的LLM,仅仅因为分块策略不同,检索准确率可以相差30%以上。 核心矛盾在于:块太大,检索精度下降(噪声多);块太小,上下文不足(语义不完整)。 好的分块策略要在这两端之间找到最优解。 六种分块策略全面对比 1. 固定大小分块(Fixed-Size Chunking) 最简单的策略:按固定token数切分,带overlap。 from langchain.text_splitter import RecursiveCharacterTextSplitter splitter = RecursiveCharacterTextSplitter( chunk_size=512, chunk_overlap=50, separators=["\n\n", "\n", "。", "!", "?", ",", " "], ) chunks = splitter.split_text(document) 参数 推荐值 说明 chunk_size 256-1024 取决于文档类型,技术文档建议512 chunk_overlap 10-20% 防止语义在切分边界断裂 优点:实现简单、速度快、可预测 缺点:可能在句子中间切断,破坏语义完整性 适用:快速原型、均匀文本(如日志、评论) 2. 语义分块(Semantic Chunking) 不按固定大小切,而是按语义相似度断点切。当相邻句子的语义相似度低于阈值时,在此处分块。 from semantic_chunker import SemanticChunker from langchain_openai import OpenAIEmbeddings # 基于Embedding相似度的语义分块 chunker = SemanticChunker( OpenAIEmbeddings(model="text-embedding-3-large"), breakpoint_threshold_type="percentile", # 或 "standard_deviation" breakpoint_threshold_amount=95, # 百分位阈值 ) chunks = chunker.split_text(document) 工作原理: 句子1 → 句子2 → 句子3 → 句子4 → 句子5 0.92 0.88 0.45↓ 0.91 0.87 ↑ 语义断点(相似度骤降) 在这里切分 # 自定义语义分块实现 import numpy as np from sklearn.metrics.pairwise import cosine_similarity def semantic_chunk(text, embeddings_model, threshold=0.5): """基于句子间语义相似度的自适应分块""" sentences = split_into_sentences(text) # 计算每对相邻句子的相似度 embeddings = [embeddings_model.embed(s) for s in sentences] similarities = [ cosine_similarity([embeddings[i]], [embeddings[i+1]])[0][0] for i in range(len(embeddings) - 1) ] # 找到相似度低于阈值的位置作为断点 chunks = [] current_chunk = [sentences[0]] for i, sim in enumerate(similarities): if sim < threshold: chunks.append(" ".join(current_chunk)) current_chunk = [sentences[i + 1]] else: current_chunk.append(sentences[i + 1]) chunks.append(" ".join(current_chunk)) return chunks 优点:语义完整、适应文档结构 缺点:计算开销大(每句话都要Embedding)、块大小不可控 适用:长文章、研究报告、新闻 ...

2026-06-30 · 4 min · 695 words · 硅基 AGI 探索者
RAG 分块策略深度对比

RAG 分块策略深度对比:语义分块 vs 文档感知 vs 层级分块

分块为何如此重要 在 RAG 系统中,分块(Chunking)是影响检索质量的第一道关卡。一个糟糕的分块策略会让最好的 Embedding 模型和最贵的 LLM 都无济于事。2026 年的分块策略已经从简单的固定长度切分进化到了语义感知、文档结构感知的智能分块。 五大分块策略对比 策略1:固定长度分块(Fixed-Size Chunking) 最基础的方式,按固定 token 数切分,带重叠窗口。 def fixed_size_chunk(text: str, chunk_size: int = 512, overlap: int = 50): tokens = tokenizer.encode(text) chunks = [] for i in range(0, len(tokens), chunk_size - overlap): chunk = tokens[i:i + chunk_size] chunks.append(tokenizer.decode(chunk)) if i + chunk_size >= len(tokens): break return chunks 优点:简单、快速、可控 缺点:可能切断语义、忽略文档结构 适用:纯文本、均匀内容 策略2:语义分块(Semantic Chunking) 基于 Embedding 相似度,在语义跳变点切分。 import numpy as np from sentence_transformers import SentenceTransformer def semantic_chunk(text: str, model, threshold: float = 0.5): # 1. 先按句子切分 sentences = split_sentences(text) # 2. 逐句计算 Embedding embeddings = model.encode(sentences) # 3. 计算相邻句子的余弦相似度 similarities = [] for i in range(len(embeddings) - 1): sim = cosine_similarity(embeddings[i], embeddings[i+1]) similarities.append(sim) # 4. 在相似度低于阈值处切分 chunks = [] current_chunk = [sentences[0]] for i, sim in enumerate(similarities): if sim < threshold: chunks.append(" ".join(current_chunk)) current_chunk = [sentences[i+1]] else: current_chunk.append(sentences[i+1]) if current_chunk: chunks.append(" ".join(current_chunk)) return chunks 优点:语义完整、边界自然 缺点:计算开销大、块大小不均匀 适用:长文本、叙述性内容 策略3:文档感知分块(Document-Aware Chunking) 基于文档结构(标题、段落、列表)进行切分。 ...

2026-06-28 · 3 min · 600 words · 硅基 AGI 探索者
rag chunking strategy evaluation

RAG分块策略对比评估

引言 分块(Chunking)是RAG系统中承上启下的关键环节:上承文档解析,下接向量检索和生成。分块策略直接影响检索精度和生成质量——太大或太小的块都会导致问题。本文对主流分块策略进行系统对比评估,并提供选型建议。 分块为何重要 分块大小的影响 块过大的问题:单个向量难以准确表示大段内容的语义;检索时相似度分数被稀释;上下文窗口浪费在不相关信息上;增大embedding计算成本。 块过小的问题:语义不完整,检索到的块可能缺少上下文;需要检索更多块才能获得完整信息;增加索引存储和检索开销。 分块边界的影响 即使大小合适,切分位置不当也会导致问题:在句子中间切断导致语义破碎;在段落中间切分丢失段落级语义;切断实体与其描述的关联。 主流分块策略 策略一:固定大小分块 按固定token数切分,通常配合一定重叠: def fixed_size_chunk(text, chunk_size=512, overlap=50): """固定大小分块""" tokens = tokenizer.encode(text) chunks = [] for i in range(0, len(tokens), chunk_size - overlap): chunk_tokens = tokens[i:i + chunk_size] chunk_text = tokenizer.decode(chunk_tokens) chunks.append(chunk_text) if i + chunk_size >= len(tokens): break return chunks 优势:实现简单、速度极快、块大小可控。 劣势:可能在句子中间切断、不感知内容结构、不同文档可能需要不同大小。 适用场景:快速原型、格式统一的文档、对速度要求高的场景。 策略二:句子级分块 以句子为最小单位进行分块: import nltk def sentence_chunk(text, max_chunk_size=512): """按句子分块""" sentences = nltk.sent_tokenize(text) chunks = [] current_chunk = [] current_size = 0 for sent in sentences: sent_size = len(tokenizer.encode(sent)) if current_size + sent_size > max_chunk_size and current_chunk: chunks.append(" ".join(current_chunk)) current_chunk = [sent] current_size = sent_size else: current_chunk.append(sent) current_size += sent_size if current_chunk: chunks.append(" ".join(current_chunk)) return chunks 优势:保持句子完整性、语义边界更合理。 劣势:块大小不均匀、长句子可能导致超大块、段落结构可能被破坏。 适用场景:自然语言文本、新闻文章、博客内容。 策略三:段落级分块 按段落切分,合并过小段落: def paragraph_chunk(text, max_chunk_size=512, min_chunk_size=100): """按段落分块""" paragraphs = text.split("\n\n") chunks = [] current_chunk = "" current_size = 0 for para in paragraphs: para_size = len(tokenizer.encode(para)) if para_size > max_chunk_size: # 段落过大,降级为句子分块 sub_chunks = sentence_chunk(para, max_chunk_size) chunks.extend(sub_chunks) elif current_size + para_size > max_chunk_size and current_chunk: chunks.append(current_chunk) current_chunk = para current_size = para_size else: current_chunk = current_chunk + "\n\n" + para if current_chunk else para current_size += para_size if current_chunk and current_size >= min_chunk_size: chunks.append(current_chunk) elif current_chunk and chunks: chunks[-1] += "\n\n" + current_chunk return chunks 优势:保持段落完整性、适合结构化文档、语义连贯性好。 ...

2026-06-27 · 3 min · 504 words · 硅基 AGI 探索者
rag chunking strategy deep

RAG 分块策略深度对比:固定/语义/递归/文档感知

为什么分块决定 RAG 质量 分块(Chunking)是 RAG 管道中被低估的环节。分块质量直接决定三件事: 检索精度:块太大,检索引入噪声;块太小,丢失上下文 生成质量:LLM 收到的上下文是否完整连贯 Token 成本:块大小直接影响每次推理的 Token 消耗 文档 → [分块] → 嵌入 → 向量库 → 检索 → 生成 ↑ 这一步决定了后面所有环节的上限 策略一:固定大小分块 原理 按固定 Token/字符数切割,最简单但最粗暴。 from langchain.text_splitter import CharacterTextSplitter def fixed_chunk(text, chunk_size=500, chunk_overlap=50): splitter = CharacterTextSplitter( separator="\n", chunk_size=chunk_size, chunk_overlap=chunk_overlap, length_function=len ) return splitter.split_text(text) 参数调优 # 不同场景的推荐参数 configs = { "faq_short": {"chunk_size": 200, "overlap": 0}, # FAQ:小块无重叠 "article": {"chunk_size": 500, "overlap": 50}, # 文章:中等块 "technical_doc": {"chunk_size": 1000, "overlap": 100}, # 技术文档:大块保完整 "code": {"chunk_size": 800, "overlap": 50}, # 代码:按函数边界 } 优缺点 优点 缺点 实现简单 可能切断句子 速度最快 语义不连贯 可预测成本 跨段落信息丢失 适用场景:快速原型、格式统一的短文本、日志分析 策略二:语义分块 Sentence 分块 按句子边界切割,保证每个块是完整句子: import nltk from nltk.tokenize import sent_tokenize def sentence_chunk(text, sentences_per_chunk=3): sentences = sent_tokenize(text) chunks = [] for i in range(0, len(sentences), sentences_per_chunk): chunk = " ".join(sentences[i:i+sentences_per_chunk]) chunks.append(chunk) return chunks 语义相似度分块 更高级的方法:计算相邻句子的嵌入相似度,在语义断裂处分块: ...

2026-06-25 · 4 min · 654 words · 硅基 AGI 探索者
鲁ICP备2026018361号