Day 14 / 共 20 天 · 第 3 周 检索与查询

后处理与提示词(精修检索结果)

检索回来的 Node 在喂 LLM 前,常要"精修"——过滤噪声、重排、补上下文。今天讲后处理器(尤其 rerank,提升 RAG 准确率最有效的技巧之一)和提示词模板。

📍 你在整条链的位置
⑤ 检索(粗筛) 后处理(精排/过滤) ⑥ 合成 D13
L01

后处理的位置

🤔 检索回来的 top-k 都好吗? 检索器返回 top-k(比如 10 个),但这 10 个未必都好——有些相关度低、有些重复、有些需要补上下文。直接全喂 LLM 会引入噪声。
💡 后处理夹在"检索"和"合成"之间,负责"精挑细选" 回想 Day 12:QueryEngine 的 retrieve = 检索 + _apply_node_postprocessors好比初筛出 10 份简历,HR 再精挑 3 份。后处理是"两阶段检索"的精排阶段——对 RAG 质量提升显著。
L02

统一接口,可串成链

postprocessor/BaseNodePostprocessor:核心 postprocess_nodes(nodes, query_bundle) -> List[NodeWithScore]——输入一批带分数的 Node,输出精修后的。

读法:又是"输入 Node、输出 Node"的统一接口——多个后处理器能串成链(先过滤 → 再重排 → 再取窗口)。像流水线,一步步精修。
L03

相似度过滤:宁缺毋滥

SimilarityPostprocessor:按 similarity_cutoff 过滤——只留分数高于阈值的。

📝 减少幻觉 库里根本没相关内容时,top-k 可能都是"矮子里拔将军"(score 都很低,如 0.3)。
similarity_cutoff=0.7 → 低于 0.7 的全扔 → 如果全被扔光,说明"知识库里没答案"(比硬喂无关内容让 LLM 瞎编强)。
宁可少给,也不给无关的 给 LLM 无关内容 = 诱导它基于错误信息瞎答(幻觉)。相似度过滤守住这道门。
L04

rerank 重排:RAG 提效神器

🤔 向量检索快,但够准吗? 向量检索只看"向量相似",有时排序不够精。有没有办法既保召回、又保精度?
① 向量粗检索快,取 top-20(保召回) ② rerank 精排重排模型逐对精算相关度 ③ 取 top-5准(喂给 LLM) 20 个 5 个 两阶段检索:粗检索保召回(多拿点),精排保精度(选最好的) LLMRerank / CohereRerank / SentenceTransformerRerank(cross-encoder,比向量更准但慢)
两阶段检索:向量粗检索取 top-20(快、召回全)→ rerank 精排取 top-5(准)。
为什么这是"提效神器" 向量检索一步到位不够准;rerank 用专门的重排模型(cross-encoder)把"查询+每个候选"一起看、给出更准的相关度分。粗检索保召回、rerank 保精度——这是提升 RAG 准确率最有效的技巧之一。代价是 rerank 要额外调模型(慢/花钱),但值得。
L05

上下文窗口(回收 Day 02/04)

MetadataReplacementPostProcessor / PrevNextNodePostprocessor:配合 Day 04 的 SentenceWindow、Day 02 的 PREV/NEXT 关系,把命中的小块"扩展"成带上下文的内容。

💡 "命中一句,给出一段"——解决精度与上下文的矛盾 SentenceWindow 检索(Day04):用单句嵌入检索(精准命中),但单句上下文不够。MetadataReplacementPostProcessor 检索命中后,把内容替换成 metadata 里存的"前后窗口"(周围几句)——检索用小粒度(准),给 LLM 用大粒度(全)。
读法:回收 Day 02/04 埋的关系伏笔——PREV/NEXT 在这里派上用场。PrevNextNodePostprocessor 用关系取相邻块。这解决了"检索精度 vs 上下文完整"的经典矛盾。
L06

prompts:RAG 的"说明书"

prompts/PromptTemplate(字符串模板+变量)、ChatPromptTemplate(多轮消息模板)。默认 QA 提示词类似:

📝 默认 QA 提示词(简化) 以下是相关资料:\n{context_str}\n\n请只根据以上资料回答问题:{query_str}
运行时 {context_str} 填检索到的 Node 文本、{query_str} 填用户问题。
改提示词常有奇效(且便宜) LLM 怎么用检索内容答题,全看提示词怎么写。加一句"如果资料里没有就说不知道,别编",能大幅减少幻觉。调 RAG 效果时,改提示词比换模型便宜得多、见效快。refine 模式(Day 13)还有专门的"精炼提示词"。
L07

PromptMixin:一行换掉深层提示词

prompts/mixin.pyPromptMixin:让组件(检索器/合成器/查询引擎)能暴露和替换自己用的提示词——get_prompts() / update_prompts()

📝 把默认英文提示换成中文约束
query_engine.update_prompts({
    "response_synthesizer:text_qa_template":
        PromptTemplate("资料:{context_str}\n只依据资料用中文回答,没有就说'资料中未提及':{query_str}")
})
→ 一行改掉深层合成器的提示词,不用动源码。
读法:回收 Day 11 BaseRetriever(PromptMixin,...)——很多组件都 mix 了它。提示词工程在应用层灵活做,不必改框架。提示词是 RAG 最易调、最见效的杠杆。
L08

今日小结 + 动手

🧠 今天你应该能回答

  • 后处理在检索和合成之间做什么?为什么是"精排"?
  • 相似度过滤为什么能减少幻觉?
  • rerank(两阶段检索)为什么是提效神器?粗检索保什么、精排保什么?
  • 上下文窗口怎么解决"命中精度 vs 上下文完整"?提示词为什么最易调?

✋ 动手

cd /Users/bitmart/work/codes/github/llama_index/llama-index-core/llama_index/core
ls postprocessor/
grep -n "class SimilarityPostprocessor\|similarity_cutoff\|def postprocess_nodes" postprocessor/node.py | head
grep -n "DEFAULT_TEXT_QA_PROMPT\|class PromptTemplate" prompts/default_prompts.py prompts/base.py 2>/dev/null | head
明天预告 · Day 15(第 3 周收官):最后一块拼图——LLM 抽象。各家 LLM 怎么被统一封装(chat/complete/流式)、ChatMessage/角色、全局 Settings,以及工具调用(Agent 的基础)。
← Day 13 Day 15 · LLM 抽象 →