小龙虾养成笔记(一):用 OpenClaw 搭一个有记忆的 AI Agent

用过 ChatGPT 的人都有过这种体验:每次打开新对话,又得从头介绍一遍”我是谁、我在做什么、我上次跟你说过什么”。对话结束,一切归零。

这不是 AI 不够聪明,而是 LLM 天生无状态——session 结束就失忆。

OpenClaw 解决的就是这个问题。它不是又一个聊天界面,而是一套让 LLM 变成持久化 Agent 的框架:有记忆、有闹钟、有手脚,关掉窗口它还在。

和OpenClaw折腾了有段时间了,打算记录一下我的个人使用心得。本文作为第一篇,重点聊两件事:怎么让它记住东西,以及怎么让它自己动起来


1. 架构速览 🏗️

先看全貌。OpenClaw 的核心组件:

1
2
3
4
5
6
7
8
9
10
11
Gateway(常驻进程)
├── Agent(你的 AI 助手)
│ ├── Workspace(文件系统 = 状态)
│ │ ├── SOUL.md ← 身份定义
│ │ ├── USER.md ← 用户画像
│ │ ├── MEMORY.md ← 长期记忆
│ │ └── memory/ ← 每日日志
│ ├── Skills(可插拔能力模块)
│ └── Cron(定时任务)
├── Channel(飞书 / Discord / Telegram)
└── Session(一次对话)

几个关键设计决策:

  • 文件系统即状态。记忆就是 markdown 文件,不需要向量数据库,cat 就能看,git 就能版本管理。
  • Gateway 常驻。不是”用的时候启动”,而是一直在跑。这样 cron 任务和心跳才有意义。
  • Skill 热插拔。新能力以 SKILL.md 的形式挂载,不改代码,重启即生效。

2. 持久化记忆:三层架构 🧠

这是我觉得 OpenClaw 最优雅的设计。记忆分三层,各司其职:

第一层:SOUL.md — 我是谁

1
2
3
4
5
# SOUL.md
_You're not a chatbot. You're becoming someone._

## Vibe
随意、轻松、像朋友聊天。不端着,不啰嗦。用中文交流。

这个文件定义 Agent 的”人格”。每次 session 启动时自动加载,所以它永远知道自己是谁。不需要你每次提醒”你是一个轻松风格的助手”。

第二层:MEMORY.md — 长期记忆

1
2
3
4
5
6
7
8
9
10
11
12
# 长期记忆

## 关于用户
- 时区 UTC+8
- 喜欢简洁的交流风格

## 环境
- 运行在 WSL2 (Ubuntu) on Windows

## 教训
- 安装 skill 后需要重启 gateway 才能刷新
- 不同 agent 发飞书消息要用各自的 accountId

这是你与小龙虾的每一次互动后沉淀下来的精华。不是对话记录的堆砌,而是从日常交互中提炼出来的重要信息。为了确保MEMORY.md能及时更新,我设置了一个每日反思任务,让我的龙虾在每天晚上回顾过去24小时的对话,将关键内容存入MEMORY.md。

1
2
3
4
【每日自我反思】
...
3. 记忆维护:回顾过去24小时对话(sessions_list + sessions_history),关键内容归入 MEMORY.md;清理过时内容
...

第三层:memory/YYYY-MM-DD.md — 每日日志

1
2
3
4
5
6
7
8
# 2026-03-21 (周六)

## 完成的事情
- 迁移了 quantified_self 数据格式
- 封装了 agent-learn skill

## 学习的内容
- 学了《段永平投资问答录》,笔记在 brain/投资/books/

这是小龙虾的日记,记录与你交流的内容的要点总结,按天存储。只有今天和昨天的会被加载到 session context 里,不会把所有历史都塞进去。

Compaction:对话压缩机制

Session 的上下文窗口是有限的。聊久了怎么办?

OpenClaw 用了 compaction 机制。当对话超过一定长度时,系统会把前面的对话压缩成一段摘要,释放 token 空间。但压缩前会触发一个 pre-compaction flush——给 Agent 一个机会把重要信息写到文件里。

