模 模界数智

把多来源产品文档做成可问答知识库:2884 个 chunk 背后的清洗与收敛

客户
一家 B2B 软件企业,多条产品线、多个交付通道
阶段
已上线
结果
入库 2884 个有效 chunk,上线时 13 条抗污染探针全部通过(后续回归基线 12/13,1 条已知失败),端到端问答系统已上线
涉及能力
企业 RAG知识库治理混合检索多轮对话本地化部署

阅读说明:系统已在客户环境运行。 客户名称与可识别的业务标识已全部隐去;文中的方法、结构与数字为真实记录。

把多来源产品文档做成可问答知识库:2884 个 chunk 背后的清洗与收敛的项目过程示意图

案例速览

项内容
问题多产品线文档散在十余种来源,问答时 A 产品问题拿 B 产品步骤作答(产品污染)
数据规模14 类来源、8 条产品线;清洗后 2884 个 chunk
项目阶段已上线;更换解析层后做过一次全量回归
验证方法13 条金标准探针,断言检索结果「必须命中 / 必须排除」哪个产品,每次构建后自动跑
结果上线时 13/13 通过;回归基线 12/13,1 条多轮话题漂移探针为已知失败
不在验证范围内回答文本准确率(未建立评估题集);权限控制(本项目数据已脱敏,未启用 ACL)

背景

客户是一家 B2B 软件企业,有多条产品线,覆盖邮件、Web、终端、网络等多个交付通道。产品文档积累了很多年,但散落在十几种不同来源里:管理员手册、售后知识库、功能列表、规格表、端口清单、PoC 实验方案、操作指引、开发接口文档、售前方案、术语表。

售后工程师查一个配置项,常常要在几个系统里翻;新人上手周期长;售前写方案时经常拿到过期的参数。客户希望有一个统一的问答入口。

问题

表面需求是「做个知识库问答」,但真正的困难有三层。

第一层:来源异构。 十几种来源,每种的结构、粒度、命名习惯都不同。手册是章节化的、知识库是问答式的、规格表是 Excel 层级表、端口清单是一行一记录。用同一套切分规则处理它们,结果必然是一锅粥。

第二层:产品污染。 多条产品线的文档措辞高度相似——同样叫「策略配置」,在不同产品里是完全不同的操作。用户问 A 产品,系统拿 B 产品的步骤来回答,这是这类知识库最常见也最致命的失败模式。纯语义检索区分不了,因为语义上它们确实很像。

第三层:数据是脏的,而且脏得不明显。

原有方式为什么不行

项目初期用了常规做法:所有文档统一转成文本、统一切分、统一嵌入、向量检索加 rerank。

结果是语料量看上去很健康——6961 个 chunk,词表 47 万。但问答质量始终上不去,且错得没有规律。

排查下来,问题出在 18 个 .doc 文件上。它们不是 Word 文档,而是某协作平台「导出为 Word」生成的 MHTML——本质是 MIME 封装的 quoted-printable HTML,图片以 base64 内嵌。转换工具把它们当纯文本处理,于是:

  • 191 个 chunk 是 MIME 头和编码残留的乱码
  • 约 4000 个 chunk 是 base64 图片数据被切成的碎片

这些垃圾 chunk 占了语料的六成,把词表撑到 47 万,稀释了所有真实内容的检索权重。而它们在统计上看起来像是「内容很丰富」。

这类问题的共性:脏数据不是客户维护不当,而是导出工具的产物。任何经过「导出为某格式」这一步的文档,都值得先验证它到底是什么格式,而不是相信文件扩展名。

关键约束

  • 索引与检索必须全部在内网完成,生成环节按合规要求可切换本地模型或云端 API
  • 模型可替换——嵌入、精排、生成三层都要抽象成接口,不绑定任何一家
  • 数据自包含——图、文、索引归集到一处,运行时不依赖原始文档目录,源文档可整体归档
  • 可追溯、可回滚——每个 chunk 记录来源;清理只做移动不做删除

做法

一、一来源一提取器,而不是一套通吃

十几种来源各写一个提取器,产出统一结构的 chunk。手册按概念/步骤拆、知识库按故障排查/最佳实践/使用指南分、规格表按(产品,类别)聚合、端口清单一行一记录并额外产出结构化旁路。

针对 MHTML 写了专用转换器:按 MIME 头识别,用邮件解析库处理,而不是走文档转换工具。修复后 22 本手册零 MIME 残留,额外抽出 405 张图,语料从虚高的 6961 回落到 2884 个真实 chunk,词表从 47 万降到 10 万。

二、元数据是一等公民

每个 chunk 带一组决定检索收敛的 facet 字段:内容角色、所属产品、能力、通道、范围(共享/产品专属)、适用范围列表、内容类别、受众。

这些字段还会拼成一段前缀,参与嵌入和关键词检索:

