知识库文档清洗:垃圾进垃圾出
先把结论甩在前面RAG 检索答不准八成不是模型菜是你喂进去的文档脏。页眉页脚、PDF 抽出来的乱码、同一段话复制了三遍——这些垃圾不清掉召回的 chunk 里全是噪声模型再聪明也是在垃圾堆里翻东西。下面是我这两个月踩出来的清洗清单,按重要性排,直接抄。背景交代一下。我给公司搭了个内部制度问答的小工具,把 200 多份 PDF/Word 规章塞进知识库。第一版上线当天就翻车——同事问年假怎么休,它给我回了一句页脚里的第 12 页 共 38 页 机密文件请勿外传。当场社死。后来我老老实实做了下面这套清洗,准确率从能用都谈不上,提到大概八成能直接采纳。1. 砍掉页眉页脚和水印行这是头号杀手。PDF 每页底部那行公司名页码日期,抽文本时会被当正文一起切进 chunk。200 页文档就是 200 条XX公司 第N页的污染。我的做法:按行频统计。同一行文本在文档里出现超过页数的 70%,基本就是页眉页脚,直接删。from collections import Counter lines [l.strip() for l in text.split(\n) if l.strip()] freq Counter(lines) page_count text.count(\f) 1 # \f 是分页符 trash {l for l, c in freq.items() if c page_count * 0.7} clean [l for l in lines if l not in trash]坑:有些正文标题也会高频出现(比如每章都有注意事项),阈值卡太低会误伤。我调到 0.7 才稳。2. 干掉 PDF 抽取产生的乱码字符PDF 转文本最爱吐两类垃圾:一是字体没映射好的(就是那个◇问号方块),二是连字fifl这种把 fi/fl 黏一起的怪东西。还有 Word 里复制来的全角空格、零宽字符 ,肉眼看不见,但会让年假和年 假被当成两个词。import re, unicodedata text unicodedata.normalize(NFKC, text) # 全角转半角、连字拆开 text text.replace(, ).replace(, ) text re.sub(r[ \t], , text)NFKC这步省了我一堆事,连字、全角数字、奇怪空格一把梭。3. 去重——逐字重复和近似重复都要管制度文档最爱大段复制粘贴。我那批文件里,本制度自发布之日起施行这句话出现了 41 次。完全一样的好处理,set 一下就行;难的是改了俩字的近似重复。我用 MinHash 做近似去重,相似度超过 0.9 的段落只留一段。小批量嫌麻烦的话,直接拿段落前 50 个字做 key 粗筛也能挡掉大半。重复类型检测手段处理完全重复哈希/set直接删近似重复(改几字)MinHash / SimHash留一条表格被拆多份看是否连续相同表头合并4. 修被切断的句子和孤行PDF 分栏、分页会把一句话从中间劈开,上半句在这页结尾,下半句在下页开头。切 chunk 时这俩被分到不同块,语义就碎了。简单规则:某行不是以句号叹号问号结尾、且下一行不是以大写或编号开头,大概率是被切断的,拼回去。中文判断标点,英文判断行尾是否完整。5. 处理表格——别让它变成一锅字符粥表格直接抽文本会变成姓名 张三 部门 技术 工号 1024这种糊成一团的东西,检索时几乎废了。我的偷懒办法:能转就转成 Markdown 表格保留结构,转不了就按行拼成姓名:张三;部门:技术这种键值对句子,至少语义还在。6. 统一编码和换行,最后留一道人工抽查全部转 UTF-8,\r\n归一成\n。然后——这步别省——随机抽 20 个 chunk 自己读一遍。我每次清洗完都抽查,基本每次都能逮到一两个前面规则没覆盖的脏数据。自动化挡 95%,剩下 5% 靠肉眼。说点实在的。这套清洗不性感,纯体力活,写正则写到怀疑人生,而且它只管把数据弄干净,弄完该不准还是不准,得自己调切分和检索。但收益是实打实的——同样的模型、同样的提示词,光把文档洗干净,我那个问答助手的可用度直接换了个台阶。搭这个助手本身倒没费多少劲。我用的是那种零代码就能配智能体的平台,拖一拖配一配,挂个大模型、传一批文档当私有知识库,半天就跑起来了,根本没写后端。真正磨人的全在数据这一关:洗文档花的时间,是搭壳子的五倍不止。所以别指望工具帮你把脏数据变干净——垃圾进,还是垃圾出,这事谁也救不了你。(顺带:模型那层我走的讯飞星辰MaaS,现成大模型 API 直接调,没自己部署算力,省心。)你们洗知识库文档时还踩过什么邪门的坑?评论区聊聊,我那个第12页机密文件的笑话不能只有我一个人闹。