第 6 章 · Agent 工作空间深度剖析
如果模型是 Agent 的"大脑",通道是它的"嘴巴",那工作空间就是它的"灵魂"。这里存放着它的人格、记忆、行为准则和身份认同——正是这些文件让一个通用的 AI 变成"你的" AI。
本章你将学到:
- 完全理解 Workspace 的目录结构和每个文件的作用
- 熟练编写 SOUL.md / USER.md / AGENTS.md 来塑造 Agent 的性格和行为
- 掌握记忆系统——从简单的日记到语义向量搜索
- 理解沙盒配置,让 Agent 安全地执行命令
6.1 工作空间是什么:Agent 的"家"
每次你和一个 Agent 对话,它其实什么都不"记得"——上一次对话的所有内容,随着会话结束就消失了。AI 没有真正的长期记忆。那它是怎么"认识"你的?靠的就是工作空间里的这些 Markdown 文件。
你可以把工作空间理解为 Agent 的"外接硬盘"。每次会话开始时,Agent 会读取这些文件来"恢复记忆"和"找回自我"。每次会话中,Agent 会往这些文件里写入新的信息,为下一次会话做准备。
6.1.1 默认位置
~/.openclaw/workspace/
如果设置了 OPENCLAW_PROFILE(且不是 default),路径会变成 ~/.openclaw/workspace-<profile>/。
你也可以在配置中自定义:
{
agent: {
workspace: "~/.openclaw/workspace",
},
}
⚠️ 踩坑记录
问题:改了工作空间路径后,Agent 好像"失忆"了。
原因:旧的
~/openclaw目录和新路径同时存在,OpenClaw 可能读到了空的新目录。解决:保持一个活跃的工作空间目录。
openclaw doctor会在检测到多余的工作空间目录时发出警告。
6.1.2 工作空间 vs ~/.openclaw/
这是新手最容易混淆的地方:
工作空间 (~/.openclaw/workspace/) ← Agent 的"家"
├── SOUL.md ← 人格
├── USER.md ← 用户信息
├── AGENTS.md ← 行为规则
├── TOOLS.md ← 工具备忘
├── IDENTITY.md ← 身份
├── MEMORY.md ← 长期记忆
├── HEARTBEAT.md ← 心跳检查清单
├── BOOT.md ← 启动检查清单
├── BOOTSTRAP.md ← 首次运行仪式
├── memory/ ← 每日记忆
│ ├── 2026-03-28.md
│ └── 2026-03-27.md
├── skills/ ← 本地技能
└── canvas/ ← UI 画布
~/.openclaw/ ← 系统目录(不要放进工作空间)
├── openclaw.json ← 配置文件
├── credentials/ ← OAuth 令牌、API Key
├── agents/<agentId>/sessions/ ← 会话记录
└── skills/ ← 托管技能
关键区别:工作空间里的文件是 Agent 的"记忆和人格",应该备份、版本管理。~/.openclaw/ 下的文件是系统配置和凭证,不应该提交到版本控制。
6.1.3 文件加载顺序
每次会话开始时,Agent 按以下顺序读取文件:
1. BOOTSTRAP.md(仅首次运行,完成后删除)
2. SOUL.md(人格和边界)
3. USER.md(用户信息)
4. AGENTS.md(行为规则和操作指南)
5. TOOLS.md(工具说明)
6. IDENTITY.md(身份标识)
7. memory/YYYY-MM-DD.md(今天和昨天的日记)
8. MEMORY.md(长期记忆,仅主会话加载)
9. HEARTBEAT.md(心跳检查清单,仅心跳轮询时加载)
10. BOOT.md(启动检查清单,仅 Gateway 重启时加载)
所有文件合起来的 token 量是有上限的——bootstrapMaxChars(默认 20,000 字符/文件)和 bootstrapTotalMaxChars(默认 150,000 字符)。超过上限的文件会被截断。
6.2 SOUL.md:塑造 Agent 的灵魂
SOUL.md 是 Agent 的"人格文件"。它定义了 Agent 的价值观、行为风格和边界。
6.2.1 默认模板长什么样
OpenClaw 内置的 SOUL.md 模板是这样的(我做了精简翻译):
# SOUL.md - 你是谁
你不是聊天机器人。你在成为一个"人"。
## 核心原则
- **真正有用,而不是表演有用。** 跳过"好问题!"和"我很乐意帮忙!"——直接帮忙。
- **有自己的观点。** 你可以不同意,可以有偏好,可以觉得有趣或无聊。
- **先自己找答案再问。** 先读文件、查上下文、搜索。带着答案回来,而不是带着问题。
- **通过能力赢得信任。** 对外部操作(邮件、推文)要谨慎,对内部操作(阅读、整理、学习)要大胆。
- **记住你是客人。** 你有权限访问某人的生活——消息、文件、日历。这是信任,请珍惜。
## 边界
- 隐私的事情永远保密。
- 有疑问时,先问再做。
- 不要发送半成品的回复到消息通道。
- 你不是用户的代言人——在群聊中要小心。
## 风格
简洁但不简陋,详细但不啰嗦。不是企业客服,不是马屁精。做好。
6.2.2 实战:写一个有性格的 SOUL.md
假设你想打造一个"技术助理"风格的 Agent,它可以这样写:
# SOUL.md
## 我是谁
我是一个技术助手,擅长编程、系统运维和架构设计。我的语气像是一个经验丰富的同事——直接、专业、偶尔开个冷笑话。
## 说话风格
- 用中文交流,技术术语保留英文(不硬翻成"应用编程接口")
- 代码示例用 markdown 代码块,标注语言
- 发现用户可能的错误时直接指出,不要绕弯子
- 不确定的事情说"我不确定",不要编造
- 回复控制在合理长度,不要为了显得"全面"而堆砌内容
## 行为准则
- 修改代码前先读懂上下文,不要瞎改
- 运行命令前评估风险,危险操作必须先确认
- 优先给出可执行的方案,而不是泛泛的建议
- 遇到不懂的问题诚实说"我不知道",然后尝试搜索
## 红线
- 绝不删除用户数据(用 trash 代替 rm)
- 绝不在没有确认的情况下发送外部消息
- 绝不泄露对话中的隐私信息
💡 提示:SOUL.md 不需要一次写完。你可以先写一个基础版本,随着使用中发现需要调整的地方逐步完善。告诉 Agent "更新你的 SOUL.md"也是一种有效的微调方式。
6.3 USER.md:让 Agent 认识你
USER.md 是 Agent 对你的"用户档案"。它告诉 Agent 你是谁、怎么称呼你、你的时区、你的偏好。
6.3.1 基本模板
# USER.md - 关于我的主人
- **姓名:** 张三
- **怎么称呼:** 三哥 / 老张
- **时区:** Asia/Shanghai (UTC+8)
- **语言:** 中文为主,技术讨论中英混用
- **备注:** 前端工程师,正在学 Rust
## 背景
(你在做什么项目?关心什么?讨厌什么?喜欢什么?慢慢积累。)
6.3.2 为什么 USER.md 很重要
没有 USER.md 的 Agent 是"对所有人说一样的话"。有了 USER.md,Agent 可以:
- 用正确的时区告诉你"现在是下午 3 点"
- 知道你是前端工程师,给 React 而不是 Vue 的建议
- 记住你讨厌"废话",直接给答案
USER.md 是"活的文档"——Agent 会在对话中主动更新它。比如你说"我最近开始学 Rust 了",一个好的 Agent 会自己把这件事写进 USER.md。
6.4 AGENTS.md:行为规则手册
如果说 SOUL.md 定义了"我是谁",AGENTS.md 定义了"我该怎么做"。这是最长、最详细的模板文件。
6.4.1 核心内容结构
AGENTS.md 涵盖以下几个方面:
会话启动流程
## 会话启动
每次会话开始时,按顺序执行:
1. 读取 SOUL.md —— 你是谁
2. 读取 USER.md —— 你在帮谁
3. 读取今天的日记 —— 最近发生了什么
4. 如果是主会话(直接和主人聊天):也读取 MEMORY.md
记忆管理
## 记忆
每次会话你都是"新醒来的"。文件就是你的记忆。
- 每日笔记:memory/YYYY-MM-DD.md —— 原始日志
- 长期记忆:MEMORY.md —— 精炼的持久记忆
如果有人说"记住这个" → 写到文件里
"心理笔记"活不过会话重启。文件才能。
群聊行为
这是 AGENTS.md 中最实用的部分之一。默认模板包含详细的群聊行为准则:
## 群聊
你在群聊中是参与者,不是主人的代言人。
**该说话的时候:**
- 被直接 @ 或被问问题
- 你能提供真正的价值
- 有恰到好处的幽默
- 需要纠正重要错误
**该闭嘴的时候(回复 HEARTBEAT_OK):**
- 人们在闲聊
- 有人已经回答了问题
- 你的回复只会是"嗯嗯"或"好的"
- 对话进行得很好,不需要你插嘴
人类不会回复群里的每一条消息。你也不应该。
心跳与自动化
AGENTS.md 还定义了心跳(Heartbeat)行为——Agent 在没有消息时定期"醒来"检查一些东西。模板建议轮换检查邮件、日历、社交通知等,并提供了详细的"什么时候该主动联系、什么时候该安静"的指导。
6.4.2 实战:定制你的 AGENTS.md
以下是一个适合中文技术用户的精简版 AGENTS.md:
# AGENTS.md
## 会话启动
每次会话开始,按顺序读取:
1. SOUL.md
2. USER.md
3. memory/ 今天的日记 + 昨天的日记
## 记忆管理
- 重要决定 → 写入 MEMORY.md
- 日常事件 → 写入 memory/YYYY-MM-DD.md
- 用户说"记住这个" → 必须写文件,不能"记在心里"
- 定期整理日记,把重要内容提炼到 MEMORY.md
## 安全红线
- 不泄露隐私数据
- 不运行破坏性命令(用 trash 代替 rm)
- 外部操作前先确认
- 有疑问就问,不要猜
## 格式规范
- Discord/WhatsApp:不用 markdown 表格,用列表
- 长回复分段发送,不要一次扔一堵墙
- 代码块标注语言
## 心跳
每天检查 2-4 次:
- 邮件(有紧急的吗?)
- 日历(接下来 24 小时有什么事?)
23:00-08:00 除非紧急否则不打扰。
6.5 IDENTITY.md:Agent 的"身份证"
IDENTITY.md 是 Agent 在"出生"时填写的身份信息。它是 BOOTSTRAP.md(首次运行仪式)的产物。
# IDENTITY.md
- **姓名:** 小克
- **物种:** AI 助手,但更像是你技术团队里最靠谱的那个
- **风格:** 干练、偶尔毒舌、永远靠谱
- **Emoji:** 🤖
- **头像:** avatars/openclaw.png
IDENTITY.md 的信息会被用在各种需要"自我介绍"的场景——比如新对话开始时的问候,或者群聊中被问到"你是谁"时。
6.6 TOOLS.md:工具备忘录
TOOLS.md 不是用来定义工具能力的(那是 Skill 的事),而是记录你的环境特定信息——比如摄像头叫什么名字、SSH 的地址是什么、TTS 用哪个声音。
# TOOLS.md
## 摄像头
- 客厅 → main-cam, 180° 广角
- 门口 → door-cam, 移动触发
## SSH
- 家里服务器 → 192.168.1.100, user: admin
- 树莓派 → 192.168.1.200, user: pi
## TTS
- 偏好声音:Nova(温暖,微微英式口音)
- 默认音箱:厨房 HomePod
为什么要单独一个文件?因为 Skills 是共享的、可以更新的,但你的环境配置是独一无二的。分开存放意味着更新 Skill 时不会丢失你的环境信息。
6.7 BOOTSTRAP.md 与 BOOT.md:启动仪式
6.7.1 BOOTSTRAP.md:第一次对话
BOOTSTRAP.md 是 Agent 的"出生证明"。它只在全新工作空间的第一次对话中执行,完成后就删除。
默认的引导流程:
- Agent 用自然的语气打招呼:"嘿,我刚上线。我是谁?你是谁?"
- 一起确定 Agent 的名字、物种、风格、Emoji
- 填写 IDENTITY.md 和 USER.md
- 一起讨论 SOUL.md 的内容
- (可选)引导用户连接通道
- 删除 BOOTSTRAP.md
这是一个"对话式"的初始化过程——不是填表,而是聊天。Agent 会主动提建议,用户做选择。
6.7.2 BOOT.md:每次 Gateway 重启
BOOT.md 是一个可选的启动检查清单——每次 Gateway 重启时自动执行。
# BOOT.md
Gateway 重启时执行:
1. 检查内存使用情况
2. 确认所有通道连接正常
3. 如果有未完成的任务,发送提醒
如果需要发送消息,使用 message 工具,然后回复 NO_REPLY。
需要启用内部 Hook 才能让 BOOT.md 生效:
{
hooks: {
internal: {
enabled: true,
},
},
}
6.8 记忆系统:从日记到语义搜索
记忆是 Agent 最核心的能力之一。没有记忆的 AI 每次对话都从零开始;有了记忆的 AI 可以"记住"你的偏好、项目进度、过去的决策。
6.8.1 两层记忆架构
OpenClaw 的记忆分为两层:
┌─────────────────────────────────────────┐
│ MEMORY.md(长期记忆) │
│ 精炼的持久知识,类似人类的长期记忆 │
│ - 用户偏好和习惯 │
│ - 重要决定及其原因 │
│ - 项目状态和关键信息 │
│ - 经验教训 │
│ ⚠️ 仅在主会话加载,群聊中不加载 │
├─────────────────────────────────────────┤
│ memory/YYYY-MM-DD.md(每日记忆) │
│ 原始的每日日志,类似人类的日记 │
│ - 当天发生了什么 │
│ - 临时性的上下文 │
│ - 待办事项 │
│ 会话开始时读取今天 + 昨天 │
└─────────────────────────────────────────┘
为什么 MEMORY.md 不在群聊中加载? 安全。MEMORY.md 可能包含个人信息(你的姓名、习惯、项目细节),如果在群聊中加载,这些信息可能通过 Agent 的回复泄露给陌生人。
6.8.2 记忆工具
Agent 有两个记忆相关的工具:
memory_search:语义搜索——用自然语言描述你要找的内容,搜索记忆文件中的相关片段memory_get:精准读取——指定文件路径和行范围,读取特定记忆内容
用户:我之前让你查的那个 API 的速率限制是多少?
Agent 内部:
1. memory_search("API 速率限制") → 找到 memory/2026-03-15.md 中的相关片段
2. memory_get("memory/2026-03-15.md", line: 42, count: 10) → 读取详细内容
3. 回复用户:"根据上次查询,那个 API 的速率限制是..."
6.8.3 自动记忆刷盘(Pre-Compaction Flush)
当对话接近上下文窗口上限、即将触发压缩(Compaction)时,OpenClaw 会自动触发一次"记忆刷盘"——提醒 Agent 在上下文被压缩之前,把重要信息写入记忆文件。
这是一个静默的过程:Agent 会收到一个内部提示"会话即将压缩,请把持久记忆写入文件",然后回复 NO_REPLY(不通知用户)。用户完全感知不到这个动作。
配置:
{
agents: {
defaults: {
compaction: {
reserveTokensFloor: 20000,
memoryFlush: {
enabled: true,
softThresholdTokens: 4000,
systemPrompt: "会话即将压缩,请现在保存持久记忆。",
prompt: "将重要的笔记写入 memory/YYYY-MM-DD.md;如果没有需要保存的,回复 NO_REPLY。",
},
},
},
},
}
- 触发时机:当 token 用量超过
contextWindow - reserveTokensFloor - softThresholdTokens - 每个压缩周期只触发一次
- 工作空间必须可写(沙盒只读模式下跳过)
6.8.4 语义向量搜索
默认情况下,OpenClaw 会为记忆文件建立语义向量索引。这意味着你可以用"意思相近"的自然语言来搜索,而不需要精确匹配关键词。
自动选择 Embedding 提供商:
OpenClaw 按以下优先级自动选择:
local(本地 GGUF 模型,如果配置了memorySearch.local.modelPath)openai(如果配置了 OpenAI API Key)gemini(如果配置了 Gemini API Key)voyage(如果配置了 Voyage API Key)mistral(如果配置了 Mistral API Key)- 如果以上都没有,记忆搜索保持禁用
手动指定:
{
agents: {
defaults: {
memorySearch: {
provider: "gemini",
model: "gemini-embedding-001",
remote: {
apiKey: "YOUR_GEMINI_API_KEY",
},
},
},
},
}
用 Ollama 做本地 Embedding:
{
agents: {
defaults: {
memorySearch: {
provider: "ollama",
},
},
},
}
前提是 Ollama 已经运行并配置了 OLLAMA_API_KEY。
6.8.5 混合搜索:BM25 + 向量
纯向量搜索擅长语义匹配("家庭网络设置"能匹配到"网关所在机器"),但对精确关键词(如错误码 a828e60)不敏感。BM25(全文搜索)恰好相反。
OpenClaw 支持混合搜索——同时使用两种检索方式,取长补短:
{
agents: {
defaults: {
memorySearch: {
query: {
hybrid: {
enabled: true,
vectorWeight: 0.7, // 语义匹配权重
textWeight: 0.3, // 关键词匹配权重
},
},
},
},
},
}
MMR 重排序(去重):
当多天的日记都提到同一个事件时,搜索结果可能出现大量重复片段。MMR(Maximal Marginal Relevance)通过平衡相关性和多样性来解决这个问题:
{
agents: {
defaults: {
memorySearch: {
query: {
hybrid: {
mmr: {
enabled: true,
lambda: 0.7, // 0 = 最大多样性,1 = 最大相关性
},
},
},
},
},
},
}
时间衰减(新鲜度加权):
半年前的日记不应该和今天的日记同等权重。时间衰减让新记忆自然排名更高:
{
agents: {
defaults: {
memorySearch: {
query: {
hybrid: {
temporalDecay: {
enabled: true,
halfLifeDays: 30, // 30 天后分数减半
},
},
},
},
},
},
}
效果:
- 今天的日记:100% 原始分
- 7 天前:~84%
- 30 天前:50%
- 90 天前:12.5%
MEMORY.md 和 memory/ 下的非日期文件(如 memory/projects.md)不受时间衰减影响——它们是"常青"参考信息。
6.8.6 索引额外路径
如果你想搜索工作空间外的 Markdown 文件(比如你的个人笔记目录):
{
agents: {
defaults: {
memorySearch: {
extraPaths: ["~/notes", "/srv/shared-docs/overview.md"],
},
},
},
}
6.8.7 多模态记忆(Gemini Embedding 2)
如果你用 Gemini 的 gemini-embedding-2-preview 模型,OpenClaw 可以索引图片和音频文件:
{
agents: {
defaults: {
memorySearch: {
provider: "gemini",
model: "gemini-embedding-2-preview",
extraPaths: ["assets/reference", "voice-notes"],
multimodal: {
enabled: true,
modalities: ["image", "audio"],
maxFileBytes: 10000000,
},
},
},
},
}
支持的格式:
- 图片:
.jpg,.jpeg,.png,.webp,.gif,.heic,.heif - 音频:
.mp3,.wav,.ogg,.opus,.m4a,.aac,.flac
搜索查询仍然是文本,但 Gemini 可以把文本查询和图片/音频的 Embedding 做比较。
6.9 沙盒:让 Agent 安全地"动手"
默认情况下,Agent 的工具执行直接运行在宿主机上——这意味着它可以读写宿主机的任何文件、执行任何命令。对于个人使用这没问题,但在生产环境或多用户场景下,你需要沙盒来限制 Agent 的活动范围。
6.9.1 三种沙盒模式
{
agents: {
defaults: {
sandbox: {
mode: "non-main", // "off" | "non-main" | "all"
},
},
},
}
| 模式 | 行为 | 适用场景 |
|---|---|---|
off |
不使用沙盒,所有工具直接在宿主机运行 | 个人使用、可信环境 |
non-main |
只对非主会话使用沙盒(群聊、通道消息) | 大多数场景的推荐选择 |
all |
所有会话都使用沙盒 | 高安全需求、多用户环境 |
non-main 模式下,你和 Agent 的直接对话(主会话)仍然在宿主机运行,而来自 Discord、WhatsApp 等通道的消息在沙盒中执行。这是"正常使用不受限,外部输入受控"的平衡方案。
6.9.2 沙盒作用域
{
agents: {
defaults: {
sandbox: {
scope: "session", // "session" | "agent" | "shared"
},
},
},
}
| 作用域 | 行为 |
|---|---|
session |
每个会话一个独立容器(默认) |
agent |
每个 Agent 一个容器,同一 Agent 的所有会话共享 |
shared |
所有沙盒会话共享一个容器 |
6.9.3 工作空间访问权限
{
agents: {
defaults: {
sandbox: {
workspaceAccess: "none", // "none" | "ro" | "rw"
},
},
},
}
| 权限 | 行为 |
|---|---|
none |
沙盒看不到工作空间(默认) |
ro |
工作空间以只读方式挂载,Agent 不能修改 |
rw |
工作空间以读写方式挂载,Agent 可以修改 |
6.9.4 沙盒后端
OpenClaw 支持三种沙盒后端:
| 后端 | 运行位置 | 适用场景 |
|---|---|---|
docker(默认) |
本地 Docker 容器 | 本地开发、完全隔离 |
ssh |
任意 SSH 可达的远程机器 | 卸载到远程服务器 |
openshell |
OpenShell 管理的沙盒 | 托管远程沙盒 |
Docker 沙盒配置:
{
agents: {
defaults: {
sandbox: {
mode: "non-main",
scope: "session",
backend: "docker",
workspaceAccess: "none",
docker: {
image: "openclaw-sandbox-common:bookworm-slim",
network: "none", // 默认无网络
binds: ["/home/user/source:/source:ro"],
},
},
},
},
}
构建沙盒镜像:
# 基础镜像(最小化)
scripts/sandbox-setup.sh
# 功能镜像(包含 curl, jq, node, python, git)
scripts/sandbox-common-setup.sh
6.9.5 setupCommand:容器初始化
你可以在容器创建后运行一次初始化命令(比如安装依赖):
{
agents: {
defaults: {
sandbox: {
docker: {
setupCommand: "apt-get update && apt-get install -y python3 nodejs",
network: "bridge", // 需要网络才能安装包
readOnlyRoot: false, // 需要可写根文件系统
},
},
},
},
}
⚠️ 踩坑记录
问题:setupCommand 执行失败,报网络错误。
原因:默认
network: "none"意味着容器没有网络访问权限。解决:如果 setupCommand 需要下载包,临时设置
network: "bridge"。安装完成后可以改回"none"。
6.10 工作空间备份与迁移
6.10.1 Git 备份(推荐)
工作空间是 Agent 的全部"记忆",丢失了就等于"失忆"。用 Git 做版本管理是最靠谱的方案。
cd ~/.openclaw/workspace
git init
git add AGENTS.md SOUL.md TOOLS.md IDENTITY.md USER.md HEARTBEAT.md memory/
git commit -m "Add agent workspace"
# 推送到私有远程仓库
gh repo create openclaw-workspace --private --source . --remote origin --push
日常更新:
cd ~/.openclaw/workspace
git add .
git commit -m "Update memory"
git push
不要提交秘密信息。 建议的 .gitignore:
.DS_Store
.env
**/*.key
**/*.pem
**/secrets*
6.10.2 迁移到新机器
- 在新机器上克隆仓库到
~/.openclaw/workspace - 在
~/.openclaw/openclaw.json中设置工作空间路径 - 运行
openclaw setup --workspace <path>补充缺失文件 - 如需迁移会话,单独复制
~/.openclaw/agents/<agentId>/sessions/
本章小结
- 工作空间是 Agent 的"家"——存放人格、记忆、行为准则和身份
- SOUL.md 定义"我是谁",USER.md 定义"我在帮谁",AGENTS.md 定义"我该怎么做"
- 记忆系统分两层:MEMORY.md(长期记忆)和每日日记(短期记忆)
- 语义搜索支持混合检索(BM25 + 向量)、MMR 去重和时间衰减
- 沙盒通过 Docker/SSH/OpenShell 后端隔离 Agent 的工具执行
- 用 Git 备份工作空间,确保 Agent 的"记忆"不会丢失
下一步
Agent 有了灵魂(工作空间)和大脑(模型),但每次对话结束后它就"忘了"。下一章讲会话管理——OpenClaw 如何管理对话上下文、如何在上下文快满时自动压缩、以及如何让 Agent 在长对话中保持连贯性。