召回:注入两区块 prepend / append 本节摘要:SDK 四步的第一步「召回」,核心不只是「取回记忆」,还要「正确地放进上下文」。本节讲清注入的两区块布局:prepend 区(放动态 L1,在用户消息之前)与 append 区(放稳定 persona/scene/工具指南,在末尾)。这种布局的精妙在于——稳定的 append 区命中模型的 KV cache(因为它在末尾不动),动态的 prepend 区虽变但不影响 cache。理解这个布局,你就理解了第 8 章 inject 策略在 SDK 里的具体落地。 一、注入不只是「塞进去」,还要「放对位置」 召回回来的记忆,不能随便找个地方塞。
本节摘要:SDK 四步的第一步「召回」,核心不只是「取回记忆」,还要「正确地放进上下文」。本节讲清注入的两区块布局:prepend 区(放动态 L1,在用户消息之前)与 append 区(放稳定 persona/scene/工具指南,在末尾)。这种布局的精妙在于——稳定的 append 区命中模型的 KV cache(因为它在末尾不动),动态的 prepend 区虽变但不影响 cache。理解这个布局,你就理解了第 8 章 inject 策略在 SDK 里的具体落地。
召回回来的记忆,不能随便找个地方塞。它在上下文里的位置,直接影响 KV cache 命中与推理效果:
注入位置的影响 上下文结构(简化): [system prompt] [记忆?] [用户消息...] [记忆?] 记忆放不同位置,效果不同: 放在用户消息之间(中间) → 每轮用户消息变,中间记忆位置变 → cache 失效 放在末尾(append) → 末尾稳定不动 → cache 命中 放在开头(prepend) → 开头稳定 → 部分命中
这就是为什么 SDK 要区分 prepend 和 append 两个区块——不同特性的记忆放不同位置,优化 cache 命中。
prepend 区放在用户消息之前,适合「动态但相关」的内容,主要是 L1:
prepend 区的内容 适用:L1 原子(与当前问题动态相关的具体事实) 位置:用户消息之前 [system prompt] [append 区:稳定内容] [prepend 区:与本次问题相关的 L1] ← 这里 [用户当前消息] 特点:随问题变化(每次召回的 L1 不同)
prepend 区的内容是「为当前问题量身召回」的 L1,所以每轮可能不同。它放在用户消息之前,让模型先看到相关事实再处理用户问题。
关键概念:prepend 区虽在用户消息前,但因为「system prompt + append 区」在它更前面且稳定,所以前面那部分仍能命中 cache。只有 prepend 区本身及其后是变化的——这是「部分命中」的折中。
append 区放在上下文末尾,适合「稳定、每次都要」的内容:
append 区的内容 适用:L3 persona、L2 场景、Skill、工具使用指南 位置:上下文末尾 [system prompt] [append 区:persona + scene + skill + 工具指南] ← 这里(末尾) [prepend 区:动态 L1] [用户消息] 特点:稳定(不每轮变),命中 cache
| 区 | 内容 | 稳定性 | cache |
|---|---|---|---|
| append | persona/scene/skill/工具指南 | 稳定 | 命中 |
| prepend | 动态 L1 | 随问题变 | 部分命中 |
append 区放末尾的设计,与第 8 章 inject 策略呼应——稳定内容享受 cache。这就是「注入两区块」与「inject 策略」的对应:append 区约等于 inject 的稳定部分,prepend 区是动态补充。
两区块布局的 cache 优化逻辑,展开看:
KV cache 的命中逻辑(简化) 模型推理时,从前往后算 KV,遇到「没变的前缀」就复用 cache 上下文:[system][append稳定][prepend动态][用户消息] 第 N 轮 vs 第 N+1 轮: [system][append稳定] → 没变 → cache 命中 ✓ [prepend动态] → 变了(召回不同L1) → 此处起 cache 失效 [用户消息] → 变了 → 失效 → 稳定前缀部分命中,只有动态部分失效 → 推理快
如果把稳定内容放中间、动态放末尾,稳定部分会被动态变化「打断」,cache 命中率下降。两区块布局把稳定内容尽量放「连续的前缀」,最大化 cache 命中。
💡 技巧:这就是为什么 append 区放末尾而非开头——看似奇怪(末尾不通常是「结论」吗),但 cache 优化的逻辑要求稳定内容形成连续前缀。理解 KV cache 的「前缀连续命中」原理,你就理解了注入布局的所有细节。
两区块布局之外,还要控制注入的总大小——这与第 6 章召回预算、第 8 章 injection 大小控制一脉相承:
注入大小控制(SDK 视角) 召回结果(经预算裁剪后) ↓ 分配到 prepend / append 两区 ├─ append 区:稳定内容,大小相对固定(有上限) └─ prepend 区:动态 L1,大小随召回变化(有上限) ↓ 总注入不超过预设阈值(如 system prompt 后总 token 数限制)
| 控制点 | 目的 |
|---|---|
| append 区上限 | 稳定内容也别太多,留空间给用户对话 |
| prepend 区上限 | 动态 L1 召回再多也只取最相关 |
| 总注入阈值 | 保证不挤掉用户问题与代码 |
这与第 6 章召回预算的「条数/字符」控制是同一思想——记忆再多,注入都要受控,避免挤掉真正重要的内容。
召回与注入清楚后,下一节看第二步——捕获,对话如何回写,以及工具如何暴露。