RAG--切片策略

文本切片方法汇总

切片方法列表

  1. 改进的固定长度切片
  2. 语义切片
  3. LLM 语义切片
  4. 层次切片
  5. 滑动窗口切片

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语义切片 ✅ 优秀 ✅ 优秀 ❌ 复杂 ❌ 慢 高质量要求
层次切片 ✅ 优秀 ❌ 差 ⚠️ 中等 ⚠️ 中等 结构化文档
滑动窗口 ⚠️ 中等 ✅ 优秀 ✅ 简单 ✅ 快速 长文档处理
相关推荐
ricky_fan2 小时前
(OpenAI)Codex 安装、部署使用方式
python·macos·conda·vim
小王不爱笑1322 小时前
Java 对象拷贝(浅拷贝 / 深拷贝)
java·开发语言·python
Flittly2 小时前
【从零手写 ClaudeCode:learn-claude-code 项目实战笔记】(9)Agent Teams (智能体团队)
python·agent
DevnullCoffe2 小时前
Open Claw × 跨境电商:5个最有价值的 AI Agent 应用场景深度拆解
python·api
zh路西法2 小时前
【宇树机器人强化学习】(六):TensorBoard图表与手柄遥控go2测试
python·深度学习·机器学习·机器人
szcsun52 小时前
关于在pycharm中新建项目创建虚拟化环境venv
ide·python·pycharm
码路飞2 小时前
体验完阿里「悟空」之后,我花 2 小时用 Python 撸了个 AI Agent 🔥
python·aigc
万里沧海寄云帆3 小时前
pytorch+cpu版本对Intel Ultra 9 275HX性能的影响
人工智能·pytorch·python
java资料站3 小时前
python爬虫入门
python