核心命题:检索链路决定回答质量,模型只是最后一环。 一句话带走:每一环都可观测、可替换,问题才能定位到具体一环。
企业知识库问答的效果,往往不是由模型大小单独决定的。模型拿到什么资料、资料是否最新、资料之间是否冲突、用户是否有权访问,都会直接影响回答。大模型有知识截止日期,不知道企业内部的最新制度和数据。检索增强生成(RAG)的思路是:用户提问时,先从企业知识库检索相关内容,再把这些内容作为上下文交给模型,让模型基于资料回答。这样回答就能引用最新的企业知识,而不是靠模型记忆瞎编。
但 RAG 引入了新的工程问题:
- •召回不准:检索回来的内容和问题不相关,模型基于错误内容回答
- •排序不对:相关内容排到了后面,没进入模型上下文
- •无答案处理:知识库里没有相关内容,模型应该说「不知道」而不是编
- •引用溯源:回答的内容来自哪里,用户能不能验证
两个典型症状:
- •用户问「报销审批需要几级签字」,AI 回答了,但引用的是差旅报销制度,不是费用报销制度——检索召回了错误的文档
- •用户问「2024 年的年假政策」,AI 引用了 2022 年的旧政策——没有做版本过滤
本章讲清楚五件事:检索链路的基本结构、关键词与向量检索的取舍、Hybrid Search 怎么实现、切分怎么选、无答案和冲突怎么处理。
一、检索链路的基本结构:从提问到回答的完整链路
整条链路可以画成这样,每一层都在收窄候选集,同时附加新的约束:
用户提问 ↓ 权限前置过滤(注入 tenant_id、team_id 等条件) ↓ 查询改写(Query Rewrite):把用户的口语化问题改写成适合检索的查询 ↓ 多路召回(Hybrid Search):关键词检索 + 向量检索,各取 Top-K ↓ 结果融合(Fusion):把两路结果合并,去重,归一化分数 ↓ 重排(Rerank):用交叉编码器或 LLM 对候选结果重新排序 ↓ 上下文拼装:把 Top-N 文档拼成 Prompt 上下文 ↓ 模型生成:基于检索到的内容生成回答 ↓ 引用展示:回答中标注来源,用户可点击跳回原文权限过滤应尽量在检索请求中前置。只有经过访问控制的候选内容,才进入融合、重排和 Prompt。这一步如果没做好,后面所有环节都可能泄露未授权内容。
每个环节的作用:
- •查询改写:用户问「报销怎么弄」,改写为「费用报销审批流程 签字级别」,提高召回准确率
- •多路召回:关键词检索适合精确匹配(如制度编号、专有名词),向量检索适合语义匹配(如「不续约」和「合同到期挽留」)
- •结果融合:两路结果的分数不在同一量纲,需要归一化后再加权合并
- •重排:召回到的 Top-K 可能有 20-50 条,用更精准的模型选出最相关的 Top-N(通常 3-5 条)送给模型
- •引用展示:回答中的每句话都要能溯源到具体文档,用户可以验证
链路设计的核心原则:每个环节都应该可观测、可替换。如果某个环节出了问题(比如召回不准),你需要能通过日志定位到是查询改写的问题还是切分的问题;如果某个环节需要升级(比如换更好的重排模型),你需要能替换它而不影响其他环节。这就是为什么链路追踪和结构化日志在检索系统中如此重要——它们不是锦上添花,而是排查问题和持续优化的基础设施。
二、关键词检索与向量检索:什么时候用哪个
关键词检索适合以下情况:
- •问题包含编号、专有名词、产品型号(如「GB/T 22239-2019 是什么」)
- •用户用的是和文档完全一致的术语(如「年假政策」)
- •需要精确匹配,不能用语义相近的内容替代(如法律条款编号)
向量检索适合表达不同但含义相近的问法。例如用户问「客户不续约怎么办」,资料标题写的是「合同到期挽留流程」。关键词检索搜「不续约」可能搜不到「挽留」,但向量检索能理解两者语义相近。
两者结合通常比单独使用一种检索更稳健,但需要注意分数归一化和权重调节。关键词得分(如 BM25 分数)和向量相似度(0-1 之间的余弦相似度)不在同一个量纲上,不能直接相加而不做处理。需要先分别归一化到 [0,1],再加权求和。
| 检索方式 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
| 关键词检索(BM25) | 精确匹配、可解释、成本低 | 无法理解语义、对同义词不敏感 | 编号、专有名词、法律条款 |
| 向量检索(Dense) | 语义理解、同义词匹配 | 可能召回语义相近但不相关的内容、成本较高 | 口语化提问、FAQ、语义模糊的问题 |
| 混合检索(Hybrid) | 兼顾精确和语义 | 实现复杂、需要调权重 | 企业知识库(推荐默认) |
一个常见的误区:有些团队认为向量检索「更先进」,所以只用向量检索就够了。实际上在企业知识库场景中,大量问题是精确匹配型的——用户问的是具体的制度条款、流程步骤、编号规则,这些内容语义上可能和其他文档很接近,但只有精确匹配的那份文档才是正确答案。纯向量检索在这种情况下容易召回「语义相近但内容不对」的文档。混合检索是更稳健的默认选择。
三、Hybrid Search 的教学示例:怎么实现混合检索
下面的函数只是用关键词命中模拟「检索候选」步骤,不是真实的向量混合检索。生产系统应替换为全文索引(如 Elasticsearch)、向量数据库(如 Milvus、pgvector)和 Rerank 服务,并在查询层注入权限条件。
from typing import List, Dict def keyword_search(query: str, docs: List[Dict], top_k: int = 10) -> List[Dict]: """关键词检索:用 BM25 或简单的词频匹配,返回带分数的候选""" results = [] query_terms = set(query.lower().split()) for doc in docs: # 简单实现:统计查询词在文档中出现的次数 score = sum(1 for term in query_terms if term in doc["content"].lower()) if score > 0: results.append({"doc": doc, "score": score, "type": "keyword"}) results.sort(key=lambda x: x["score"], reverse=True) return results[:top_k] def vector_search(query: str, docs: List[Dict], top_k: int = 10) -> List[Dict]: """向量检索:用 Embedding 计算余弦相似度,返回带分数的候选""" # 实际实现需要调用 Embedding 模型,这里用随机分数模拟 import random results = [] for doc in docs: score = random.uniform(0.5, 0.95) # 模拟余弦相似度 results.append({"doc": doc, "score": score, "type": "vector"}) results.sort(key=lambda x: x["score"], reverse=True) return results[:top_k] def normalize_scores(results: List[Dict]) -> List[Dict]: """把分数归一化到 [0, 1]""" if not results: return results max_score = max(r["score"] for r in results) min_score = min(r["score"] for r in results) if max_score == min_score: for r in results: r["norm_score"] = 1.0 else: for r in results: r["norm_score"] = (r["score"] - min_score) / (max_score - min_score) return results def hybrid_search(query: str, docs: List[Dict], alpha: float = 0.5, top_k: int = 10) -> List[Dict]: """ 混合检索:关键词检索 + 向量检索,加权融合 alpha: 关键词检索的权重,0-1 之间 """ keyword_results = normalize_scores(keyword_search(query, docs, top_k)) vector_results = normalize_scores(vector_search(query, docs, top_k)) # 合并两路结果,按 doc_id 去重,分数加权求和 merged = {} for r in keyword_results: doc_id = r["doc"]["doc_id"] merged[doc_id] = {"doc": r["doc"], "final_score": alpha * r["norm_score"]} for r in vector_results: doc_id = r["doc"]["doc_id"] if doc_id in merged: merged[doc_id]["final_score"] += (1 - alpha) * r["norm_score"] else: merged[doc_id] = {"doc": r["doc"], "final_score": (1 - alpha) * r["norm_score"]} results = sorted(merged.values(), key=lambda x: x["final_score"], reverse=True) return results[:top_k]正式的混合检索可以抽象成:final_score = alpha * norm(keyword_score) + (1 - alpha) * norm(vector_score)
alpha不是固定常量。包含编号和专有名词的问题通常提高关键词权重(alpha=0.7),表达模糊意图的问题可以提高向量权重(alpha=0.3)。这个权重应通过评测集验证,而不是凭感觉设定。
怎么调 alpha:准备 30-50 条真实问题的评测集,每条标注正确答案所在的文档。分别用 alpha=0.3/0.5/0.7 跑一遍,看哪个 alpha 的证据召回率最高。
进阶:动态 alpha 策略。更成熟的做法是根据问题类型自动调整 alpha。可以训练一个简单的分类器,判断用户问题属于「精确匹配型」还是「语义匹配型」,然后动态选择 alpha。比如问题中包含编号、引号、专有名词时,自动提高关键词权重;问题以「怎么」「如何」「为什么」开头时,适当提高向量权重。这种策略不需要用户手动选择,对终端用户完全透明。
四、重排:为什么召回了还不算数
融合之后拿到的是一批「可能相关」的候选,通常 20-50 条。这批量不能直接送给模型——模型的上下文有限,塞太多反而稀释重点,而且候选里必然混着大量弱相关内容。重排(Rerank)的任务是把这 20-50 条按真实相关性重新排序,选出 3-5 条真正该进上下文的。
为什么不能直接用召回分数排序:召回阶段的关键词分数和向量分数都是把问题和文档分开算再比较的——文档的向量在入库时就算好了,不用看问题。这种做法快,但它只能粗略判断「像不像」,判断不了「这段话到底有没有回答问题」。重排阶段反过来:把问题和文档拼在一起送进模型,逐条判断这条文档对这个问题有没有用。慢,但准。
| 阶段 | 计算方式 | 问题与文档是否同时参与 | 速度 | 精度 |
|---|---|---|---|---|
| 召回(双塔) | 文档预先编码,问题单独编码,算向量距离 | 否,两者各自独立编码 | 快,可预计算 | 粗,只能判断语义相近 |
| 重排(交叉编码器) | 问题与文档拼接后一起送进模型打分 | 是,逐条联合编码 | 慢,无法预计算 | 细,能判断是否真的回答了问题 |
这个差别决定了两者不能互相替代。用重排做全量召回,复杂度是 O(文档总数),一个百万级知识库每次查询要跑一百万次模型推理,不可行;用召回直接定序,就会出现「语义相近但答非所问」的文档挤掉正确答案。所以标准做法是两段式:召回负责从百万量级快速筛到几十条,重排负责从几十条精准选出三五条。前面第三节讲的alpha调的是召回段,这一节讲的是第二段。
重排最典型的救命场景:重复内容和近似内容占位。同一份制度的三个版本、同一段说明在五份文档里各出现一次——这些内容在向量空间里极其接近,会一起挤进 Top-K。召回阶段的分数区分不了它们的「该不该用」,只有重排把问题和文档合起来看,才能把「现行版且直接回答问题的」那一条挑到最前面。这也是为什么重排之前必须先去重(见第 95 章 RAG 的核心流程)。
选哪种重排:
| 方案 | 特点 | 适用 |
|---|---|---|
| 交叉编码器(Cross-Encoder) | 专门的排序模型,精度高,延迟可控 | 默认选择,候选 20-50 条时最合适 |
| LLM 重排 | 用大模型直接排序或打分,零样本可用、可解释 | 候选少、需要解释排序理由、或没有训练好的排序模型时 |
| 规则加权 | 按字段权重(如条款号精确匹配加分)提权 | 作为补充,不单独承担排序 |
重排的工程约束:第一,候选数不能无限加大——重排是逐条推理,候选从 50 加到 200,延迟会线性上涨而收益递减,通常 20-50 条就够了。第二,重排前必须去重,否则同一文档的多个版本会占满候选位,既浪费重排算力又干扰排序。第三,重排也要可观测——记录每条候选的召回分和重排分,两者排名差异大的条目特别值得看,那里往往藏着召回阶段的系统性偏差。
怎么判断重排有没有用:对比重排前后的同一批查询,看正确答案在最终 Top-N 里的命中率变化。如果加了重排命中率几乎不动,说明召回段已经把正确答案排得很靠前,重排的边际收益低;如果动得很明显,说明召回段的排序不可信,这时候重点要放在重排上,而不是继续调alpha。
五、切分与上下文组织:chunk 大小和方式直接影响检索质量
检索质量不仅由索引决定,也由切分决定。一个 chunk 太长,容易同时包含多个主题和权限边界;一个 chunk 太短,语义不完整,模型无法理解上下文。
建议根据内容类型选择切分方式:
| 内容类型 | 推荐切分方式 | chunk 大小 | 原因 |
|---|---|---|---|
| 制度、手册、Wiki(有标题层级) | 递归字符切分 | 300-500 token | 标题天然是语义边界,顺着结构切最稳 |
| 合同条款、FAQ(短句密集) | 句窗切分 | 1-3 句 + 前后文 | 句子之间强依赖,需要上下文才能理解 |
| 访谈纪要、邮件、会议纪要(无标题) | 语义切分 | 话题突变处断开 | 没有标题层级,靠语义相似度判断边界 |
| 操作步骤、流程文档 | 按步骤序号切分 | 1-3 步一个 chunk | 步骤不能被切断,否则答案不完整 |
每个上下文块都应携带来源、版本和更新时间。回答中的引用 ID 应映射到用户可以再次访问且经过授权检查的原始资料。如果 chunk 没有元数据,引用溯源就做不了,用户无法验证回答的正确性。
案例:某银行操作规程库首版上线,切分器只看字符长度(每 800 字一刀切),结果「大额转账复核」流程的第 3、4 步之间被切开。柜员问「大额转账复核流程」,AI 只检索到前 3 步,回答漏掉了「双人复核」这一关键控制点。后来改成「标题 + 步骤序号」组合切,强制同一步骤不切断,命中率从 0.64 升到 0.86。
切分与权限的交叉问题:如果一个 chunk 横跨了两个权限边界(比如前半部分属于「内部」密级,后半部分属于「机密」密级),应该怎么处理?答案是:切分时就要考虑权限边界,一个 chunk 不能横跨不同的密级或团队归属。否则检索时要么按高密级处理(导致低密级用户看不到本来能看的内容),要么按低密级处理(导致高密级内容泄露给低密级用户)。这就是为什么数据接入阶段(第三章)的权限打标必须在切分之前完成。
六、无答案和冲突答案:允许说「不知道」比硬编更安全
一个可信的知识库系统必须允许回答「当前资料不足」。如果强行让模型回答,模型会基于不相关的内容编造,比直接说「不知道」更危险。
建议设置以下降级规则:
| 场景 | 判断条件 | 系统行为 |
|---|---|---|
| 无相关内容 | 检索结果的最高相似度 < 阈值(如 0.5) | 返回「当前知识库中没有找到相关内容,请尝试换个问法或联系人工」 |
| 内容冲突 | 检索到的文档中存在相互矛盾的表述 | 返回「知识库中存在不一致的信息,建议以最新版本为准(引用最新文档)」 |
| 置信度低 | 重排后的 Top-1 分数 < 阈值 | 返回「以下回答仅供参考,建议核对原文(附引用)」 |
| 权限不足 | 用户无权访问相关文档 | 返回「您没有权限查看相关内容,请联系管理员」(不暴露文档存在) |
| 文档过期 | 检索到的文档已过期 | 优先返回最新版本,如果只有过期版本,标注「该文档可能已过期」 |
怎么设置阈值:用评测集跑一遍,看正确答案的相似度分布和错误答案的相似度分布,找到一个能把两者分开的阈值。比如正确答案的相似度都 > 0.6,错误答案都 < 0.5,那阈值就设在 0.55。
案例:某客服知识库问答,早期没有无答案处理,用户问「你们公司的 CEO 是谁」(知识库里没有),模型编造了一个名字。后来加了相似度阈值,最高相似度 < 0.5 时返回「没有找到相关内容」,这类编造问题就消失了。
降级规则的优先级:当多个降级条件同时触发时,需要明确优先级。建议的顺序是:权限不足 > 文档过期 > 内容冲突 > 无相关内容 > 置信度低。权限不足必须最先处理,因为如果用户无权访问相关文档,系统不应该告诉用户「没有找到相关内容」——这会暴露文档的存在性。正确的做法是直接返回「您没有权限查看相关内容」,不透露任何其他信息。
七、查询改写:用户的原话往往不能直接拿去检索
检索链路的第一道加工是查询改写,但它最容易被跳过——因为用户的原句看起来「就是问题本身」。实际上,用户提问用的是口语和简称,知识库里的文本用的是术语和全称,两者之间的词面差距会直接吃掉召回率。
四类常见改写动作:
| 改写动作 | 解决的问题 | 例子 |
|---|---|---|
| 术语归一 | 口语简称对上文档全称 | 「报销怎么弄」 → 「费用报销审批流程」 |
| 同义词扩展 | 同一概念的不同说法 | 「不续约」 → 「不续约 OR 合同到期 OR 挽留」 |
| 指代消解 | 多轮对话里的「它」「这个」 | 「它的审批人是谁」 → 补全为上一轮提到的单据名 |
| 意图澄清 | 问题过短、歧义大 | 「年假」 → 追问或补全为「年假 天数 计算方法」 |
什么情况下不该改写:改写不是越多越好。如果用户的问题里含编号、专有名词、法条号,改写反而可能引入同义词噪声,把精确匹配的优势稀释掉。这类问题应当原样保留并提高关键词权重(对应第三节的alpha调高)。判断规则可以写死:正则命中GB/T、版本号、工单号、型号格式时,跳过同义词扩展。
改写本身也可能引入错误,所以要可观测。每次改写都要记录「原查询 → 改写查询」,并允许在评测集上单独度量改写环节的收益。如果改了写反而让召回率下降,说明改写规则和业务术语不对齐——这时候要改的是规则,不是模型。查询改写是规则问题,不是模型问题,这句话在客户现场被验证过很多次。
八、引用溯源:用户能不能验证,决定他敢不敢用
前七节都在解决「回答得准不准」,这一节解决「用户凭什么相信」。一个知识库产品的信任门槛不是回答的正确率,而是用户能不能自己核实——答对了但无法验证,用户仍然不敢拿它当依据。
引用要做到什么粒度:只说「来自知识库」是不够的。合格的引用至少要能让用户点击后落到原文的具体位置。
| 粒度 | 用户能做什么 | 是否合格 |
|---|---|---|
| 无引用 | 只能选择信或不信 | 不合格 |
| 文档级(文档名) | 知道来自哪份文档,还要自己翻 | 勉强 |
| 段落级(文档 + chunk) | 能快速定位到相关段落 | 合格 |
| 段落级 + 页码/锚点 | 一步跳到原文位置 | 合格(推荐) |
引用要经过和检索同样的权限检查。这是最容易被忽略的一点:引用链接必须走和检索一致的授权判断。如果引用链接是一个可以直接访问的 URL,用户就能通过点击引用绕过权限——检索阶段挡住了文档,引用链接又把它打开了。正确做法是引用链接指向一个受控跳转接口,该接口重新校验当前用户权限,无权则返回提示而不是原文。
引用缺失时宁可少答。如果某个结论无法对应到任何 chunk,正确的处理是不把这个结论写进回答,而不是照样写出来、只是不标注来源。标注是承诺,不是装饰——没有来源的句子在用户眼里和编造没有区别。
引用覆盖率应作为验收指标。可以这样定义:引用覆盖率 = 带引用的句子数 / 总句子数,目标值通常在 90% 以上。低于这个值说明生成环节没有把证据约束住,模型正在用训练记忆补全。
把本章翻译成 AI FDE hub 工程契约
AI FDE 如何设计企业知识库检索链路 这件事,最终要落到一份能被四方签收的契约上。下面这份 YAML 就是它的字段模板:
# AI FDE hub · 检索链路 · 工程契约示例 chapter: 005 framework: "AI FDE hub 三段式交付(入场 / 搭建 / 离场)" tags: ["AI", "RAG", "Hybrid", "Rerank"] scope: role: "AI FDE 工程师" boundary: "对接客户业务负责人、合规、研发、测试四方共同验收" retrieval_pipeline: steps: ["权限前置过滤", "查询改写", "多路召回", "结果融合", "重排", "上下文拼装", "生成", "引用展示"] hybrid_search: keyword_weight: "alpha=0.5(可按问题类型调整)" fusion: "归一化后加权求和" rerank: "Top-50 → Top-5" fallback_rules: - "最高相似度 < 0.5:返回无答案" - "内容冲突:标注不一致,优先最新版本" - "置信度低:标注仅供参考" - "权限不足:不暴露文档存在"和相邻章节的关系:本章与前后相邻的第 4 章《企业 AI 应用的权限治理:别让 RAG 成为越权入口》、第 6 章《从问答到执行:AI Agent 的现场交付方法》同处一个主题段,共用同一套「产物 + 退出条件 + 决策门」语言——第 4 章保证候选集里只有合法文档,本章保证这些文档被准确捞出并正确排序,第 6 章再把链路从「回答」推进到「执行」。
Toy Project vs. 生产级系统 · 8 项关键差异
这张表聚焦检索链路上最容易「演示时看不出、上线后处处不对劲」的地方。它的特点是:这里每一项的差距都不会让系统报错,只会让回答悄悄变差——所以只能靠评测和 trace 发现,不能靠客户投诉发现。
| 维度 | Toy Project | 生产级系统 | 差距代价 |
|---|---|---|---|
| 检索方式 | 纯向量检索,单一召回路径 | Hybrid Search + 动态 alpha 调节 | 编号类问题召回错文档,用户拿到语义相近但不对的答案 |
| 分数融合 | 直接取 Top-K,不做归一化 | 两路分数归一化后加权融合 | 量纲差一个数量级,融合排序实际只被一路主导 |
| 重排能力 | 无重排,检索即最终结果 | 交叉编码器或 LLM Rerank | 最相关的答案排在 20 名开外,被 Top-N 截断 |
| 切分策略 | 固定字符长度一刀切 | 按内容类型选择切分方式 | 步骤被切断,答案漏掉关键控制点 |
| 无答案处理 | 模型硬编,什么都敢答 | 相似度阈值 + 分级降级规则 | 编造不存在的制度,用户照做造成实际损失 |
| 引用溯源 | 无引用,用户无法验证 | 每个回答标注来源文档 + 段落 | 出事无法定位责任,用户不敢信也不敢用 |
| 查询改写 | 用户原句直接检索 | Query Rewrite + 同义词扩展 | 口语化提问召不回来,用户以为系统「没有这个资料」 |
| 评测体系 | 凭感觉判断「答得好不好」 | 30-50 条标注评测集 + 召回率指标 | 每次调整都是盲改,改好改坏说不清 |
客户现场最常见的三种反模式
这三种做法在检索链路调优时反复出现,共同点是都在用「更先进的组件」替代「更准确的定位」——链路本身没被当作一个整体来看。提前识别比事后补救成本低一个数量级。
| 反模式 | 典型表现 | 正确做法 | 不推荐原因 |
|---|---|---|---|
| 只用一种检索方式 | 「向量检索最先进,只用向量就够了」,结果精确匹配型问题大量召回错误文档 | 默认 Hybrid Search,根据评测集调 alpha | 编号和专有名词类问题系统性失效,且失效得不像故障 |
| 不切分直接灌入 | 整份文档作为一个 chunk 入向量库,一个 chunk 包含多个主题和权限边界 | 按内容类型选择切分方式,chunk 不横跨权限边界 | 答案只覆盖文档开头,后文形同不存在 |
| 不允许说「不知道」 | 模型什么都答,知识库里没有的内容也编造出来 | 设置相似度阈值 + 分级降级规则,宁可说「没找到」也不编 | 一次编造就摧毁用户对全部回答的信任 |
附录:检索链路速查
一句话记法:检索链路的价值不在于每一环用了多先进的模型,而在于能沿着链路把问题定位到具体一环。
链路八环分工表:
| 环节 | 主要职责 | 失效后果 |
|---|---|---|
| 权限前置过滤 | 只让经授权的候选进入融合、重排和 Prompt | 未授权内容泄露 |
| 查询改写 | 把口语问题改写成适合检索的查询 | 口语化提问召不回来 |
| 多路召回 | 关键词 + 向量各取 Top-K | 精确匹配或语义匹配一类问题失效 |
| 结果融合 | 两路分数归一化后加权合并 | 融合排序被单一量纲主导 |
| 重排 | 用交叉编码器从 20-50 条选出 3-5 条 | 正确答案被截断在 Top-N 之外 |
| 上下文拼装 | 把 Top-N 文档拼成 Prompt 上下文 | 重点被稀释 |
| 模型生成 | 基于检索内容生成回答 | 靠训练记忆补全、编造 |
| 引用展示 | 标注来源,链接走受控跳转 | 用户无法验证,不敢用 |
边界表(降级规则):
| 边界场景 | 触发条件 | 系统行为 |
|---|---|---|
| 无相关内容 | 最高相似度 < 阈值(如 0.5) | 返回「没有找到相关内容」 |
| 内容冲突 | 文档间存在矛盾表述 | 标注不一致,优先最新版本 |
| 置信度低 | 重排后的 Top-1 分数 < 阈值 | 标注「仅供参考」,附引用 |
| 权限不足 | 用户无权访问相关文档 | 不暴露文档存在,返回无权限 |
| 文档过期 | 检索到的文档已过期 | 优先最新版本,否则标注「可能已过期」 |
现场速查:
| 现场症状 | 根因判断 | 先做什么 | 不该做什么 |
|---|---|---|---|
| 引用了错误制度的文档 | 召回或重排环节 | 看 trace 日志确认召回了哪些文档 | 不要直接换更大的模型 |
| 引用了旧版政策 | 缺版本过滤或无答案规则 | 检查文档元数据与降级条件 | 不要让模型自行判断版本 |
| 步骤答案漏掉关键控制点 | 切分把步骤切断 | 改按「标题 + 步骤序号」组合切 | 不要只加长 chunk 了事 |
| 编号类问题答错 | 纯向量召回 | 默认 Hybrid,调高关键词权重 | 不要迷信「向量最先进」 |
| 编造不存在的制度 | 无答案阈值缺失 | 设相似度阈值 + 分级降级规则 | 不要只加提示词约束 |
| 引用链接可绕过权限 | 引用未走受控跳转 | 改为重新校验权限的跳转接口 | 不要直接暴露原文 URL |
判断顺序:先看 trace 日志 → 确认召回了哪些文档 → 判断是查询改写、切分还是重排的问题 → 再针对性优化对应环节。
一句收尾:回答不准时最怕的不是链路简单,而是链路是个黑盒——不知道该改哪一环,就只能反复换模型。
和相邻章节的关系:本章与第 4 章《企业 AI 应用的权限治理:别让 RAG 成为越权入口》、第 6 章《从问答到执行:AI Agent 的现场交付方法》同处一个主题段,共用同一套「产物 + 退出条件 + 决策门」语言——第 4 章保证候选集里只有合法文档,本章保证这些文档被准确捞出并正确排序,第 6 章再把链路从「回答」推进到「执行」。
思考题
用户问「报销审批需要几级签字」,AI 回答了但引用的是差旅报销制度。你觉得问题出在检索链路的哪一环?怎么排查?
参考答案:问题可能出在召回或重排环节。排查步骤:1)看日志,确认检索召回了哪些文档,有没有费用报销制度;2)如果没召回费用报销制度,可能是查询改写的问题(用户的问题没被改写到「费用报销」关键词)或切分的问题(费用报销制度被切散了,没被检索到);3)如果召回了但排到后面,可能是重排的问题(重排模型把差旅报销排到了前面);4)如果召回和排序都对,可能是上下文拼装的问题(费用报销制度没被选进 Top-N)。解决方法:先看 trace 日志定位具体环节,再针对性优化——查询改写加同义词、切分按标题层级、重排用更精准的模型。
换个说法:检索链路的价值不在于每一环用了多先进的模型,而在于能沿着链路把问题定位到具体一环。回答不准时最怕的不是链路简单,而是链路是个黑盒——不知道该改查询改写、切分还是重排,就只能反复换模型,每次都像重新掷一次骰子。
AI FDE hub
本文由 AI FDE hub 出品
关注「AI PDE 陪跑计划」,获取 AI 现场交付方法论