Agentpath
原理29 / 31 节 · 预计 35 分钟

长期记忆与检索:什么该进提示词

记住一切等于什么都记不住。记忆系统的价值在于取舍。

学完这节你能做到

  • 区分会话内状态、项目知识与长期偏好三类记忆,各用不同存法
  • 设计一次检索注入,控制它占用的上下文预算
  • 避免记忆污染:过时的偏好比没有偏好更糟

「让 agent 记住一切」听起来很美。实际做出来的效果通常是: 它记住了三个月前的一条过时偏好,然后固执地按它执行。

记忆系统的难点从来不是存,是取舍

三类记忆,三种载体

把「记忆」拆开,很多问题会自动消失:

类型例子存哪生命周期
会话内状态这次任务改了哪些文件、当前进展会话本身(+ 压缩摘要)一次任务
项目知识用 bun 不用 npm、这个目录是生成产物AGENTS.md、skill、仓库文档跟着仓库
长期偏好「我要简短的回答」「先给结论」全局 AGENTS.md跨项目、很少变

看清这个划分之后会发现:大多数「需要记忆系统」的需求,其实是需要写文件。 项目知识写进仓库、偏好写进全局配置,两者都是纯文本、可审查、可 diff、可版本控制。

Pi 的做法正是如此:上下文文件从 ~/.pi/agent/AGENTS.md、 各级父目录、当前目录三处层叠加载。没有神秘的向量库,就是文件。

先用文件,撑不住了再上检索

文件方案的上限比多数人以为的高得多。当项目知识增长到「一份 AGENTS.md 放不下」时, 下一步是拆成多个 skill(按需装载),而不是直接上 RAG。

会话内状态:外置比压缩好

长任务里最有效的记忆手段特别朴素:让 agent 把进展写进文件

<!-- TODO.md,由 agent 自己维护 -->
## 目标
把 40 处 fetchLegacy( 换成 fetchV2(

## 进展
- [x] src/api/(31 处)—— 已改,typecheck 通过
- [ ] src/web/(12 处)—— 进行中
- [ ] tests/(4 处)

## 决定
- src/api/legacy-shim.ts 的 3 处**不改**:那是兼容层,语义不同

好处是压缩发生时这些信息不会丢 —— 摘要可能丢细节,文件不会。 Pi 的 compaction 摘要里也确实有 ## Progress## Next Steps 段落, 但能落到文件的东西就别指望摘要

iPi 也没有内置 TODO

「没有内置待办」是它明确列出的取舍之一,替代方案就是一个 TODO.md。 理由和这里一样:文件是可见、可编辑、可版本控制的,而内置状态不是。

什么时候真的需要检索

三个条件同时满足才值得上 RAG:

  1. 知识量远超上下文窗口(比如整个 wiki、几年的工单)。
  2. 每次任务只需要其中很小一部分
  3. 「哪一部分」无法提前确定(能确定的话,写 skill 让它按需读就行)。

不满足的常见情况:

  • 「几十页的内部文档」→ 拆成几个 skill,比向量库准得多。
  • 「代码仓库」→ grep 通常比语义检索准。代码检索的关键词是精确的。
  • 「最近几次会话的内容」→ 会话文件本身可以搜,不需要 embedding。

检索注入的三条纪律

真要做检索,把它当成「往上下文里花钱」来设计:

① 给它预算。 检索结果最多占多少 token,写死。 超了就砍条数,不要因为「相关度都还行」就全塞进去。

const MAX_INJECT = 3000
let used = 0
const picked = []
for (const doc of ranked) {
  if (used + doc.tokens > MAX_INJECT) break
  picked.push(doc); used += doc.tokens
}

② 带来源和时间。 每条注入内容标上出处和更新时间, 让模型能判断可信度,也让人能追溯:

[知识库 · 部署手册 · 更新于 2026-03-11]
预发环境的发布需要走 xxx 流水线……

③ 注入到消息里,不要注入系统提示。 又是缓存那件事 —— 检索结果每轮都不一样,塞进系统提示等于每轮缓存全废。 用 before_agent_start 返回 message 是对的位置。

记忆污染:比没有记忆更糟

一条三个月前的记录写着「部署用 deploy.sh」,而现在早就换成流水线了。 agent 拿着它反复出错,而且说得很有信心

四条防污染:

做法说明
带时间戳,并让模型看见「更新于 2026-03-11」会让它对旧信息保持怀疑
可失效给记忆条目设 TTL,或者绑定到某个版本/分支
单一事实来源同一件事只记一处。记两处,早晚不一致
写入要有门槛别让 agent 自动把每个结论都写成长期记忆

最后一条最容易被忽视。「自动记住有用的东西」听起来很智能,实际结果是 知识库里塞满了它当时的猜测。写入长期记忆应该是显式动作 —— 人说「记住这个」,或者至少有一道审阅。

×agent 自己写的记忆最危险

它记下的往往是「本次任务里的临时结论」,而不是普遍事实。 下一次任务里,这条临时结论会以「已知事实」的姿态出现, 而且没有任何标记提示它只是一次猜测。

一个务实的组合

绝大多数团队用这套就够,几乎不需要写代码:

全局 ~/.pi/agent/AGENTS.md   —— 个人偏好(10 行以内)
项目 AGENTS.md               —— 项目硬约束与事实(50 行以内)
skill                        —— 长流程、低频知识(按需装载)
TODO.md / 笔记文件           —— 长任务的进展外置
会话树 + /tree               —— 回到任意历史节点

真正需要向量检索的,通常是产品形态(比如接客服知识库), 而不是工程 agent 的日常。

检查点单选

团队有一份持续更新的「线上环境速查表」(各服务的域名、端口、负责人,约 200 行,每周都在变)。最合适的处理是?

这一节的结论

  1. 拆成会话内状态、项目知识、长期偏好三类,各用各的载体。
  2. 大多数「记忆」需求其实是「写文件」—— 可审查、可 diff、可版本控制。
  3. 长任务的进展外置到 TODO.md,别指望压缩摘要。
  4. RAG 的三个前提:知识量远超窗口、每次只用一小部分、无法提前确定是哪部分。
  5. 注入要有预算、带来源和时间、放在消息里而不是系统提示。
  6. 长期记忆的写入必须有门槛 —— agent 自动记下的临时结论是污染的主要来源。

延伸资料