第九章:记忆与任务——AI 的跨会话笔记本
📌 本章李明轩在做什么:付费社群每周要发一篇周报,要引用本周社群里讨论过的话题。一周横跨 7 天,他不可能让 AI 在一次会话里搞定。他需要让 AI 把"本周已经引用过哪些话题"、"会员最常问的问题"这些经验记到磁盘上,下次会话自动读回来。
为什么 AI 需要记忆
在第三章里,我们提到了"新鲜上下文即可靠性"原则——每次迭代 AI 都从零开始读取信息。这引出了一个矛盾:
- 新鲜上下文意味着每次 AI 都要重新理解环境
- 但重要的经验和决策不应该在每次迭代后消失
Ralph 通过两套持久化机制解决这个矛盾:
- 记忆文件(memories.md):AI 跨会话的"学习笔记"
- 任务系统(tasks.jsonl):工作进度的"代办清单"
一句话:上下文窗口每次都清空(保证新鲜),磁盘每次都保留(保证不遗忘)——两者配合才能既避免老对话的遗忘,又积累项目经验。
记忆文件:AI 的学习笔记本
记忆文件位于 .ralph/agent/memories.md,是一个普通的 Markdown 文本文件,由 AI 自己维护。
记忆的内容
AI 会把以下类型的信息写入记忆:
项目模式(Patterns):
## Project Patterns
- 这个项目使用 pytest 进行测试,测试文件放在 tests/ 目录
- 数据库查询使用 SQLAlchemy ORM,不直接写 SQL
- API 响应格式:{"status": "success|error", "data": {...}, "message": "..."}
- 所有新功能需要在 CHANGELOG.md 里添加条目
已修复的问题(Fixes):
## Fixes Applied
- 导入 requests 库时,需要先激活虚拟环境:source .venv/bin/activate
- pytest-asyncio 版本问题:在 pyproject.toml 里固定到 0.21.x
- 数据库迁移前必须先运行 alembic upgrade head
重要决策(Decisions):
## Decisions
- 选择 FastAPI 而不是 Flask,原因:需要原生 async 支持
- 用户认证使用 JWT,不用 session,原因:支持移动端
- 配置文件使用环境变量,不硬编码,原因:安全考虑
重复出现的错误(Recurring Issues):
## Recurring Issues
- 在这个项目里,datetime 对象必须带时区信息,否则比较会报错
- API 测试时记得先启动 mock 服务器:make mock-server
记忆是如何被使用的
每次迭代开始时,Ralph 会把 memories.md 的内容注入到 AI 的上下文里,放在一个特殊的 <memories> 标签里。AI 在做决策时会参考这些记忆,避免重复犯同样的错误。
手动添加记忆
不只是 AI,你也可以手动向记忆文件添加内容:
# 用命令行添加记忆
ralph tools memory add "注意:这个项目的 API 密钥不能出现在任何测试文件里"
# 或者直接编辑文件
vim .ralph/agent/memories.md
这是"用信号导航"法则的直接体现:当 AI 反复在某个地方犯错时,把正确的做法写入记忆,比在帽子指令里写复杂规则更有效。
记忆的清理
随着项目进行,记忆文件会越来越长。记忆文件是普通的 Markdown 文本,直接用编辑器打开删除不再相关的条目即可:
# 直接编辑记忆文件,删除过时的条目
vim .ralph/agent/memories.md
如果想清理整个 .ralph/ 工作目录(例如重新开始一个项目),可以使用:
# 预览会删除什么(不实际删除)
ralph clean --dry-run
# 清理诊断日志
ralph clean --diagnostics
注意:ralph clean 只会清理 .ralph/agent/ 下的记忆与任务文件;.ralph/ 下的事件日志(events-*.jsonl)、循环注册表(loops.json)、锁文件(loop.lock)等不会被它动到,更不会删除你的项目代码。
任务系统:进度跟踪的代办清单
任务系统通过 .ralph/agent/tasks.jsonl 文件跟踪所有工作的进度。
任务的生命周期
pending(待开始)
↓
in_progress(进行中)
↓
closed(完成)
或
reopened(重新打开,需要修改)
任务文件的结构
每行一个任务,完整字段示例(真实输出,略作格式化):
{"id":"task-1705300801-a3f2","title":"创建项目骨架","description":"scaffold the repo","key":"code-assist:my-project:step-01:scaffold","status":"closed","priority":3,"blocked_by":[],"loop_id":"primary-20240115-100001","created":"2024-01-15T10:00:01+00:00","started":"2024-01-15T10:00:05+00:00","closed":"2024-01-15T10:12:44+00:00"}
{"id":"task-1705301453-7c01","title":"实现核心功能","description":"core logic","key":"code-assist:my-project:step-02:core","status":"open","priority":3,"blocked_by":[],"loop_id":"primary-20240115-100001","created":"2024-01-15T10:10:53+00:00","started":"2024-01-15T10:11:39+00:00"}
{"id":"task-1705302021-bb44","title":"完善测试","description":"write tests","key":"code-assist:my-project:step-03:tests","status":"open","priority":3,"blocked_by":["task-1705301453-7c01"],"created":"2024-01-15T10:20:21+00:00"}
任务 ID 格式是
task-<Unix 时间戳>-<4 位 16 进制>,由 Ralph 运行时生成;后文示例里出现task-1705301453-7c01这类 ID,都是占位符,实际使用时请用ralph tools task list看到的真实 ID 替换。
查看任务状态
运行时任务通过 ralph tools task 子命令管理(注意:ralph task 是生成 .code-task.md 文件的命令,功能不同):
# 列出所有任务
ralph tools task list
# 只列出待处理的任务
ralph tools task ready
# 查看某个任务的详细信息(把示例 ID 换成你本地的真实 ID)
ralph tools task show task-1705301453-7c01 --format json
任务在恢复中的作用
假设你的电脑在任务运行到一半时断电了。重新启动后:
# 重新启动 Ralph
ralph run -p "继续上次的任务"
Ralph 会读取任务文件,知道哪些已经完成、哪些正在进行,从断点处继续,而不是从头开始。
记忆与任务的协作:一个完整的例子
让我们看看在一个多天的项目里,记忆和任务如何协同工作:
第一天
你:ralph run -p "为这个 Python 项目添加邮件发送功能"
Ralph 运行了 5 次迭代:
- 任务1:安装 smtplib 配置 (完成)
- 任务2:实现发送函数 (完成) ← 在这里遇到了 SSL 证书问题,
- 任务3:添加重试机制 (完成) AI 记录到记忆里
- 任务4:编写测试 (完成)
- 背压检查:全部通过
- 循环完成
.ralph/agent/memories.md 现在包含:
## Fixes Applied
- 发送邮件时需要设置 ssl_context=ssl.create_default_context(),
否则在某些服务器上会有 SSL 错误
- SMTP 测试使用 unittest.mock.patch('smtplib.SMTP') 模拟,
不要真正发送邮件
第二天(新的会话)
你:ralph run -p "添加邮件发送的队列功能,异步处理"
Ralph 在新的迭代里,自动读取了第一天的记忆:
- 知道测试要用 mock,不会真的发邮件
- 知道 SSL 的处理方式,不会再踩同样的坑
代码任务文件(.code-task.md)
除了运行时任务(存在 .jsonl 文件里),Ralph 还支持另一种任务形式:代码任务文件(.code-task.md)。
这是一个 Markdown 格式的任务规格文档,适合用于较复杂的功能:
---
status: pending
created: 2024-01-15
started: null
completed: null
---
# 任务:添加邮件验证功能
## 描述
实现一个邮件地址验证函数,用于用户注册时的输入验证。
## 背景
目前注册接口不验证邮件格式,导致脏数据进入数据库。
## 技术要求
1. 验证 RFC 5322 标准格式
2. 检查域名是否存在(可选,可关闭)
3. 返回详细的错误信息(不只是"格式错误")
## 验收标准
1. **基本格式验证**
- 给定:一个标准格式的邮件地址
- 当:调用 validate_email() 函数
- 则:返回 True
2. **无效格式拒绝**
- 给定:各种格式错误的邮件地址
- 当:调用 validate_email() 函数
- 则:返回 False 和具体的错误说明
3. **测试覆盖**
- 给定:完整的测试套件
- 当:运行 pytest
- 则:所有测试通过,覆盖率 > 90%
把这个文件放在 .ralph/tasks/ 目录里,然后运行:
ralph run -H builtin:code-assist \
--prompt ".ralph/tasks/validate-email.code-task.md"
Ralph 会按照这个文档里的验收标准来判断任务是否完成。
任务的手动管理
在某些情况下,你可能需要手动管理任务状态:
# 创建/更新一个任务(ensure:存在则更新,不存在则创建)
# 语法:ralph tools task ensure --key <KEY> <TITLE> [--description <DESCRIPTION>]
ralph tools task ensure --key "fix:login-css" "修复登录页 CSS" \
--description "修复登录页面的 CSS 问题"
# 以下示例里的 task-id 形如 task-1776737176-532e(Ralph 生成),
# 复制你在 `ralph tools task list` 看到的完整 ID 替换即可
# 手动关闭一个任务
ralph tools task close task-1776737176-532e
# 重新打开一个已关闭的任务(发现了新问题)
ralph tools task reopen task-1776737176-532e
# 查看任务详情
ralph tools task show task-1776737176-532e
什么不应该存入记忆
记忆文件的价值在于跨会话的持久学习,以下内容不适合放入记忆:
- 临时的调试信息:
正在调试 issue #123(这是当前会话的临时状态) - 已经修复并提交的 bug:这些信息在代码和 commit message 里已经有了
- 可以从代码库里直接读取的信息:比如"使用 Python 3.11"(代码里有 pyproject.toml)
记忆里应该存的是那些不写下来 AI 就容易忘记或弄错的东西:隐性约束、踩过的坑、反常识的决策。
本章小结
memories.md是 AI 的跨会话学习笔记,自动积累项目经验tasks.jsonl是工作进度的代办清单,支持跨会话恢复.code-task.md文件提供结构化的任务规格,适合复杂功能- 可以手动向记忆添加内容,作为"信号"指导 AI 行为
- 记忆越精准有用,AI 在这个项目里的工作质量越高
记忆和任务系统让 AI 的工作可以跨夜延续。但李明轩还有个现实问题——白天上班时他没法打开终端看循环跑到哪里了。他需要一个手机上能看的面板。下一章讲可视化仪表盘。