a↗Agent 工程实战中文课程 / v1.0.0⌕ 搜索课程/
本页目录

M03 检索、上下文与记忆

本章产出:一个有权限过滤、来源引用和失败分解的检索链路,以及可测量的上下文预算策略。

1. 为什么“接了向量数据库”还会答错

用户问:“包裹在运输中,能直接退款吗?”检索器找到了包含“退款”的旧政策,模型认真引用了它,结论仍然错误。另一次检索拿到了当前政策,却属于另一商店;还有一次检索找对了政策,但上下文截断删掉了“仅适用于物流确认丢失”的限定。

这里分别是版本错误、权限错误和上下文选择错误。增加Embedding维度不能直接修复它们。RAG是从数据治理到答案证据的完整链路,而不只是相似度搜索。

2. 数据进入索引之前,先定义身份与版本

每个文档块保存doc_id、chunk_id、tenant_id、policy_version、有效时间、正文、来源以及访问控制标签。文档更新需要建立新版本并使旧索引失效,不能把旧政策的引用ID悄悄映射到新内容。

分块的目标是保留可独立理解的语义单元。退款条件与例外最好在同一个块里;过长的表格则保留表头与上级主题。复制太多重叠段落会浪费上下文,也可能让重复内容压倒其他证据。

查询时先根据认证身份限定可见文档,再在可见集合中检索。若后端只能全局检索后过滤,也必须保证不可见内容不进入日志、模型或缓存,并考虑过滤后召回不足。课程默认用先过滤的简单实现。

3. 用词法检索建立一个可解释基线

BM25用词频、文档长度和词的稀有程度对文档打分。一个常见形式是:

score(d,q) = Σ IDF(t) × tf(t,d)(k1+1) / [tf(t,d)+k1(1-b+b×|d|/avgdl)]

本课程选IDF(t)=ln(1+(N-df(t)+0.5)/(df(t)+0.5)),k1=1.2,b=0.75。这些是教学配置,不代表对中文售后最优。查询词在简单实现中去重,以免不小心重复累加。

中文分词必须明确。参考实现将连续中文串拆成双字片段,并保留拉丁字母/数字词元。这是为了无需外部依赖地复现实验,不是生产分词推荐。它会漏掉跨词的语义,正好作为后续优化对象。

先测试三个可解释问题:查询中“丢失”是否召回丢件政策?“还没收到”能否匹配同一概念?“退款”这个宽泛词会不会把例外条款挤出前列?不要跳过基线直接依赖复杂系统。

4. 混合检索与重排解决不同的问题

向量检索可以补充词面不同的语义匹配,但也可能把主题相近、条件不同的内容混在一起。词法检索容易精确命中订单号、错误码和产品名。二者可以通过排序融合组合。

本课程用倒数排名融合RRF举例:RRF(d)=Σ 1/(k+rank_i(d)),排名从1开始;缺席某列表贡献0。它不要求两种原始分数在同一尺度。课程互动默认k=60只是常见演示配置,不是调优结论。

重排器在小候选集合上重新判断相关性;它不能弥补候选集合里根本没有正确文档的情况。先测Recall@k,再测重排后的MRR或nDCG,最后测答案。不要只看一个端到端分数而不知道瓶颈在何处。

Anthropic的Contextual Retrieval提供了在索引时补充块级上下文的思路。课程扩展会让你比较原始块与带文档主题的块,但不照搬其报告的改进幅度。S04

I06 · 互动推演独立打开 ↗

亲手合并两个检索排名

用RRF融合排名而非不加校准地相加原始分。

合成教学数据 · 未运行真实模型
静态推演与完整规格

I06 亲手合并两个检索排名

关联章节:M03 · 交互类型:ranking-lab · 状态:提供纯逻辑参考函数,UI待实现

教学目标

用RRF融合排名而非不加校准地相加原始分。

初始状态

