3.9 KiB
3.9 KiB
句子分块改进文档
问题描述
在原始的NER提取过程中,我们发现了一些实体被截断的问题,比如:
"丰复久信公"(应该是"丰复久信营销科技有限公司")"康达律师事"(应该是"北京市康达律师事务所")
这些截断问题是由于原始的基于字符数量的简单分块策略导致的,该策略没有考虑实体的完整性。
解决方案
1. 句子分块策略
我们实现了基于句子的智能分块策略,主要特点:
- 自然边界分割:使用中文句子结束符(。!?;\n)和英文句子结束符(.!?;)进行分割
- 实体完整性保护:避免在实体名称中间进行分割
- 智能长度控制:基于token数量而非字符数量进行分块
2. 实体边界安全检查
实现了 _is_entity_boundary_safe() 方法来检查分割点是否安全:
def _is_entity_boundary_safe(self, text: str, position: int) -> bool:
# 检查常见实体后缀
entity_suffixes = ['公', '司', '所', '院', '厅', '局', '部', '会', '团', '社', '处', '室', '楼', '号']
# 检查不完整的实体模式
if text[position-2:position+1] in ['公司', '事务所', '协会', '研究院']:
return False
# 检查地址模式
address_patterns = ['省', '市', '区', '县', '路', '街', '巷', '号', '室']
# ...
3. 长句子智能分割
对于超过token限制的长句子,实现了智能分割策略:
- 标点符号分割:优先在逗号、分号等标点符号处分割
- 实体边界分割:如果标点分割不可行,在安全的实体边界处分割
- 强制分割:最后才使用字符级别的强制分割
实现细节
核心方法
_split_text_by_sentences(): 将文本按句子分割_create_sentence_chunks(): 基于句子创建分块_split_long_sentence(): 智能分割长句子_is_entity_boundary_safe(): 检查分割点安全性
分块流程
输入文本
↓
按句子分割
↓
估算token数量
↓
创建句子分块
↓
检查实体边界
↓
输出最终分块
测试结果
改进前 vs 改进后
| 指标 | 改进前 | 改进后 |
|---|---|---|
| 截断实体数量 | 较多 | 显著减少 |
| 实体完整性 | 经常被破坏 | 得到保护 |
| 分块质量 | 基于字符 | 基于语义 |
测试案例
-
"丰复久信公" 问题:
- 改进前:
"丰复久信公"(截断) - 改进后:
"北京丰复久信营销科技有限公司"(完整)
- 改进前:
-
长句子处理:
- 改进前:可能在实体中间截断
- 改进后:在句子边界或安全位置分割
配置参数
max_tokens: 每个分块的最大token数量 (默认: 400)confidence_threshold: 实体置信度阈值 (默认: 0.95)sentence_pattern: 句子分割正则表达式
使用示例
from app.core.document_handlers.extractors.ner_extractor import NERExtractor
extractor = NERExtractor()
result = extractor.extract(long_text)
# 结果中的实体将更加完整
entities = result.get("entities", [])
for entity in entities:
print(f"{entity['text']} ({entity['type']})")
性能影响
- 内存使用:略有增加(需要存储句子分割结果)
- 处理速度:基本无影响(句子分割很快)
- 准确性:显著提升(减少截断实体)
未来改进方向
- 更智能的实体识别:使用预训练模型识别实体边界
- 动态分块大小:根据文本复杂度调整分块大小
- 多语言支持:扩展到其他语言的分块策略
- 缓存优化:缓存句子分割结果以提高性能
相关文件
backend/app/core/document_handlers/extractors/ner_extractor.py- 主要实现backend/test_improved_chunking.py- 测试脚本backend/test_truncation_fix.py- 截断问题测试backend/test_chunking_logic.py- 分块逻辑测试