FDE W3D3 学习手册 · 权限和文档治理(Chunk 级 ACL / 失效删除 / 死信重试)
W3 Day3 · A 级(必须掌握,面试核心)· 5h · 学完能讲透"企业 RAG 的权限闸与文档生命周期:谁能看、旧了怎么退场、错了怎么兜底"
本日定位:W3D1 讲了数据底座(元数据/血缘),W3D2 讲了检索执行(混合+Rerank),W3D3 落到"治理与安全"——企业 RAG 不只是"能搜到",更要"搜得对的人、旧的下得去、错的兜得住"。这呼应你做医疗数据治理时最熟悉的"权限 + 一致性 + 重试"三件套。
学完能回答:① Chunk 级 ACL 怎么实现、检索时怎么过滤;② 文档更新/删除时索引一致性怎么保证、死信和重试怎么设计;③ 评测集怎么扩到 30 个 Cases。
使用方法:通读原理 → 重点看「🔧工程含义」「🎤面试话术」「⚠易错点」→ 做自测清单 → 配合《FDE-W3D3-评测题.md》。选中不熟的词可标注(左下★重要 / 右下📌待查)。
一、权限与文档治理全景:企业 RAG 的"安全闸"
消费级 RAG(如公开文档问答)不用管权限,但企业 RAG 直接关系商业机密与个人隐私:一份《高净值客户特药福利》手册,普通客服不该看到;一个客户的理赔记录,其他客户绝不可检索。文档治理则保证"知识库不是一潭死水"——条款修订、手册下线、解析失败都要有严谨处理,否则检索结果会混入过期/越权内容。
治理三大命题:① 权限(谁该看)→ Chunk 级 ACL;② 生命周期(旧的怎么退场)→ 失效/删除/增量更新;③ 可靠性(错的怎么兜底)→ 重试/死信/一致性校验。三者共同决定企业 RAG 的"可信边界"。
工程含义:权限与治理是"合规红线"。医疗行业受《个人信息保护法》、保险监管约束,越权泄露客户健康信息后果严重。这不是"锦上添花",是上线前置条件。你的数据治理经验在这里直接变现。
企业 RAG 和消费级最大的区别就是"治理"——谁能看、旧的怎么下、错的怎么兜。具体三件事:Chunk 级 ACL 控制权限,文档失效/删除/增量更新管生命周期,重试+死信+一致性校验保可靠性。医疗场景里越权泄露客户健康信息是直接违规,所以这是上线前置条件,不是可选项。
① "先上线后补权限"是高危做法——一旦越权检索发生就是事故。② 权限不能只做在应用层"展示时遮罩",必须在检索层就过滤,否则被绕过/被向量库直查就泄露。③ 治理和 W3D1 的元数据强绑定:ACL、状态、版本都依赖 chunk 上挂的元数据字段。
二、Chunk 级 ACL 数据模型设计
权限要到 Chunk 级而非 Document 级——一份 PDF 里可能前 10 页公开、后 5 页仅限理赔审核岗。所以 ACL 要挂在每个 chunk 上。
2.1 三种常见授权维度
| 维度 | 示例 | chunk 上字段 |
| 用户(user) | 仅保单持有人本人 | allowed_users: ["u_1001"] |
| 角色(role) | 理赔审核岗、客服岗 | allowed_roles: ["claims_auditor"] |
| 部门(dept) | 华东分公司、特药事业部 | allowed_depts: ["special_drug"] |
2.2 chunk 上的 ACL 字段设计
{
"chunk_id": "c_8f3a...",
"content": "高净值客户特药年度额度 50 万...",
"acl": {
"allowed_roles": ["claims_auditor", "vip_advisor"],
"allowed_depts": ["special_drug"],
"allowed_users": [],
"visibility": "internal" // public / internal / restricted
}
}
2.3 设计要点
- 继承 + 覆盖:chunk 默认继承 document 级 ACL,敏感段落可单独收紧(覆盖)。
- 用位或组合:检索时"用户角色命中 OR 部门命中 OR 显式用户"即放行,避免维度爆炸。
- 默认最小权限:未标注的 chunk 按"仅内部"处理,防止漏配导致公开泄露。
工程含义:ACL 到 chunk 级是"最小授权原则"的落地。Document 级太粗(一份手册里混着公开与机密),用户级太细(每条都配不现实)。角色+部门二维组合 + 默认最小权限,既安全又可控。
权限要做到 Chunk 级,因为一份 PDF 里可能前几页公开、后面几页只有理赔审核岗能看。ACL 挂在每个 chunk 上,用"角色+部门+显式用户"三个维度,检索时命中任一即放行(OR 组合)。默认最小权限——没标的 chunk 当内部处理,防止漏配泄露。chunk 默认继承文档级 ACL,敏感段落再单独收紧。
① ACL 只做用户级会维度爆炸(每 chunk 列全用户),必须上"角色/部门"抽象。② 默认权限设成"公开"是灾难——漏配就泄露,必须默认最小(internal/restricted)。③ 继承关系要清晰:chunk 覆盖 document 时,更新 document ACL 不会自动同步到已覆盖的 chunk,要约定清楚。④ ACL 字段也要版本化,权限变更要可追溯。
三、检索时的权限过滤(用户 / 角色 / 部门)
权限过滤必须发生在检索阶段(预过滤),确保越权 chunk 根本不进候选集。以 ES 为例:
def build_acl_filter(user):
return {
"bool": {
"should": [
{"terms": {"acl.allowed_roles": user.roles}},
{"terms": {"acl.allowed_depts": user.depts}},
{"terms": {"acl.allowed_users": [user.id]}}
],
"must_not": [ {"term": {"acl.visibility": "restricted_external"}} ],
"minimum_should_match": 1
}
}
# 检索:ACL 过滤 与 BM25/向量 召回 在 bool 内 AND
query = {
"bool": {
"filter": [ build_acl_filter(current_user) ], # 权限硬约束
"should": [ {"match": {"content": q}},
{"knn": {"field":"embedding","query_vector":qv,"k":50}} ]
}
}
3.1 关键原则
- filter 不是 must:用
filter 上下文(不评分、可缓存),权限是硬约束不参与相关性打分。
- 最小权限校验在服务端:不能依赖前端传"用户角色"——要从服务端会话取,防伪造。
- LLM 也要收到过滤后的上下文:即便检索过滤了,传给 LLM 的 chunks 必须是已授权的。
工程含义:权限过滤是" WHERE 条件 + 安全闸"。用 filter 上下文既能保证不评分不影响召回质量,又能被 ES 缓存提速。服务端取身份是关键——任何"客户端声明角色"的方案都能被绕过。
权限过滤必须放检索阶段用预过滤,越权 chunk 根本不进候选。ES 里用 bool.filter 挂 ACL 条件(角色/部门/用户命中其一即放行,minimum_should_match=1),filter 不评分还能被缓存提速。身份必须从服务端会话取,不能信前端传的角色——否则能被伪造绕过。传给 LLM 的也必须是已过滤的 chunks。
① 把权限当 must 会影响评分且不被缓存,应用 filter 上下文。② "前端传 role"会被篡改绕过,必须从服务端会话/网关取身份。③ 只过滤检索不够——LLM 拿到的上下文也要是过滤后的,且最终回答不能"顺带引用"越权 chunk。④ 测试要覆盖"越权用户应召回 0 条"的负向 case。
四、文档失效、删除与索引失效处理
4.1 三种"下线"语义
| 操作 | 含义 | 索引处理 |
| 失效(deprecate) | 条款过期但保留审计 | chunk.status=deprecated,检索过滤排除 |
| 删除(delete) | 彻底移除 | 物理删除向量 + 元数据,记删除日志 |
| 替换(replace) | 新版上线旧版退场 | 新 chunk active + 旧 chunk deprecated(原子切换) |
4.2 软失效优于硬删除
医疗合规要求"可追溯",所以优先 软失效(status 标记)而非物理删。只有确认无审计价值且合规允许才硬删。
下线请求 → 校验权限/合规 → 标记 status=deprecated(软)或 物理删除(硬)
→ 同步更新"文档→chunk"索引映射 → 触发增量重算(如影响召回统计)
工程含义:失效/删除不是"删库跑路",是受控的状态迁移。软失效保留审计链、支持回滚;物理删除要留删除日志与备份点。替换要"原子"——新旧切换瞬间完成,避免用户一会儿看到旧版一会儿新版。
文档下线分三种:失效(保留审计,标 deprecated)、删除(物理移除+记日志)、替换(新版 active、旧版 deprecated 原子切换)。医疗合规优先软失效,因为要可追溯、可回滚。关键是所有下线都是"受控状态迁移",不是直接删,而且要同步更新文档到 chunk 的索引映射,避免脏数据。
① 直接物理删而不留日志,审计追溯断链,监管质疑时无法自证。② 替换非原子会导致用户短暂看到混合版本,要用"先标新 active 再标旧 deprecated"或版本指针切换。③ 失效后忘了同步更新"文档→chunk"映射,会有孤儿 chunk 仍被索引。④ 删除操作要有二次确认与权限校验,防误删。
五、增量更新与一致性保证
5.1 增量更新流程
文档小改(如某页条款数字调整)不必全量重摄取,只更新受影响 chunk:定位变更 chunk → 重新解析该块 → 重算 embedding → 原子替换旧向量。
5.2 一致性三要素
原文件 ⇄ 解析结果 ⇄ 向量索引 三者必须一致
改其一 → 要么级联更新另两者,要么标记不一致待修复
- 版本一致:chunk 的 doc_version/embedding_version 与实际内容匹配。
- 计数一致:document 的 chunk 数 = 索引中该 doc 的 active chunk 数。
- 引用一致:chunk 的 source/page 指向真实存在的内容。
工程含义:增量更新省成本(不必全量重算),但引入"部分更新导致不一致"的风险。必须有"变更→级联更新→一致性校验"的闭环,否则索引慢慢腐化(W3D1 说的"数据腐烂")。
小改不必全量重摄取,只更新受影响的 chunk:定位变更块→重解析→重算向量→原子替换。但增量更新要保证"原文件、解析结果、向量索引"三者一致——改一个要级联改另外两个,否则索引会慢慢腐烂。还要校验版本一致、计数一致(文档 chunk 数 = 索引里 active 数)、引用一致。
① 增量只更新了向量却忘了更新 chunk 的 doc_version,导致版本漂移(呼应 W3D1)。② 部分更新中途失败会留"半成品"chunk,要有事务/补偿。③ 计数不一致若不校验,检索可能命中已失效 chunk。④ 增量与全量并存时要防冲突(同一 doc 同时跑两种任务)。
六、失败重试与死信队列(DLQ)
6.1 重试策略
| 策略 | 做法 | 适用 |
| 立即重试 | 失败马上重试 1~2 次(短退避) | 瞬时故障(网络抖动、限流) |
| 指数退避 | 等待 2^n 秒后重试 | 依赖服务繁忙 |
| 死信队列 | 超过最大重试进 DLQ 待人工/定时处理 | 持久失败(格式错、权限错) |
6.2 死信队列设计
def handle_ingest(task):
for attempt in range(MAX_RETRY := 5):
try:
run_pipeline(task); return mark_success(task)
except TransientError:
sleep(backoff(attempt)); continue
except PermanentError as e:
send_to_dlq(task, reason=str(e)); return # 不无限重试
send_to_dlq(task, reason="exceeded retries")
死信记录至少含:task_id、失败阶段、错误类型、原始输入引用、重试次数、首次/最后失败时间、payload 快照。便于排查与重放。
工程含义:重试不能无限——持久错误(如解析器崩、格式不支持)重试 N 次也失败,占着 worker 还产生错误结果。死信队列把"处理不了的"隔离出来,告警+人工介入,保证主流程不被脏任务拖死。这正是你 ETL 里"失败任务进异常表"的翻版。
摄取失败要分瞬时和持久:瞬时故障(网络抖、限流)用指数退避立即重试;持久错误(格式不支持、权限错)重试也没用,超过最大次数就进死信队列(DLQ)隔离,告警+人工处理。死信记录要带 task_id、失败阶段、错误类型、重试次数、payload 快照,方便重放。这和你 ETL 里"失败任务进异常表"一模一样。
① 无限重试持久错误会拖垮整个摄取管道(worker 被占满)。② 死信不能"进了就忘"——要有监控告警和定期重放机制,否则失败任务堆积成知识库缺口。③ 退避要加 jitter,避免大量任务同时重试造成"重试风暴"。④ DLQ 也要有容量上限与老化策略。
七、原文件 / 解析结果 / 索引一致性校验
三份数据(原始文件、解析后的结构化文本、向量索引)可能因中途失败而漂移,需要定期/事件触发校验。
| 校验项 | 方法 | 不一致时 |
| 文件↔解析 | 重算 file_hash 比对,抽样全文比对 | 重新解析该 doc |
| 解析↔索引 | 每个 chunk 应有对应向量;向量数=active chunk 数 | 补算缺失向量 |
| 索引↔元数据 | chunk 的 status/version 与实际一致 | 修正状态/版本 |
| 文档↔chunk 映射 | doc.chunk_count = 索引中该 doc 的 chunk 数 | 清理孤儿/补建 |
def consistency_check(doc_id):
src_hash = sha256(load_raw(doc_id))
parsed = load_parsed(doc_id)
chunks = es.count(filter={"document_id": doc_id, "status":"active"})
vectors = vector_store.count(document_id=doc_id)
assert parsed.file_hash == src_hash, "解析与源不一致"
assert chunks == vectors, "chunk 数与向量数不一致"
# 不一致 → 入修复队列
工程含义:一致性校验是"数据可信的守门员"。它把 W3D1 的元数据(hash/version/status)真正用起来——定期扫一遍,发现"有 chunk 没向量""有向量版本旧了"就自动进修复队列。没有它,索引腐化是静默的。
原文件、解析结果、向量索引三份数据会因中途失败漂移,要定期校验:文件↔解析用 hash 比对,解析↔索引看 chunk 数和向量数是否相等,索引↔元数据看 status/version 是否一致,文档↔chunk 映射看计数对不对。不一致就自动进修复队列重算。这把 W3D1 设计的 hash/version/status 真正用起来了,防止索引静默腐化。
① 一致性校验要"可修复"而不只是"报警"——发现缺失向量要能自动补算,否则只是知道坏了修不了。② 全量校验成本高,要增量(只查变更 doc)+ 定时全量兜底。③ 校验本身也可能失败/超时,要设超时与重试,别让校验任务卡死。④ 修复过程要保证幂等,重复跑不产生脏数据。
八、ES Metadata Filter 实现 ACL 过滤
Elasticsearch 的 terms 查询是 ACL 过滤的利器——用服务端用户身份构造过滤条件。
# 服务端取身份(不从前端信任)
user_roles = get_roles_from_session(request) # ["claims_auditor"]
user_depts = get_depts_from_session(request) # ["special_drug"]
user_id = get_user_id(request) # "u_1001"
acl_filter = {
"bool": {
"should": [
{"terms": {"acl.allowed_roles": user_roles}},
{"terms": {"acl.allowed_depts": user_depts}},
{"terms": {"acl.allowed_users": [user_id]}}
],
"minimum_should_match": 1
}
}
# 与召回 AND:{ "bool": { "filter": [acl_filter], "should": [bm25, knn] } }
工程含义:ES terms 查询天生匹配"集合相交",角色/部门授权直接用。配合 W3D2 的 bool+knn 混合检索,ACL 作为 filter 上下文零评分、可缓存。关键是身份从会话取,条件在服务端构造——这是权限不外泄的底线。
ES 的 terms 查询天生做"集合相交"——用户角色集合和 chunk 的 allowed_roles 集合任一相交即放行,正好是角色/部门授权的语义。ACL 作为 bool.filter 挂上,和 BM25+向量召回 AND,filter 不评分还能缓存。身份必须从服务端会话取,过滤条件在服务端构造,绝不能信前端。
① terms 查询要求字段是 keyword 类型,ACL 字段若设为 text 会被分词失效。② 空用户集合(如 roles=[])配合 minimum_should_match=1 会"全不匹配"——要处理"公开 chunk"用 visibility=public 单独放行。③ 过滤条件拼接要用参数化,防注入(尤其用户 id 进查询)。④ 别把 ACL 逻辑只写在应用层 if 判断,检索层必须过滤。
九、LangChain 自查询检索器(Self-Query Retriever)
自查询检索器让 LLM 从自然语言问题里自动抽取结构化过滤条件(metadata filter),把"用户口语"转成"ES 过滤+语义查询"。
from langchain.retrievers import SelfQueryRetriever
from langchain.retrievers.self_query.base import AttributeInfo
metadata_field_info = [
AttributeInfo(name="acl.allowed_roles", description="可访问角色", type="list[string]"),
AttributeInfo(name="doc_version", description="文档版本", type="string"),
AttributeInfo(name="section", description="章节", type="string"),
]
retriever = SelfQueryRetriever.from_llm(
llm, vectorstore, "保险知识库", metadata_field_info,
search_kwargs={"k": 8}
)
# 用户问"理赔审核岗能看的靶向药报销范围" → LLM 生成 filter: allowed_roles contains claims_auditor
docs = retriever.get_relevant_documents("理赔审核岗能看的靶向药报销范围")
工程含义:自查询把"用户描述的权限/范围"自动转成 metadata 过滤,减少手写规则。但它生成的 filter 必须再和服务端真实 ACL 做交集——不能让 LLM 决定"用户能看到什么"(否则被 prompt 注入绕过权限)。自查询是"用户意图"的便利层,最终权限仍以服务端 ACL 为准。
LangChain 自查询检索器用 LLM 从自然语言里抽结构化过滤条件,比如用户问"理赔审核岗能看的靶向药范围",它自动生成 allowed_roles contains claims_auditor 的 filter。很方便,但生成的 filter 必须再和服务端真实 ACL 取交集——绝不能让 LLM 决定用户能看到什么,否则被 prompt 注入就能越权。自查询只是"意图便利层",权限底线还是服务端 ACL。
① 自查询生成的 filter 不能代替权限校验,必须和服务端 ACL 取交集,防 prompt 注入越权。② LLM 抽 filter 可能抽错字段/值,要有字段白名单校验,非法字段直接拒绝。③ 自查询增加一次 LLM 调用延迟,高频场景要缓存或降级为规则。④ metadata_field_info 描述要准,否则 LLM 抽错。
十、文档治理的运维与监控
| 监控项 | 含义 | 告警 |
| ACL 命中率 | 检索中被权限过滤掉的比例 | 异常高/低都查 |
| 越权访问尝试 | 用户请求了无权限 doc | 立即告警(安全) |
| 孤儿 chunk | 索引里有但文档已删/失效 | >0 即修复 |
| 死信堆积 | DLQ 任务数 | >0 即处理 |
| 软失效占比 | deprecated chunk 比例 | 过高说明清理滞后 |
工程含义:治理不是"配一次就完",要持续可观测。越权访问尝试是安全事件级告警;孤儿 chunk 和死信堆积是数据腐烂信号。医疗场景建议定期出"权限审计报告"给合规团队。
治理要持续可观测:监控 ACL 命中率、越权访问尝试(安全事件级告警)、孤儿 chunk(索引里有但文档已删)、死信堆积、软失效占比。越权访问要立即告警,孤儿 chunk 和死信大于 0 就修。医疗建议定期出权限审计报告给合规团队——这就是数据治理的常态动作。
① 越权访问只记日志不告警,等于没防。② 孤儿 chunk 不清理会持续污染检索,要自动修复任务。③ 软失效 chunk 长期不物理清理会拖慢索引、占存储。④ 审计报告要能回答"某用户此刻能看到哪些文档",这是合规的硬要求。
十一、评测集扩展到 30 Cases 的策略
W3D1 你有 10 个 Golden Case,W3D3 治理主题要把评测集扩到 30,重点是补权限与治理类 case。
10 个(基础问答) → +10 权限/ACL case → +10 失效/删除/一致性/重试 case → 共 30
| 新增类别 | 示例 | 测什么 |
| 越权负向 | 普通客服检索"高净值特药额度"应召回 0 | ACL 过滤生效 |
| 权限正向 | 理赔审核岗检索同内容应命中 | 角色授权正确 |
| 失效一致性 | 手册失效后旧条款不应再被召回 | status 过滤 |
| 死信降级 | 解析失败的手册不应污染检索 | 失败隔离 |
工程含义:评测集要随功能长。治理功能(权限/失效/重试)不上评测,就等于"没人验证的安全闸"。每加一个治理能力就补对应 case,且权限类必须以"负向 case(应召回 0)"验证——只测正向会漏掉越权漏洞。
W3D1 的 10 个基础 case,到 W3D3 扩到 30:加 10 个权限/ACL case(越权应召回 0、授权应命中),加 10 个失效/删除/一致性/重试 case(手册失效后旧条款不应召回、解析失败不污染检索)。关键是权限类必须包含"负向 case"——只测正向会漏掉越权漏洞,那才是最危险的。
① 评测集只加正向 case 不设越权负向 case,等于没测权限。② 失效/删除 case 要验证"旧版本确实不再被召回",否则软失效没生效也发现不了。③ 死信 case 要确认失败任务不污染检索结果。④ 评测集版本要同步更新(eval_v2),前后对比才有意义(呼应 W3D1)。
十二、面试达标线①:Chunk 级 ACL 实现与检索过滤
| 问题 | 答案要点 |
| ACL 挂哪 | 挂每个 chunk(非 document 级),角色+部门+用户三维,默认最小权限 |
| 检索时怎么过滤 | bool.filter 上下文 + terms 查询,命中任一即放行;身份从服务端会话取 |
| 为什么检索层过滤 | 应用层遮罩可被绕过/直查向量库泄露;过滤在检索阶段彻底隔离 |
| 自查询注意 | LLM 生成的 filter 须与服务端 ACL 取交集,防注入越权 |
核心一句话:ACL 挂到 chunk 级(角色+部门+用户三维、默认最小权限),检索时用 ES bool.filter + terms 查询在服务端做预过滤,身份从会话取不信任前端;自查询检索器生成的 filter 必须再和真实 ACL 取交集。权限过滤必须在检索层,不能只做展示遮罩——否则被直查向量库就泄露。
十三、面试达标线②:更新/删除一致性与死信重试设计
更新/删除:软失效(status=deprecated)优先 → 同步文档→chunk 映射 → 替换要原子
一致性:原文件⇄解析⇄向量 三份一致,定期校验+自动修复队列
重试:瞬时故障指数退避,持久错误进 DLQ(带 task_id/阶段/错误/重试次数),告警+重放
- 文档下线三语义:失效(保留审计)/删除(物理+日志)/替换(原子切换新旧)。
- 一致性三要素:版本一致、计数一致(doc chunk 数=索引 active 数)、引用一致。
- 增量更新:只更新受影响 chunk,级联更新另两份数据,防索引腐化。
- 死信重试:区分瞬时/持久错误,持久错误超重试进 DLQ 并告警重放,主流程不被拖死。
十四、W3D3 自测清单
- 能说清企业 RAG 为什么必须做权限与文档治理(合规红线)。
- 能设计 Chunk 级 ACL 数据模型(角色/部门/用户三维 + 默认最小权限 + 继承覆盖)。
- 能写出检索时 ACL 过滤的 ES 查询(bool.filter + terms + minimum_should_match)。
- 能说明为什么权限过滤必须在检索层而非应用层遮罩,身份为何从服务端取。
- 能区分文档失效/删除/替换三语义,说清软失效优先与原子替换。
- 能解释增量更新流程与"原文件⇄解析⇄向量"三者一致性要素。
- 能设计失败重试策略(立即重试/指数退避/死信队列)并说明为何不死重试。
- 能列出死信记录应包含的信息与重放机制。
- 能说出一致性校验的四项(文件↔解析/解析↔索引/索引↔元数据/文档↔chunk 映射)。
- 能写出 ES terms 查询实现 ACL 过滤,并点出字段须 keyword、空集合处理。
- 能讲清 LangChain 自查询检索器原理及"生成的 filter 须与真实 ACL 取交集"。
- 能讲清评测集扩到 30 的策略(补权限负向/失效/死信 case)与达标线①②。
十五、高频面试题速记卡
Q:权限为什么要做到 Chunk 级而不是 Document 级?
一份 PDF 里常混着公开与机密段落,Document 级太粗会过度暴露或过度限制。Chunk 级遵循最小授权,角色+部门+用户三维组合。
Q:权限过滤放检索层还是应用层?
必须检索层(预过滤),越权 chunk 根本不进候选。应用层遮罩可被直查向量库绕过,是泄露隐患。
Q:用户身份能不能从前端传?
不能。必须从服务端会话/网关取,否则角色可被伪造,ACL 形同虚设。
Q:文档下线用软失效还是硬删除?
医疗合规优先软失效(status=deprecated,保留审计、可回滚);仅确认无审计价值才硬删并留日志。
Q:为什么检索结果会混入旧版本条款?
替换非原子或失效后没同步文档→chunk 映射,导致 deprecated chunk 仍被召回。要原子切换+一致性校验。
Q:死信队列解决什么问题?
持久错误重试也没用,无限重试会拖垮管道。DLQ 隔离失败任务+告警+重放,主流程不被脏任务卡死。
Q:原文件、解析、向量三者怎么保证一致?
定期/事件校验:hash 比文件↔解析、chunk 数=向量数、status/version 一致、文档↔chunk 计数一致,不一致进修复队列。
Q:LangChain 自查询检索器能决定权限吗?
不能。它只把自然语言转成 filter 意图,生成的 filter 必须和服务端真实 ACL 取交集,防 prompt 注入越权。
Q:ES terms 查询在 ACL 里干嘛用?
做"集合相交"——用户角色/部门集合与 chunk 的 allowed 集合任一相交即放行,正是授权语义;字段须 keyword 类型。
Q:评测集扩到 30 为什么要补负向 case?
权限类必须含"越权应召回 0"的负向 case,只测正向会漏掉越权漏洞——那是最危险的。
FDE W3D3 学习手册 · 权限和文档治理(面试级)· 配合《FDE-W3D3-评测题.md》自测
📌 待查★ 重要