Skip to main content

智能分块 (Smart)

智能分块是 KnowFlow 的默认分块策略,它基于 Markdown 抽象语法树(AST)进行智能切分,在保持语义完整性的同时控制块的大小。适用于大多数文档场景。

核心概念

智能分块的核心思想是:识别文档的语义单元,智能合并和切分,在块大小和语义完整性之间取得平衡

与其他策略的区别:

  • vs 标题分块: 不仅考虑标题,还考虑段落、列表、表格等语义单元
  • vs 父子分块: 只生成一个层级,处理更快
  • vs 正则分块: 理解文档结构,不是简单的模式匹配

工作原理

1. Markdown AST 解析

智能分块首先将 Markdown 文档解析成抽象语法树(AST),识别各种语义单元。

文档示例:

## 系统架构

系统采用三层架构设计。

### 主要组件

系统包含以下组件:

1. 前端展示层
2. 业务逻辑层
3. 数据存储层

| 组件 | 技术栈 |
|------|--------|
| 前端 | React |
| 后端 | Spring Boot |

```python
def hello():
print("Hello World")

**AST 结构:**

Document ├─ Heading (level=2): "系统架构" ├─ Paragraph: "系统采用三层架构设计。" ├─ Heading (level=3): "主要组件" ├─ Paragraph: "系统包含以下组件:" ├─ List (ordered) │ ├─ ListItem: "前端展示层" │ ├─ ListItem: "业务逻辑层" │ └─ ListItem: "数据存储层" ├─ Table │ ├─ Header: ["组件", "技术栈"] │ ├─ Row: ["前端", "React"] │ └─ Row: ["后端", "Spring Boot"] └─ CodeBlock (language=python): "def hello()..."


### 2. 语义单元识别

智能分块识别以下语义单元:

#### 2.1 标题 (Heading)

```markdown
# H1 一级标题
## H2 二级标题
### H3 三级标题

处理规则:

  • 标题本身很少作为独立的块
  • 标题与其后的内容组合成块
  • 标题是重要的切分边界提示

2.2 段落 (Paragraph)

这是一个段落,包含完整的语义。

这是另一个段落。

处理规则:

  • 绝不在段落中间切分
  • 段落是最基本的语义完整单元
  • 多个小段落可以合并成一个块

2.3 列表 (List)

有序列表:

1. 第一项
2. 第二项
3. 第三项

无序列表:

- 项目 A
- 项目 B
- 项目 C

嵌套列表:

1. 父项 1
- 子项 1.1
- 子项 1.2
2. 父项 2

处理规则:

  • 尽量保持列表完整
  • 如果列表很长,可以在列表项之间切分
  • 绝不在列表项内部切分

2.4 表格 (Table)

| 列 1 | 列 2 | 列 3 |
|------|------|------|
| 数据 | 数据 | 数据 |
| 数据 | 数据 | 数据 |

处理规则:

  • 表格必须保持完整,绝不切分
  • 表格及其标题保持在同一个块
  • 表格前的说明文字尽量与表格一起

2.5 代码块 (Code Block)

```python
def example():
return "code"

**处理规则:**
- **代码块必须保持完整**
- 代码块不能被截断
- 代码块及其说明保持在一起

#### 2.6 引用块 (Blockquote)

```markdown
> 这是一段引用文字
> 可以跨多行

处理规则:

  • 引用块保持完整
  • 不在引用块内部切分

3. 智能合并算法

智能分块使用贪心算法进行块的合并:

算法流程:

current_chunk = []
current_size = 0
target_size = chunk_token_num # 例如 256

for block in ast_blocks:
block_size = calculate_tokens(block)

# 情况 1: 当前块为空,直接添加
if current_size == 0:
current_chunk.append(block)
current_size += block_size

# 情况 2: 添加后不超过目标大小,合并
elif current_size + block_size <= target_size:
current_chunk.append(block)
current_size += block_size

# 情况 3: 添加后超过目标大小
else:
# 如果当前块已有内容,保存当前块,开始新块
if current_size >= min_chunk_tokens:
save_chunk(current_chunk)
current_chunk = [block]
current_size = block_size
# 如果当前块太小,强行添加这个 block
else:
current_chunk.append(block)
current_size += block_size

# 保存最后一个块
if current_chunk:
save_chunk(current_chunk)

示例:

假设 chunk_token_num = 300, min_chunk_tokens = 50

