AI图鉴

AI图鉴首页 › AI 资讯 › 企业知识库 RAG 实战:混合检索、权限过滤与答案溯源

企业知识库 RAG 实战:混合检索、权限过滤与答案溯源

来源:掘金 · 发布时间:10-23 · 由 AI图鉴每小时自动聚合

企业知识库 RAG 实战:混合检索、权限过滤与答案溯源 企业知识库问答的难点,不只是让大模型读懂一份文件。文档需要正确解析和更新,搜索结果需要符合当前用户权限,回答还要能指出依据来自哪份文件、哪个版本

企业知识库 RAG 实战:混合检索、权限过滤与答案溯源

企业知识库问答的难点,不只是让大模型读懂一份文件。文档需要正确解析和更新,搜索结果需要符合当前用户权限,回答还要能指出依据来自哪份文件、哪个版本和哪个位置。

RAG(Retrieval-Augmented Generation,检索增强生成)把“先查资料,再组织答案”串成一条流程。企业知识库还需要把登录授权、文档审核、异步索引、混合检索、引用核验和运行追溯接在一起,才能让答案有据可查,知识变更也能安全生效。

本文围绕企业知识库的常见落地架构,拆解 RAG 的工作方式,并通过员工年假问答走一遍完整示例。文中的参数是便于理解的起始值,实际表现需要用目标文档、模型和业务问题评测。

先看整体架构

业务入口与 AI 处理分开:统一 Web 路由层调用 .NET 类库,完成登录上下文、业务授权和数据管理;Python 私网服务负责文档解析、OCR、切片、向量化、检索与模型编排。

浏览器 / 公众号 / 小程序 / 客户系统

│

▼

统一 Web 路由层

│ 反射调用

▼

.NET 业务类库

├── 登录上下文、租户与 ACL

├── MySQL:业务事实与任务状态

├── 对象存储:原件与派生文件

└── 受控内网调用

│

▼

Python AI 私网服务

├── 文档解析、OCR、切片

├── Embedding 与模型适配

├── Elasticsearch:BM25 全文检索

└── Milvus:稠密向量检索

这种拆分有两个实际好处:AI 解析和模型适配可以独立扩展;租户授权的最终判断仍留在业务服务,不交给检索索引或提示词决定。Python 服务不直接连接业务 MySQL,也不对终端用户开放公网 API。

每个组件各管什么

MySQL 是业务状态的权威来源。ES 和 Milvus 里的 published、租户 ID、文档 ID、密级等字段可以帮助预过滤,却不能代替 MySQL 的授权检查。索引可能延迟、残留或重建,因此只把它当检索投影。

入库:从文件到可检索片段

知识库里的文件并不会上传后立刻进入正式问答。入库链路大致如下:

上传校验

→ 内容扫描与策略检查

→ 文档解析 / OCR

→ 规范化文本块

→ 按结构切片

→ 审核

→ 写入 ES 与 Milvus 的 staging 代际

→ 校验数量、hash 和检索可见性

→ 切换 MySQL 发布指针

解析时保留原文位置

不同格式需要保留不同定位信息:

- PDF 保留页码。

- Word 保留标题层级和段落。

- Excel 保留工作表名称及行列坐标。

- PowerPoint 保留幻灯片页和区域。

- 图片保留 OCR 区块和图像区域坐标。

定位信息会跟着片段进入引用记录。否则答案即使找到正确内容,也只能显示文件名,无法快速回到原文。

旧版 DOC、XLS、PPT 等格式需要先提示转换,或交给隔离的转换 Worker;压缩包和 Office 文件还要限制文件数量、解压比例,宏不执行。OCR 结果和文档正文都属于不可信输入,不能因为经过模型处理就视为安全内容。

切片不要把一条规则拆散

可以从 tokenizer 计算约 512 tokens、片段重叠约 64 tokens 开始试验。这个数值不是通用答案:操作手册、政策条款、表格和代码的最佳切片大小往往不同,最终要通过业务问题评测。

