亚马逊AWS官方博客

为民航企业构建带入库质量门禁的 RAG 知识库系统

摘要:本文介绍了为某民航企业构建的一套带入库质量门禁的 RAG 知识库系统。该企业管理数百份多级别规章手册,标准 RAG 只管”存”不管”质”,无法应对两类核心问题:同一文档的版本差异(修订了什么、改了哪些条款)和不同文档对同一事项描述的矛盾(上级手册改了安全策略,下级手册仍引用旧版)。我们的方案在入库环节加了一道 Quality Gate——系统按向量相似度自动分流,高相似度走版本对比(章节对齐 + 字级 diff + LLM 过滤),低相似度走跨文档一致性检测(语义配对 + LLM 矛盾判定),结果合并为预审核报告供人工确认后才入库;同时在问答环节加入实时冲突标注,确保用户不会被矛盾信息误导。系统模块化设计,支持整体部署或单模块接入已有知识库。


一、客户背景与需求

某民航企业信息技术部门希望用大模型技术改造内部知识库。业务场景是:员工日常需要频繁查阅各类规章手册,但现有 OA 系统只支持关键词搜索,效率低、覆盖不全,还时常命中过期版本。客户的期望是”像问人一样问系统,直接给出答案和出处”。

该企业信息技术部门管理着数百份规章手册,从公司级的《信息安全管理手册》到部门级的《运维操作规范》,覆盖 IT 运维、安全管控、应急响应等业务域。所有手册以 PDF 附件形式挂在内部 OA 上,员工靠关键词搜索定位内容。

现场调研中梳理出四个核心痛点:

  • 语义缺失:关键词只做字面匹配,”数据备份要求”搜不到”备份策略”相关内容
  • 深层信息不可及:大量知识埋在正文表格里(如某张表的第三列数值),关键词搜索无法触达
  • 多版本混淆:同一手册 v18 和 v22 同时在 OA 里流通,员工无法判断哪份生效
  • 跨文档矛盾积累:二级手册修订了安全策略,三级手册仍引用旧版描述,无人追踪

了解完现状后,我们最初计划搭建一套标准 RAG 系统——文档入库、语义检索、LLM 生成答案。但在用客户真实手册做原型验证时,一个更根本的问题暴露出来:标准 RAG 只管”存”不管”质”。文档进来就切块、向量化、写库,不关心新内容与已有内容是否矛盾,也不追踪版本间到底改了什么。

对民航这类合规性要求极高的行业而言,”知识库里有矛盾”比”没有知识库”更危险——员工会默认信任系统的回答。

二、系统设计思路

意识到”只管存不管质”才是真正要解决的问题后,我们调整了方案定位:不做一个简单的 RAG 问答界面,而是交付一套完整的企业级知识库系统,串联”文档解析 → 入库预审核 → RAG 问答 → 冲突标注”全链路。核心设计决策是在文档入库环节加一道质量门禁(Quality Gate)——不等用户问到矛盾才暴露问题,而是入库时就主动拦截。

系统支持两种接入方式:作为独立知识库平台整体部署,替代企业现有文档管理系统;或者将核心模块(版本差异引擎、入库预审核等)单独抽出,作为增强组件接入企业已有的 RAG 系统或知识库平台——各模块通过标准 Python 包接口调用,不要求替换现有架构。

四个核心模块及其分工:

模块 职责 解决的问题
doc_parser(文档解析) 将 PDF/Word 解析为带章节定位的结构化段落与表格;默认 parse_backend=auto,根据文档特征自动选择后端 深层信息不可检索
version_diff(版本差异引擎) 同名文档新旧版本的语义配对 + 字级 diff + LLM 过滤 人工逐页比对费时且易遗漏
rag_server(入库预审核 + RAG 问答) 预审核任务编排、跨文档一致性检测、版本对比报告生成、语义检索、多轮对话、实时冲突标注、原型 Web UI 跨文档矛盾无人发现 + 自然语言查询
llm_chat(LLM 调用抽象) 多后端适配(Bedrock Converse / OpenAI-compatible)、重试、对话会话管理 统一 LLM 接入层

模块间依赖关系:

图 1:doc_parser 和 llm_chat 向 version_diff 提供解析结果与 LLM 判定能力;三个模块最终被 rag_server(FastAPI 编排层)整合调用

