一次记忆召回的控制流旅程 本节摘要:上一节画了四个组件的静态拓扑,本节让它们动起来——跟踪一次完整的「用户发问 → 记忆被召回 → 答复被沉淀」的控制流旅程。这次旅程分两个半场:前半场是「召回并答复」,Agent 的请求被代理层拦截,确定身份与场景,召回记忆,注入上下文,转发 LLM,返回答复;后半场是「回写并沉淀」,代理层把这次对话回写给核心服务,触发异步抽取 Pipeline,把对话提炼成 L1/L2/L3 记忆。本节是第 8 章八步管道的「预告版」,先用一节篇幅把全旅程的骨架立起来,让你在后续读源码精读时心里有这张路线图。
本节摘要:上一节画了四个组件的静态拓扑,本节让它们动起来——跟踪一次完整的「用户发问 → 记忆被召回 → 答复被沉淀」的控制流旅程。这次旅程分两个半场:前半场是「召回并答复」,Agent 的请求被代理层拦截,确定身份与场景,召回记忆,注入上下文,转发 LLM,返回答复;后半场是「回写并沉淀」,代理层把这次对话回写给核心服务,触发异步抽取 Pipeline,把对话提炼成 L1/L2/L3 记忆。本节是第 8 章八步管道的「预告版」,先用一节篇幅把全旅程的骨架立起来,让你在后续读源码精读时心里有这张路线图。
先看整条旅程的全貌,它天然分成「召回并答复」与「回写并沉淀」两段:
═════════════ 前半场:召回并答复(同步,用户在等) ═════════════ Agent发问 → 代理层拦截 → 确定身份场景 → 召回记忆 → 注入上下文 → 限流 → 转发LLM → 收到答复 → 返回Agent │ ═════════════ 后半场:回写并沉淀(异步,用户已走) ═════════════ ▼ 回写对话 → 触发抽取Pipeline → L1/L2/L3 逐层提炼 → 成为下次可召回的记忆
关键概念:前半场是「同步」的——用户在等答复,所以召回必须快(毫秒级,详见第 6 章召回预算);后半场是「异步」的——用户已经拿到答复走了,抽取可以在后台慢慢做。这个「同步召回、异步沉淀」的分工是整个系统的节奏基础。
跟踪前半场的每一站,先建立「站名 → 做什么」的映射:
| 站 | 动作 | 用时 | 失败会怎样 |
|---|---|---|---|
| 拦截 | 代理层截住 Agent 请求 | 即时 | 流量没进系统,Agent 报连接错 |
| 确定身份 | auth 换 user_id,sessionInit 定 team/agent/task | 毫秒级 | 无法确定权限范围,召回无的放矢 |
| 召回记忆 | 按权限范围 + 当前问题检索记忆 | 目标 < 200ms | 降级为无记忆答复(不阻塞) |
| 注入上下文 | inject 稳定内容 / toolize 易变内容 | 即时 | 上下文缺记忆,质量降级 |
| 限流 | TPM/QPM 滑窗检查 | 即时 | 触发限流则拒绝或排队 |
| 转发 LLM | 把注入后的请求发给真正 LLM | 取决于 LLM | LLM 故障则返回错误 |
| 返回 | 答复原路返回 Agent | 即时 | — |
前半场数据流(简化) Agent请求 ──▶ [拦截] ──▶ [确定身份] │ ▼ [召回记忆] ◀── 核心服务 + 知识服务 │ ▼ [注入上下文] ──▶ [限流] ──▶ [转发LLM] │ ▼ (LLM答复) ──▶ [返回Agent]
💡 技巧:前半场最关键的工程目标是「召回快」——用户在等。这就是为什么系统设计了两条注入策略(inject 命中 cache、toolize 按需调用)与召回预算(条数/字符/超时),都为了让前半场不拖慢响应。详见第 6 章与第 8 章。
「确定身份」这一站容易被忽略,但它是召回能否精准的前提。它确定的是一个三元组:
确定身份要定的三元组 team_id ── 你在哪个团队(决定能看到哪些 team 资产) agent_id ── 你是哪个 Agent(决定 Loadout 装配了什么) task_id ── 当前什么任务(可选,进一步缩小场景)
为什么召回前要先定这个三元组?因为第 3 章会讲的装配机制是「先按 Team/User/Agent/可见性缩小权限范围,再检索」。范围不定,召回就会把不该看到的记忆也取回来,既浪费上下文又有泄密风险。
代理层用一个交互式表单(sessionInit)来确定这个三元组——首次接入时它会问你「在哪个团队、用哪个 Agent、做什么任务」,确定后后续请求自动带上。详见第 8 章。
用户拿到答复走了,但旅程没结束。后半场在后台默默跑:
| 站 | 动作 | 节奏 |
|---|---|---|
| 回写 | 代理层把对话回写给核心服务 | 即时(不等用户) |
| L0 录制 | 对话作为 L0 原始上下文完整保存 | 即时 |
| L1 抽取 | 异步从 L0 抽事实/偏好/约束/事件 | 异步,秒级~分钟级 |
| L1 去重 | 新抽出的 L1 与已有 L1 去重 | 异步 |
| L2/L3 沉淀 | 围绕场景聚合、提炼画像 | 更慢,周期性 |
后半场数据流(异步) 对话结束 │ ▼ [回写] ──▶ [L0录制] ──▶ (异步触发) │ ▼ [L1抽取] ──▶ [L1去重] │ ▼ [L2场景聚合] / [L3画像提炼] │ ▼ (成为下次可召回的记忆)
⚠️ 注意:后半场的「异步」意味着——你刚说完一句话,立刻去查控制台,可能还看不到提炼后的 L1 Atom。这是正常的,不是没沉淀。抽取 Pipeline 需要时间(尤其用 LLM 做抽取时)。第 1 章验收时提到的「措辞不同的 L1」就是这条异步链跑完的结果。
一个常见误区是只关注前半场(召回让 Agent 变聪明),忽视后半场(回写让记忆持续生长)。但后半场才是「复利」的来源:
没有回写(只有召回) 每次对话都用旧记忆,记忆不增长 → 用着用着就过时了 有回写(召回 + 回写) 每次对话都产生新记忆 → 记忆持续生长 → 越用越聪明(复利)
这就是为什么代理层的八步管道里,extract(回写)是和 forward(转发)同等重要的一步——它不是「日志记录」,而是「记忆生长的入口」。这一点在第 11 章 Loop 复利场景里会成为核心论点。
旅程骨架已立。下一节用一张对照表,把这套系统与聊天历史、普通 RAG、Mem0 的差异钉死,让你彻底明白它填补的空缺。