切片时优先沿标题、段落和列表边界拆分。表格要保留表头,过长表格按行分组,不能只按固定字符数切断。每片记录稳定的 chunk_id、页码或区域、hash、解析器版本、切片器版本、Embedding 模型版本和索引 generation。

一个可用于检索的片段记录通常不止有正文,还要有可过滤字段和原文定位:

{

"chunk_id": "483",

"tenant_id": "tenant-17",

"kb_id": "kb-hr",

"document_id": "doc-leave-policy",

"version_id": "ver-2026-03",

"generation": 4,

"title_path": ["员工休假制度", "年休假"],

"content": "连续工作满一年不满十年的员工,每年享有 5 天带薪年休假。",

"page": 12,

"chunk_index": 3,

"valid_from": "2026-03-01",

"valid_to": null,

"content_hash": "sha256:...",

"embedding_model_version": "embedding-v2"

}

ES 文档会包含可检索正文和词项字段;Milvus 保存向量及必要的过滤字段;关系库保存片段 ID、hash、版本和定位。大段正文不必在每个存储里重复保留。各存储通过稳定的 chunk_id、version_id 和 generation 关联。

例如,年假规则应保留完整条件与结果:

标题:员工休假制度 / 年休假

正文:员工连续工作满一年不满十年的,每年享有 5 天带薪年休假。

来源:员工休假制度.pdf,第 12 页,第 3 片

若只切出“每年享有 5 天”,适用条件就丢失了;若只保留标题“年休假”,检索也没有足够依据回答。

审核通过后再发布索引

索引构建期间,新内容先写入 staging generation,旧的已发布版本继续提供查询。ES 和 Milvus 都写入成功,并且数量、hash 和抽样查询通过后,业务服务才在 MySQL 事务中切换活动版本和 generation 指针。

跨 MySQL、ES、Milvus 和对象存储不存在一个统一原子事务。因此采用“先构建并验证索引,再切换权威指针”的方式。半成品索引不能被问答读取;旧索引可以在新版本发布后异步清理。发布指针只在一处权威存储中更新,查询每次读取当前活动代际,避免不同存储各自决定“哪个版本生效”。

可以将文档状态拆为业务状态和索引状态:

业务状态:uploaded → parsing → review_pending → approved → published

└────────→ rejected

索引状态:queued → building → validating → active → retiring → deleted

└───────────────→ failed / retrying

“审核通过”不等于“索引已发布”。索引失败时,文档仍不能被问答召回;重试使用相同幂等键和稳定主键,避免重复生成片段。删除和撤权的顺序相反:先更新权威状态使查询立即拒绝,再异步删除 ES、Milvus 中的旧投影。

问答:先授权,再检索和生成

用户提交问题后,在线 RAG 流程可以概括为:

登录身份与租户范围确认

→ 知识库和文档权限过滤

→ 问题标准化与条件识别

→ BM25、向量及结构化检索

→ 融合排序 / 可选重排

→ 再次授权复核并读取证据

→ 大模型按证据生成答案

→ 校验引用并返回

将问答拆成有序阶段,可以记录每步耗时、状态和错误码。带图片的查询会额外经过图片校验、OCR 和视觉理解;图片作为当轮会话附件,默认不会自动进入知识库。

第一步:确定有权搜索的范围

服务根据登录上下文确认租户、成员、启用的知识库和当前用户的数据范围。权限包含 discover(可见)、read(阅读/检索)、edit、share、forward、download、delete 等独立动作。

能看见知识库名称,不等于可以读取正文;能管理知识库,也不自动获得内容读取权。目录和文档可能继承 ACL,拒绝规则优先。密级、有效期、文档状态、租户授权和用户成员状态同样需要通过检查。

检索之前先对可访问的知识库、文档、已发布版本和索引代际做过滤。小型权限集合可以将可读文档 ID 作为检索过滤条件;集合很大时,应按范围分批检索并设扫描上限,避免先取固定 top-k 再过滤,导致合法结果被无权结果挤掉。候选返回后,再由业务授权服务核验;读取正文、提交给模型、展示引用和打开历史记录时也需要复核。未授权内容不能进入模型上下文、用户可见 trace 或答案缓存。