{
  "rankings": [
    [
      "A",
      "B"
    ],
    [
      "B",
      "C"
    ]
  ],
  "k": 60
}
操作控件
  • 调整每份排名顺序

  • 修改k(0–100整数)

  • 添加重复文档

  • 计算逐项贡献

  • 重置

状态变化规则
  • 每份榜单文档只计第一次出现;rank从1开始。

  • 显示每份贡献和总分,按总分降序、ID升序稳定排序。

黄金案例与反馈
base

输入:


{
  "rankings": [
    [
      "A",
      "B"
    ],
    [
      "B",
      "C"
    ]
  ],
  "k": 60
}

期望:


{
  "order": [
    "B",
    "A",
    "C"
  ],
  "B": 0.03252247488101534
}

B分别在两榜第2/第1,因此两份贡献相加。

duplicate

输入:


{
  "rankings": [
    [
      "A",
      "A"
    ]
  ],
  "k": 60
}

期望:


{
  "A": 0.01639344262295082
}

同一榜单重复出现不增加信用。

完成条件
  • 算出B的两个分量

  • 解释重复条目处理

反馈层次
  • 提交预测后显示结果;允许跳过预测但记录跳过,不阻止阅读

  • 结果同时显示状态变化、原因与被拒绝动作;不是只给红绿灯

  • 第一次错误给边界提示,第二次提供最小反例;参考推导始终可主动打开

  • 重置恢复固定初始状态并保留历史尝试供用户手动清除

无障碍与静态替代
  • 全部操作有原生button/input/select替代,不依赖拖拽

  • 图与动画提供同步文字状态表;支持prefers-reduced-motion

  • 状态改变用aria-live=polite摘要,不逐字朗读长日志

  • 焦点不跳走;错误提示关联输入;颜色不是唯一编码

无JavaScript时直接展示初始输入、规则和黄金案例表,读者仍能完成纸面推演。状态动画仅作解释,不能成为获取答案的唯一途径。

持久化与重置

使用版本化键agent-course:1:I06,仅保存本地学习状态。支持单卡重置和全站清除;存储失败时以内存模式继续,不阻断阅读。

必须避免的误导

第二份榜单是教学输入,不伪称真实embedding结果。

执行边界

纯本地教学状态机;不执行任意代码,不连接真实资金/模型/宿主Shell。

逻辑参考

web/reference/engines.mjs中的rrf;对应测试在web/reference/engines.test.mjs。UI可复用或等价移植,但不得改变黄金结果。

5. 有引用,不等于被证据支持

“引用了P02”只能证明系统输出了一个标识,不能证明结论由P02支持。我们分别检查证据存在、权限允许、版本有效、语义支持,以及引用粒度是否足够定位原文。

对于“物流仍在运输中”,正确回答应该引用当前政策的条件,指出当前订单尚不满足丢件退款条件,并说明可采取的下一步。它不应把“运输中可能丢失”偷换成“已确认丢失”。

回答找不到证据时,允许明确说明不足或请求澄清。不能要求模型每次都给确定结论,同时又惩罚所有合理拒答。

6. 上下文预算是一项调度决策

设可用上下文上限为W,系统与工具定义占S,保留的历史占H,检索证据占R,预计输出预算占O,安全余量为M,则必须满足S+H+R+O+M≤W。真实token数与具体模型分词器有关;网页卡片中的token值是固定教学输入,不用中文字符数冒充实际token。

给你1200个输入预算,候选内容包括:当前订单事实200、有效政策300、用户明确限制100、旧工具输出700、历史寒暄400。最便宜的策略不是把所有内容等比例缩短,而是保留决定动作正确性的事实,先去掉无关或可重新获取的内容。

压缩不能改变事实优先级。摘要里“用户同意退款”不是审批记录;摘要里的订单余额也不是执行时的最终余额。业务事实应该在需要写操作时重新读取与验证。

I07 · 互动推演独立打开 ↗

上下文预算分配台