[图 1:doc_parser 和 llm_chat 向 version_diff 提供解析结果与 LLM 判定能力;三个模块最终被 rag_server(FastAPI 编排层)整合调用]

三、部署架构

部署方案如下:

Embedding 采用 fastembed(ONNX Runtime),纯 CPU 即可运行文档解析、向量化和预审核流程,无需 GPU 即可完成入库侧全部功能验证。如果希望加速 Embedding 计算,可使用 GPU 实例(如 g4dn/T4)。

问答环节需要 LLM 推理能力,具体部署方式取决于区域:海外区域直接调用 Amazon Bedrock,无需自备 GPU;中国区域由于 Bedrock 不可用,需要在 GPU 实例(如 EC2 g5/A10G)上自建 LLM 推理服务(如 llama.cpp + GLM-4.7-Flash)。

海外区域(推荐,运维最轻):

组件 亚马逊云科技 服务 说明
应用服务 ECS Fargate + ALB FastAPI 后端 + fastembed(CPU 即可);Web 与 Worker 独立扩缩
LLM 推理 Amazon Bedrock 调用 Claude / GPT 等,按需付费,无需管理 GPU
向量检索 Amazon OpenSearch Serverless 段落向量索引,支持向量 + 全文 + metadata 过滤
文档存储 Amazon S3 原始 PDF/Word + 解析产物 + 审核报告
业务数据库 Amazon Aurora PostgreSQL 文档族、版本状态、审核事务
对话/任务状态 Amazon DynamoDB 多轮对话状态、预审核任务进度,TTL 自动清理
用户认证 Amazon Cognito 托管用户池 + OIDC

中国区域(Bedrock 不可用,需自建 LLM):

组件 亚马逊云科技 服务 说明
应用服务 ECS Fargate + ALB FastAPI 后端 + fastembed(CPU 即可);Web 与 Worker 独立扩缩
LLM 推理 EC2 g5.2xlarge(A10G 24GB, 8C16G) 自建 LLM 服务(llama.cpp + GLM-4.7-Flash)
向量检索 Amazon OpenSearch Service(k-NN) 段落向量索引
业务数据库 Amazon Aurora PostgreSQL 文档元数据、用户信息
对话历史 Amazon DynamoDB 多轮对话状态,TTL 自动清理
文档存储 Amazon S3 原始 PDF/Word + 模型权重
密钥管理 AWS Secrets Manager + KMS API 密钥、数据库凭证
用户认证 Keycloak(ECS Fargate) OIDC 认证
监控 Amazon CloudWatch 日志、指标、告警

我们采用 “自定义质量门禁 + 亚马逊云科技 托管基础设施” 的组合:自定义 Worker 负责解析、差异识别和人工审核状态,通过审核的内容再写入 OpenSearch 向量库,问答由 LLM 提供能力。

Embedding 选型方面,系统使用 BAAI/bge-small-zh-v1.5,通过 fastembed(ONNX Runtime)封装,无 torch 依赖,CPU 即可运行。模型权重从 S3 加载。

图 2:系统整体架构,涵盖文档解析、语义配对、LLM 判定、RAG 问答四个核心组件

[图 2:系统整体架构,涵盖文档解析、语义配对、LLM 判定、RAG 问答四个核心组件]

四、关键能力一:文档解析

项目启动后第一个要解决的问题是把客户的 PDF 手册转化为机器可理解的结构化数据。我们试了几个主流开源解析库,发现民航管理手册的排版有几处特殊性,通用方案处理不好:

排版特征 具体表现 造成的问题
左侧编号列 章节编号(1.1、1.1.2)独立排在页面最左侧,正文居右 按坐标聚行时编号与正文错位拼接
跨页表格 一张表跨 2-3 页,续页重复表头 被拆成多个独立表格,整体性丢失
页眉页脚 每页底部的修订日期、文件编号、页码 与正文仅差几个像素,容易混入
空白模板 签到表、申请单等无实质内容的表格 入库后产生噪音,干扰检索
图 3:手册目录页实际排版。左侧 margin 区域章节编号与右侧标题存在明显空间分离

[图 3:手册目录页实际排版。左侧 margin 区域章节编号与右侧标题存在明显空间分离]