AST Blocks          Token 数    操作              当前块大小
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Heading: "系统架构" 10 → 添加到块 1 10
Paragraph A 80 → 添加到块 1 90
Heading: "主要组件" 10 → 添加到块 1 100
Paragraph B 60 → 添加到块 1 160
List (3 items) 90 → 添加到块 1 250
Table 120 → 超过 300,保存块 1
→ 开始块 2 120
Paragraph C 70 → 添加到块 2 190
CodeBlock 80 → 添加到块 2 270
Paragraph D 50 → 超过 300,保存块 2
→ 开始块 3 50
Heading: "总结" 8 → 添加到块 3 58
Paragraph E 100 → 添加到块 3 158
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

结果:
块 1: 250 tokens (Heading + Paragraph A + Heading + Paragraph B + List)
块 2: 270 tokens (Table + Paragraph C + CodeBlock)
块 3: 158 tokens (Paragraph D + Heading + Paragraph E)

4. 特殊元素处理

表格的特殊处理

规则: 表格绝对不能被切分,即使超过 chunk_token_num

## 数据统计

以下是详细的数据统计表格:

| 项目 | Q1 | Q2 | Q3 | Q4 |
|------|----|----|----|----|
| ... (假设表格有 400 tokens) ... |

如果 chunk_token_num = 256:

  • ✅ 将整个表格(400 tokens)作为一个块
  • ❌ 不会将表格拆分成两个块

前置说明文字处理:

  • 如果表格前有说明文字,尽量与表格放在同一块
  • 如果说明文字+表格超过 chunk_token_num * 1.5,可能分开

代码块的特殊处理

def complex_function():
# 假设这个函数有 500 tokens
...

规则:

  • 代码块不能被截断
  • 如果代码块超过 chunk_token_num,整个作为一个块
  • 代码块前的说明文字尽量保持在一起

列表的智能切分

短列表(完整保留):

系统支持以下功能:
1. 用户管理
2. 权限控制
3. 数据分析

→ 整个列表保持在一个块中

长列表(智能切分):

详细功能列表:
1. 功能 A (包含详细说明,50 tokens)
2. 功能 B (包含详细说明,60 tokens)
3. 功能 C (包含详细说明,55 tokens)
4. 功能 D (包含详细说明,50 tokens)
5. 功能 E (包含详细说明,65 tokens)
...

如果 chunk_token_num = 256:

  • 块 1: 标题 + 功能 1-3 (约 250 tokens)
  • 块 2: 功能 4-5 (约 115 tokens)

关键: 在列表项之间切分,不在列表项内部切分。

5. 块大小控制

智能分块通过以下机制控制块大小:

目标大小 (chunk_token_num):

  • 这是期望的块大小
  • 算法会尽量接近这个值
  • 但不是硬性限制

最小大小 (min_chunk_tokens):

  • 小于此值的块会被合并或丢弃
  • 避免产生无意义的小块

实际大小范围:

通常: [chunk_token_num * 0.7, chunk_token_num * 1.3]
特殊情况: 可能超出此范围(大表格、长代码块)

示例:

chunk_token_num = 256
min_chunk_tokens = 10

实际块大小分布:
块 1: 245 tokens ✓ 接近目标
块 2: 310 tokens ✓ 略超,但可接受(包含大表格)
块 3: 189 tokens ✓ 略小,但可接受
块 4: 8 tokens ✗ 太小,会被合并到块 3 或丢弃
块 5: 500 tokens ✓ 很大,但包含完整代码块,不能切分

配置参数

完整配置示例

{
"chunk_token_num": 256, // 目标块大小
"min_chunk_tokens": 10, // 最小块大小
"enable_heading_in_content": false, // 是否在块中包含标题层级
"enable_vision_enhancement": false, // 是否启用图片理解
"vision_description_format": "[图片描述]: {desc}",
"vision_batch_size": 3
}

参数详解

chunk_token_num (默认: 256)

作用: 每个块的目标 token 数量

推荐值:

  • 短问答场景: 128-256 tokens

    • 问题简单,不需要太多上下文
    • 例如: FAQ,名词解释
  • 通用场景: 256-512 tokens (推荐)

    • 平衡检索精度和上下文完整性
    • 适合大多数技术文档
  • 长上下文场景: 512-1024 tokens

    • 需要更多背景信息
    • 例如: 教程,分析报告

