免费POC, 零成本试错
AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


我要投稿

做了十几个知识库项目后,我把入库前的文档摸底流程产品化了

发布日期:2026-01-21 21:13:28 浏览次数: 1543
作者:韦东东

微信搜一搜,关注“韦东东”

推荐语

企业知识库建设的关键第一步:如何高效评估文档质量?本文分享从实战中提炼的文档预检工具包,帮你避开数据治理的大坑。

核心内容:
1. 知识库项目常见痛点:文档质量参差不齐导致报价与实施偏差
2. 文档预检工具包的三大应用场景(售前/交付/内部治理)
3. 实战打磨出的功能设计原则与技术实现要点

杨芳贤
53AI创始人/腾讯云(TVP)最具价值专家

过去两年做企业大模型应用,知识库类型的项目咨询占比算是最高的,有公众号、知乎这些平台上来的,也有线下转介绍的。大家上来普遍会先问报价:有大概几千份文档,做一套知识库多少钱?早期我会根据文档数量大概估一个工时,结果后来很多项目做起来发现完全不是那么回事。同样是两千份,有的企业文档结构清晰、格式统一,清洗入库一周搞定;而有的企业文档里夹杂着扫描件、合并单元格、论坛爬虫数据,光清洗就得折腾半个月。数据治理这部分往往会占到整个工程量的大头,但之前都是 case by case 地处理,繁琐且重复。报价报低了,干起来又累又亏;报价报高了,尤其是远程来的咨询,没有信任基础,很多事儿就不了了之了。

后来我改成让客户先发一些脱敏后的样例文档过来,跑一遍预检再报价。但这个做法也有些问题。大部分客户挑选的样例往往不能代表全貌,要么挑的太简单,要么挑的太复杂,总之讲不清楚实际情况。基于样例做报价和 POC,还是会有偏差。再后来和一些信任关系比较好的线下客户合作,签完保密协议之后能直接接触到全量文档。拿到全量数据之后,我会先做一遍整体的文档分布分析和入库前的质量检查,看看格式分布、扫描件占比、敏感信息、文档长度分布这些。这样才能给出靠谱的工作量评估,把握一期需求边界、哪些二期处理、和老板对齐预期。

做了十几个项目之后,这套流程跑熟了,我开始想着能不能把这些逻辑产品化。先把数据治理这部分尽快抽象出来,整理成一个可复用的工具包。后续还会陆续把分块策略、检索策略、检索效果评测这些也做一些抽象,整理一些经验给大家参考。这个工具包我规划了三种使用场景(内部治理、产品交付、售前咨询),这篇主要讲的是第一步数据质量评估模块,也就是入库预处理。

这篇试图说清楚:

这个工具包的三种使用场景,技术选型和第一版功能,在实际使用过程中发现了哪些属于过度开发、哪些应该砍掉,功能收敛之后的设计原则,几个值得展开的技术细节,以及产品体验上的一些打磨。

以下,enjoy:

1

   

三种使用场景

关于这个工具包的使用场景,一方面是开头提到的售前场景,客户不愿意给原始数据,那就让他在本地跑一遍,生成一份脱敏报告发过来,我拿着报告就能给出靠谱的报价。另一方面是日常做项目交付的时候,拿到客户的文档包,得先跑一遍摸清楚数据情况,然后才能决定怎么清洗、怎么分块、哪些需要特殊处理。这套流程以前每个项目都要重新搭一遍,现在抽象成工具包之后,新项目直接跑就行。

当然,这两个场景都是解决我自己做项目的问题。但我意识到其他在做知识库项目的朋友可能也有类似的需求。比如企业内部的 IT 团队,想盘点一下历史文档资产,看看哪些能直接入库、哪些需要 OCR、哪些可能有敏感信息。这类需求其实挺普遍的,只是大家以前都在各自写脚本,没有一个现成的工具可以直接用。

