2.1 文本预处理基础 为什么预处理至关重要 在RAG系统中,"垃圾进,垃圾出"(Garbage In, Garbage Out)是一个永恒的法则。无论你的向量数据库多么强大、嵌入模型多么先进、LLM多么智能,如果输入的原始文本质量低劣,最终生成的回答也必然无法令人满意。文本预处理是RAG数据管线的第一步,也是最容易被忽视但影响最深远的一环。 文本预处理的目标是将原始、杂乱的文本数据转换为干净、标准化、适合下游处理(分块、向量化、检索)的高质量文本。这一过程虽然不像选择嵌入模型那样"炫技",但往往决定了RAG系统的整体效果上限。 文本清洗的核心步骤 编码规范化 处理来自不同来源的文本时,编码问题是最常见的隐患: 统一为UTF-8编码:确保所有文本使用UTF-8编码处理,避免乱码。
在RAG系统中,"垃圾进,垃圾出"(Garbage In, Garbage Out)是一个永恒的法则。无论你的向量数据库多么强大、嵌入模型多么先进、LLM多么智能,如果输入的原始文本质量低劣,最终生成的回答也必然无法令人满意。文本预处理是RAG数据管线的第一步,也是最容易被忽视但影响最深远的一环。
文本预处理的目标是将原始、杂乱的文本数据转换为干净、标准化、适合下游处理(分块、向量化、检索)的高质量文本。这一过程虽然不像选择嵌入模型那样"炫技",但往往决定了RAG系统的整体效果上限。
处理来自不同来源的文本时,编码问题是最常见的隐患:
&、<、  等实体,需要正确解码。import html import re def normalize_encoding(text): # HTML实体解码 text = html.unescape(text) # 全角转半角(英文和数字) text = re.sub( r'[\uff01-\uff5e]', lambda m: chr(ord(m.group()) - 0xfee0), text ) return text
不同数据源会引入不同类型的噪声:
噪声去除原则:宁可保守也不要过度清洗。过度清洗可能丢失有价值的上下文信息。建议使用基于规则和基于模型的混合方法——规则方法处理明确的噪声模式(如HTML标签),模型方法处理需要语义判断的情况(如判断某段文字是否为正文还是页脚)。
"" vs "")、统一省略号(... vs ⋯⋯)。-、*、•、①②③)统一为标准格式。对于中文为主、英文为辅的场景,大小写处理需要区分对待:
RAG → rag,API → api),但在生成阶段保留原始大小写。这一策略可以提升检索的鲁棒性。LLM、BERT、GPT),维护一个白名单,跳过规范化。1,000 → 1000,1.5k → 1500,50% → 0.5。2024年1月15日 / Jan 15, 2024 / 2024-01-15 → 统一为 2024-01-15。KB / Kb / kb → 统一表示。这些标准化处理看似琐碎,但对于RAG检索的一致性至关重要——用户搜索"1.5千"和"1500"应该能命中同一段内容。
在RAG语境下,停用词处理需要谨慎:
def detect_template_noise(documents, threshold=0.8): """检测在超过threshold比例的文档中出现的短语,视为模板噪声""" from collections import Counter phrase_counter = Counter() for doc in documents: phrases = extract_ngrams(doc, n_range=(2, 5)) phrase_counter.update(set(phrases)) total = len(documents) noise = [p for p, c in phrase_counter.items() if c / total > threshold] return noise
在多语言文档集合中,预处理管线需要能够:
langdetect、fasttext 等库)。预处理完成后,需要量化评估清洗质量:
| 指标 | 计算方式 | 目标 |
|---|---|---|
| 字符有效率 | 有效字符数 / 总字符数 | > 95% |
| 编码错误率 | 含乱码的文档数 / 总文档数 | < 1% |
| 平均文档长度 | 预处理后平均字符数 | 符合业务预期 |
| 信息密度 | 非模板内容占比 | > 80% |
| 处理耗时 | 单文档平均处理时间 | 满足SLA要求 |
建议构建一个预处理质量仪表盘,定期监控上述指标,及时发现数据质量问题。
一个健壮的预处理管线应具备以下特性:
每个清洗步骤都是独立的处理单元,输入一个文档输出一个文档。步骤之间通过标准数据结构传递。
class PreprocessPipeline: def __init__(self): self.steps = [ EncodingNormalizer(), HtmlCleaner(), WhitespaceNormalizer(), TemplateNoiseRemover(), FormatStandardizer(), QualityChecker() ] def process(self, document): result = document for step in self.steps: result = step.process(result) if result.quality_score < 0.3: result.flag = "low_quality" break return result
每个处理步骤都应是幂等的——对同一文档执行多次预处理,结果应保持一致。这保证了管线的可重试性。
通过配置文件控制每个步骤的启用/禁用和参数调整,而非硬编码。不同数据源可以使用不同的配置:
pipeline: - name: encoding_normalizer enabled: true params: target_encoding: utf-8 - name: html_cleaner enabled: true params: strip_tags: true remove_scripts: true - name: template_noise_remover enabled: true params: threshold: 0.8 custom_patterns: - "免责声明.*" - "机密.*"
对无法处理的文档不应导致管线崩溃,而是标记异常原因并跳过或降级处理。所有异常应有详细的日志记录,便于后续排查。
文本预处理是RAG系统的地基工程。虽然不如嵌入模型和LLM那样引人注目,但它直接决定了整个系统的数据质量上限。核心要点包括:
在下一节中,我们将讨论文档加载与解析技术,了解如何将各种格式的原始文档高效地转换为结构化的文本数据。