1
2
3
4
5
6
对话进行中...
↓ 上下文快满了
↓ 触发 pre-compaction flush
↓ Agent 把关键信息写入 memory/2026-03-21.md
↓ 压缩旧对话为摘要
↓ 继续对话

但实测下来,自动compaction可能会导致最近一两回合对话的信息丢失(可能因为这部分对话正好卡在了pre-compaction flush和compaction之间)。如果这部分对话正好包含关键信息的话,龙虾“失忆”的现象就会特别明显。

所以我在 AGENTS.md 里加了一条规则:做完就记 memory,不等 pre-compaction flush。因为 compaction 随时可能发生,重要的东西要立刻落盘。


3. 自主调度:Cron + Heartbeat ⏰

有了记忆,Agent 不会失忆了。但它还是被动的——你不说话它就歇着。

Cron:定时任务

OpenClaw 内置了 cron 系统。每个 cron 任务在独立的 session 里运行,互不干扰。

1
2
3
4
5
6
7
# 创建一个每天 22:00 执行的反思任务
openclaw cron create \
--name "self-reflect" \
--schedule "0 22 * * *" \
--timezone "Asia/Shanghai" \
--agent main \
--message "回顾今天的对话,记录教训,更新记忆..."

例如,我现在跑着这些 cron:

时间 任务 做什么
19:00 learn 从知识库学习新文章
22:00 self-reflect 每日反思
23:00 ai-daily-news 自动生成 AI 日报
23:20 investment-analysis 对给定标的进行分析并给出投资建议

Heartbeat:心跳巡查

Cron 是精确定时,Heartbeat 是模糊轮询。Gateway 每隔一段时间 ping 一下 Agent,Agent 决定要不要做点什么。

适合心跳的场景:批量检查(邮件+日历+通知一起看)、不需要精确时间的巡查、比较轻量级的任务。

适合 cron 的场景:精确时间、需要隔离的 session、需要指定不同 model 的任务。

我目前还没有找到需要Heartbeat的场景,因此我的HEARTBEAT.md 里就一行:

1
无需执行任何操作。

4. Skill:可复用的能力封装 🔧

当你发现多个 Agent 在 cron prompt 里写着差不多的逻辑时,就该封装成 Skill 了。

封装前:每个 cron 写一大段 prompt

1
2
3
4
5
6
7
8
9
10
11
investment-learn 的 prompt(25 行):
1. 读取 brain/.notion-manifest.json...
2. 读取 data/learned-articles.json...
3. 筛选 tagDir 为 "投资" 的文章...
...

job-coach-learn 的 prompt(25 行):
1. 读取 brain/.notion-manifest.json... ← 重复!
2. 读取 data/learned-articles.json... ← 重复!
3. 筛选 tagDir 为 "求职" 的文章...
...

封装后:一个 Skill + 参数化调用

SKILL.md(定义一次):

1
2
3
4
5
6
7
8
9
---
name: agent-learn
description: Agent 知识学习 skill。从多个数据源学习新内容。
---
## 参数
| 参数 | 说明 |
|------|------|
| brain_tag | 知识库的 tagDir 名称 |
| drive_folder_token | 飞书云文档文件夹(可选)|

cron prompt(精简到 3 行):

1
2
3
按 agent-learn skill 学习新内容。参数:
- brain_tag: 投资
- drive_folder_token: XXX

Skill 的三级加载机制也值得一提:

  1. Metadata(name + description)— 始终在 context 里,~100 词
  2. SKILL.md body — 匹配到才加载,<5k 词
  3. references/ 和 scripts/ — 按需读取,不限大小

这保证了:装 20 个 Skill 不会撑爆 context,只有用到的才会加载。


养虾一段时间,最直观的感受是:它开始像一个”人”了。不是说它有多聪明,而是更像一个身边的伙伴——知道昨天发生了什么,记得我给过的反馈,懂得我的喜好,具有主观能动性(会自我反思和主动干活)。

当然坑也踩了不少,也没少花时间在给龙虾“治病”上。但这正是学习的过程与折腾的乐趣所在。