所以这个工具包封装的不只是几个脚本,更有价值的地方是背后的一套工作流,文档该怎么分类、扫描件该怎么识别、敏感信息该怎么检测、统计报告该展示哪些指标。这些都是过去十几个项目踩坑之后沉淀下来的经验。把这些经验封装成工具,一方面自己用着省事,另一方面或许也能给有类似需求的盆友提供一些参考。

2

   

快速原型与踩坑

2.1

   

技术选型与第一版功能

技术选型上没什么特别的,后端用 FastAPI + Python,主要是文档处理的库生态丰富;前端用原生 HTML/CSS/JS,轻量,不需要 Node 构建工具;进度推送用 SSE,比 WebSocket 简单,单向推送足够了;图表用 ECharts,开箱即用,深色主题支持也好。

第一版做了挺多功能。递归扫描文件夹、识别各种格式、统计格式分布,这些是基础。PDF 会自动判断是文字型还是扫描型。敏感信息检测支持手机号、邮箱、身份证、银行卡。重复文件用 MD5 去重。还做了一个风险评分,0-100 分,红黄绿三档分级。前端是仪表盘风格的可视化报告,看起来挺像那么回事。

当时的心态就是功能越多越好,尽量全面。但跑起来之后发现了很多问题。

2.2

   

暴露的几个问题

首当其冲的是是评分逻辑不对。很多正常的 Word 文档被标记成"中风险",扣了 30 分。查下来发现是 .doc 格式(老版 Word)用 python-docx 解析会失败,我把"解析失败"等同于"文件有问题",这个逻辑是错的。后来加了 .doc 格式的单独处理逻辑,在 macOS 上用 textutil 提取文本(Windows 可用 LibreOffice headless / antiword / Tika 作为后备),同时区分"解析失败"和"文件损坏",前者只轻微扣分。

其次是敏感信息检测误报率太高。有次测试显示"银行卡检测出 53 个",但实际文档里根本没有银行卡号。原因是正则匹配 16 位数字,财务表格里的合同编号、发票号全部中招。这个问题当时没想到好的解法,先搁置了。

还有统计颗粒度不够的问题。既然叫做入库预处理,那肯定得知道文档长度的分布,P50 是多少、P90 是多少,这样才能决定分块策略。于是我又加了长度分布统计、长度区间直方图、预计 chunk 数和 token 数、还有分块策略建议。但这时候的心态变成了想到什么就加什么。功能越堆越多,但隐约感觉哪里不对。直到后来找了两个真实项目里分别测试了下,又发现一堆问题。

2.3

   

几个过度开发的功能

先说敏感信息检测。前端展示的是"手机号: 524,邮箱: 58,银行卡: 53"这样的统计数字。看完之后只知道这些敏感信息在哪些文件里,不知道是真的敏感信息还是误报,更不知道下一步该怎么处理。说白了,就是把初筛结果当成最终结论呈现了,但初筛结果本身是不可操作的。

再说分块建议。我做了一个功能,根据文档长度分布,推荐一个 chunk size,比如"推荐 300 字"。但仔细想想,这个功能完全是画蛇添足。分块策略本身取决于很多因素,像业务场景、embedding 模型的上下文窗口、检索时的精度要求。这些业务背景信息在使用这个工具包的时候,实际上我作为用户,实际上可能还没有了解的很全面,这种做法是在试图用脚本代替业务判断,肯定不对。

还有风险评分。最开始设计了一套评分逻辑,0-100 分,红黄绿三档。但测试的时候发现两个文件显示"文件损坏",实际上用 Office 打开完全正常。查下来发现一个是 ~$ 前缀的临时文件(确实打不开),另一个是老格式文件(Python 库解析失败,但 Office 能打开)。原始脚本里把"解析失败"等同于"损坏",这个逻辑本身就是错的。更尴尬的是,扫描型 PDF 因为"解析成功、无敏感信息"反而得了 100 分,根本不在风险清单里,但扫描件明明需要 OCR 处理。

