OpenClaw 是如何使用上下文工程来自动进化的?
这个视频谈谈 OpenClaw 在 agent 方面的架构。OpenClaw 本身不只是 agent,而是一个网关服务,但这篇文章我们主要从 Agent 的角度解析它。核心回答两个问题:
- OpenClaw 是怎么做到基于复杂上下文的?
- OpenClaw 是如何做到主动的?
答案可以概括为:通过工程化的上下文管理实现自动进化。下面我们展开,从 System Prompt 和 Memory 两个核心机制来看 OpenClaw 如何处理复杂上下文,再介绍 Cron/Heartbeat/Message 三种主动性机制。
一、System Prompt:四层上下文架构
OpenClaw 的 system prompt 不是简单的信息罗列,而是一个从”系统能力”到”用户定制”的分层结构。这种分层直接支持复杂上下文的处理能力。
具体来看,这四层分别是:
层次 1:能力声明(Capabilities) —— 告诉 agent 它”能做什么”。包括当前可用的工具列表及简要说明、如何按需加载技能指令(通过 read 读取 SKILL.md),以及可用的模型别名。
层次 2:安全与约束(Safety & Constraints) —— 划定行为的边界。这里明确禁止权力寻求、自我复制、绕过监管等行为,同时说明沙盒运行环境的路径和权限级别。
层次 3:操作指南(Operational Guidance) —— 提供日常操作的快速参考,比如网关管理命令、memory_search 的使用时机、gateway tool 的使用场景,以及跨会话消息发送的方法。
层次 4:项目上下文(Project Context) —— 这是最灵活的一层,通过工作目录中的文件注入,是用户定制的核心。这些文件包括:
| 文件 | 作用 |
|---|---|
| AGENTS.md | 告诉智能体:每次会话该读什么文件、怎么管理记忆、什么时候该说话/沉默、安全边界、群聊礼仪、心跳检查策略等。相当于”员工手册”。 |
| SOUL.md | 定义名字、性格、说话风格、价值观。比如:你叫小明,说话简洁幽默,偏好用中文回答,遇到不确定的事会坦诚说不知道。 |
| IDENTITY.md | SOUL.md 的别名/补充 部分模板用 IDENTITY.md 代替或补充SOUL.md,作用相同——定义智能体的角色定位。两者可以只用一个。 |
| MEMORY.md | 需要长期记忆的东西 |
| TOOLS.md | 给智能体记录外部工具的使用注意事项和本地配置细节。比如: > - SSH 到服务器用 ssh myserver,密钥已配好> - 摄像头名字叫 “Front Door” > - 用 ElevenLabs TTS 时默认用 “Adam” 声音 注意:它不定义工具本身(工具由插件/技能提供),只是”使用笔记”。 |
| USER.md | 用户画像 告诉智能体关于”你”的信息:你的名字、职业、偏好、常用工具、时区等。让智能体不用每次重新了解你。比如: > 我叫胡琦琦,全栈开发者,偏好 TypeScript,时区 UTC+8,喜欢简洁的回答。 |
| HEARTBEAT.md | 心跳任务清单 智能体会定期收到心跳轮询(默认约每 30 分钟)。收到心跳时,它会读取 HEARTBEAT.md,按里面的指示执行后台任务。没任务就回复 HEARTBEAT_OK。典型内容: > - 检查邮箱有没有紧急邮件 > - 看看日历未来 2 小时有没有会议 > - 每天下午 3 点提醒我喝水 保持简短,因为每次心跳都会消耗 token。 |
这里有一个关键机制需要理解:这些文件会直接注入 system prompt,但有字符限制,防止窗口爆掉。如果文件缺失,system prompt 会标记 [MISSING]。
针对不同的使用场景,OpenClaw 还提供三种 system prompt 模式:
- “full” 模式(主 agent)包含完整的 4 层架构加 Runtime;
- “minimal” 模式是精简版(Tooling + Workspace + Runtime),用于处理复杂/耗时任务,避免污染主会话上下文,用于 sub agent。
- “none” 模式则只有基础身份,给简单任务的 sub agent 用。
二、Memory:双轨制记忆系统
如果说 system prompt 解决了”当下该知道什么”,那么记忆系统回答的就是复杂上下文问题的另一个关键:如何让 agent 在记住海量信息的同时,还能快速检索出这次需要的信息?
OpenClaw 的 Memory 系统采用 “文件为源、数据库为索引” 的双重存储架构:文件系统保存原始内容,SQLite 数据库建立可搜索的索引。这种设计兼顾了人类可读性和机器检索效率。
文件存储:源头内容
所有记忆内容首先以文件形式存在,分为两类:
1. 长期记忆文件(Markdown 格式)
- MEMORY.md:位于工作目录根,存放精选的长期记忆
- memory/*.md:按日记录的日志文件,如
memory/2025-02-06.md - 人类可读,便于直接编辑和管理
2. 会话记录文件(JSONL 格式)
- 路径:
~/.openclaw/agents/<agentId>/sessions/YYYY-MM-DD.jsonl - 机器格式,每行一条消息,记录完整对话历史
- 用于自动回溯,但不易人工阅读
简单来说,.md 是”精选知识库”(人工维护),.jsonl 是”全量流水账”(自动生成)。
数据库存储:搜索索引
为了快速检索,系统会自动将文件内容索引到 SQLite 数据库(位于 ~/.openclaw/memory.db)。数据库不存储原始文件的完整内容,而是存储可搜索的文本块及其向量嵌入:
| 表 | 用途 |
|---|---|
files | 跟踪已索引的文件路径、修改时间、内容哈希 |
chunks | 存储文本块(分块后的内容)及其向量嵌入(JSON 格式) |
chunks_vec | sqlite-vec 虚拟表,存储二进制向量用于相似度搜索 |
chunks_fts | FTS5 虚拟表,存储分词后的文本用于关键词搜索 |
embedding_cache | 按内容哈希缓存嵌入结果,避免重复计算 |
什么内容会做 embedding?
只有文本内容会被分块和向量化:
- Markdown 文件:按 token 数分块(默认约 256-512 tokens),块之间有重叠(32-64 tokens),保留行号引用
- Session JSONL:解析出用户和助手消息,格式化为
"User: {content}"或"Assistant: {content}",每个会话文件作为一个文档
数据库通过文件监听和定期同步机制保持与源文件的同步。当文件修改时,系统会检测内容哈希变化,仅重新索引变更的文件。
记忆检索:混合搜索
当用户询问之前的工作、做过的决策、日期/时间相关、相关人员、用户偏好或待办事项时,必须先运行 memory_search。这种设计确保 agent 在处理涉及历史上下文的问题时,能够主动检索相关信息。
搜索采用混合策略:向量搜索擅长语义匹配(比如 “Mac Studio gateway host” 能匹配 “the machine running the gateway”),而 BM25 擅长精确匹配(ID、代码符号、错误字符串)。最终得分由两者加权计算:finalScore = 0.7 * vectorScore + 0.3 * textScore。
双重访问:注入 vs RAG
这里需要澄清 MEMORY.md 的一个特殊设计:它同时存在两种访问方式。
第一种是注入访问——文件内容直接注入 system prompt。优点是零延迟、每次请求都携带,但受 20k 字符上限限制,适合高频访问的核心记忆。
第二种是RAG 访问——通过 memory_search / memory_get 按需检索。优点是无容量上限且支持语义搜索,适合大容量、需要模糊匹配的记忆。
这两种方式不是互斥的,而是互补的——核心内容靠注入快速访问,完整内容靠 RAG 深度检索。
上下文保护:预刷新机制
长期运行的会话会遇到上下文窗口限制的问题。OpenClaw 通过**压缩(Compaction)**来解决——将旧对话总结成摘要,丢弃原始消息。
但压缩会导致信息丢失。为此 OpenClaw 在压缩前触发一次静默的 agentic turn:上下文接近上限时,agent 先将关键信息写入 memory/YYYY-MM-DD.md,然后再执行压缩。这确保了关键信息在上下文被截断前被固化到磁盘。
三、主动性机制:从被动响应到主动触达
这部分回答第一个问题:OpenClaw 是如何做到主动的?
传统 Bot 是”用户问 → Bot 答”的被动模式。OpenClaw 通过三种机制实现主动性,每种都由特定的工具支持。
Cron:定时触发
通过 cron 工具创建定时任务。例如每周一早上 9 点触发提醒:
{
action: "create",
schedule: "0 9 * * 1",
systemEvent: "Weekly standup reminder..."
}触发时系统发送 systemEvent 作为用户消息,agent 收到后像处理普通消息一样处理。典型场景包括每日总结、定时检查、生日祝福等。
Heartbeat:定期自检
Heartbeat 是 OpenClaw 内置的定期自检机制。通过 heartbeat.every 配置(默认 30 分钟),系统会定期触发 agent 执行一次检查:
- agent 读取
HEARTBEAT.md(如果存在)获取检查清单 - 评估当前是否有需要关注的事项(待办、未完成任务等)
- 如果一切正常,回复
HEARTBEAT_OK——系统静默,不向用户发送消息 - 如果有事项需要关注,回复具体内容——系统主动推送给用户
这是一种静默的主动监控:大多数时间什么都不发生,但一旦发现需要关注的事情,agent 会主动提醒。
HEARTBEAT.md 示例:
# Heartbeat checklist
- 检查收件箱是否有紧急邮件
- 查看未来 2 小时内的日历事件
- 检查是否有后台任务完成,如有则总结结果
- 如果空闲超过 8 小时,发送一个简短的问候agent 会在每次心跳时读取这个清单,批量处理所有检查项。如果一切正常,回复 HEARTBEAT_OK;如果有需要关注的事情,则主动推送给用户。
Message:主动推送
通过 message 工具的 action=send,agent 可以从”被动回复当前会话”转变为”主动推送任意频道/用户”。这是真正的主动触达能力,让 agent 能够在发现重要情况时主动通知用户。
四、结论:上下文工程与自动进化
现在回到文章开头的两个问题。
OpenClaw 是怎么做到基于复杂上下文的?
通过四种策略:
| 策略 | 实现 | 效果 |
|---|---|---|
| 分层缓存 | System Prompt 4 层结构 | 高频信息常驻,低频按需加载 |
| 双轨记忆 | 注入(20k) + RAG(无上限) | 快速访问 + 深度检索 |
| 混合搜索 | 向量 70% + BM25 30% | 语义模糊匹配 + 精确符号匹配 |
| 预刷新 | Pre-compaction flush | 关键信息在截断前固化 |
| OpenClaw 是如何做到主动的? |
通过三种机制:Cron 实现定时触发、Heartbeat 实现定期自检、Message 实现主动推送。
OpenClaw 的”自动进化”不是科幻意义上的 AI 自我改进,而是工程化的上下文管理。其精髓在于:不是让模型变聪明,而是让上下文恰到好处地支持模型的推理——记住该记住的(Memory 双轨系统)、在正确的时间做正确的事(Cron/Heartbeat/Message)。这就是 OpenClaw 使用上下文工程实现自动进化的方式。
┌─────────────────────────────────────────────────────────────┐
│ 上下文工程架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ System Prompt │◄────│ Memory System │ │
│ │ (4 Layers) │ │ (File + SQLite) │ │
│ └────────┬────────┘ └─────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Agent 决策 │ │
│ └────────┬────────┘ │
│ │ │
│ ┌──────┴──────┬──────────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────┐ ┌─────────┐ ┌─────────┐ │
│ │ Cron │ │Heartbeat│ │ Message │ │
│ │定时触发│ │主动监控 │ │主动推送 │ │
│ └──────┘ └─────────┘ └─────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────┐
│ 写入 Memory.md │
│ (知识固化) │
└────────────────────────┘