长期记忆
长期记忆用于长期保存未来可能值得回忆的过去,使 Agent 跨聊天会话持续继承过去的经历、背景、决定与未完成事项,而不是每次从零开始。
判断一件事是否值得记住:
如果未来某个交互不知道这件事,是否会丢失有意义的上下文——导致重复提问、重复决定、误解用户,或无法延续之前的进展?
不要因为一件事曾经出现过就记住它,也不要求它必须永久稳定才值得记住。值得记住的内容既可以是持续有效的知识,也可以是一次重要经历、某项决定、事情的发展过程,或尚未结束的上下文。
存储布局
长期记忆存放在两个地方:
.agents/nutstore-sync/memory/
├── archive/ # 权威记忆:每日一个 Markdown 文件
│ └── <YYYY>/<YYYY-MM-DD>.md
└── catalog/ # 检索目录:每年一个 TSV,可重建
└── <YYYY>.tsv
在 bash 文件系统中务必使用以下完整路径,不要构造其他变体:
/.agents/nutstore-sync/memory/archive/<YYYY>/<YYYY-MM-DD>.md/.agents/nutstore-sync/memory/catalog/<YYYY>.tsv
向用户提及记忆文件时,使用知识库相对路径 .agents/nutstore-sync/memory/...,不要带开头的 /。
权威性
- 每日记忆文件是唯一权威数据源。文件名
<YYYY-MM-DD>.md就是日期,也是稳定 ID;文件完整路径完全由日期唯一推导,一旦写入就永不重命名、永不移动、永不因任何分类而重组。 catalog/是派生检索目录。它只把每日文件 frontmatter 中的date与index原样集中复制。目录可删除、可重建,但绝不反向写回每日记忆文件。- 记忆文件都是普通 Markdown,用户可以随时阅读、修改或删除。
文件格式
每日一个 Markdown 文件:
---
date: <YYYY-MM-DD>
index: '检索摘要:覆盖当天记录的所有主题与关键内容'
---
## <YYYY-MM-DD>
- <一条记忆条目>
- <另一条记忆条目>
index 的硬性约束
- 只能占一行,必须用单引号或双引号包裹;
- 禁止包含制表符或换行(否则会破坏
catalog/<YYYY>.tsv的列结构); - 只写正文中真实存在的信息,不虚构;
- 不得为了简短而漏掉当天任何一个独立主题;
- 不复制整篇正文;
- 避免「进行了讨论」「确定了方案」「记录了问题」这类没有区分度的套话。
index 应该写什么
index 是给未来未知查询做全文匹配的检索摘要,不是标签列表。合格摘要应当包含:
- 人名、项目名、对象名、专有名词;
- 关键决定及其对象,关键数字、日期、状态;
- 遗留的问题、待办事项;
- 用户使用过的、以后的查询可能重新出现的具体说法。
未来查询未必使用总结出来的规范术语,大多使用具体名称或关键短语,因此摘要要保留这些可检索文本。
写入与冻结规则
- 当天文件:正文只允许追加;
index可随新条目反复重新生成(覆盖旧的index),但绝不删除或改写已有正文。 - 历史文件:本地日期跨日后,正文与
index一同冻结;之后普通维护不得修改历史文件。 - 历史文件就是最终储存地,不需要再次搬移归档。真正随时间变化的是检索入口(catalog),不是文件位置。
- 「纠正」和「忘记」是用户的专门请求,不受冻结规则限制(见「修正与遗忘」)。
年度检索目录(catalog)
catalog/<YYYY>.tsv 每年一个纯文本文件,一行对应一个记忆日:
<YYYY-MM-DD><TAB><index>
- 一行中的
index必须与该日文件 frontmatter 的index完全一致,不做二次总结。 - 生成时机:某个自然日结束、该日文件被冻结后,把该日的
date + index追加进对应年份的 TSV。 - 若跨日时没有运行,下次使用记忆功能时补做;先读取已存在的日期行,只补缺失的行,避免重复。
检索流程
检索始终由近及远、按顺序展开:
- 当前会话上下文:先使用会话已经带上的内容。
- 最近 30 天(插件注入):插件把最近窗口内每天的文件位置与
index直接带进上下文;若检索目标落在窗口内,直接读取当天文件。 - 全部历史目录:从用户描述中提取 1–3 个区分度最高的名称、对象或关键短语(专有名称、具体对象、关键动作、数字/日期),扫描年度目录:
grep -HniE '检索词a|检索词b|检索词c' /.agents/nutstore-sync/memory/catalog/*.tsv
候选行过多时,再做交集过滤:
grep -HniE '检索词a|检索词b' /.agents/nutstore-sync/memory/catalog/*.tsv | grep -iE '检索词c|检索词d'
- 读取原文:由命中行日期推导路径,读取当日完整记忆:
grep -n '' /.agents/nutstore-sync/memory/archive/<YYYY>/<YYYY-MM-DD>.md
需要更多背景时才读整个文件,不要无谓地把全部档案读入上下文。
未命中时的降级
catalog 不保证能命中所有自然语言提问(用户措辞可能不同)。未命中时按序降级:
- 扫描全部归档文件的原始 frontmatter
index行:
grep -RnE '^index:.*(检索词a|检索词b)' /.agents/nutstore-sync/memory/archive
- 仍未命中,才扫描正文——全库扫描是最后的恢复路径,低频、昂贵,不是日常检索手段:
grep -RniE '检索词a|检索词b|检索词c' /.agents/nutstore-sync/memory/archive
一旦上层找到正确文件,立即把对应日期行补齐/重建到 catalog/<YYYY>.tsv,让下次命中走正常索引路径。
重建 catalog
以下情况必须重建受影响年份的 TSV:
- 目录文件丢失或缺失日期行;
- 用户改动、删除或移动了历史记忆文件;
- 目录行的内容与文件
index不一致; - 检索结果指向不存在的文件;
- 执行过「修正与遗忘」之后。
重建只从日文件复制而来,不需要理解正文:
find /.agents/nutstore-sync/memory/archive/<YYYY> -name '*.md',列出该年份全部文件;- 逐个读取 frontmatter,取
date:与index:两行; - 拼成
<date><TAB><index>,重写catalog/<YYYY>.tsv。
修正与遗忘
- 纠正:尽量在历史文件外修正——在今天文件中追加一条更正记忆,用今天
index记下被纠正的主题与新的正确信息;召回时更新近的更正优先。 - 忘记:用户明确要求删除或遗忘目标记忆时,才允许删除或编辑对应历史内容;之后必须重建受影响年份的目录。
约束
- 只用 bash 工具集(find、grep、read/append、mv、mkdir)操作普通文本;不引入数据库、embedding、向量检索、搜索服务、知识图谱——这些都不是这个环境里的需求。
- 永远用日期文本或标题定位,不用行号(行号会漂移)。
- 记忆文件一旦写入就永不移动、永不重写;需要更正时按「修正与遗忘」处理。
- catalog 永远可重建,archive 永远不可覆盖。
综上:索引必须来自真实文件,检索链只能由近向远,降级路径不能成为常规路径。