doc_parser 模块设计为多后端可切换——默认 parse_backend=auto,根据文档特征自动路由:PyMuPDF(速度快、依赖少,适合数字文本 PDF)、pdfplumber(精细坐标控制,适合有无边框表格的文档)或 Docling/MinerU(深度表格解析,适合扫描件或复杂版式)。对于本项目的民航手册,PyMuPDF 配合自定义的编号分离和跨页表格合并逻辑即可满足需求。

解析层的设计原则是通用规则 + 统计自适应优先,配置项兜底。系统内置了一套覆盖面较广的默认行为:章节正则覆盖 1.1.2、第六章、(一) 等常见中文公文编号格式;页眉页脚通过出现频率统计自动识别(重复出现在 30% 以上页面的行自动剔除);空白模板表格按空单元格率自动过滤。大多数规范类企业文档无需任何配置即可直接解析。

对于本项目民航手册中”左侧 margin 编号列与正文分离”这种少见排版,系统提供配置项做精细适配——但这只是极端情况下的补充手段,不是常规依赖:

from doc_parser import parse

doc = parse("信息安全管理手册_v22.pdf", config={
    "margin_number_x": 130,  # 左侧编号列 x 坐标阈值(仅该手册需要;设为 0 则禁用)
})

# 对于大多数文档,零配置即可:
# doc = parse("普通文档.pdf")

# 输出结构化段落(章节号 + 页码定位)+ 表格
print(f"段落: {len(doc.paragraphs)}, 表格: {len(doc.tables)}")
for para in doc.paragraphs[:3]:
    print(f"  [{para.section}] p.{para.page} | {para.text[:50]}...")

用客户 179 页的信息安全管理手册验证:

指标 结果
章节识别准确率 ~95%(改进前约 50%)
跨页表格自动合并 14 处
空白模板表格过滤 17 个
端到端解析耗时 < 5 秒

五、关键能力二:入库预审核

在介绍预审核流程前,有必要说明系统的文档版本管理策略:同一逻辑文档在知识库中仅保留一份 active 版本参与 RAG 检索。当新版本入库并确认后,旧版本自动标记为 inactive——仍可查看和溯源,但不再出现在问答检索结果中。这避免了”新旧版本同时被检索到导致矛盾回答”的根本性问题。

文档解析解决了”信息进得来”的问题,但进来的信息质量谁来把关?这是整个项目最核心的设计——也是本系统区别于标准 RAG 的关键所在。

每次新文档上传时,系统对库中每个已有文档逐一比较,根据整体相似度自动分流到不同比较模式:

1. 先用 Embedding 快速计算新文档与库中每份文档的整体相似度,按相似度降序排列

2. 同名文档 OR 相似度 ≥ 阈值(默认 0.85)→ 判定为”疑似版本更新”,执行版本对比(章节对齐 + 字级 diff)

3. 其余文档 → 执行跨文档一致性检测(语义配对 + LLM 矛盾判定)

4. 结果渐进式推送至前端,最相关的文档优先呈现

版本分流的核心逻辑(对应代码实现):

is_version = same_filename or similarity >= version_threshold  # 默认 0.85
图 4:入库预审核流程。系统对库中每份文档评估相似度后自动分流——高相似度走版本对比,低相似度走一致性检测,结果合并为预审核报告供人工确认

[图 4:入库预审核流程。系统对库中每份文档评估相似度后自动分流——高相似度走版本对比,低相似度走一致性检测,结果合并为预审核报告供人工确认]

5.1 跨文档一致性检测

对于相似度较低的文档对(不太可能是同一文档的版本更新),系统将新文档的每个段落与该文档做段落级语义配对:通过 Embedding 找出 “说的是同一件事但表述不同” 的段落对,再交由 LLM 判断属于真正矛盾还是仅措辞差异。

from version_diff import DiffEngine

engine = DiffEngine(config={
    "embedding": {"model": "BAAI/bge-small-zh-v1.5"},
    "llm": {"provider": "openai", "base_url": "http://localhost:8080/v1",
             "model": "GLM-4.7-Flash"},
    "diff": {"similarity_threshold": 0.80},
})

# 加载知识库已有文档
engine.add("信息安全管理手册_v22.pdf")
engine.add("部门工作手册_v8.pdf")

