文章目录
NLP是什么?
NLP(natural language processing)(自然语言处理)。
为什么要动态切片?
静态切片太死板,主要有如下几种方式。
1、按长度
2、按分隔符
3、按正则
静态切片-固定长度切片
代码:
python
def static_fixed_split(text, chunk_size):
"""
静态切分:严格按字符数切割,无视语义和标点。
"""
chunks = []
# 使用步长切片,步长等于块大小,意味着没有重叠 (overlap=0)
for i in range(0, len(text), chunk_size):
chunk = text[i : i + chunk_size]
chunks.append(chunk)
return chunks
# 测试文本
text = """
自然语言处理(NLP)是人工智能的一个重要领域。
它主要研究如何让计算机理解、解释和生成人类语言。
BERT、GPT 等预训练模型极大地提升了各项任务的性能。
"""
# 设置一个较短的固定长度,故意展示切断效果
chunk_size = 20
static_chunks = static_fixed_split(text, chunk_size)
print(f"【静态固定长度切分】(每块 {chunk_size} 字符):\n")
for i, chunk in enumerate(static_chunks):
print(f"--- Chunk {i+1} ---")
print(repr(chunk)) # 使用 repr 显示换行符等不可见字符
print(chunk)
print()
# 预期问题演示:
# 你可能会看到 "领域。\n它主要" 被切断,或者 "BERT、" 被切成 "B" 和 "ERT、"
# 例如:某一块可能是 "工智能的一个重要领",句子没说完就断了。
静态切片-单一分隔符切片
如下代码用的是换行符切片:
python
def static_line_split(text):
"""
静态切分:仅按换行符切割。
缺点:如果某一行特别长(如一段话没换行),它会变成一个巨大的块;
如果某一行只有一个字,它就是一个极小的块。长度不均匀。
"""
# 简单的 split 不会合并短行,也不会切分长行
return text.split('\n')
text = """
第一段很短。
第二段非常非常长,因为它包含了很多内容但是没有换行,这会导致静态切分失效,产生一个超大的块,超出模型限制。
第三段。
"""
lines = static_line_split(text)
print("【静态按行切分】:\n")
for i, line in enumerate(lines):
if line.strip(): # 跳过空行
print(f"--- Line {i+1} (长度: {len(line)}) ---")
print(line)
print()
静态切片-正则表达式切片
代码:
python
import re
def static_regex_split(text, pattern):
"""
静态切分:按正则模式强制分割。
"""
# re.split 会直接按模式切断,不保证语义完整
parts = re.split(pattern, text)
# 过滤掉空字符串
return [p for p in parts if p.strip()]
text = "苹果好吃。香蕉也不错。葡萄很甜。西瓜很大。橙子很酸。"
# 强制每遇到一个句号就切分(这看起来像动态,但如果逻辑复杂就是静态的)
# 这里演示一个更"静态"的例子:每两个句号切一次,不管内容
# 注意:re.split 捕获组的行为可能需要调整,这里简单演示按句号切
chunks = static_regex_split(text, r'(?<=。)')
print("【静态正则切分】:\n")
for i, chunk in enumerate(chunks):
print(f"Chunk {i+1}: {chunk}")
# 更极端的静态例子:强行每 5 个字符切一次(忽略标点)
# 这在正则里很难优雅表达,通常还是用切片,但逻辑是一样的:无视语义。
动态切片
动态切片有效的解决了静态切片的问题。
主要用到两项技术:
1、jieba中文分词。
2、langchain文本切片。
这个两个要结合使用。
动态切片-jieba示例
python
import jieba
# 待处理的文本
text = "乒乓球拍卖完和自然语言处理是人工智能的重要方向"
# 1. 精确模式 (默认):试图将句子最精确地切开,适合文本分析
print("【精确模式】:")
words_exact = list(jieba.cut(text, cut_all=False))
print("/".join(words_exact))
# 输出示例: 乒乓球/拍卖/完/和/自然语言处理/是/人工智能/的/重要/方向
# 2. 全模式:把句子中所有的可以成词的词语都扫描出来,速度非常快,但不能解决歧义
print("\n【全模式】:")
words_full = list(jieba.cut(text, cut_all=True))
# 过滤掉空字符串并打印
print("/".join([w for w in words_full if w]))
# 输出示例: 乒乓/乒乓球/球/拍卖/卖/完/和/自然/自然语言/自然语言处理/语言/语言处理/处理/...
# 3. 搜索引擎模式:在精确模式的基础上,对长词再次进行切分,提高召回率,适合搜索引擎
print("\n【搜索引擎模式】:")
words_search = list(jieba.cut_for_search(text))
print("/".join(words_search))
# 输出示例: 乒乓球/拍卖/完/和/自然/语言/处理/自然语言/自然语言处理/是/人工/智能/人工智能/的/重要/方向
# 4. 动态添加自定义词典 (解决特定领域术语切分错误)
print("\n【添加自定义词典后】:")
# 假设 "乒乓球拍" 是一个专有名词,不希望被切分为 "乒乓球/拍"
jieba.add_word("乒乓球拍")
# 修改文本以演示效果
text2 = "这个乒乓球拍卖完了"
words_custom = list(jieba.cut(text2))
print("/".join(words_custom))
# 输出: 这个/乒乓球拍/卖/完/了
动态切片-langchain示例
python
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 模拟一段较长的文本
long_text = """
自然语言处理(NLP)是人工智能的一个重要领域。
它主要研究如何让计算机理解、解释和生成人类语言。
常见的任务包括分词、词性标注、命名实体识别、情感分析等。
随着深度学习的发展,Transformer 架构成为了 NLP 的主流模型。
BERT、GPT 等预训练模型极大地提升了各项任务的性能。
在实际应用中,我们需要处理大量的长文档,这时候就需要进行文本切分。
文本切分不仅要考虑长度,还要尽量保持语义的完整性。
"""
# 初始化文本分割器
# chunk_size: 每个切片的大小 (字符数)
# chunk_overlap: 切片之间的重叠大小 (字符数),用于保持上下文连贯
# separators: 切分的优先级顺序,优先按段落、换行、句号等切分
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=50, # 每块约 50 个字符
chunk_overlap=10, # 重叠 10 个字符
length_function=len,
separators=["\n\n", "\n", "。", ",", "",]
)
# 执行动态切分
chunks = text_splitter.split_text(long_text)
print(f"原始文本长度: {len(long_text)}")
print(f"切分后的块数: {len(chunks)}\n")
for i, chunk in enumerate(chunks):
print(f"--- Chunk {i+1} ---")
print(chunk)
print()
区别
| 特性 | 静态切片 (Static) | 动态切片 (Dynamic / Recursive) |
|---|---|---|
| 切分依据 | 固定字符数、固定行号、简单分隔符 | 语义边界(段落、句子)、递归搜索最佳断点 |
| 上下文保持 | 无 (Overlap=0),容易切断句子 | 有 (Overlap>0),保留上下文连贯性 |
| 块大小 | 严格固定(硬切分)或不均匀(按行) | 近似固定,但在语义边界处灵活调整 |
| 计算成本 | 极低 (O(n)) | 较高 (需要遍历和判断) |
| 适用场景 | 日志文件处理、定长数据编码、对语义不敏感的任务 | RAG (检索增强生成)、大模型上下文窗口管理、情感分析 |
| 主要风险 | 语义断裂 (例如把 "人工" 和 "智能" 分开) | 可能会产生略多于预期的块数 |