第二步:混合检索找候选证据

系统同时使用两类主要检索:

- Elasticsearch BM25:适合员工编号、产品型号、错误码、文件编号等关键词精确匹配。

- Milvus 稠密向量检索:适合含义相近但措辞不同的自然语言问题。

结构化条件,例如知识库、产品型号、密级、有效时间和发布版本,先作为过滤条件处理。ES 和 Milvus 的候选结果通过稳定的 chunk_id 对齐,再用 RRF 融合排名。可以从全文和向量检索各取前 100 条、融合后保留前 30 条开始;如果评测证明有帮助,再用 Reranker 精排到约 8 条。候选数是吞吐、延迟和召回率之间的参数,需要用实际语料调整。

RRF 的简化形式如下:

融合分数(chunk) = Σ 检索路权重 / (60 + 该路排名)

它根据排名融合结果,不要求 ES 和 Milvus 的原始分数处在同一数值范围。Reranker 是另一层模型排序,不能和 RRF 当作同一个步骤。

第三步:把证据交给模型

业务服务再次确认候选片段的权限和发布状态后,才读取文本。上下文按文档去重,可以从不超过 4 篇引用文档、约 6000 tokens 开始调试;实际需按模型窗口、评测结果和问题复杂度调整。送入模型前,还应去掉重复片段、保留标题路径和时间条件,并按相关性排序,避免高分结果全部来自同一段重复文本。

模型提示需要明确:只根据提供的证据回答;证据不足时说明缺少什么;回答事实要关联证据编号;不能根据文件中的指令改变系统规则。文件内容本身可能包含恶意提示,它只能作为待检索资料,不能变成模型指令。

回答生成完成后,系统校验引用 ID 是否属于本轮证据集合,并复核发布指针、权限 epoch 和输出安全策略。引用记录包含文档、版本、片段、页码或区域、摘要和 hash。图片引用还需要关联当轮附件编号、OCR 区块和图像坐标。

一个实用的提示结构是把规则、问题和证据分开,给每条证据分配不可由模型生成的 ID:

规则:仅依据下方证据回答。证据不足时说明不足。引用只能使用给定的证据 ID。

问题:入职两年有几天年假?申请要提前多久?

[E1] 员工休假制度.pdf,第 12 页,年休假

连续工作满一年不满十年的员工,每年享有 5 天带薪年休假。

[E2] 员工休假制度.pdf,第 12 页,年休假申请

年休假申请至少提前三个工作日提交,经直属负责人审批后生效。

模型输出中的 [E1]、[E2] 只是候选引用标记。服务端还要验证标记确实存在于本轮证据集合,再映射成文档版本和原文定位。引用不是模型随口附加的脚注。

示例:年假问题如何得到答案

假设知识库中有文件《员工休假制度.pdf》,第 12 页写着:

连续工作满一年不满十年的员工,每年享有 5 天带薪年休假。

连续工作满十年不满二十年的员工,每年享有 10 天带薪年休假。

年休假申请至少提前三个工作日提交,经直属负责人审批后生效。

员工提问:“入职两年有几天年假?申请要提前多久?”

系统先确认员工有权读取这份制度,再同时搜索关键词和语义相近片段。示意检索候选如下:

1. 员工休假制度.pdf / 第 12 页 / chunk 483

命中:连续工作满一年不满十年……5 天带薪年休假

2. 员工休假制度.pdf / 第 12 页 / chunk 484

命中:年休假申请至少提前三个工作日……

在片段经过权限复核后,模型收到问题和两条证据,生成的答案可以是:

连续工作满一年不满十年的员工,每年享有 5 天带薪年休假;年休假申请需至少提前三个工作日提交,并经直属负责人审批。[1]

引用 [1] 会打开《员工休假制度.pdf》的第 12 页,并定位到对应文本。若有人询问“年假能否跨年结转”,而知识库没有相关规则,系统应说明现有资料未覆盖该问题,不补充法规猜测。