想到这里我意识到,问题的本质是在堆功能,还没有理清核心逻辑。

2.4

   

功能分类与取舍

于是我把所有功能拆开来,做了些分类:哪些是准确的?哪些是不准确的?哪些是主观的?

准确的功能应该保留。格式分布统计、PDF 文字型/扫描型分流、文档长度分布、MD5 重复检测——这些都是客观的、可验证的,输出就是输出,没有歧义。

不准确的功能需要改进。敏感信息检测的问题不是不能做,而是不能只给一个统计数字,得展示具体在哪个文件、哪个位置、前后文是什么,让人能判断是不是误报。风险评分的问题是用评分来划分风险,逻辑不如规则分类清晰,不如直接按"扫描件"、"解析失败"、"含敏感信息"这些规则来分类。

主观的功能应该删除。健康评分没有业界标准,不同业务场景标准完全不同,给一个分数反而误导。推荐 chunk size 更是开玩笑,这本身也不是脚本能决定的事。预计 chunk 数和 token 数依赖的假设太多,参考价值很低。

这轮优化下来,功能列表砍掉了一小半,但剩下的每一个都变得更具象了。

3

   

功能收敛与设计原则

经过前面的试错,我重新梳理了产品定位。整体的处理流程大概是这样的:

核心逻辑其实很简单:这个工具的最终目的,是服务于下游的分块策略和检索策略。所以输出的不应该是一份静态的文档质检报告,而应该是一份可操作的配置清单,告诉下游系统每份文档应该走什么处理管线。

3.1

   

最终保留的功能

想清楚定位之后,功能列表就变得很聚焦:格式分布统计。扫描文件夹后,统计每种格式有多少份,占比多少。这是最基础的数据,100% 准确,没有歧义。

PDF 页面类型识别。判断 PDF 是文字型、扫描型还是混合型。文字型可以直接提取文本,扫描型需要先做 OCR。核心逻辑是按页判断——每页字符数低于阈值就算扫描页,扫描页占比超过 70% 就标记整个文件为扫描型。这是一条启发式,用于分流与估算,不保证严格正确;因此所有阈值可配置,且输出‘待确认’列表。

# PDF类型判定核心逻辑scan_ratio = scan_pages / page_countif scan_ratio >= 0.7:    pdf_type = "SCAN"      # 扫描型elif scan_ratio > 0.2:    pdf_type = "MIXED"     # 混合型else:    pdf_type = "TEXT"      # 文字型

文档长度分布。统计所有文档的字符数,输出分位数(P25/P50/P75/P90/P99)和长度区间分布。这个数据直接决定分块策略(这里用字符数作为粗粒度 proxy,真正落地仍需结合目标 embedding 模型的 tokenizer 与上下文窗口。)——如果大部分文档都在 2000 字以内,那分块粒度就不用太细。

# 长度分位数计算sorted_counts = sorted(char_counts)p50 = percentile(sorted_counts, 50)  # 中位数p90 = percentile(sorted_counts, 90)  # P90p99 = percentile(sorted_counts, 99)  # P99

重复检测。两层机制:MD5 用于识别完全相同的文件,SimHash 用于识别高相似度的文档(比如不同版本的同一份文件)。MD5 是精确匹配,SimHash 需要人工确认,所以输出是"待确认的版本冲突列表"。

敏感信息检测。支持手机号、邮箱、身份证检测,银行卡检测默认关闭(误报率太高)。关键改进是从"只展示统计数字"变成"展示待审核列表",每条匹配记录都附带上下文。


3.2

   

文档分类标签体系

不是简单地把文件分成"好"和"坏",而是给每个文档打上一个质量标签,说明它应该走什么处理管线:







