文本切片方法汇总
切片方法列表
- 改进的固定长度切片
- 语义切片
- LLM 语义切片
- 层次切片
- 滑动窗口切片
1. 改进的固定长度切片
核心原理
在传统固定长度切片基础上,优先在句子边界(。!?.!?)进行切分,通过重叠机制保障上下文连续性,同时维持切片长度的可控性。
方法特点
- ✅ 实现逻辑简单,文本处理速度快
- ✅ 切片长度统一,便于批量管理
- ✅ 兼顾上下文完整性(重叠机制)
适用场景
- 需要统一控制切片长度的标准化处理场景
- 批量处理海量技术文档、规范文件、结构化文本
代码实现
python
def improved_fixed_length_chunking(text, chunk_size=512, overlap=50):
"""
改进的固定长度切片 - 优先在句子边界切分
参数说明:
text: str - 待切片的原始文本
chunk_size: int - 目标切片长度(默认512字符)
overlap: int - 切片间重叠字符数(默认50字符)
返回值:
list[str] - 切分后的文本块列表(无空字符串)
"""
chunks = []
start = 0
while start < len(text):
# 初始切片结束位置
end = start + chunk_size
# 尝试在句子边界切分(向前查找100个字符内的结束符)
if end < len(text):
for i in range(end, max(start, end - 100), -1):
if text[i] in '.!?。!?': # 支持中英文句子结束符
end = i + 1
break
# 提取并清理当前切片(去除首尾空白)
chunk = text[start:end].strip()
# 过滤空切片
if chunk:
chunks.append(chunk)
# 移动起始位置(保留重叠部分)
start = end - overlap
return chunks
2. 语义切片
核心原理
基于自然语言处理(NLP)技术,严格按照句子、段落等语义独立单位进行切分;核心原则是保持语义完整性,避免在句子/语义中间断开,确保每个切片都是完整的语义单元;切分无重叠,完全贴合自然语义边界。
方法特点
- ✅ 语义完整性强,最大程度保留文本原有逻辑
- ✅ 检索/理解准确性高,符合人类阅读习惯
- ❌ 切片长度不均匀,无法标准化控制长度
- ❌ 依赖基础NLP能力,实现复杂度高于固定长度切分
适用场景
- 新闻、小说、论文等自然语言文本处理
- 问答系统、文本检索、智能摘要等需要精准语义理解的场景
- 对切片长度无强制要求,优先保障语义完整的业务场景
python
def semantic_chunking(text, max_chunk_size=512):
"""基于语义的切片 - 按句子分割"""
# 使用正则表达式分割句子
sentences = re.split(r'[.!?。!?\n]+', text)
chunks = []
current_chunk = ""
for sentence in sentences:
sentence = sentence.strip()
if not sentence:
continue
# 如果当前句子加入后超过最大长度,保存当前块
if len(current_chunk) + len(sentence) > max_chunk_size and current_chunk:
chunks.append(current_chunk.strip())
current_chunk = sentence
else:
current_chunk += " " + sentence if current_chunk else sentence
# 添加最后一个块
if current_chunk.strip():
chunks.append(current_chunk.strip())
return chunks
3. LLM 语义切片
核心原理
利用大语言模型(LLM)强大的语义理解能力,智能识别文本逻辑结构与语义边界,在保证每个切片语义完整、逻辑连贯的前提下,实现更精准的长度控制。
方法特点
- ✅ 语义理解能力强,分割点选择智能合理
- ✅ 兼顾语义完整性与长度可控性
- ❌ 依赖 GPU 算力,推理速度相对较慢
- ❌ 调用成本较高,不适合超大规模批量处理
适用场景
- 对切片质量要求高的专业场景
- 句式复杂、逻辑嵌套深的文本
- 预算充足、追求高精度分割的项目
python
def advanced_semantic_chunking_with_llm(text, max_chunk_size=512):
"""使用LLM进行高级语义切片"""
# 检查环境变量
api_key = '******'
if not api_key:
print("警告: 未设置 DASHSCOPE_API_KEY 环境变量,将使用基础语义切片")
return fallback_semantic_chunking(text, max_chunk_size)
client = OpenAI(
api_key=api_key,
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
prompt = f"""
请将以下文本按照语义完整性进行切片,每个切片不超过{max_chunk_size}字符。
要求:
1. 保持语义完整性
2. 在自然的分割点切分
3. 返回JSON格式的切片列表,格式如下:
{{
"chunks": [
"第一个切片内容",
"第二个切片内容",
...
]
}}
文本内容:
{text}
请返回JSON格式的切片列表:
"""
try:
print("正在调用LLM进行语义切片...")
response = client.chat.completions.create(
model="qwen-turbo-latest",
messages=[
{"role": "system", "content": "你是一个专业的文本切片助手。请严格按照JSON格式返回结果,不要添加任何额外的标记。"},
{"role": "user", "content": prompt}
]
)
result = response.choices[0].message.content
print(f"LLM返回结果: {result[:200]}...")
# 清理结果,移除可能的Markdown代码块标记
cleaned_result = result.strip()
if cleaned_result.startswith('```'):
# 移除开头的 ```json 或 ```
cleaned_result = re.sub(r'^```(?:json)?\s*', '', cleaned_result)
if cleaned_result.endswith('```'):
# 移除结尾的 ```
cleaned_result = re.sub(r'\s*```$', '', cleaned_result)
# 解析JSON结果
chunks_data = json.loads(cleaned_result)
# 处理不同的返回格式
if "chunks" in chunks_data:
return chunks_data["chunks"]
elif "slice" in chunks_data:
# 如果返回的是包含"slice"字段的列表
if isinstance(chunks_data, list):
return [item.get("slice", "") for item in chunks_data if item.get("slice")]
else:
return [chunks_data["slice"]]
else:
# 如果直接返回字符串列表
if isinstance(chunks_data, list):
return chunks_data
else:
print(f"意外的返回格式: {chunks_data}")
return []
except json.JSONDecodeError as e:
print(f"JSON解析失败: {e}")
print(f"原始结果: {result}")
# 尝试手动解析
try:
# 尝试提取JSON部分
json_match = re.search(r'\{.*\}', result, re.DOTALL)
if json_match:
json_str = json_match.group()
chunks_data = json.loads(json_str)
if "chunks" in chunks_data:
return chunks_data["chunks"]
except:
pass
except Exception as e:
print(f"LLM切片失败: {e}")
4. 层次切片
核心原理
依托文档自身的层级结构(如一级标题、二级标题、章节、段落等)进行分层切分,严格遵循文档固有的逻辑架构,将文本按层级拆解为不同粒度的切片,清晰保留文档的层级关联。
方法特点
- ✅ 完美保留文档原有结构,切片与文档逻辑高度契合
- ✅ 支持层次化查询、回溯,便于快速定位文档片段
- ✅ 切片逻辑清晰,符合人类对文档的阅读和理解习惯
- ❌ 高度依赖文档格式规范性,无明确层级(如纯文本)的文档无法适用
- ❌ 切分粒度受文档原有层级限制,灵活性较低
适用场景
- 有明确层级结构的结构化文档(如产品手册、行业规范、技术文档)
- 包含多级标题、章节划分的文档(如论文、报告、说明书)
- 需保留文档逻辑关系、支持层级化检索的场景
py
def hierarchical_chunking(text, target_size=512, preserve_hierarchy=True):
"""层次切片 - 基于文档结构层次进行切片"""
chunks = []
# 定义层次标记
hierarchy_markers = {
'title1': ['# ', '标题1:', '一、', '1. '],
'title2': ['## ', '标题2:', '二、', '2. '],
'title3': ['### ', '标题3:', '三、', '3. '],
'paragraph': ['\n\n', '\n']
}
# 分割文本为行
lines = text.split('\n')
current_chunk = ""
current_hierarchy = []
for line in lines:
line = line.strip()
if not line:
continue
# 检测当前行的层次级别
line_level = None
for level, markers in hierarchy_markers.items():
for marker in markers:
if line.startswith(marker):
line_level = level
break
if line_level:
break
# 如果没有检测到层次标记,默认为段落
if not line_level:
line_level = 'paragraph'
# 判断是否需要开始新的切片
should_start_new_chunk = False
# 1. 如果遇到更高级别的标题,开始新切片
if preserve_hierarchy and line_level in ['title1', 'title2']:
should_start_new_chunk = True
# 2. 如果当前切片长度超过目标大小
if len(current_chunk) + len(line) > target_size and current_chunk.strip():
should_start_new_chunk = True
# 3. 如果遇到段落分隔符且当前切片已经足够长
if line_level == 'paragraph' and len(current_chunk) > target_size * 0.8:
should_start_new_chunk = True
# 开始新切片
if should_start_new_chunk and current_chunk.strip():
chunks.append(current_chunk.strip())
current_chunk = ""
current_hierarchy = []
# 添加当前行到切片
if current_chunk:
current_chunk += "\n" + line
else:
current_chunk = line
# 更新层次信息
if line_level != 'paragraph':
current_hierarchy.append(line_level)
# 处理最后一个切片
if current_chunk.strip():
chunks.append(current_chunk.strip())
return chunks
5. 滑动窗口切片
核心原理
使用固定大小的窗口在长文本上逐步滑动切分,窗口之间设置一定重叠量;依靠重叠机制保证上下文连贯,避免关键信息被截断,从而提升检索召回效果。
方法特点
- ✅ 上下文连续性好,大幅减少关键信息丢失
- ✅ 检索召回率更高,适合长文本片段匹配
- ❌ 会产生大量重复重叠内容,占用更多存储与计算资源
- ❌ 切片数量多,后续处理效率会略有下降
适用场景
- 长文档、书籍、长篇报告等文本处理
- 重视上下文连贯性的检索与问答场景
- 需要高召回率、不希望信息被窗口生硬切断的场景
5. 滑动窗口切片
核心原理
使用固定大小的窗口在长文本上逐步滑动切分,窗口之间设置一定重叠量;依靠重叠机制保证上下文连贯,避免关键信息被截断,从而提升检索召回效果。
方法特点
- ✅ 上下文连续性好,大幅减少关键信息丢失
- ✅ 检索召回率更高,适合长文本片段匹配
- ❌ 会产生大量重复重叠内容,占用更多存储与计算资源
- ❌ 切片数量多,后续处理效率会略有下降
适用场景
-
长文档、书籍、长篇报告等文本处理
-
重视上下文连贯性的检索与问答场景
-
需要高召回率、不希望信息被窗口生硬切断的场景
def sliding_window_chunking(text, window_size=512, step_size=256):
"""滑动窗口切片"""
chunks = []for i in range(0, len(text), step_size): chunk = text[i:i + window_size] if len(chunk.strip()) > 0: chunks.append(chunk.strip()) return chunks
切片策略对比
| 策略 | 语义保持 | 长度控制 | 实现复杂度 | 处理速度 | 适用场景 |
|---|---|---|---|---|---|
| 改进固定长度 | ⚠️ 中等 | ✅ 优秀 | ✅ 简单 | ✅ 快速 | 技术文档、规范 |
| 语义切片 | ✅ 优秀 | ⚠️ 中等 | ⚠️ 中等 | ⚠️ 中等 | 自然语言文本 |
| LLM语义切片 | ✅ 优秀 | ✅ 优秀 | ❌ 复杂 | ❌ 慢 | 高质量要求 |
| 层次切片 | ✅ 优秀 | ❌ 差 | ⚠️ 中等 | ⚠️ 中等 | 结构化文档 |
| 滑动窗口 | ⚠️ 中等 | ✅ 优秀 | ✅ 简单 | ✅ 快速 | 长文档处理 |