如何选择:

检查文档内容密度:
- 段落短,列表多 → 较小值(128-256)
- 段落长,解释详细 → 较大值(512-1024)
- 混合内容 → 中等值(256-512)

注意: 这是目标值,不是强制值。实际块大小可能因语义单元而有所不同。

min_chunk_tokens (默认: 10)

作用: 过滤过小的文本块

推荐值:

  • 严格过滤: 50-100 tokens

    • 只保留有意义的内容块
    • 适合高质量文档
  • 宽松过滤: 10-30 tokens (推荐)

    • 保留更多信息
    • 适合一般文档
  • 不过滤: 0-5 tokens

    • 保留所有内容,包括很短的注释
    • 适合简洁的技术文档

示例:

min_chunk_tokens = 50

块 A: 48 tokens → 被丢弃或合并到相邻块
块 B: 52 tokens → 保留

enable_heading_in_content (默认: false)

作用: 将标题层级路径添加到块内容开头

启用前:

系统采用三层架构设计,包括前端、业务层和数据层。

启用后:

# 用户手册 > ## 第三章 系统架构 > ### 3.1 总体设计 > 系统采用三层架构设计,包括前端、业务层和数据层。

何时启用:

  • ✅ 文档层级深(3 层以上)
  • ✅ 多文档混合检索(区分不同文档)
  • ✅ 块需要独立理解
  • ❌ 标题信息冗余
  • ❌ 想节省 token

产品使用指南

1. 在 KnowFlow 中配置

步骤 1: 选择智能分块

  1. 创建或编辑知识库
  2. 在"分块方法"中选择"智能分块(Smart)" (默认选项)
  3. 点击"配置"进行参数调整

步骤 2: 配置基础参数

块大小配置:

块大小: 256 tokens          (推荐)
最小块大小: 10 tokens (推荐)

如何选择块大小:

场景 A: FAQ 知识库

块大小: 128 tokens
最小块大小: 20 tokens
原因: 问答简短,不需要大块

场景 B: 技术文档

块大小: 512 tokens
最小块大小: 50 tokens
原因: 技术说明详细,需要完整上下文

场景 C: 混合内容

块大小: 256 tokens
最小块大小: 10 tokens
原因: 通用设置,适应各种内容

步骤 3: 高级选项

高级选项:
☐ 在内容中包含父标题
→ 仅在文档层级深时启用

☐ 启用图片理解
→ 文档包含重要图片时启用

图片描述格式: [图片描述]: {desc}
图片批量大小: 3

步骤 4: 上传文档并验证

  1. 上传测试文档
  2. 查看"分块预览"
  3. 检查块的大小和内容
  4. 根据效果调整参数

2. 验证分块效果

检查清单

✓ 块大小是否合理?

  • 大部分块在目标大小附近(±30%)
  • 没有过多的极大或极小块
  • 特殊元素(表格、代码)完整

✓ 语义是否完整?

  • 段落没有被截断
  • 列表项完整
  • 表格完整
  • 代码块完整

✓ 块内容是否有意义?

  • 每个块都包含完整的信息
  • 没有孤立的标题
  • 没有无意义的碎片

常见问题处理

问题 1: 有些块特别大(>1000 tokens)

原因: 包含大表格或长代码块

解决方案:

选项 A: 接受现状

大块通常是因为保持表格/代码完整性,这是正常的

选项 B: 减小块大小

{
"chunk_token_num": 512 // 从 256 增加到 512,给大元素更多空间
}

选项 C: 调整文档结构

# 修改前: 一个超大表格

# 修改后: 拆分成多个小表格
## 基础数据
| ... 小表格 ... |

## 详细数据
| ... 另一个小表格 ... |

问题 2: 块大小不均匀

原因: 文档内容密度差异大(有的地方文字多,有的地方列表多)

解决方案:

这是正常现象。智能分块会尽量保持语义完整性,块大小差异是可接受的。

如果差异过大:

{
"chunk_token_num": 384, // 增加目标大小,容纳更多内容
"min_chunk_tokens": 50 // 提高最小值,过滤碎片
}

问题 3: 有很多小块(<50 tokens)

原因: 文档有很多短段落或注释

解决方案:

提高最小块大小:

{
"min_chunk_tokens": 50 // 从 10 提高到 50
}

或者检查文档质量,移除无意义的碎片内容。

问题 4: 表格被意外切分