在有限预算下保留不可丢失状态并标出压缩代价。

合成教学数据 · 未运行真实模型
静态推演与完整规格

I07 上下文预算分配台

关联章节:M03 · 交互类型:budget-composer · 状态:提供纯逻辑参考函数,UI待实现

教学目标

在有限预算下保留不可丢失状态并标出压缩代价。

初始状态

{
  "budget_units": 100,
  "blocks": [
    {
      "id": "rules",
      "size": 20,
      "required": true
    },
    {
      "id": "task",
      "size": 15,
      "required": true
    },
    {
      "id": "pending_op",
      "size": 15,
      "required": true
    },
    {
      "id": "evidence",
      "size": 30,
      "required": false
    },
    {
      "id": "old_logs",
      "size": 70,
      "required": false
    }
  ],
  "selected": [
    "rules",
    "task",
    "pending_op",
    "evidence"
  ]
}
操作控件
  • 选取/移除块

  • 将旧日志压缩到15单位

  • 预算滑块50–150

  • 检查约束

  • 查看丢失事实警告

状态变化规则
  • 预算单位是教学长度单位,不是Provider token。

  • 必需块不可无声删除;允许尝试但显示硬失败。

  • 压缩旧日志会生成派生块并保留来源,不代表语义保真已证实。

黄金案例与反馈
base

输入:


{
  "selected": [
    "rules",
    "task",
    "pending_op",
    "evidence"
  ]
}

期望:


{
  "used": 80,
  "feasible": true
}

余量20;是否有足够证据仍要任务评测。

all

输入:


{
  "selected": [
    "rules",
    "task",
    "pending_op",
    "evidence",
    "old_logs"
  ]
}

期望:


{
  "used": 150,
  "feasible": false
}

超预算50。

drop-op

输入:


{
  "selected": [
    "rules",
    "task",
    "evidence"
  ]
}

期望:


{
  "used": 65,
  "feasible": false,
  "missing": [
    "pending_op"
  ]
}

更短却丢失未确认操作状态。

完成条件
  • 找到一份可行上下文

  • 演示省长度但破坏不变量的方案

反馈层次
  • 提交预测后显示结果;允许跳过预测但记录跳过,不阻止阅读

  • 结果同时显示状态变化、原因与被拒绝动作;不是只给红绿灯

  • 第一次错误给边界提示,第二次提供最小反例;参考推导始终可主动打开

  • 重置恢复固定初始状态并保留历史尝试供用户手动清除

无障碍与静态替代
  • 全部操作有原生button/input/select替代,不依赖拖拽

  • 图与动画提供同步文字状态表;支持prefers-reduced-motion

  • 状态改变用aria-live=polite摘要,不逐字朗读长日志

  • 焦点不跳走;错误提示关联输入;颜色不是唯一编码

无JavaScript时直接展示初始输入、规则和黄金案例表,读者仍能完成纸面推演。状态动画仅作解释,不能成为获取答案的唯一途径。

持久化与重置

使用版本化键agent-course:1:I07,仅保存本地学习状态。支持单卡重置和全站清除;存储失败时以内存模式继续,不阻断阅读。

必须避免的误导

不自动推断任务成功率;这张卡只检查预算与必需信息。

执行边界

纯本地教学状态机;不执行任意代码,不连接真实资金/模型/宿主Shell。

逻辑参考

web/reference/engines.mjs中的contextBudget;对应测试在web/reference/engines.test.mjs。UI可复用或等价移植,但不得改变黄金结果。

7. 四种上下文策略,怎样公平比较

Full history保留全部记录,作为小任务基线;Sliding window只保留最近若干轮,简单但可能丢掉早期约束;Summary compaction把较早内容压缩成结构化摘要,有额外模型费用和信息失真风险;Observation masking用受授权的引用替换较老的大工具结果,需要支持按需重新读取。

