
本文介绍一种灵活、轻量且兼容原生 LangChain 文本切分器的方法,通过正则预处理将带标记(如 )的敏感文本块整体保留,再交由 RecursiveCharacterTextSplitter 处理其余部分,从而避免破坏语义完整性。
本文介绍一种灵活、轻量且兼容原生 langchain 文本切分器的方法,通过正则预处理将带标记(如 `
在使用 LangChain 构建 RAG 应用时,RecursiveCharacterTextSplitter 是最常用的文本切分工具。但其默认行为会对所有字符(包括空格、换行、标点)一视同仁地切分,无法识别“需整体保留”的关键段落——例如嵌入式代码块、结构化 JSON 片段、法律条款原文或带自定义标签的富文本内容。
直接修改 separators 列表(如将
✅ 推荐方案:正则预分割 + 分治式切分
核心思想是:先用正则表达式将原文按
以下是完整、可复用的实现:
import re
from langchain.text_splitter import RecursiveCharacterTextSplitter
def split_with_protected_blocks(
text: str,
protected_tag: str = "<nosplit>",
chunk_size: int = 500,
chunk_overlap: int = 100,
separators: list = ["\n\n", "\n", " ", ""]
) -> list[str]:
# Step 1: 使用捕获组正则分割 —— 保留含标签的完整块
# 模式:匹配 <nosplit>...<nosplit> 整体,并确保前后边界清晰
pattern = rf"({re.escape(protected_tag)}[^]*?{re.escape(protected_tag)})"
parts = re.split(pattern, text)
result_chunks = []
splitter = RecursiveCharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=chunk_overlap,
separators=separators,
keep_separator=False
)
for part in parts:
if not part.strip():
continue
# 若该段以 protected_tag 开头,视为受保护块,整体保留并去标签
if part.strip().startswith(protected_tag):
cleaned = part.strip().replace(protected_tag, "").strip()
if cleaned: # 避免空块
result_chunks.append(cleaned)
# 否则为普通文本,交由 LangChain 切分器处理
else:
chunks = splitter.split_text(part)
result_chunks.extend(chunks)
return result_chunks
# ✅ 使用示例
nosplit_block = "<nosplit>Keep all this together, very important! Seriously though it is...<nosplit>"
text = "Giggity! " + nosplit_block + " Ahh yeah...\nI just buy a jetski."
chunks = split_with_protected_blocks(
text=text,
protected_tag="<nosplit>",
chunk_size=5, # 小尺寸便于演示效果
separators=["\n\n", "\n", " ", ""] # 完整支持默认分隔符链
)
print(chunks)
# 输出:
# ['Giggity!', 'Keep all this together, very important! Seriously though it is...', 'Ahh', 'yeah...', 'I', 'just', 'buy', 'a', 'jetski.']? 关键设计说明:
- re.split(pattern, text) 使用捕获组 (...),确保匹配到的
... 块作为独立元素保留在 parts 列表中,而非被丢弃; - re.escape(protected_tag) 防止标签中含正则元字符(如 [, ], *)引发意外匹配;
- [^]*? 是非贪婪匹配任意字符(含换行),确保最短匹配闭合标签;
- 对普通文本调用 splitter.split_text(),完全复用 LangChain 的递归逻辑(包括 chunk_size、chunk_overlap、多级 separators 回退机制),无功能降级;
- 受保护块仅做标签剥离与首尾空格清理,零切分,语义完整性 100% 保障。
⚠️ 注意事项:
- 标签必须成对出现且闭合正确,否则正则可能跨段匹配;建议在预处理阶段校验或添加容错逻辑(如只取首个闭合对);
- 若需支持嵌套
,需改用更复杂的解析器(如 html.parser 或自定义状态机),正则不再适用; - 在生产环境中,可将该函数封装为 ProtectedTextSplitter 类,继承 TextSplitter 接口,无缝接入 LangChain Pipeline。
此方法无需魔改 LangChain 源码、不牺牲切分精度、不引入额外依赖,是平衡灵活性、可维护性与工程健壮性的最优实践。