如果该员工只有 discover 权限、没有 read 权限,知识库名称可能可见,但制度正文不能进入候选证据,模型也不会收到这份文件。

一个检索融合代码片段

下面的 Python 代码演示把 BM25 和向量检索的排名通过 RRF 合并。输入列表必须已经应用知识库、发布状态和授权过滤;此函数只负责排序,不承担权限判断。

from collections import defaultdict

def reciprocal_rank_fusion(result_lists, weights=None, k=60):

"""result_lists 是多路检索结果,每项为按相关性排序的 chunk_id 列表。"""

if weights is None:

weights = [1.0] * len(result_lists)

scores = defaultdict(float)

for results, weight in zip(result_lists, weights):

for rank, chunk_id in enumerate(results, start=1):

scores[chunk_id] += weight / (k + rank)

return sorted(scores.items(), key=lambda item: item[1], reverse=True)

bm25 = ["chunk-483", "chunk-210", "chunk-484"]

dense = ["chunk-484", "chunk-483", "chunk-901"]

for chunk_id, score in reciprocal_rank_fusion([bm25, dense]):

print(f"{chunk_id}: {score:.4f}")

输出排名大致为:

chunk-483: 0.0325 # BM25 第 1,向量检索第 2

chunk-484: 0.0323 # BM25 第 3,向量检索第 1

chunk-210: 0.0161 # 只被 BM25 召回

chunk-901: 0.0159 # 只被向量检索召回

同一片段在多路检索中出现时会累加排名贡献,因此能兼顾精确词命中和语义相似命中。k 和各路权重需要用标注问题集评估,不能把示例值当作线上最优参数。RRF 能融合排名,却无法补回所有检索路都漏掉的片段;召回阶段仍需单独评估。

文档处理为什么采用异步任务

PDF 解析、OCR 和向量生成耗时不可控,不适合阻塞在上传请求里。常见做法是由业务 API 写入任务主状态和 Outbox 事件,再由后台 Worker 领取任务并处理;AI Worker 执行各阶段,再通过受控内部业务入口回写阶段状态和日志。

任务需要具备稳定幂等键、心跳、租约、重试和死信处理。消息队列通常按至少一次投递处理,因此重复消息必须能够安全重跑;索引写入使用稳定主键 upsert,避免重复消费生成重复片段。Outbox 用于处理数据库提交成功但消息发布失败的窗口:业务记录和待投递事件先在同一数据库事务提交,发布器之后持续投递未确认事件;消费者按 event_id 去重,完成持久化后才确认消息。

进度日志记录任务 ID、文档版本、阶段、序号、页码或区域、片段 hash、token 数、配置版本、耗时和状态。日志列表默认不携带正文;正文预览必须重新做权限校验。密钥、完整图片字节和未经脱敏的敏感正文不写入运行日志。

图片问答和多模态资料

图片问答的 MVP 可以采用 OCR 与视觉摘要转成可检索文本,不直接把图片向量检索作为第一阶段必需能力。图片先校验真实格式和解码尺寸,再进行 OCR、表格识别或视觉理解;每个结果带置信度和区域坐标。

图片中的低置信度参数需要提示核对。OCR 置信度只反映文字识别的可信程度,不等于答案正确率。图片里出现的 URL、二维码或“忽略之前规则”等文字仍是内容数据,不应触发外部访问或改变模型行为。

单张图片 OCR 失败时,可以标记失败并继续处理其余图片;如果所有图片都失败且没有可用文字问题,应请求补充清晰材料。多图引用使用本轮的图 1、图 2 顺序,并定位到 OCR 区块或图像区域。

更新、撤权和故障时如何保持一致

索引的存在不代表内容当前有效。文档作废、删除、过期或权限撤销时,先更新 MySQL 权威状态并递增相应发布或安全 epoch,使新查询立即拒绝旧内容;ES 和 Milvus 的物理清理可以异步重试。

缓存也要与授权范围绑定。答案缓存键需包含租户、授权范围摘要、权限 epoch、发布 epoch、模型版本、提示词版本、标准化问题和附件 hash。缓存命中后仍重新核验引用权限;秘密级请求不复用跨用户答案缓存。