标签
判断依据
推荐处理方式
Clean_Markdown
结构清晰,可直接解析
直接分块入库
Scan_PDF
扫描型 PDF
先 OCR /vlm再分块
Table_Heavy
表格多 / 合并单元格多
表格专用转换
Image_Heavy
图片密集
多模态模型处理
Parse_Failed
解析失败
需人工检查

这个分类的好处是直接对接后续流程。拿到一份文档,看标签就知道该怎么处理,不需要再做二次判断。

3.3

   

敏感信息的改进

原来只展示一个数字"手机号: 524",现在改成展示具体的匹配列表,每条记录包含:匹配类型(手机号/邮箱/身份证)、脱敏后的内容(如 1381234

、上下文(前后各 50 字符)、文件路径和位置

# 敏感信息检测:提取上下文context_start = max(0, match.start() - 50)context_end = min(len(text), match.end() + 50)context = text[context_start:context_end]

这样实际使用的时候,看到的是一份待审核清单,可以逐条判断是不是误报,然后决定是删除、脱敏还是保留。银行卡检测默认关闭,因为 16 位数字的误报率实在太高。

3.4

   

可配置的阈值

所有涉及判断的参数都做成了可配置项,默认值只是基于项目经验的推荐值:

# settings.py 配置示例pdf_detection:  min_text_chars_per_page: 50   # 每页最少字符数  scan_page_ratio_threshold: 0.7  # 扫描页占比阈值
sensitive:  context_chars: 50             # 上下文字符数  enable_bank_card: false       # 银行卡检测默认关闭
similarity:  simhash_distance_threshold: 5  # SimHash汉明距离阈值

这个设计的核心原则是输出客观数据,不做主观评分。阈值是什么,就在配置里写清楚,实际使用的时候可以根据业务场景调整。需要人工判断的地方,明确标记为"待确认",把决策权留给人工操作。

4

   

几个值得展开的技术点

前面讲了整体的设计思路,这里再展开说几个实现过程中踩过的坑。

4.1

   

PDF 扫描型判定没那么简单

最初我以为逻辑很简单:能解析出文字的就是文字版,解析不出的就是扫描版。但实际情况比这复杂。

纯文字 PDF(比如 Word 导出的)能正常解析,没问题。纯扫描 PDF(扫描仪生成的)解析不出文字,也好判断。问题出在中间地带——双层 PDF。很多公司会用 Adobe Acrobat 给扫描件加上 OCR 文字层,这种 PDF 技术上能解析出文字,但质量可能很差,错字乱码一堆。还有图文混排的 PDF(比如 PPT 导出的),部分页面有文字,部分全是图。最终的判断逻辑是按页来看:

# 页面类型判定if page_chars < 50:    page_type = "scan"      # 扫描页elif page_chars > 200:    page_type = "text"      # 文字页else:    page_type = "low_density"  # 低密度页(封面、目录或OCR质量差)

然后统计扫描页的占比,超过 70% 就标记整个文件为扫描型。当然,这个阈值也是可配置的。

4.2

   

SimHash 相似度检测

MD5 只能检测完全相同的文件。但实际场景里更常见的是"差不多但不完全一样"的情况,比如同一份文档的不同版本,或者只改了几个字。这时候用 SimHash。

SimHash 的原理是把文档转成一个 64 位的哈希值,然后比较两个哈希值之间的汉明距离(有多少位不同)。距离越小,文档越相似。

# 汉明距离计算def hamming_distance(hash1: int, hash2: int) -> int:    x = hash1 ^ hash2  # 异或找出不同的位    count = 0    while x:        count += 1        x &= x - 1     # 清除最低位的1    return count


汉明距离
建议处理
0-3
高概率重复,建议人工确认
4-6
可能相似,可选确认
>6
不算相似,忽略

默认阈值设的是汉明距离 ≤5,约等于 90% 相似。但这里有个重要的认知需要和各位对齐:相似不等于冲突。两篇介绍同一产品的文档可能高度相似但都有价值,系统只能识别出"这两份很像",不能判断"哪个是旧版该删",这还是需要人来确认。

4.3

   

大型 Excel 的处理

这个问题本来没在计划里,是跑真实数据的时候发现的。有些 Excel 有几万行,直接转文本后 token 数爆炸,入库成本很高,检索效果还差。

原因是表格数据本质上是结构化查询场景。比如"找销售额大于 100 万的客户",这种需求用 SQL 查很快,向量检索不擅长做数值比较和过滤(但可以用结构化索引/SQL/倒排/元数据过滤做数值比较)。所以大表更适合走 Text-to-SQL 而不是 RAG。

最终加了一个 Excel 行数阈值的判断,超过 5000 行的会单独标记出来,建议走其他方案处理。

5

   

产品体验打磨

功能逻辑跑通之后,最后的 10% 工作量关于产品体验打磨的部分,也是往往决定了一个工具是否能真的用起来的关键。

5.1

   

从"看报告"到"做处理"的闭环

前面花了很多时间纠结怎么展示数据。但有一个问题被忽略了:看完报告之后,下一步是什么?

比如看到"需 OCR:4 份",第一反应肯定是"哪 4 份?我看看"。如果这时候工具只能展示一个数字,或者一个静态列表,就得去文件管理器里一层层找文件。这不仅麻烦,而且降低了效率。

改进的做法是加了"一键打开"功能。点击卡片展开列表,点击列表项调用系统 API 直接打开本地文件。实现很简单,后端就一行代码:

subprocess.run(['open', file_path])  # macOS

这看似只是一个小功能,但它把工具从一个只读的仪表盘变成了一个可操作的控制台。

5.2

   

离线报告导出

这个离线报告功能上线大概有半个多月了,期间经过了三四个真实客户的打磨,逐步确定了现在这版报告模板。

之前让客户发样例文档过来,样例往往不能代表全貌。有些客户可能挑了几份干净的发过来,结果真正做项目的时候发现大量扫描件和乱七八糟的格式。现在流程变成了直接把工具发给潜在客户,让他在本地跑一遍全量数据,然后把生成的脱敏报告发回来。报告的整体设计遵循纯净数据原则:

彻底脱敏:文件名替换成 FILE_A023,路径移除,敏感信息只保留聚合计数;客观中立:移除所有"建议优化"、"风险极高"这类主观评价,只展示客观事实;单文件 HTML:图表和样式都内联,直接双击就能打开

拿到报告之后,我一般会先做个总体评估:扫描型 PDF 占多少、表格密集的文档有多少、P90 的文档长度大概在什么水平。这些数据心里有数之后,就能大致判断项目的复杂度。如果复杂度不高,简单沟通一下范围和周期就能报价。如果通过报告发现文档数量大、复杂度高的占比也不低,我一般会建议先做付费 POC。一方面是为了筛选认真的客户,另一方面也是因为 POC 本身有成本,比如扫描件多的话 OCR 要调外部 API,这些都需要提前讲清楚。

POC 阶段一般会和客户充分沟通落地方案。知识库项目不是一期就要覆盖全部几千上万份文档,而是先根据业务场景有针对性地选一批,把简单的、中等复杂度的先落地跑起来,复杂的文档后面慢慢处理。技术上可以一次性全量处理,但不建议这么做。知识库项目的核心逻辑还是小步快跑、快速迭代,先上线一版能用的,然后根据实际使用中的反馈持续优化。

6

   

被砍掉的功能

开发过程中其实还有两个功能被列在计划里,但最后决定先不做了。

6.1

   

文档截图预览

原来的设想是在列表上悬浮显示文档首页截图,在不打开文件就能快速判断内容。但做起来发现投入产出比不高。PDF 截图很简单,用 PyMuPDF 几行代码就能搞定,但 Word 和 Excel 的自动化截图很麻烦,通常需要依赖 LibreOffice 或 Headless Browser。这会让项目的部署难度上升一个量级,Docker 镜像可能从几百 MB 变成几个 GB。

后来想想,既然是本地运行的工具,看截图可能是隔靴搔痒,直接一键打开原文件更直接。所以用"一键打开"替代了"截图预览",保持架构的轻量化。

6.2

   

智能聚类

原来的设想是自动对文档进行向量化,用 K-Means 聚类自动发现文档的潜在分类,比如"这堆是合同"、"那堆是技术文档"。

如果要做这个功能,核心问题是 K 值怎么确定。K 就是"想分几类",但通常事先并不知道该分几类。这时候常用的做法是肘部法:尝试不同的 K 值(比如 2、3、4...20),计算每个 K 对应的"组内距离和"(SSE,越小说明分得越紧凑)。

组内距离和   ↑   |    *   |      *   |        *  ← 这里开始变平缓(肘部)   |          * * * * *   +------------------------→ K值        2   4   6   8  10

曲线像一只手臂,拐点(肘部)对应的 K 值通常就是最佳选择。实际应用的话,还可以让系统自动选出 K 值之后,取每个聚类的 1-2 个代表文档,让人来命名这一类,或者用 LLM 自动生成类别名称。这部分技术思考是有的,但最终没做,主要是两个原因:

一是定位越界。这个工具的核心定位是入库前的结构质检,关注的是格式、质量、复杂度这些客观指标。聚类属于"内容理解"范畴,一旦引入就变成了语义分析工具,性质完全不一样了。其次是考虑到环境负担。即使是轻量级的 Embedding 模型,也会显著增加依赖(比如 Torch)和运行内存。对于一个定位为快速盘点的工具,下载几百 MB 的模型显得太重了。

最终决定坚持结构化质检的定位,把语义分析留给下游的 RAG 系统去处理。如果后续有需求,可能会作为独立插件来做。感兴趣盆友可以按照上面的思路自己尝试一下。

7

   

写在最后

最后简单总结一下这个工具包的工程量。后端大概 28 个 Python 脚本,2500 多行代码;前端原生 HTML/CSS/JS,接近 3000 行。整体架构是 FastAPI 做后端、SSE 做进度推送、ECharts 做可视化。

开发的难点不在于代码量,而在于业务逻辑的边界处理。比如 PDF 扫描型判定,表面上看就是"有没有文字",实际上要处理双层 PDF、图文混排、OCR 质量差这些灰色地带。再比如敏感信息检测,正则匹配很简单,但怎么降低误报率、怎么展示上下文让人能判断真伪,这些都是一个个项目踩出来的。还有各种文档格式的解析——docx、doc、xlsx、pptx、pdf,每种格式的坑都不一样,老格式文件解析失败、表格有合并单元格、PDF 有加密保护,这些边界情况都得处理。

核心的业务逻辑其实就几个点:输出客观数据不做主观评分,所有阈值可配置,需要人工判断的明确标记为"待确认"。这些原则听起来简单,但都是吃过亏之后总结出来的。如果你在企业一线做知识库相关的项目,不管是企业内部的数据治理,还是做乙方的项目交付,这个工具都能帮你省掉拿到数据先摸底这个环节的工作量。直接跑一遍,格式分布、扫描件占比、敏感信息、文档长度,心里就有数了。

这个工具包定价 99 块钱(点击左下方“阅读原文”即可购买)。如果购买了我的企业大模型应用案例视频课程,或者是知识星球的成员,可以免费获得。后续还会继续迭代。目前规划的方向包括分块策略推荐(根据文档特征给出不同的分块方案对比)、检索效果评测(用标注数据评估召回率)等。如果你有其他想法或者使用中遇到问题,欢迎反馈。

视频课程已完更,共计51节,总时长14个小时(单节13分钟)。限时365元,等新书1月底前后上市后会上调价格。

53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询