比较时固定任务、模型配置和总预算,至少记录成功率、输入/输出token、摘要费用、重新检索次数与总延迟。若摘要策略降低每轮token却导致更多轮调用,总成本仍可能上升。

上下文工程强调持续选择进入模型的信息,是一个有用的分析视角;“长上下文必然差”或“摘要必然提升效果”都不是本课程结论。S03

8. 记忆不等于把聊天记录永远保存

任务内状态、会话记忆和跨会话偏好应该分开。临时订单事实有时效;用户偏好需要来源和更正机制;授权记录由业务系统保存;原始工具输出可能包含敏感信息,不能默认写入长期向量库。

一个长期记忆对象可以包含subject、fact、source、observed_at、expires_at和confidence。但confidence不是真实性证明。发生冲突时要按数据权威、时间和用户更正处理,而不是简单选择相似度最高的记忆。

跨租户共享记忆默认禁止。删除原文后,相应索引、摘要和缓存也需要明确的失效策略。课程测试通过两个租户的相似订单验证这一边界。

9. 完成标准

L03要求先实现确定性词法基线,再用预先给定的第二组排名演示RRF;真实Embedding属于可选扩展,不能把给定排名当成已跑模型的成绩。报告至少一个召回失败、一个版本错误和一个上下文丢约束案例。

你需要能够解释:检索失败与生成失败如何区分,为什么权限过滤在模型之前,为什么会话摘要不能授权退款,以及压缩如何可能增加而不是减少总成本。

K03 · 上下文是一份工作集,不是全部历史

K03 上下文是一份工作集,不是全部历史

类型:上下文工程 · 关联章节:M03 · 阅读方式:先做下面的推演,再看参考讨论。

原文在说什么

原文将上下文工程视为管理模型可用信息的过程,讨论选择、压缩与外部状态等策略。

对本课程的具体启发(课程推论)

类比有限工作集:持久事实留在数据库,模型只拿本轮必要状态、证据和工具定义。压缩可以降低输入,但压掉未确认操作状态可能制造重复副作用。

两分钟推演

给一个超预算上下文排序:系统约束、当前请求、有效审批摘要、十页旧工具日志、证据ID、已确认操作结果。说明哪些可以摘要,哪些应保留引用。

参考讨论

约束与当前任务不可随意删;审批与未确认操作必须有权威外部记录并在当前决策中可见;冗余日志可裁剪,关键证据保留可取回引用。

不能从这里推出什么

更短不等于更好。摘要模型可能遗漏事实,应测任务完成率与错误类型。

原始来源

本卡是原创中文概括与教学延伸,不是全文翻译,也不表示原作者认可本课程。不要把原文中的结果替换成本项目实测结果。

独立阅读 →
K04 · Contextual Retrieval不是把整个文档塞给模型

K04 Contextual Retrieval不是把整个文档塞给模型

类型:检索扩展 · 关联章节:M03 · 阅读方式:先做下面的推演,再看参考讨论。

原文在说什么

原文介绍为文档块补充局部上下文以改善检索的思路,并结合词法和向量检索讨论。

对本课程的具体启发(课程推论)

本课程的政策片段先解决租户、有效版本与来源标识,再考虑增加“这段属于哪份政策”的上下文。对商店规则,失效版本过滤比模型写得好看的摘要更先决。

两分钟推演

对“七日内可退”补写不超过两句的块上下文,包含商品范围、政策版本和时间参照;禁止增加原文没有的规则。

参考讨论

上下文应解释“自签收起七日、未拆封、policy-v2”,而不是凭空补充“所有商品随时可退”。元信息可直接由可信字段生成。

不能从这里推出什么

原文实验结果不等于你的语料收益;额外预处理有成本,也可能把错误上下文传播给检索。

原始来源

本卡是原创中文概括与教学延伸,不是全文翻译,也不表示原作者认可本课程。不要把原文中的结果替换成本项目实测结果。

独立阅读 →
做当章练习 →