检索故障的处理要明确:

- ES 或 Milvus 单路故障,另一通路仍有经授权的证据时可以降级,并在追溯信息中标出。

- 两路检索都失败时返回暂不可用,不能让模型凭空补答。

- 模型调用失败时可以返回授权后的检索证据列表。

- MySQL 或权限服务不可用时,问答应拒绝服务,不能放宽权限范围。

- 队列不可用时保留 Outbox 任务,上传状态显示待处理。

用评测判断系统是否真的有用

检索、答案和权限需要分开评测。可以先建立 100 条人工标注集:60 条文字问题、30 条图片问题、10 条提示注入/无权限/跨租户问题,并标注相关片段、答案要点、允许引用和是否应该拒答。样本应覆盖精确参数、表格、多文档组合、过期版本和资料中无答案等问题。

可将以下数值作为试点目标,最终门槛应由业务风险和实际测量决定:

- 可回答问题 Recall@10 不低于 85%。

- 人工核验答案正确率不低于 85%。

- 引用定位及支持关系正确率不低于 95%。

- 权限、跨租户和撤权负例泄露为 0。

- 无证据场景正确拒答率不低于 95%。

出现错误时,先判断问题在哪一层:原文解析不完整、切片破坏上下文、正确片段没有召回、候选排序不佳、授权过滤遗漏,还是模型误读了证据。只改提示词通常无法修复检索缺失或权限问题。

总结

企业知识库 RAG 是一条带权限和版本控制的资料处理链:文档经过解析、切片、审核和双索引校验后发布;问题先限定授权范围,再通过全文与向量检索召回证据;模型根据证据组织答案,引用在返回前再次校验。

关键是让每一层职责清楚:业务数据库掌握文档状态和授权事实,AI 服务负责解析与检索编排,全文和向量索引提供可重建的召回能力。这样回答能够追溯到来源,文档更新和权限变化也有清晰的生效路径。

本文由 AI图鉴自动抓取并翻译,版权归原作者所有;如需查看原文请点下方链接。

相关 AI 工具

Tale

Tale 是开源的人机协作项目工作空间,可让团队与 AI agents 共享任务、文件和对话,委派工作并审查

AutoResearch

AutoResearch 面向 AI 建模科研,串联文献探索、研究想法、模型实现、GPU 实验、图表整理和论

BigModel

智谱推出的企业级大模型开放平台(MaaS)

Doc2X

Doc2X 是 AI 文档处理工作台,可将 PDF、扫描件、图片和 Office 文档解析为可编辑的 Wor

相关免费羊毛

Perplexity

免费版:每日 AI 搜索额度

Cohere

每月 1000 次免费请求,专注 RAG

Hyperbolic

注册送 $1 永久免费额度

Perplexity

学生半价 Perplexity Pro(10 美元/月)

同源资讯

索引建了查询却更慢——优化器选错索引与Index Merge的隐藏代价

掘金 · 10-23

Coding Agent 的知识也会漂移:用固定快照检查 Vercel Plugin 升级

掘金 · 10-23

云栖实录|Hologres 5.0全新发布:Agent Native 的全模态实时数仓

掘金 · 10-23

用 AI 做 PPT 被辞退,法院判公司赔:员工贴进对话框的数据,到底谁负责?

掘金 · 10-23

以实时驱动智能:Apache Doris Summit 2026 盛大落幕,开启 Agentic AI 时代数据

掘金 · 10-23

花椒 AI 应用工程化实践:灵泡泡的工作流、版本管理与任务恢复

掘金 · 10-23

阅读原文(juejin.cn)

标题、摘要与正文均来自该信源的公开页面,版权归原作者所有;本站自动聚合与翻译,仅作出处跳转。

← 返回 AI 资讯列表AI工具图鉴首页

返回 AI图鉴首页 · 提交工具 · 商务合作 · 关于本站 · 588 款 AI 工具分类导航 · 每日 AI 热门项目与动态