Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

一个 AI 的记忆

你可能遇到过这种情况

你正在用 AI 编程助手开发一个项目。第一天的会话里,你花了半小时向 AI 解释:

  • 项目用的是 Rust + Axum 技术栈
  • 数据库用的 DuckDB 而不是 PostgreSQL
  • 认证模块用的 JWT,不是 Session
  • 部署目标是 ARM 架构的嵌入式设备

AI 听懂了,帮你写了完美的代码。

第二天,你开了一个新会话,AI 全忘了。它又开始建议你用 Express.js、连 PostgreSQL、用 Session 认证……

💡 这就是 AI 的“金鱼记忆“问题:每次新会话都是一张白纸。

记忆:让 AI 拥有跨会话的知识

pi-memory 就是来解决这个问题的。它给 AI 装上了一个“笔记本“:

  • 自动记录:AI 在会话中做出的架构决策、踩过的坑、达成的共识
  • 自动加载:每次新会话开始时,AI 自动读取之前的关键知识
  • 按项目隔离:不同项目的记忆互不干扰

工作原理

┌─────────────────────────────────────────┐
│              AI 会话                      │
│                                          │
│  ┌──────────┐     ┌──────────────────┐  │
│  │ 用户对话  │ ──→ │ AI 自动提取知识点  │  │
│  └──────────┘     └────────┬─────────┘  │
│                            │             │
│                            ▼             │
│                   ┌─────────────────┐    │
│                   │  memory_update   │    │
│                   │  写入记忆文件     │    │
│                   └─────────────────┘    │
│                                          │
│  ┌──────────┐     ┌──────────────────┐  │
│  │ 新会话    │ ──→ │ before_agent_start│  │
│  │ 开始      │     │ 自动加载记忆索引   │  │
│  └──────────┘     └──────────────────┘  │
└─────────────────────────────────────────┘

自动注入:每轮对话自动加载记忆索引

pi-memory 在每个会话开始时(before_agent_start 事件)会自动执行以下操作:

  1. 读取 memory-prompt.md — 记忆系统的使用说明(告诉 AI 有记忆功能、文件在哪)
  2. 读取 MEMORY.md 索引 — 全局 ~/.pi/agent/memory/MEMORY.md + 项目 .pi/memory/MEMORY.md
  3. 注入到 system prompt — AI 在每轮对话开头就能看到所有记忆的标题和关键词

这意味着 AI 不需要主动去“查“记忆——记忆索引已经在它的上下文里了。AI 看到 JS_replace_$陷阱 这样的标题,就知道有这条记忆存在,需要时用 read 工具读取完整内容。

⚠️ 注入的是索引,不是全部内容。MEMORY.md 里只有标题和关键词,不是完整的记忆内容。AI 需要 read 具体文件才能获取细节。

记忆的核心结构:

组件作用
MEMORY.md索引文件,列出所有记忆的标题和关键词(自动注入到每轮对话)
记忆文件(.md每个文件一个主题,包含具体知识点(按需读取)
memory_update 工具AI 用来写入/更新记忆文件 + 自动更新 MEMORY.md 索引
memory_index 工具AI 用来查看已有记忆(手动查询)
before_agent_start 钩子会话开始时自动注入记忆索引到 system prompt

记忆文件的格式

每个记忆文件遵循统一格式:

# 标题

关键词:`kw1` `kw2` `kw3` ...

## 具体内容

- 知识点 1
- 知识点 2
- 决策记录:为什么选择了方案 A 而不是方案 B

文件命名规则:主题--关键词1,关键词2,关键词3.md

例如:数据库选型--DuckDB,嵌入式,ARM,列存,分析查询.md

实际案例:新项目的第一周

让我们看一个真实的场景。假设你在开发一个数据分析工具:

第 1 天:项目初始化

你和 AI 讨论了技术选型,决定用 Python + FastAPI + DuckDB。会话结束时,AI 自动写入记忆:

# 技术栈决策

关键词:`Python` `FastAPI` `DuckDB` `技术选型`

## 选择理由

- FastAPI:异步支持好,自动生成 API 文档
- DuckDB:嵌入式分析数据库,无需单独部署,适合单机分析场景
  - 不选 PostgreSQL:项目不需要并发写入,嵌入式更简单
- Python 3.12+:用了新的类型语法

第 3 天:踩了一个坑

你在 DuckDB 的日期处理上遇到了问题——默认时区是 UTC,但你的用户在中国。AI 帮你解决后,写了一条记忆:

# DuckDB时区问题

关键词:`DuckDB` `时区` `日期` `UTC` `Asia/Shanghai`

## 问题和解决方案

DuckDB 默认用 UTC 时区。查询 `SELECT NOW()` 返回 UTC 时间。

解决:在连接时设置 `SET timezone = 'Asia/Shanghai'`

注意:不要在 SQL 层面做时区转换,在 Python 层用 datetime 处理更可靠。

第 7 天:新会话,无需重复解释

你开了一个新会话说“给分析接口加个导出 CSV 的功能“。AI 已经知道:

  • 项目用 FastAPI + DuckDB
  • 时区用 Asia/Shanghai
  • 数据库查询在 Python 层处理

不需要你再说一遍。

这就是记忆的价值:省去了每次重复解释的 30 分钟。

最佳实践

✅ 应该记住的内容

  • 技术决策:为什么选了 A 而不是 B
  • 踩过的坑:遇到的问题和解决方案
  • 项目约定:命名规范、目录结构、部署方式
  • 架构知识:模块关系、数据流、关键接口

❌ 不应该记住的内容

  • 临时调试信息(“这个变量值是 42”)
  • 已经过时的结论(记得定期清理)
  • 通用编程知识(AI 本来就知道怎么写 for 循环)

记忆文件管理

记忆不是越多越好。系统设有多层保护机制:

阈值行为
20 个提示注意控制数量
25 个警告接近上限,建议清理合并
40 个硬拒绝写入,必须先清理

清理方法:

  1. 合并:同主题的多文件合并为一个
  2. 归档:过时的结论被新结论取代,删掉旧的
  3. 拆分:单文件超过 200 行时,按子主题拆分

此外,记忆系统还有冲突检测——如果新文件与已有记忆的 topic 相同或关键词重叠 3 个以上,会直接拒绝写入,强制先处理冲突(合并或覆盖)。

配置

pi-memory 通过 pi 的 settings.json 安装:

{
  "packages": [
    "pi-memory"
  ]
}

无需额外配置,安装即用。记忆文件存储在项目的 .pi/memory/ 目录下。

记忆的作用域

作用域路径用途
项目级.pi/memory/项目特有的知识(架构、决策、坑)
全局~/.pi/agent/memory/跨项目通用的知识(工具链、编码纪律)

进阶场景:记忆清理与知识演化

场景:记忆碎片化了

用了一个月,记忆文件越来越多:

.pi/memory/
├── 数据库选型--DuckDB,嵌入式,ARM.md
├── DB选型--数据库,DuckDB,性能.md       ← 跟上一个重复!
├── 部署问题--Docker,ARM,内存.md
├── 部署问题2--Docker,内存,OOM.md      ← 跟上一个也重复!
├── auth-bug--JWT,过期,refresh.md
├── fastapi-cors--CORS,FastAPI,跨域.md
├── test-tricks--vitest,mock,测试.md
└── ... (还有 20 个文件)

AI 在每次写入前会自动检查(memory_index),如果发现同主题的已有记忆,会先合并再写入。但如果碎片化已经发生,需要手动清理。

清理步骤

  1. 让 AI 执行 memory_index,查看当前所有记忆
  2. 标记同主题的文件(关键词 3+ 重叠)
  3. 让 AI 读取标记的文件,合并为一个
  4. memory_update 覆盖写入到已有文件的文件名(而不是新建文件名,否则会触发冲突检测被拒绝)
  5. 删除旧的碎片文件

场景:旧结论被推翻了

上个月写的记忆说“用 Express.js 做后端“,但这个月项目决定迁移到 FastAPI。每次 AI 读到旧记忆都会用 Express 的思路,产生错误的建议。

处理方式:用 memory_update 覆盖旧文件,写入新结论:

# 后端框架选型

关键词:`FastAPI` `Python` `迁移`

## 当前决策

2026-05: 从 Express.js 迁移到 FastAPI。

## 迁移原因

- 需要更好的异步支持
- Python 生态的数据分析库更丰富
- Express.js 版本已归档,不再更新

> ⚠️ 旧结论(已废弃):使用 Express.js + TypeScript

关键:不要只删旧文件——把新结论和旧结论的关系写清楚,这样 AI 不会在别的上下文里又“发明“出旧的方案。

场景:跨项目的知识复用

你在项目 A 里踩了一个坑,想确保项目 B 不会重蹈覆辙。

方案:把通用知识写到全局记忆:

~/.pi/agent/memory/
└── npm-file引用陷阱--npm,file引用,node_modules,缓存.md

全局记忆对所有项目可见。这样不管在哪个项目里,AI 都会知道“npm file: 引用有缓存陷阱“。

原则

  • 项目特有的知识(这个项目的架构、约定)→ 项目级 .pi/memory/
  • 通用经验(工具链踩坑、编码纪律)→ 全局 ~/.pi/agent/memory/

下一步

现在 AI 有了记忆,能记住过去的知识。但面对一个大项目,它知道第一步该做什么、第二步该做什么吗?

下一章,我们来看如何让 AI 学会规划

English