给 Pi Agent 补一套跨会话记忆:pi-hermes-memory 安装与使用教程
Pi 默认不记跨会话。本文基于 pi-hermes-memory 0.9.8,讲清楚它怎么把记忆、会话搜索和 Skills 分开,并给出可以直接跑通的安装、索引、检索和配置步骤。
Pi 的核心故意不内置记忆。会话一关,上一次你说过的偏好、项目约定、和那些已经踩过的坑,默认都不会带到下一个会话。
这不是缺陷,是定位。Pi 把记忆、MCP、Sub-agent 都留给插件。但对于长期维护同一个项目的人来说,每次重新解释「用 pnpm、别用 npm」很快就会累。
pi-hermes-memory 就是来补这块的。它把 Nous Research Hermes Agent 的记忆设计搬到 Pi:持久记忆、会话搜索、程序化 Skills、纠错检测和背景学习循环。当前 npm 包是 0.9.8,GitHub 上已经 400+ star。
我之前推荐过 @fradser/pi-memory。那个更轻,适合只想把项目约定写进 Markdown。pi-hermes-memory 更重:它不只存事实,还能搜旧会话、从失败里学东西、把解法存成 Skill。
本文基于
pi-hermes-memory 0.9.8和 Pi>= 0.80.6。扩展迭代很快,安装前建议对一下 README 和 CHANGELOG。
先看结论
这个扩展把知识分成三层,不要混在一起:
| 层 | 存什么 | 怎么进上下文 | 适合什么 |
|---|---|---|---|
| 持久记忆 | 事实、偏好、纠错、工具坑 | 默认按需搜索,不塞 System Prompt | 跨会话仍然成立的东西 |
| Skills | 可复用流程 | 描述可发现,正文按需读 | 怎么做某一类事 |
| 会话搜索 | 历史对话 | 只有搜的时候花 Token | 「上周我们讨论过 auth 吗?」 |
还有一个专门层:Standing Instructions。它不是记忆,是你亲手钉上去、每个会话都会注入的硬规则。禁止类指令要放这里,不要寄希望于模型自己去搜。
最小使用路径就三步:
pi install npm:pi-hermes-memory
然后在 Pi 里:
/memory-index-sessions
/memory-interview
/learn-memory-tool
它到底解决什么问题
Pi 会话是 JSONL 事件树。历史会留在磁盘上,但新会话不会自动把旧对话塞进 Prompt。这对于 Agent Harness 是对的:上下文有预算,不能把一年的聊天记录都带上去。
缺的是三件事:
- 事实不能跨会话。 你用 pnpm、不要写 CHANGELOG、测试放
__tests__/,这些东西不应该每次重说。 - 过程不会留下来。 Agent 花了 40 次工具调用才搞定一个 Bazel 问题,下次又从零开始。
- 旧会话不能查。 「我们上周讨论过登录流吗?」这句话在原生 Pi 里没有答案。
pi-hermes-memory 的做法是:Markdown 作人可读的真源,SQLite FTS5 作按需检索,Skills 作程序化知识。默认 policy-only:System Prompt 只注入「什么时候该搜记忆」的策略,不把整份 MEMORY.md 塞进去。第一轮 Token 保持低,记忆仍然能用。
安装
全局安装:
pi install npm:pi-hermes-memory
或者从 GitHub 安装:
pi install git:github.com/chandra447/pi-hermes-memory
安装后重启 Pi。升级旧版本时,启动会自动迁移旧目录:
~/.pi/agent/memory→~/.pi/agent/pi-hermes-memory- 旧的平铺 Skills 会改成 Pi 原生的
skills/<slug>/SKILL.md
不用手动搬。
Homebrew / Node ABI 不匹配
这个扩展依赖 better-sqlite3。Pi 如果是 Homebrew 装的,而扩展是另一个 Node ABI 编出来的,会话搜索可能报:
was compiled against a different Node.js version using NODE_MODULE_VERSION ...
扩展会尝试自动 npm rebuild better-sqlite3。仍失败就手动一次:
cd ~/.pi/agent/npm/node_modules/better-sqlite3
npm rebuild better-sqlite3
更稳的做法是 Pi 和扩展都用 npm 安装,共享同一个 Node。
第一次打开 Pi 之后做什么
不要一开始改配置。先把历史会话索引进去,再把自己介绍一下。
/memory-index-sessions
这会把 ~/.pi/agent/sessions/ 里已有的 JSONL 导进 SQLite FTS5。之后才能问:
上次我们讨论过 auth 吗?把关键结论找出来。
接着填用户档案:
/memory-interview
它会问几个短问题,写进 USER.md。名字、沟通偏好、主要技术栈,这些东西应该由你说,不要让模型猜。
最后让 Agent 自己读一遍使用说明:
/learn-memory-tool
如果你以前就在 Markdown 里手写过记忆,再补一次:
/memory-sync-markdown
这会把旧 Markdown 条目回填到 SQLite,memory_search 才能找到它们。
记忆、用户档案、Skills,三个不同的盒子
别把所有东西都写进 MEMORY.md。
| 盒子 | 文件 | 写什么 | 限制 |
|---|---|---|---|
| memory | MEMORY.md | 环境事实、项目约定、工具坑 | 导出 5000 字符 |
| user | USER.md | 你是谁、怎么聊、喜欢什么风格 | 导出 5000 字符 |
| project | projects-memory/<project>/MEMORY.md | 只对这个仓库成立的事 | 导出 5000 字符 |
| failure | 分类记忆 | 失败、纠错、insight、约定、工具坑 | 可搜索 |
| skills | skills/<slug>/SKILL.md | 怎么做某一类事 | 无限 |
| standing | STANDING.md | 你亲手钉的硬规则 | 20 条 / 2000 字符 |
全局记忆在 ~/.pi/agent/pi-hermes-memory/,项目记忆在 ~/.pi/agent/projects-memory/<project>/。都是普通 Markdown,可以直接打开改。
一条记忆应该短、单一、可验证。「今天改了三个文件」不要存。「这个仓库用 pnpm,npm install 会打破 lockfile」才应该存。
纠错会马上写入
你说「不要这样」、「用 yarn 而不是 npm」、「我说了用 pnpm」时,扩展会尝试立即存一条 correction,不等到 10 轮后的背景回顾。
这是它比普通记忆插件更有用的地方。你不用把同一个错误讲三遍。
背景学习不是每句话都存
默认每 10 个 turn,或者每 15 次工具调用,扩展会回顾当前对话,把值得留下的东西写进记忆。会话结束或上下文压缩前还会 flush 一次。
这些回顾会多花一次 LLM 调用。可以用 llmModelOverride 指定一个更便宜的模型,不要让回顾跟主会话抢同一个贵的模型。
禁止类规则要钉住,不要寄希望于搜索
policy-only 有一个结构性限制:一条记忆只有在 Agent 先搜到它 时才会生效。对于偏好这没问题——搜不到就用默认风格,代价不高。对于禁止就不行了。
「从来不要对 / 跑 find」这种规则,模型在准备跑命令的那一刻,恰好没有理由去搜记忆。
解法是 /memory-pin:
/memory-pin never run find / or other root-wide filesystem searches
/memory-pin
/memory-pin remove 2
/memory-pin clear
钉住的规则写进 STANDING.md,每个会话都注入。背景回顾、合并、纠错检测 都写不进这个文件。只有你的编辑器或 /memory-pin 能改它。
硬限额是 20 条 / 2000 字符。超了会被截断,并且会在注入块里明说省略了什么。
想看当前会话真正注入了什么:
/memory-preview-context
Pi 的 TUI 不显示 System Prompt。这是唯一能直接看到记忆策略和 standing 块的方法。
Skills:把解法存成流程
记忆存事实。Skills 存步骤。
一个复杂任务跑完后(单轮 8 次以上工具调用、至少 2 种不同工具),扩展会问你要不要存一份可复用流程。Agent 也可以在正常工作里调 skill_manage,不用等自动提示。
Skills 分两个范围:
- global:
~/.pi/agent/pi-hermes-memory/skills/<slug>/SKILL.md,跨项目可用 - project:
~/.pi/agent/projects-memory/<project>/skills/<slug>/SKILL.md,只在这个仓库
它们不和你自己安装的 ~/.pi/agent/skills/ 混在一起。这是 0.9.1 之后刻意回到的设计:扩展写出来的流程,可以整批审计或清掉,不会误删你手装的 Skill。
管理界面:
/memory-skills
支持模糊搜索、多选、批量移到全局或当前项目、批量删除。g 移到全局,p 移到项目,d 删除。
项目 Skill 通过 Pi 的 resources_discover 被发现。刚创建或刚移动的项目 Skill 如果当前会话看不到,/reload 或开新会话就行。
常用命令
| 命令 | 作用 |
|---|---|
/memory-insights | 看当前记忆和用户档案 |
/memory-skills | Skills 管理 TUI |
/memory-consolidate | 手动合并,释放 Markdown 空间 |
/memory-interview | 初次填用户档案 |
/memory-switch-project | 列出所有项目记忆 |
/memory-index-sessions | 批量索引旧会话 |
/memory-sync-markdown | 把 Markdown 记忆回填到 SQLite |
/memory-preview-context | 预览注入到 Prompt 的内容 |
/memory-pin | 钉住 / 列出 / 删除 standing 规则 |
/learn-memory-tool | 教 Agent 怎么用这套记忆 |
平时不用手动调工具。你直接说「记住这个仓库用 pnpm」、「以前我们怎么处理过登录过期」,Agent 会自己决定是 memory_add 还是 session_search。
你真正需要改的配置
配置文件在 ~/.pi/agent/hermes-memory-config.json。默认就能用。我建议只改这几项:
{
"memoryMode": "policy-only",
"standingInstructionsEnabled": true,
"llmModelOverride": "openrouter/deepseek/deepseek-v4-flash",
"llmThinkingOverride": "off",
"nudgeInterval": 10,
"nudgeToolCalls": 15,
"flushOnShutdown": true
}
memoryMode 不要改回 legacy-inject,除非你明确想把整份记忆塞进 System Prompt。那会每轮都花 Token,而且记忆越长越容易和当前任务冲突。
llmModelOverride 很有用。背景回顾、纠错保存、会话 flush、合并都走这个模型。主会话用贵的编码模型,回顾用便宜的快模型,费用差异会很快显出来。
其他常用项:
| 项 | 默认 | 什么时候改 |
|---|---|---|
sessionRetentionDays | 0 | 会话很多时设正整数天数,只清 SQLite 行,不删 JSONL |
quickCheckOnOpen | true | 启动慢可以关,运行时的损坏恢复仍在 |
reviewEnabled | true | 不想花回顾 Token 就关 |
correctionDetection | true | 一般不建议关 |
排查生命周期延迟可以带这个环境变量启动:
PI_TIMING=1 pi
它会把启动同步、回填、flush、数据库打开的耗时打到 stderr。
数据放在哪
~/.pi/agent/
├── pi-hermes-memory/
│ ├── MEMORY.md
│ ├── USER.md
│ ├── STANDING.md
│ ├── sessions.db
│ └── skills/<slug>/SKILL.md
├── projects-memory/<project>/
│ ├── MEMORY.md
│ └── skills/<slug>/SKILL.md
└── hermes-memory-config.json
Markdown 条目用 § 分隔。不要在记忆正文里写这个符号,否则重载会被拆成两条。
sessions.db 是 SQLite,存会话索引和记忆镜像。Markdown 仍然是人可读的真源;SQLite 满了不会偷偷把写失败的 Markdown 溢出去。policy-only 下 SQLite 是查询主体,写入可以超过 Markdown 导出上限;legacy-inject 仍然受 5000 字符限制。
每次写入都会走内容扫描:API Key、Token、SSH 私钥、提示注入、角色劫持都会被拦下。这是它和「把聊天记录 dump 进一个文件」最大的区别之一。
容易踩的坑
1. 中文搜索要三个字以上
FTS5 用 trigram tokenizer。一个字、两个字的 memory_search 可能搞不到。查中文记忆时用更长的短语,或者带一个英文 token。
2. 旧会话不索引就搜不到
安装后必须跑一次 /memory-index-sessions。之后的新会话会自动索引,不用每次手动导。
3. 搜不到 Markdown 里明明有的东西
先跑 /memory-sync-markdown。如果 FTS 索引坏了,工具结果会告诉你搜索降级了,并给修复命令,不会再装成「成功写入 0 条」。
4. Standing 不是工具拦截
/memory-pin 只是注入指令。真正要拦一个危险命令,还是要写 tool_call guard 或者用操作系统层隔离。
5. 不要和 @fradser/pi-memory 同时开
两个扩展都会给 Agent 加记忆工具和回顾逻辑。同时开会重复写入、重复花 Token、出了问题也难判断是谁在管。选一个就行。
我的区分很直接:
- 只想记住项目约定,并把安全的技术信息镜像到仓库
.memory/→@fradser/pi-memory - 想要会话搜索、纠错学习、Skills 积累、standing 规则 →
pi-hermes-memory
一个可以直接照着跑的工作流
第一天:
pi install npm:pi-hermes-memory
/memory-index-sessions
/memory-interview
/memory-pin 不要对用户主目录跑 find,也不要把凭据写进记忆
接下来几天正常用 Pi。你纠正 Agent 时,它会自己存 correction。复杂任务结束后,它会问你要不要存 Skill。
一周后检查一次:
/memory-insights
/memory-skills
/memory-preview-context
把没用的 Skill 删掉,把错误的记忆改掉。记忆系统的质量取决于你有没有定期看一眼,不是取决于它能不能自动存。
最后
Pi 不内置记忆,是因为记忆有很多种合理实现。pi-hermes-memory 选的是 Hermes 那一路:事实当成可搜索的 Markdown,流程当成 Skill,历史对话当成 FTS 索引,禁止当成用户亲笔的 standing 规则。
它不会让 Agent 变得更聪明。它只是把你已经花过的代价,留到下一个会话还能用。
装完之后最有用的一件事,不是把配置项都改一遍,而是跑一次 /memory-index-sessions,再钉一两条你真正不想重复的规则。