# 对新文档执行预审核
result = engine.pre_review("IT 运维管理规范_v5.pdf")
if not result.is_safe:
    print(f"发现 {len(result.inconsistencies)} 处潜在矛盾:")
    for inc in result.inconsistencies:
        print(f"  {inc.doc_a} vs {inc.doc_b}: {inc.summary}")

为控制 LLM 调用成本,我们采用规则预过滤 + LLM 判定的两级策略:

5. 规则预分类(零成本):用正则识别明显的非实质性差异——日期/版本号变化、章节编号重排、修订记录表行等——直接放行,不调用 LLM。跨文档场景下,还有专门的噪音过滤器(CrossNoiseFilter)处理层级称谓差异、同义表述等天然存在的非矛盾性差异

6. LLM 精确判定:仅对规则无法确定的候选对调用 LLM,输出分类标签:inconsistency(真矛盾)、substantive(实质变更)、refinement(合理细化)、metadata(元数据变动)等

实测中规则层过滤了 30%~50% 的候选对,有效降低了推理开销。

预审核完成后,系统自动生成结构化的审核报告(review_report 模块),包含矛盾清单、版本差异摘要、变更分类统计,可直接导出为管理员审阅的文档。

5.2 版本对比

当系统判定某份已有文档与新文档高度相似(同名或相似度 ≥ 0.85,疑似同一文档的版本更新)时,自动切换到版本对比模式,执行全量 diff:

7. 章节号对齐:按层级编号(如 §10.4.2.3)将新旧版本段落一一配对

8. 字级 Diff:对配对段落计算精确的增删改差异

9. 表格 Diff:跨页表格先按表头相似度配对,再逐行逐列比较

10. LLM 过滤:剔除纯格式、纯编号类噪音,保留有业务意义的变更

# 版本对比
version_result = engine.version_compare(
    old_filepath="信息安全管理手册_v22.pdf",
    new_filepath="信息安全管理手册_v23.pdf",
)

print(f"实质性变更: {len(version_result.changes)} 处")
print(f"已过滤的细微变更: {len(version_result.minor_changes)} 处")

for change in version_result.changes[:3]:
    print(f"\n[{change.change_type}] {change.section}")
    print(f"  旧: {change.old_text[:80]}")
    print(f"  新: {change.new_text[:80]}")
    print(f"  摘要: {change.summary}")

两项检查的结果合并为一份预审核报告交给管理员。管理员确认无误后,文档正式入库。这份报告本身也可直接作为《手册修订说明及内容对比清单》的初稿——过去需要人工逐页比对数小时的工作,现在 30 秒自动生成。

图 5:版本对比截图

[图 5:版本对比截图]

六、关键能力三:带冲突标注的 RAG 问答

质量门禁保障了增量入库的可靠性,但库里已有的历史文档之间可能仍存在遗留冲突——客户在评审原型时明确提出了这个担忧。因此我们在问答环节加入了实时冲突检测:当检索到的段落来自不同文档且存在矛盾描述时,系统在答案中明确标注冲突来源,而非简单任选一方或给出模糊回答。

系统设计上,检索层(retriever 模块)与问答层(qa_engine 模块)分离,方便后续替换检索后端(如从本地 FAISS 迁移到 OpenSearch Serverless)或接入外部向量库,而不影响问答逻辑。

6.1 表格的双粒度入库

表格数据在入库时会同时生成两种检索单元:

  • table:保留完整 Markdown 表格,作为上下文和审计证据
  • table_row:把每一行转换成”列名=值”的结构化文本,用于精确命中设备、阈值和角色

例如,用户询问”负载均衡器是什么型号”时,行级块比整张资产表更容易召回目标设备;生成答案时仍可以附带整表、文档和页码来源。

图 6:表格内容检索截图

[图 6:表格内容检索截图]

6.2 问答流程

11. 用户提问 → 语义检索 top-K 相关段落

12. 对检索结果做跨文档冲突检测(Jaccard 2-gram 相似度门控 + LLM 确认)

13. 拼接 context + 冲突提示 → LLM 生成答案

14. 返回:答案 + 来源引用 [1][2] + 冲突标记(若有)

response = qa_engine.ask("信息安全培训的考核标准是什么?", session_id="user1")

print(response.answer)
print(f"来源: {[s['source_file'] for s in response.sources]}")

