先理解
刚接触这个知识点
补齐先备概念,读原理与反例,再用自己的话解释为什么。
从核心原理开始 →理解 → 实现 → 排错 → 取舍
建立分阶段证据与指标,避免所有错误都用换模型解决。
知识内容核对 2026-10-03 · 原题来源核对 2026-10-02
建议先理解:
提示、结构化输出与迭代验收 →上下文与生成预算 →工具调用的结构、授权与业务契约 →按当前基础选择起点,也可以依次深入。遇到不熟悉的概念,先回到核心原理;完成后用知识练习检查理解。
LEARN · PRACTICE · REFLECT
先沿着原理、问答和迁移案例阅读。需要检查理解时,再切换巩固练习或展开个人记录。
核心知识 · RAG 的证据流与分阶段诊断
先备概念:信息检索排名、流水线中间结果、标注集与对照实验
回答依赖的证据必须先存在,再被召回、保留并完整送入模型。沿证据流寻找最早丢失点,才知道哪一阶段的改动能够影响错误。
熟悉后端的人可以把它类比为请求经过解析、过滤、排序和序列化:上游返回过某个字段,不代表客户端最终收到它。RAG 也是如此。“文档有答案”“候选有答案”“上下文有答案”“回答有证据”是四件不同的事。诊断从原文开始,否则会把入库丢表头误判为召回不足。
先给问题标注最小必要证据,例如错误码、触发条件、解决步骤所在的三个块;固定索引、权限和查询版本。按块 ID 记录每一步输入输出与剔除原因。若错误码在第 18 名但最后只选 5 块,故障还不能简单叫作生成差:可能是排序未抬升它,也可能是组装器只截前五,而业务需要两份证据的组合。
Recall@k 检查候选是否包含所需证据,排名指标检查它的位置,上下文审计检查实际文本及条件是否完整,主张核对检查结论能否从这些文本推出。向量高分或 RRF 高分都是排序信号,不是事实概率。只看最终正确率可能掩盖多个阶段互相补偿;只看召回率又可能奖励把大量噪声塞进提示词。
保持生成器不变,将候选替换为人工选定的正确证据,若仍错误就查看组装和生成;将完整证据直接送入模型仍错,才有理由研究指令、推理或答案验证。反例是更强模型凭已有知识碰巧答对,但引用仍错;这不能证明召回修好了。实验同时统计无答案、权限限定和版本限定问题,避免把“答得更多”当作可靠性提升。
先固定问题、索引版本和权限范围,保存查询改写、候选文档、重排结果、实际送入模型的上下文及最终引用。若正确证据根本没进入候选,是召回或数据问题;进入候选却被挤掉,是重排问题;选中却被截断,是上下文组装问题;证据已完整送入却仍答错,才重点查生成和指令。用标注问题分阶段评估,比较召回率、排序和引用支持程度,不只看回答流畅不流畅。
保留原问题、改写问题、用户权限、知识版本、分块策略和检索参数。先确认原始资料是否包含答案,入库解析是否丢掉表格、标题或关键条件。文档不存在或过期时,再强的模型也只能猜。对每个候选记录 document_id、chunk_id、版本、检索渠道和排名;这些用于诊断,但日志本身也必须遵守权限和脱敏要求。没有实际上下文快照,只看最终回答无法可靠定位错误。
给测试问题标注能够支撑答案的证据块。候选阶段检查 Recall@k;排序阶段看正确证据的位置,可用 MRR 或 nDCG;上下文阶段检查关键段落是否完整、相互矛盾版本是否被混合、引用标识是否仍对应原文;生成阶段检查每个结论是否由证据支持、是否遗漏适用条件。证据进了候选不代表模型见到了它,证据被送入也不代表回答真正引用了它。拒答问题要单独评测,避免只统计有答案样本。
术语、错误码和精确标识常需要关键词检索,表达变化可由向量召回补充。混合检索需要合并不同排名,不能直接相加量纲不同的相似度与 BM25 分数。Azure AI Search 使用 RRF 按排名融合,语义重排是后续阶段,分数另有含义。下面代码只演示融合机制。召回不足时再检查改写、分块、过滤与候选数;排序不好才调整重排;上下文不足则减少重复并保留条件段落;生成不忠实时才调整指令和输出验证。
固定一批覆盖精确术语、模糊表达、跨文档推理、无答案和权限限制的问题。每次只改变一类配置,比较阶段指标、最终证据支持率、延迟与成本。人工复核失败样本并标注根因,不能拿模型自评的一个分数代替全部事实判断。数据、索引、重排器和提示词版本一起记录,才能回放。某个问题变好不代表整体变好,尤其扩大 top-k 可能带来更多噪声与上下文成本。
Python 3 标准库演示。输入是假设的两个排名列表,没有真实检索、向量模型或语义重排;rank_constant 与检索 top-k 是不同参数。
def rrf(rankings, rank_constant=60):
if rank_constant <= 0:
raise ValueError("rank_constant must be positive")
scores = {}
for ranking in rankings:
seen = set()
for rank, doc_id in enumerate(ranking, start=1):
if doc_id in seen:
continue
seen.add(doc_id)
scores[doc_id] = scores.get(doc_id, 0.0) + 1 / (rank_constant + rank)
return sorted(scores.items(), key=lambda item: (-item[1], item[0]))
keyword = ["exact-error-code", "overview", "faq"]
vector = ["overview", "exact-error-code", "runbook"]
for doc_id, score in rrf([keyword, vector]):
print(doc_id, f"{score:.6f}")
预期输出
exact-error-code 0.032522
overview 0.032522
faq 0.015873
runbook 0.015873沿着问题的前提和约束继续向下读。先理解参考解答,再尝试收起答案,用自己的话解释因果和取舍。
第 1 层正确证据在 top-20,却没进入最终提示词,怎么查?
从主问题进入证据已召回但中途丢失的具体边界。
逐项比对重排输出和最终上下文快照,检查名次截断、重复去重、Token 预算、父块展开和格式转换。给被丢弃块记录明确原因。若必要证据在候选但没送入,先修排序或组装;不要直接增大生成模型。还要核对真正发往 API 的文本,页面显示的候选列表不能代替它。
沿着这个回答继续深入
第 2 层块排进前五了,但条件句仍没进入提示词,下一步查哪里?
父问排除了候选缺失,进一步排除排序后暴露文本转换失真。
检查文本截断和摘要转换,不再只查排名。保存原块到实际上下文的字符或段落映射,特别检查表头、否定和“仅在某版本”这类条件。块 ID 相同不证明内容相同;若组装器只保留首段,需要按必要证据重组,而不是机械保留前 N 个块。
沿着这个回答继续深入
第 3 层为了省 Token 压缩证据,怎样知道摘要没改变结论?
预算修复引入压缩后,新的故障是语义条件丢失,需要检验保真而非长度。
把关键主张、条件、数值和来源定位列成保真检查项,用原文核对摘要。压缩可以删重复描述,不能把“仅对新索引”改成“对所有索引”。抽检未通过时保留原证据或分次读取;摘要用于导航,关键判断仍引用可定位的原段落。
第 1 层为什么不能把 BM25 分数与向量分数直接相加?
排序问题进一步要求理解分数的语义。
BM25 的幅度受词频、语料统计等影响,向量分数由距离度量和引擎变换决定,两者同数值不代表同意义。直接相加可能让某一路量纲压倒另一路。可以按排名做 RRF,或用标注数据校准、学习融合;校准结果也不能默认跨语料和查询分布不变。
第 1 层扩大 top-k 后回答更差,可能是什么原因?
改变候选数量后,检查下游约束如何反向影响答案。
更多候选可能带入重复块、旧版本和相互冲突的条件,有限预算又挤掉关键证据;上下文更长也不保证模型更忠实。分别测候选证据覆盖与最终上下文覆盖,才能区分“召回变好但组装变坏”和“本来新增的都是噪声”。应调整去重、选证据和预算,而不是认定 top-k 越大越好。
先找出改变的条件,再判断原方案中哪些前提仍成立。下面的案例是教学推演,便于将原理迁移到新问题。
改变的条件:从单块问答变为多证据组合
延伸问题:每条文档都被召回,答案却遗漏限制条件,怎样定位?
将支持主结论和限制条件的块标成一个必要证据集合,检查两者是否一起进入最终上下文。普通“命中任一块”指标会报成功,因此增加集合完整率。若完整送入仍遗漏,检查生成器是否按主张保留限制,而不是继续扩大召回。
保持不变的原理:必要证据集合必须贯穿所有阶段,单块相关性不能替代答案完整性。
改变的条件:查询相同,但授权集合很小
延伸问题:可以临时去掉权限过滤确认是否有答案吗?
生产请求不能取消过滤。用具备合法测试权限的离线标注集,对比引擎前过滤与后过滤的召回行为,并记录有权证据是否被候选截断。确认过滤表达式与身份版本后,在授权范围内调整搜索模式或候选规模。空结果也可能表示可访问资料不足。
保持不变的原理:诊断不扩大数据访问边界,正确答案必须建立在允许读取的证据上。
依据公开技术资料设计;参考资料支持技术机制,场景与评分标准为本站设计,不代表某公司面试原题。 新增问答与迁移案例用于原理讲解,来源核查与案例运行验证分别记录。
读完后可以对照这些标准解释原理、边界和取舍。掌握程度由你自评;需要进一步验证时,再完成下方小任务。
把检索前过滤的思想迁移到记忆版本与恢复。观察撤销后已有草稿怎样失效。
python3 cli.py memory-put --db memory.sqlite
python3 cli.py submit --db memory.sqlite
python3 cli.py run --db memory.sqlite --lease-seconds 2 --fault after_draft
python3 cli.py memory-forget --db memory.sqlite
# 等待至少 2 秒后分别执行
python3 cli.py run --db memory.sqlite
python3 cli.py inspect --db memory.sqlite验证本地作用域、版本与撤销阻断;旧检查点仍保留,不提供日志、备份和检查点的彻底删除。
给出正确证据在候选第 30 名、上下文只取前 5 名的诊断。