Lab 07 — RAG 与上下文工程
预计 60–90 分钟。标注 ✅ 的步骤无需 API key;🔑 需要 ANTHROPIC_API_KEY。 示例 01/02 均已实跑验证通过(exit 0)。
Lab A:单路 vs 混合检索 ✅
- 运行
python3 examples/01_hybrid_vs_single_retrieval.py,观察逐查询表:BM25 在 TS-999 等 exact 查询全中,Vector 在 money back 等 semantic 查询跨词面命中。
- 对照聚合指标表:Hybrid 的 recall@5 / precision@5 / MRR 相对两路单路的变化。
- 修改
QUERIES:新增一条 exact 查询(如 "where is error code TS-777 documented")与一条 semantic 查询(如 "can I log in with my company account",golden 自选),重跑并预测哪路单路会失手、Hybrid 是否补上。
- 思考(读代码即可回答):
- 玩具 embedding 把未知 token 哈希到弱维度(
RARE_WEIGHT = 0.3)模拟了真实 embedding 的什么缺陷?(答:精确/罕见 token 被概念信号稀释——官方 TS-999 例子的机制。)
- RRF 融合为什么只看排名不看原始分数?(答:两路分数量纲不可比,排名天然可比。)
Lab B:分块策略对比 ✅
- 运行
python3 examples/02_chunking_strategies.py,对照两张表:
- 块统计:固定 10 块 → 重叠 14 块(膨胀代价);语义 30 块(碎块化风险);结构化 6 块(平均 68.8 词/块)。
- 检索评测:Structural hit@1 = 1.00,Semantic+上下文前缀 0.80,纯 Semantic 0.70,Fixed/Overlap 0.50。
- 找到逐查询明细里两条 context_loss 查询(
ACME revenue grow、Beta Systems ... security incident):解释为什么纯 Semantic 把它们排到第 3/第 12 名,而 Structural 与前缀策略能救回。
- 动手调参(文件顶部常量):
CHUNK_WORDS 40 → 25:观察「金标句被切断数」如何上升。
OVERLAP_WORDS 12 → 24:切断数下降但块数如何膨胀?
SEMANTIC_THRESHOLD 0.12 → 0.05:语义块变大变少(合并更多),0.3 则更碎。
- 思考:本实验用「节标题」近似情境前缀,官方 Contextual Retrieval 用什么生成前缀?为什么官方方案还要配 prompt caching?(答:廉价 LLM 读整篇文档+当前块生成 50–100 token 前缀;整篇文档进缓存一次,逐块生成才便宜——$1.02/百万文档 token。)
Lab C:检索指标手算 ✅(纸笔)
设金标相关块 R = {d1, d3},某系统 Top-5 返回顺序为 [d2, d1, d5, d3, d4]:
- 计算 Recall@5、Precision@5、MRR。
- 若 d1 的相关度是 3、d3 是 1、其余为 0,按 nDCG 的思路说明为什么 [d1, d2, d3, …] 的排序比 [d2, d1, d5, d3, …] 得分高(对数折损:排得越靠前增益越大)。
- 判断题:把 K 从 5 调到 5000,Recall@K 一定不降——为什么说这是「指标作弊」?(对照 Lab A 思考:recall 必须与 precision/nDCG 同看。)
(参考:Recall@5 = 2/2 = 1.0;Precision@5 = 2/5 = 0.4;MRR = 1/2 = 0.5。)
Lab D:真实 Citations 与情境前缀 🔑(可选进阶)
- 密钥通过环境变量提供,代码中不硬编码。官方 Python SDK 会自动读取环境变量
ANTHROPIC_API_KEY,因此最简写法根本不需要显式取值:
import anthropic
client = anthropic.Anthropic() # 自动读取环境变量中的密钥
(若在其他框架中需显式读取,仓库规范统一用 os.getenv("…") 形式。)
- 用 Messages API 构造带
document 块的请求,在文档块上设 "citations": {"enabled": true},问一个文档里有明确答案的问题;检查响应中的 cited_text 与出处指针。
- 验证官方计费行为:对比开启/关闭 citations 的
usage.output_tokens(cited_text 不计入输出 token)。
- 情境前缀迷你实验:取一份长文档的一个代词句(如 "The company's revenue grew by 3%..."),先单独问模型「这是哪家公司哪个季度的?」(预期:不知道/编造);再把整节标题链拼在句前重复提问(预期:能归属)。这就是 Contextual Retrieval 修复的「上下文丢失」。
- 注意约束:同一请求内所有文档块要么全开、要么全不开 citations;当前仅支持文本引用。
完成标准
- ☐Lab A:能口述 BM25/Vector 各自的系统性盲区与 Hybrid 为什么互补(RRF 只看排名)
- ☐Lab B:能口述四种分块策略的风险列、context loss 的成因与两种修复(标题链 / 情境前缀)
- ☐Lab C:能手算 recall/precision/MRR,并解释「recall 靠加大 K 作弊」
- ☐能口述官方三层改进数字链:上下文嵌入 -35% → +上下文 BM25 -49% → +reranking -67%(Top-20 检索失败率)
- ☐能口述「塞库 vs RAG vs agentic」的官方决策顺序与各自触发条件
📚 目录