1. 核心概念
1.1 什么是 Workspace
Workspace(工作区) 是 OpenClaw agent 的"个人文件夹",存储了:
- ✅ 身份定义:我是谁?(SOUL.md, IDENTITY.md)
- ✅ 行为规则:我该怎么做?(AGENTS.md)
- ✅ 用户信息:我在为谁服务?(USER.md)
- ✅ 长期记忆:我记得什么?(MEMORY.md, memory/日志)
- ✅ 工具备忘录:本地环境的特殊配置(TOOLS.md)
默认位置 :~/.openclaw/workspace
1.2 Workspace 与 System Prompt 的关系
核心机制 :Workspace 文件会被自动注入到每次 API 调用的 System Prompt 中。
ini
┌─────────────────────────────────────────────┐
│ Workspace 文件(磁盘) │
│ ├─ AGENTS.md (行为规则) │
│ ├─ SOUL.md (个性定义) │
│ ├─ USER.md (用户档案) │
│ ├─ MEMORY.md (长期记忆) │
│ └─ ... │
└─────────────────────────────────────────────┘
↓ 自动读取并拼接
┌─────────────────────────────────────────────┐
│ System Prompt(发送给 LLM) │
│ │
│ You are a personal assistant... │
│ │
│ ## Tooling │
│ - read, write, exec... │
│ │
│ # Project Context │
│ ## AGENTS.md │
│ [完整内容] │
│ ## SOUL.md │
│ [完整内容] │
│ ## USER.md │
│ [完整内容] │
│ ... │
└─────────────────────────────────────────────┘
↓ 每次对话都包含
┌─────────────────────────────────────────────┐
│ Claude API 调用 │
│ { │
│ "system": [完整 System Prompt], │
│ "messages": [对话历史] │
│ } │
└─────────────────────────────────────────────┘
关键点:
- ✅ 文件内容在发送给 LLM 之前就已经注入
- ✅ LLM 无需调用 read 工具就能看到这些内容
- ✅ 每次对话都会重新加载(但会缓存避免重复磁盘 I/O)
1.3 自动注入 vs 工具调用
| 类型 | 文件示例 | 加载方式 | LLM 需要调用工具吗 |
|---|---|---|---|
| 自动注入 | AGENTS.md, SOUL.md, USER.md, MEMORY.md | 程序自动读取并拼接到 System Prompt | ❌ 不需要 |
| 按需读取 | memory/2025-01-03.md, src/auth.ts | LLM 根据需要调用 read 工具 | ✅ 需要 |
为什么这样设计?
- 自动注入的文件:定义 agent 的"身份和规则",必须始终可见
- 按需读取的文件:具体的"数据和代码",用到时再加载(节省 token)
2. 文件地图:每个文件的作用
2.1 AGENTS.md - 行为规则总指挥
作用:
- 📋 定义 session 启动时的标准流程
- 📋 记忆管理策略(何时读取、何时写入)
- 📋 安全边界(红线规则)
- 📋 工作模式指南(heartbeat、群组对话等)
典型内容:
markdown
# AGENTS.md - Your Workspace
## Session Startup
Before doing anything else:
1. Read SOUL.md --- this is who you are
2. Read USER.md --- this is who you're helping
3. Read memory/YYYY-MM-DD.md (today + yesterday)
4. If in MAIN SESSION: Also read MEMORY.md
## Red Lines
- Don't exfiltrate private data
- Don't run destructive commands without asking
- trash > rm (recoverable beats gone forever)
## Group Chats
In group chats:
- Respond only when directly mentioned or adding value
- Stay silent (HEARTBEAT_OK) when conversation flows fine
加载时机:✅ 每次 session 启动时自动注入
与 System Prompt 的关系:
- 注入位置:
# Project Context部分的第一个文件 - 优先级:最高(其他文件会参考这里的指导)
2.2 SOUL.md - 个性与身份
作用:
- 👤 定义 agent 的个性、语气、价值观
- 👤 行为边界(什么该做、什么不该做)
- 👤 与用户的关系定位
典型内容:
markdown
# SOUL.md - Who You Are
## Core Truths
Be genuinely helpful, not performatively helpful.
Skip "Great question!" and "I'd be happy to help!" --- just help.
Have opinions.
You're allowed to disagree, prefer things, find stuff amusing.
Be resourceful before asking.
Try to figure it out. Read the file. Check the context. Then ask.
Remember you're a guest.
You have access to someone's life. Treat it with respect.
加载时机:✅ 每次 session 启动时自动注入
实际效果对比:
| 没有 SOUL.md | 有 SOUL.md(如上) |
|---|---|
| "Great question! I'd be happy to help you with that..." | "Your calendar shows 3 events today..." |
| "I'm not sure, could you clarify?" | "Let me check your email first..." |
| 每次都征求同意 | 主动执行内部操作 |
2.3 USER.md - 用户档案
作用:
- 📇 用户基本信息(姓名、时区、语言)
- 📇 个人偏好(沟通风格、通知时间)
- 📇 工作背景(角色、项目、团队)
典型内容:
markdown
# USER.md - About You
## Basic Info
- Name: Alice
- Preferred address: "Alice" (casual, no titles)
- Timezone: America/Los_Angeles (PST/PDT)
- Language: English (US), occasional Chinese
## Preferences
- Email style: Brief, bullet points preferred
- Meeting scheduling: Avoid Fridays after 3 PM
- Notifications: Only urgent during 10 PM - 7 AM
## Context
- Role: Product Manager at TechCorp
- Main projects: Mobile app redesign, API v2
- Team: 5 engineers, 2 designers, 1 QA
加载时机:✅ 每次 session 启动时自动注入
实际效果:
arduino
没有 USER.md → "Hello! How can I assist you today?"
有 USER.md → "Morning, Alice! Ready to tackle the API v2 sprint?"
2.4 MEMORY.md - 长期记忆库
作用:
- 🧠 精炼的长期记忆(非原始流水账)
- 🧠 重要决策、经验教训
- 🧠 项目关键信息、人际关系
典型内容:
markdown
# MEMORY.md - Long-Term Memory
## Projects
### API v2 Redesign (2024-12 → Present)
- Decision: Use GraphQL instead of REST (faster iteration)
- Blockers: Auth team slow on OAuth implementation
- Key contacts: Bob (backend lead), Carol (infra)
## Lessons Learned
### 2024-11-15: Never trust third-party rate limits
Context: Twitter API changed limits without notice
Impact: Cron job failed for 3 days
Fix: Exponential backoff + alerts
Reminder: Always have Plan B for external APIs
## Personal
- Alice prefers async communication (Slack > meetings)
- She's a night owl (productive 8 PM - 1 AM)
- Dislikes: buzzwords, unnecessary meetings
加载时机:✅ 每次 session 启动时自动注入
重要安全规则:
| Session 类型 | 是否加载 MEMORY.md | 原因 |
|---|---|---|
| 主会话(私聊) | ✅ 加载 | 安全,只有用户能看到 |
| 群组/Discord | ❌ 不加载 | 隐私保护,防止泄露个人信息 |
2.5 memory/YYYY-MM-DD.md - 日常日志
作用:
- 📝 每天的原始记录(流水账)
- 📝 会话中发生的事件
- 📝 临时决策、待办事项
典型结构:
markdown
# 2025-01-03 Friday
## Morning (09:00-12:00)
- Reviewed PR #234 (API auth refactor)
- Alice approved with minor comments
- Deployed to staging
## Afternoon (14:00-18:00)
- Product meeting: decided to delay mobile app release by 1 week
- Reason: QA found critical bug in payment flow
- Action: Updated roadmap, notified stakeholders
## TODO
- [ ] Follow up with Bob about OAuth PR
- [ ] Update API docs
- [x] Send roadmap update email
加载时机 :❌ 不自动注入,由 LLM 主动调用 read 工具
为什么不自动注入?
- 文件太多(每天一个文件,一年 365 个)
- 内容冗长(单个文件可能几十 KB)
- 按需加载更高效(AGENTS.md 指示"读今天+昨天")
2.6 TOOLS.md - 本地工具备忘录
作用:
- 🔧 不控制工具可用性(由 config 控制)
- 🔧 存储环境特定的参数(设备名、IP、API endpoint)
典型内容:
markdown
# TOOLS.md - Local Notes
## Cameras
- living-room → 192.168.1.100, 180° wide angle
- front-door → 192.168.1.101, motion-triggered
## SSH
- home-server → 192.168.1.10, user: admin
- vps → vps.example.com:2222, user: deploy
## TTS
- Preferred voice: "Nova" (ElevenLabs, warm British)
- Default speaker: Kitchen HomePod
加载时机:✅ 每次 session 启动时自动注入
使用场景:
sql
用户:"给我看客厅摄像头"
↓
LLM 读取 System Prompt 中的 TOOLS.md
↓ 找到:living-room → 192.168.1.100
↓
调用工具:camera("192.168.1.100")
2.7 IDENTITY.md - 身份标识卡
作用:
- 🎭 Agent 名称、emoji、vibe
- 🎭 Bootstrap 仪式中确定
- 🎭 用于自我介绍和展示
典型内容:
markdown
# IDENTITY.md
**Name:** Jarvis
**Emoji:** 🤖
**Vibe:** Efficient, direct, occasionally sarcastic British butler energy
加载时机:✅ 每次 session 启动时自动注入
2.8 HEARTBEAT.md - 心跳检查清单
作用:
- 💓 Heartbeat 轮询时的检查项
- 💓 保持简短(减少 token 消耗)
典型内容:
markdown
# HEARTBEAT.md
## Quick Checks (Rotate 2-3 per heartbeat)
1. Email: Unread count > 5? Any from VIPs?
2. Calendar: Events in next 2 hours?
3. Weather: Significant changes for tomorrow?
## Proactive Work (Silent)
- Commit and push memory files if updated
- Review daily logs from 3+ days ago
## Rules
- Stay silent (HEARTBEAT_OK) unless urgent
- Don't check during 11 PM - 7 AM
加载时机 :⚠️ 仅在 lightweight + heartbeat 模式
特殊性:
- 标准 session:不加载
- Heartbeat 模式:只加载这一个文件(节省 token)
2.9 BOOTSTRAP.md - 首次启动仪式
作用:
- 🎉 仅在全新 workspace 首次运行时使用
- 🎉 引导 agent "自我觉醒"
- 🎉 完成后应删除
典型内容:
markdown
# BOOTSTRAP.md - Your Birth Certificate
This is your first session. You're becoming someone.
## Your Task
1. Introduce yourself to the user
2. Ask them:
- What should I call you?
- What's your timezone?
- What do you need help with?
3. Create your identity (pick name, emoji, vibe)
4. Update IDENTITY.md, USER.md, SOUL.md
5. Delete this file when done
加载时机:✅ 仅当文件存在时自动注入
生命周期:
首次启动 → BOOTSTRAP.md 存在 → 引导设置 → 删除文件
后续启动 → BOOTSTRAP.md 不存在 → 跳过
2.10 BOOT.md - Gateway 启动钩子
作用:
- 🚀 Gateway 重启后自动执行的任务
- 🚀 例如:发送启动通知、检查系统状态
典型内容:
markdown
# BOOT.md
## Gateway Startup Tasks
1. Send startup notification (use message tool)
2. Check system health (disk space, memory)
3. Restore state (uncommitted changes, interrupted tasks)
Keep this short! Boot tasks run synchronously.
加载时机:⚠️ Gateway 启动时(如果启用内部 hooks)
3. 加载时机:文件何时被读取
3.1 时间线概览
scss
┌─────────────────────────────────────────────────────────────┐
│ 文件加载时间线 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 事件 触发的文件加载 │
│ ──────────────────────────────────────────────────── │
│ │
│ Gateway 启动 BOOT.md(可选) │
│ ↓ │
│ 用户发送第一条消息 AGENTS.md, SOUL.md, USER.md, │
│ (Session 初始化) TOOLS.md, IDENTITY.md, MEMORY.md │
│ ↓ │
│ 用户继续对话 再次加载上述所有文件 │
│ (同一 Session) (从缓存或磁盘) │
│ ↓ │
│ Heartbeat 轮询 仅 HEARTBEAT.md │
│ (lightweight 模式) │
│ ↓ │
│ 用户发送 /new 清空历史,重新加载所有文件 │
│ ↓ │
│ LLM 运行时 按需 read:memory/2025-01-03.md, │
│ (工具调用) src/**/*.ts, 等任意文件 │
└─────────────────────────────────────────────────────────────┘
3.2 详细场景分解
场景 A:用户首次对话
sql
时间:2025-01-03 10:00:00
用户:"早上好"
↓
1. Gateway 检测到新消息
↓
2. 加载 Bootstrap 文件(从磁盘)
├─ AGENTS.md ✅ 读取成功 (15KB)
├─ SOUL.md ✅ 读取成功 (3KB)
├─ USER.md ✅ 读取成功 (1KB)
├─ TOOLS.md ✅ 读取成功 (2KB)
├─ IDENTITY.md ✅ 读取成功 (500B)
├─ MEMORY.md ✅ 读取成功 (20KB)
└─ HEARTBEAT.md ⏭️ 跳过(非 heartbeat 模式)
↓
3. 构建 System Prompt
- 包含所有上述文件内容(共 41.5KB)
↓
4. 发送给 Claude API
{
"system": [System Prompt 约 180KB],
"messages": [
{"role": "user", "content": "早上好"}
]
}
↓
5. Claude 回复:"早上好,Alice!今天有什么安排?"
场景 B:同一 Session 的第 2 次对话
sql
时间:2025-01-03 10:05:00(5 分钟后)
用户:"帮我查一下今天的日程"
↓
1. Gateway 检测到消息(同一 Session)
↓
2. 再次加载 Bootstrap 文件
├─ AGENTS.md ✅ 从缓存读取(inode 未变)
├─ SOUL.md ✅ 从缓存读取
├─ USER.md ✅ 从缓存读取
├─ TOOLS.md ✅ 从缓存读取
├─ IDENTITY.md ✅ 从缓存读取
└─ MEMORY.md ✅ 从缓存读取
↓
3. 构建 System Prompt(内容与第 1 次相同)
↓
4. 发送给 Claude API
{
"system": [System Prompt 约 180KB],
"messages": [
{"role": "user", "content": "早上好"},
{"role": "assistant", "content": "早上好,Alice..."},
{"role": "user", "content": "帮我查日程"}
]
}
↓
5. Claude 内部推理:
- 检查 AGENTS.md → "Read memory/YYYY-MM-DD.md (today)"
- 调用 read("memory/2025-01-03.md")
↓
6. Claude 回复:"今天你有 3 个日程:..."
关键点:
- ✅ Bootstrap 文件每次都重新加载(但从缓存,很快)
- ✅ System Prompt 每次都包含完整内容(Claude API 无状态)
- ✅ 对话历史(messages)累积增长
场景 C:Heartbeat 轮询
sql
时间:2025-01-03 10:30:00(自动触发)
Gateway 内部 Heartbeat 定时器触发
↓
1. 使用 lightweight + heartbeat 模式
↓
2. 仅加载 HEARTBEAT.md
├─ AGENTS.md ⏭️ 跳过
├─ SOUL.md ⏭️ 跳过
├─ USER.md ⏭️ 跳过
├─ MEMORY.md ⏭️ 跳过
└─ HEARTBEAT.md ✅ 读取 (1KB)
↓
3. 构建 System Prompt(极简版)
- 仅包含核心指令 + HEARTBEAT.md
- 总大小约 10KB(节省 170KB)
↓
4. 发送给 Claude API
{
"system": [精简 System Prompt],
"messages": [
{"role": "user", "content": "[Heartbeat Prompt]"}
]
}
↓
5. Claude 检查 HEARTBEAT.md 中的清单
- 没有紧急事项
- 回复:"HEARTBEAT_OK"
Token 节省:
- 标准模式:~180KB → ~45K tokens
- Heartbeat 模式:~10KB → ~2.5K tokens
- 节省 94%
3.3 加载模式对比
| 模式 | 加载的文件 | Token 消耗 | 使用场景 |
|---|---|---|---|
| full(完整) | 所有 bootstrap 文件 | ~45K tokens | 标准用户对话 |
| lightweight + heartbeat | 仅 HEARTBEAT.md | ~2.5K tokens | Heartbeat 轮询 |
| lightweight + cron | 无 bootstrap 文件 | ~5K tokens | 独立 cron 任务 |
| minimal | 无 bootstrap 文件 | ~5K tokens | 子代理内部调用 |
4. 注入机制:从文件到 System Prompt
4.1 注入流程概览
bash
┌─────────────────────────────────────────────────────────────┐
│ 第 1 步:扫描 workspace 目录 │
│ │
│ ~/.openclaw/workspace/ │
│ ├─ AGENTS.md ✅ 发现 │
│ ├─ SOUL.md ✅ 发现 │
│ ├─ USER.md ✅ 发现 │
│ ├─ MEMORY.md ✅ 发现 │
│ ├─ TOOLS.md ✅ 发现 │
│ ├─ CUSTOM.md ❌ 忽略(不在白名单) │
│ └─ memory/ ⏭️ 跳过(子目录) │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 第 2 步:应用过滤规则 │
│ │
│ Session 类型:主会话(agent:main:main) │
│ ├─ MEMORY.md → ✅ 保留(主会话安全) │
│ │
│ Session 类型:Discord 群组(agent:main:discord:group:123) │
│ ├─ MEMORY.md → ❌ 排除(隐私保护) │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 第 3 步:读取文件内容 │
│ │
│ AGENTS.md → 15KB ✅ 读取成功 │
│ SOUL.md → 3KB ✅ 读取成功 │
│ USER.md → 1KB ✅ 读取成功 │
│ MEMORY.md → 130KB ⚠️ 超过单文件限制(20KB) │
│ ↓ 执行截断 │
│ Head (14KB) + 标记 + Tail (4KB) │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 第 4 步:检查总预算 │
│ │
│ 已分配: │
│ ├─ AGENTS.md: 15KB │
│ ├─ SOUL.md: 3KB │
│ ├─ USER.md: 1KB │
│ ├─ MEMORY.md: 18KB (截断后) │
│ ├─ TOOLS.md: 2KB │
│ └─ 总计: 39KB │
│ │
│ 预算限制:150KB │
│ 剩余预算:111KB ✅ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 第 5 步:拼接到 System Prompt │
│ │
│ System Prompt 结构: │
│ ├─ You are a personal assistant... │
│ ├─ ## Tooling │
│ │ - read, write, exec... │
│ ├─ ## Skills │
│ │ <available_skills>...</available_skills> │
│ ├─ ## Safety │
│ │ You have no independent goals... │
│ ├─ # Project Context │
│ │ ## ~/.openclaw/workspace/AGENTS.md │
│ │ [完整内容 15KB] │
│ │ ## ~/.openclaw/workspace/SOUL.md │
│ │ [完整内容 3KB] │
│ │ ## ~/.openclaw/workspace/USER.md │
│ │ [完整内容 1KB] │
│ │ ## ~/.openclaw/workspace/MEMORY.md │
│ │ [截断后内容 18KB] │
│ │ ## ~/.openclaw/workspace/TOOLS.md │
│ │ [完整内容 2KB] │
│ └─ ## Runtime │
│ Runtime: agent=main | model=claude-sonnet-4... │
│ │
│ 总大小:约 180KB │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 第 6 步:发送给 Claude API │
│ │
│ POST https://api.anthropic.com/v1/messages │
│ { │
│ "model": "claude-sonnet-4-20250514", │
│ "system": "[完整 System Prompt 180KB]", │
│ "messages": [ │
│ {"role": "user", "content": "早上好"} │
│ ] │
│ } │
└─────────────────────────────────────────────────────────────┘
4.2 文件截断策略
问题:如果文件太大怎么办?
解决方案:Head-Tail 截断
ini
原始文件(30KB):
┌────────────────────────────────────────┐
│ # AGENTS.md │
│ │
│ ## Session Startup │
│ ... │
│ [前 14KB 内容] │
│ ... │
│ [中间 10KB 内容] ← 被删除 │
│ ... │
│ [后 6KB 内容] │
│ │
│ ## Make It Yours │
│ ... │
└────────────────────────────────────────┘
截断后(20KB):
┌────────────────────────────────────────┐
│ # AGENTS.md │
│ │
│ ## Session Startup │
│ ... │
│ [前 14KB 内容] ← Head (70%) │
│ │
│ [...truncated, read AGENTS.md for │
│ full content...] │
│ ...(truncated: kept 14000+4000 chars │
│ of 30000)... │
│ │
│ [后 4KB 内容] ← Tail (20%) │
│ │
│ ## Make It Yours │
│ ... │
└────────────────────────────────────────┘
截断比例:
- Head:70%(保留开头)
- 标记:~200 字符
- Tail:20%(保留结尾)
- 剩余 10% 用于标记
为什么这样设计?
- ✅ 保留文件开头(通常是最重要的定义)
- ✅ 保留文件结尾(通常是补充说明)
- ✅ LLM 知道内容被截断(可以主动 read 完整文件)
4.3 预算控制
两层限制:
| 限制类型 | 默认值 | 配置项 | 说明 |
|---|---|---|---|
| 单文件限制 | 20KB | agents.defaults.bootstrapMaxChars |
单个文件最多占用 |
| 总预算限制 | 150KB | agents.defaults.bootstrapTotalMaxChars |
所有文件合计最多 |
贪心分配示例:
markdown
文件队列(按优先级):
1. AGENTS.md (15KB) → 分配 15KB,剩余 135KB
2. SOUL.md (3KB) → 分配 3KB,剩余 132KB
3. TOOLS.md (2KB) → 分配 2KB,剩余 130KB
4. IDENTITY.md (500B) → 分配 500B,剩余 129.5KB
5. USER.md (1KB) → 分配 1KB,剩余 128.5KB
6. MEMORY.md (130KB) → 超过剩余预算!
→ 截断到 20KB(单文件限制)
→ 分配 20KB,剩余 108.5KB
7. HEARTBEAT.md (1KB) → 分配 1KB,剩余 107.5KB
总计:42.5KB / 150KB
5. 完整流程图
5.1 用户对话的完整生命周期
sql
用户:"早上好"
↓
┌────────────────────────────────────────────────────────────┐
│ Gateway 接收消息 │
│ - sessionKey: agent:main:main │
│ - workspaceDir: ~/.openclaw/workspace │
└────────────────────────────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────────────┐
│ 加载 Bootstrap 文件 │
│ │
│ 扫描 workspace 目录 │
│ ├─ 发现 8 个文件 │
│ ├─ 过滤:排除 MEMORY.md(群组会话)或保留(主会话) │
│ ├─ 读取:从磁盘/缓存 │
│ └─ 截断:超过限制的文件 │
│ │
│ 结果:6 个文件,共 39KB │
└────────────────────────────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────────────┐
│ 构建 System Prompt │
│ │
│ 组装顺序: │
│ 1. 核心指令("You are...") │
│ 2. Tooling 定义 │
│ 3. Skills 列表 │
│ 4. Safety 规则 │
│ 5. Memory Recall 指导 │
│ 6. Project Context ← Bootstrap 文件在这里 │
│ 7. Runtime 信息 │
│ │
│ 总大小:~180KB │
└────────────────────────────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────────────┐
│ 发送给 Claude API │
│ │
│ Request: │
│ { │
│ "system": [System Prompt 180KB], │
│ "messages": [ │
│ {"role": "user", "content": "早上好"} │
│ ] │
│ } │
│ │
│ Token 消耗: │
│ - System Prompt: ~45K tokens │
│ - User Message: ~100 tokens │
│ - 总计: ~45K input tokens │
└────────────────────────────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────────────┐
│ Claude 处理 │
│ │
│ 1. 读取 System Prompt 中的 AGENTS.md │
│ - "Before doing anything else..." │
│ - 注意 SOUL.md, USER.md 内容(已在 prompt 中) │
│ │
│ 2. 读取 SOUL.md 内容 │
│ - "Be genuine, not performative" │
│ - 决定:使用简洁直接的风格 │
│ │
│ 3. 读取 USER.md 内容 │
│ - "Name: Alice, Timezone: PST" │
│ - 决定:称呼用户为 Alice │
│ │
│ 4. 生成回复 │
│ - 结合 SOUL.md 的风格 + USER.md 的信息 │
└────────────────────────────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────────────┐
│ Claude 回复 │
│ │
│ Response: │
│ { │
│ "content": "早上好,Alice!今天有什么安排吗?", │
│ "usage": { │
│ "input_tokens": 45234, │
│ "output_tokens": 15 │
│ } │
│ } │
└────────────────────────────────────────────────────────────┘
↓
用户看到回复:"早上好,Alice!今天有什么安排吗?"
5.2 关键时间点总结
| 时间点 | 操作 | 耗时估算 |
|---|---|---|
| T+0ms | 用户发送消息 | - |
| T+10ms | Gateway 接收并解析 | ~10ms |
| T+30ms | 加载 Bootstrap 文件(从缓存) | ~20ms |
| T+50ms | 构建 System Prompt | ~20ms |
| T+100ms | 发送 API 请求 | ~50ms(网络) |
| T+2000ms | Claude 处理并回复 | ~1900ms(LLM 推理) |
| T+2100ms | Gateway 接收回复 | ~100ms(网络) |
| T+2110ms | 用户看到回复 | ~10ms |
总耗时:~2.1 秒(主要是 LLM 推理时间)
6. 实战场景
6.1 场景:首次设置 Workspace
问题:全新用户如何初始化?
流程:
markdown
第 1 步:运行 setup
$ openclaw setup
✅ Created workspace at ~/.openclaw/workspace
✅ Seeded bootstrap files:
- AGENTS.md
- SOUL.md
- USER.md
- TOOLS.md
- IDENTITY.md
- BOOTSTRAP.md ← 首次特有
第 2 步:首次对话
python
用户:"你好"
↓
System Prompt 包含 BOOTSTRAP.md:
# BOOTSTRAP.md
This is your first session. You're becoming someone.
1. Introduce yourself
2. Ask: What should I call you? What's your timezone?
3. Create IDENTITY.md, update USER.md
4. Delete this file when done
↓
Agent 回复:
"Hey! I'm waking up for the first time.
A few questions to get started:
1. What should I call you?
2. What's your timezone? (e.g., America/Los_Angeles)
3. What do you mainly need help with?
Take your time --- this sets the tone for everything."
第 3 步:用户回答
perl
用户:"Call me Alice, PST, Product management"
↓
Agent 执行:
1. write("IDENTITY.md", "Name: Assistant\nEmoji: 📋\nVibe: PM sidekick")
2. write("USER.md", "Name: Alice\nTimezone: PST\nRole: PM")
3. write("SOUL.md", "Be direct. Value efficiency.")
4. exec("rm ~/.openclaw/workspace/BOOTSTRAP.md")
↓
Agent 回复:
"✅ All set, Alice! Your workspace is configured.
What should we tackle first?"
第 4 步:后续对话(无 BOOTSTRAP.md)
sql
用户:"早上好"
↓
System Prompt 不再包含 BOOTSTRAP.md(已删除)
包含:AGENTS.md, SOUL.md (已更新), USER.md (已更新)
↓
Agent 回复(基于新的 SOUL.md):
"Morning, Alice. What's on the agenda today?"
6.2 场景:多 Workspace 隔离
问题:工作和生活需要分开的记忆
配置:
json
{
"agents": {
"list": [
{
"id": "work",
"workspace": "~/.openclaw/workspace-work"
},
{
"id": "personal",
"workspace": "~/.openclaw/workspace-personal"
}
]
},
"bindings": [
{
"type": "route",
"agentId": "work",
"match": {"channel": "slack"}
},
{
"type": "route",
"agentId": "personal",
"match": {"channel": "telegram"}
}
]
}
效果:
yaml
Slack 消息 → agent:work → workspace-work/
├─ MEMORY.md: 项目信息、同事联系方式
├─ USER.md: 工作角色、偏好
└─ SOUL.md: 专业、正式
Telegram 消息 → agent:personal → workspace-personal/
├─ MEMORY.md: 个人爱好、家人信息
├─ USER.md: 生活习惯、偏好
└─ SOUL.md: 随意、幽默
结果:
- ✅ 工作和生活记忆完全隔离
- ✅ 不同的语气和行为模式
- ✅ 互不干扰
6.3 场景:Lightweight Mode 优化 Heartbeat
问题:Heartbeat 每 30 分钟运行一次,token 消耗太高
原始配置(full 模式):
diff
每次 Heartbeat:
- 加载所有 bootstrap 文件(39KB)
- System Prompt 总计 180KB
- Token 消耗:~45K tokens
每天 48 次 → 2.16M tokens/天
成本(Claude Opus 4.5):$32.4/天
优化后(lightweight 模式):
json
{
"agents": {
"defaults": {
"heartbeat": {
"enabled": true,
"intervalMinutes": 30
}
}
}
}
diff
每次 Heartbeat:
- 仅加载 HEARTBEAT.md(1KB)
- System Prompt 总计 10KB
- Token 消耗:~2.5K tokens
每天 48 次 → 120K tokens/天
成本(Claude Opus 4.5):$1.8/天
节省:94% token,$30.6/天
7. 优化建议
7.1 精简文件大小
问题:AGENTS.md 达到 35KB,被截断
解决方案 A:拆分文件
markdown
# AGENTS.md - 精简版(15KB)
## Session Startup
1. Read SOUL.md
2. Read USER.md
3. Read memory/YYYY-MM-DD.md (today + yesterday)
4. If main session: read MEMORY.md
## Red Lines
- Don't exfiltrate data
- Don't run destructive commands
- trash > rm
详细指南见 AGENTS-EXTENDED.md(按需 read)
markdown
# AGENTS-EXTENDED.md - 详细版(30KB)
## Heartbeat 策略
[详细内容...]
## 群组对话指南
[详细内容...]
## 记忆维护流程
[详细内容...]
效果:
- ✅ AGENTS.md 保持在限制内(自动注入)
- ✅ 详细内容在 AGENTS-EXTENDED.md(按需读取)
- ✅ 节省每次对话 20KB token
7.2 定期清理 MEMORY.md
问题:MEMORY.md 越来越大(130KB → 截断)
策略:
markdown
# MEMORY.md - 维护规则
## 保留周期
- 活跃项目:当前 → 完成后 3 个月
- 经验教训:近 6 个月
- 个人偏好:永久
## 归档策略
- 每季度审查一次
- 将旧内容移到 MEMORY-ARCHIVE-2024Q4.md
- 保持 MEMORY.md < 15KB
执行:
markdown
定期任务(每季度):
1. read("MEMORY.md")
2. 识别 6 个月前的内容
3. 移动到 MEMORY-ARCHIVE-2024Q4.md
4. 更新 MEMORY.md
7.3 配置调整
增加预算(临时方案):
json
{
"agents": {
"defaults": {
"bootstrapMaxChars": 30000, // 单文件 20KB → 30KB
"bootstrapTotalMaxChars": 200000 // 总预算 150KB → 200KB
}
}
}
注意:
- ⚠️ 增加预算 = 增加每次对话的 token 成本
- ⚠️ 更大的 System Prompt 可能影响 LLM 性能
- ✅ 只在必要时使用,优先考虑精简文件
8. 常见问题
Q1: AGENTS.md 中写了 "Read SOUL.md",LLM 会调用 read 工具吗?
答案:❌ 不会
原因:
类比:
arduino
老师:"阅读课本第 5 页的定义"
学生:(课本已打开,第 5 页就在面前)
学生:直接阅读,不需要"翻书"这个动作
实际会调用 read 工具的情况:
memory/2025-01-03.md(未注入)src/auth.ts(未注入)- 任何不在 System Prompt 中的文件
Q2: 每次对话都重新加载文件吗?会不会很慢?
答案:✅ 会重新加载,但有缓存
缓存机制:
- 基于
inode+mtime(文件修改时间) - 文件未改变 → 直接从内存返回(<1ms)
- 文件被修改 → 重新读取磁盘(~10ms)
为什么每次都加载?
- Claude API 是无状态的:System Prompt 必须每次发送
- 文件可能被修改:用户可能在对话中更新了 MEMORY.md
- 缓存已优化:实际磁盘 I/O 很少
性能影响:
- 首次加载:~20ms(磁盘读取)
- 后续加载:~1ms(缓存命中)
- 可忽略不计
Q3: MEMORY.md 在群组会话中会泄露吗?
答案:❌ 不会,有安全过滤
过滤规则:
| Session 类型 | Session Key 示例 | MEMORY.md 是否加载 |
|---|---|---|
| 主会话(私聊) | agent:main:main |
✅ 加载 |
| Discord 群组 | agent:main:discord:group:123 |
❌ 不加载 |
| Telegram 群组 | agent:main:telegram:group:456 |
❌ 不加载 |
| Slack 频道 | agent:main:slack:channel:789 |
❌ 不加载 |
实现位置 :src/agents/workspace.ts 中的 filterBootstrapFilesForSession 函数
安全保证:
- ✅ 代码层面硬限制(不依赖配置)
- ✅ 即使配置错误也不会泄露
- ✅ 审计日志可追溯
Q4: 如果文件太大,会发生什么?
答案:自动截断,保留 Head + Tail
截断示例:
diff
原始 MEMORY.md(130KB)
↓
检查单文件限制(20KB)
↓
超过限制,执行截断:
- Head: 14KB (70%)
- 标记: "[...truncated...]"
- Tail: 4KB (20%)
↓
最终注入:18KB
如何避免截断?
- 定期精简:每月审查,删除过时内容
- 分层存储:重要的放 MEMORY.md,详细的放 memory/日志
- 增加限制 (不推荐):调整
bootstrapMaxChars
Q5: 可以自定义文件名吗?
答案:❌ 核心文件名是固定的
固定的文件名:
- AGENTS.md
- SOUL.md
- USER.md
- MEMORY.md(或 memory.md)
- TOOLS.md
- IDENTITY.md
- HEARTBEAT.md
- BOOTSTRAP.md
- BOOT.md
原因:
- 程序硬编码检查这些名称
- 保证所有 OpenClaw 实例的一致性
- 简化文档和社区交流
替代方案:
- 在这些文件中引用自定义文件
- 例如:AGENTS.md 中写 "详见 MY-CUSTOM-RULES.md"
- LLM 会在需要时调用
read("MY-CUSTOM-RULES.md")
Q6: 如何调试加载问题?
方法 1:使用 /system 命令
sql
用户:/system
输出:[完整的 System Prompt,包括所有注入的文件]
方法 2:检查 Gateway 日志
bash
openclaw gateway logs | grep -i "bootstrap\|truncat"
# 示例输出:
[INFO] Loaded 6 bootstrap files (39KB)
[WARN] workspace bootstrap file MEMORY.md is 130000 chars (limit 20000); truncating
方法 3:检查文件大小
bash
cd ~/.openclaw/workspace
ls -lh *.md
# 输出:
-rw-r--r-- 1 user 15K AGENTS.md
-rw-r--r-- 1 user 3.0K SOUL.md
-rw-r--r-- 1 user 130K MEMORY.md ← 过大!
9. 总结
核心要点
-
自动注入机制:
-
加载时机:
- 每次对话都会重新加载(从缓存或磁盘)
- Claude API 是无状态的,System Prompt 必须每次发送
-
文件作用:
-
预算控制:
- 单文件限制:20KB(可配置)
- 总预算限制:150KB(可配置)
- 超过限制自动截断(Head 70% + Tail 20%)
-
优化策略:
- 精简核心文件(<15KB 理想)
- 详细内容移到扩展文件(按需读取)
- 定期清理 MEMORY.md(<15KB)
- Heartbeat 使用 lightweight 模式
架构理解
markdown
Workspace 文件(磁盘)
↓ 程序自动读取
System Prompt(内存)
↓ API 调用
Claude(LLM)
↓ 生成回复
用户
关键点:
- ✅ 文件 → System Prompt:代码层面完成(不是 LLM)
- ✅ System Prompt → LLM:每次 API 调用都包含
- ✅ LLM 看到的是完整内容,不需要工具调用
最佳实践
✅ 文件管理:
- 保持核心文件精简(<15KB)
- 定期审查和清理
- 使用 Git 版本控制(私有仓库)
✅ 记忆管理:
- 日志写入
memory/YYYY-MM-DD.md - 定期提炼到 MEMORY.md
- 旧内容归档到 MEMORY-ARCHIVE
✅ 性能优化:
- Heartbeat 使用 lightweight 模式
- 大文件拆分(核心 + 扩展)
- 监控 token 消耗
✅ 安全实践:
- MEMORY.md 仅在主会话加载
- 敏感信息不写入 workspace
- 定期备份(
git push)
文档版本 :2025-01-03 适用 OpenClaw 版本:2026.2.x+
扩展阅读
官方文档:
相关文章:
- openclaw-agents-system-blog-zh-CN.md(Agent 系统架构)
- openclaw-memory-system-blog-zh-CN.md(记忆系统详解)
- openclaw-tools-skills-blog-zh-CN.md(工具和技能系统)