原因: 这不应该发生,可能是解析错误

解决方案:

  1. 检查 Markdown 表格格式是否正确
  2. 尝试不同的 PDF 解析器(MinerU/DOTS)
  3. 联系技术支持

3. 最佳实践

推荐配置模板

FAQ 知识库:

{
"chunk_token_num": 128,
"min_chunk_tokens": 20,
"enable_heading_in_content": false
}

技术文档(通用):

{
"chunk_token_num": 256,
"min_chunk_tokens": 10,
"enable_heading_in_content": false
}

技术教程(长上下文):

{
"chunk_token_num": 512,
"min_chunk_tokens": 50,
"enable_heading_in_content": true
}

代码文档:

{
"chunk_token_num": 384,
"min_chunk_tokens": 20,
"enable_heading_in_content": false
}

多文档混合检索:

{
"chunk_token_num": 256,
"min_chunk_tokens": 10,
"enable_heading_in_content": true // 帮助区分不同文档
}

文档结构建议

✓ 适合智能分块的文档:

## 功能介绍

系统提供以下核心功能:

1. **用户管理**: 支持用户注册、登录、权限管理等功能。
2. **数据分析**: 提供多维度的数据分析和可视化。
3. **报表生成**: 自动生成各类业务报表。

### 详细说明

用户管理模块采用 RBAC 权限模型...

| 角色 | 权限 |
|------|------|
| 管理员 | 全部权限 |
| 普通用户 | 查看权限 |

✗ 不太适合的文档:

功能A功能B功能C...  (缺少结构)

或者:

巨大的单一段落,没有任何标题、列表或表格,所有内容都挤在一起...(缺少语义分隔)

使用场景

适合的场景

通用技术文档

  • 包含文字、列表、表格、代码的混合内容
  • 示例: 用户手册、API 文档、技术博客

没有明确标题结构的文档

  • 扁平结构或标题层级不规范
  • 智能分块会自动识别段落边界

代码文档和教程

  • 需要保持代码块完整性
  • 智能分块不会截断代码

快速开始的默认选择

  • 不确定用哪种策略时,先用智能分块
  • 效果通常不错,适用范围广

不适合的场景

需要严格按章节切分

  • 用户需要按标题导航
  • 建议使用标题分块

需要同时提供精确检索和完整上下文

  • 例如法律文档、学术论文
  • 建议使用父子分块

特殊格式的文本文件

  • 日志文件、数据文件
  • 建议使用正则分块

技术原理(简要说明)

AST 解析器

KnowFlow 使用 markdown-it-py 库解析 Markdown:

from markdown_it import MarkdownIt

md = MarkdownIt()
tokens = md.parse(markdown_text)

# tokens 包含文档的 AST 结构

Token 计数

使用 tiktoken 库计算 token 数量:

import tiktoken

encoding = tiktoken.get_encoding("cl100k_base") # GPT-4 编码
tokens = encoding.encode(text)
token_count = len(tokens)

算法复杂度

  • 时间复杂度: O(n),n 为文档长度
  • 空间复杂度: O(n)
  • 处理速度: 中等(比标题分块慢,比父子分块快)

常见问题

1. 智能分块和标题分块有什么区别?

特性智能分块标题分块
切分依据多种语义单元仅标题
块大小控制
是否需要标题
适用范围广结构化文档

2. 为什么有的块超过了 chunk_token_num?

答: 这是正常的。智能分块优先保证语义完整性:

  • 表格不会被切分
  • 代码块不会被截断
  • 段落不会被打断

3. 如何让块大小更均匀?

答:

  1. 调整 chunk_token_num 为更大的值
  2. 提高 min_chunk_tokens
  3. 如果需要绝对均匀,考虑使用正则分块(但会牺牲语义完整性)

4. 智能分块会识别 HTML 标签吗?

答: 会。如果 Markdown 中包含 HTML,智能分块会尽量保持 HTML 标签的完整性。

5. 列表很长时会如何处理?

答:

  • 短列表(<5 项): 保持完整
  • 长列表: 在列表项之间切分,但不会在列表项内部切分

6. 为什么推荐智能分块作为默认策略?

答:

  • ✅ 适用范围最广
  • ✅ 不需要文档有特定结构
  • ✅ 自动平衡块大小和语义完整性
  • ✅ 处理速度适中
  • ✅ 配置简单

相关资源