
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 优势:保持段落完整性、适合结构化文档、语义连贯性好。 ...