if response.has_conflicts:
    print("⚠️ 以下文档对此问题的描述存在矛盾:")
    for c in response.conflicts:
        print(f"  关于「{c['point']}」:")
        print(f"    {c['doc_a_file']} 说: {c['doc_a_says'][:60]}")
        for other in c['doc_others']:
            print(f"    {other['file']} 说: {other['says'][:60]}")

这样即便知识库中留有历史矛盾(管理员评估后选择放行入库的情况),终端用户也能在问答时得到明确的冲突提示,不会被单一说法误导。

七、实际效果

我们用客户信息技术部门实际管理的手册进行了初步验证,以下为几个典型场景。

7.1 版本差异识别

客户拿出刚完成修订的信息安全管理手册(v22 → v23),用系统跑一遍,验证能否替代人工编写《修订说明及内容对比清单》:

旧版 §10.4.2.3:”若 UPS 电量消耗较快时,可关闭非关键设备”

新版 §10.4.2.3:”若预计的恢复时间较长,或 UPS 电量消耗较快时,可关闭非关键设备(如非必要运行的服务器、机房测试设备等),确保重要设备正常供电(如核心交换机、防火墙、各专线路由器以及重要系统的服务器等)”

系统判定为 substantive(实质性变更):新版增加了触发条件(”预计恢复时间较长”)并补充了设备清单。

7.2 一致性检查

将库中多份手册同时加载,模拟新手册入库时的跨文档一致性检测。系统找到如下配对:

二级手册 §2.3.10.1:”考核 80 分以上为合格,补考不及格者不得参加岗位工作”

三级手册 §3.7.5.2:”考核 80 分合格…可在 1 个月内 申请补考一次”

系统判定为 refinement(合理细化):三级手册增加了补考时间窗口约束,未违反上级的 80 分合格线规定。

7.3 效率对比

客户团队试用后的反馈汇总:

传统方式 本系统
版本对比 人工逐页比对(3-5 小时/份) 自动生成差异清单(< 30 秒)
跨文档矛盾 用户问到时才暴露 入库时主动拦截
知识库问答 关键词搜索,自行翻阅原文 自然语言提问,答案附带来源引用
合规审计 手写修订说明,容易遗漏 机器生成检测报告,可直接作为审计证据

八、落地建议

  • 建立身份认证、日志、加密、备份和任务恢复能力。
  • 增加多可用区、自动扩缩容、死信队列、灾备、租户与权限过滤、审计报表、模型评测和成本治理。
  • 每一步都应保留四个核心业务语义:文档 hash 幂等、同一文档族只有一个默认主版本、历史版本可追溯、人工审核决策可审计。

九、适用场景

本方案面向的核心场景是”多层级制度文档 + 频繁版本迭代”的企业知识库:

  • 民航/交通:规章手册层级管理、适航文件版本追踪
  • 金融机构:监管规章、内控手册、操作规程的一致性管理
  • 医疗机构:诊疗规范、药品管理制度的版本追踪与冲突检测
  • 制造企业:质量管理体系文档的修订管理

十、相关链接

➡️ 下一步行动:

相关产品:

  • Amazon Bedrock — 用于构建生成式人工智能应用程序和代理的端到端平台
  • Amazon OpenSearch — 搜索和分析引擎
  • Amazon S3 — 适用于 AI、分析和存档的几乎无限的安全对象存储
  • Amazon Aurora — 适用于 PostgreSQL、MySQL 和 DSQL 的无服务器关系数据库服务
  • Amazon DynamoDB — 无服务器分布式 NoSQL 数据库

相关文章:

*前述特定亚马逊云科技生成式人工智能相关的服务目前在亚马逊云科技海外区域可用。亚马逊云科技中国区域相关云服务由西云数据和光环新网运营,具体信息以中国区域官网为准。

本篇作者

申洪汭

西云数据(NWCD)快速原型解决方案架构师,专注于 AI 应用领域。曾就职于多家头部外企及互联网企业,主要负责支持企业客户 AI 解决方案的架构设计及原型开发,有丰富的行业实践经验。


AWS 架构师中心:云端创新的引领者

探索 AWS 架构师中心,获取经实战验证的最佳实践与架构指南,助您高效构建安全、可靠的云上应用