[产品: X] [文档类型: 操作步骤] [能力: 数据识别/指纹] [通道: 邮件]
[适用范围: 共享,适用 X/Y/Z]

检索精度由 facet 决定,不是靠 embedding 猜产品。 这是整个项目最核心的一条设计判断。

三、共享内容存一份,专属内容按产品实例化

跨产品的共用能力只存一份,带「适用哪些产品」的列表;产品专属的操作步骤按产品拆开并标出分歧点。过滤规则是确定性的:内容属于目标产品,或者内容是共享的且适用范围包含目标产品。

四、多轮对话的软继承

用户在多轮中往往不重复说产品名。系统需要判断这一轮该不该沿用上一轮的产品上下文。

做法不是简单继承,而是看证据:如果本轮问的是共享能力,继承;如果检索结果里出现「明确声明了适用产品、但排除继承产品」的内容达到一定数量,说明这个能力不属于继承产品,主动放弃继承走全局检索;如果另一个产品的内容压倒性占优,切换。

实际解决的问题:用户先聊了产品 A,接着问某个存量数据发现功能。该功能是产品 B 和 C 的共享能力、适用范围明确不含 A。软继承判定为「放弃继承」,走全局检索给出正确答案,而不是绑死在 A 上答错。

五、混合检索 + 证据门禁

关键词检索用自实现的中文双字分词倒排(精确命中缩写、端口号、产品名),与向量检索融合,叠加 facet 加权和时效性微调,再用精排模型在候选池内语义排序。

汇总类、端口类、术语类查询跳过精排——这些问题 facet 和结构化查表已经给出正确答案,精排只会引入噪声。

最后一道是证据门禁:用融合分判断证据是否充分,输出「充分 / 部分 / 需要对比 / 需要澄清 / 不相关」五种状态。澄清只在多个产品真正竞争时触发;证据一致指向单一产品时直接作答,不做无谓的反问。

验证方式

13 条抗污染探针——每条是一个金标准查询,断言「必须命中什么、必须排除什么产品」。比如「问数据识别指纹原理时,共享能力块必须进入结果,某产品专属的协议匹配内容必须排除」。这些规则从人的经验变成了可回归的自动断言,每次构建后自动跑。

首要指标是产品污染率,不是回答准确率。 配套指标包括错误产品步骤率、共享内容误判为专属率、结构化问题误走向量率、拒答正确率、澄清正确率。

需要如实说明:这些指标是项目定下的目标口径,目前实测的只有探针这一层。探针验证的是检索结构对不对(拿到的是不是该产品的内容),不是最终回答文本对不对;本项目没有建立成规模的回答评估题集,因此不报告回答准确率。

结果

项结果
入库 chunk2884 条(清理前虚高至 6961)
词表规模10 万(清理前 47 万)
抗污染探针上线时 13 / 13 通过;更换解析层后回归基线 12 / 13(1 条已知失败,见下文)
图片资产419 张,归集后原文页可图文渲染
第三方依赖2 个(pyyaml、openpyxl),无 RAG 框架
系统状态已上线,支持多用户登录、会话隔离、流式问答、原文回看

语料来源构成:手册 656 · 售后知识库 644 · 端口 267 · 用户手册 212 · 售前方案 200 · API 181 · 规格 169 · 功能列表 159 · 操作指引 130 · PoC 121 · 术语 112 · 场景 24 · 汇总 9。

经验与边界

三条可迁移的经验:

  1. 先验证数据是什么,再决定怎么处理。 六成语料是垃圾这件事,在任何指标上都不会自己浮出来——它表现为「回答质量差且没规律」。
  2. 多产品知识库的第一指标是污染率,不是准确率。 一个回答得体但张冠李戴的系统,比一个明确说「我不确定」的系统危险得多。
  3. 把领域规则写进过滤层,不要交给模型猜。 「这个能力适用哪些产品」是确定性事实,应该是一次表查询,不是一次语义判断。

边界:

  • 抗污染探针目前 13 条,覆盖的是已知的高风险边界,新增产品线时需要同步扩充
  • 仍有一条已知失败:上一轮聊 A 产品、本轮问的其实是 B 产品的功能,而两者文档用词相近时,系统没有从 A 切到 B。回归基线据此冻结为 12/13,没有删掉这条探针
  • 只验证了检索层,没有成规模的回答评估集;回答准确率未测
  • 本项目数据已脱敏,没有启用权限控制。这个案例证明的是数据治理与检索收敛,不能作为知识库权限安全已验证的证据
  • 生成环节仍依赖大模型,证据门禁能控制「拿什么答」,但不能完全消除表述层面的偏差
  • 本案例的 facet 体系是按这家企业的产品结构设计的,换一家企业需要重做这一层——这也是这类项目无法产品化交付的原因

相关文章

在做类似的项目?

可以从一个真实业务场景开始,先判断值不值得做、数据是否具备条件、安全和权限问题在哪里,再决定是否进入 PoC。

预约 30 分钟交流