1. 为什么你的 OpenClaw 总是“差点意思”
很多人第一次跑 OpenClaw(社区里也叫 Moltbot、Clawdbot)时,都会经历同一个心理曲线:装完那一刻很兴奋,聊两句觉得还行,用三天之后开始觉得“它好像不太懂我”。回复不算错,但就是隔着一层;你昨天刚说过的项目背景,今天它又问一遍;你让它盯着某个指标,它要么一声不吭,要么在你开会时疯狂弹消息。
问题基本不在模型,而在架构。OpenClaw 的行为根基是磁盘上的三个 Markdown 文件:SOUL.md、USER.md、MEMORY.md,再加上两个调度系统 Heartbeat(心跳)和 Cron(定时)。这五个部件决定了代理“怎么想、为谁想、记得什么、什么时候自己动”。只改其中一个,就像给汽车换了轮胎却没调方向盘,能开,但一直跑偏。
这篇面向想真正把 OpenClaw 落地配置起来的开发者。我会先讲清 SOUL、USER、MEMORY 三层结构各自负责什么、边界在哪,再给出可以直接复制的config.toml骨架和settings.json片段,最后用具体命令验证主动机制是否触发、记忆读写是否生效。如果你之前只是把默认文件跑起来就用,这篇能帮你把“能用”推到“好用”。
2. 三层结构:SOUL 管表达,USER 管背景,MEMORY 管沉淀
2.1 SOUL.md 决定代理的思考与表达方式
SOUL.md 是代理每次会话开始时读取的第一份文件,它定义语气、回复优先级、行为边界。默认版本是工程师写的通用模板,能跑,但不会贴合你的工作习惯。它分两半:前半部分写沟通偏好,比如开场方式、给结论还是先铺垫、遇到不确定时是标注不确定性还是先给最佳猜测;后半部分写操作边界,也就是代理在外部内容(转发的邮件、共享文档)里遇到指令时该怎么办、执行影响对话之外系统的操作前需要多大确认。
负面约束和正面指令一样重要。不想要客套话就明确写“不要用排比句、不要用‘首先其次最后’”。这些禁令消除的是那种说不清哪里别扭、但会慢慢让你放弃工具的摩擦。
2.2 USER.md 决定代理为谁工作
USER.md 回答“我在为谁工作”。只填名字、时区和一行职位是不够的。要写你正在推进的项目、组织里的关键人物、你和他们的关系、你的优先级、当前卡住你的东西。细节越多,代理越能在不重复提问的情况下结合背景给建议。
它也是失效最快的文件,优先级每周甚至每天都在变。建议每晚花五分钟微调,这是对这份文件杠杆率最高的维护习惯。SOUL 定义沟通方式,USER 定义沟通背景,USER 没配好,SOUL 基本是摆设。
2.3 MEMORY.md 决定长期沉淀什么
OpenClaw 的持久记忆默认关闭,需要显式开启。它分两层:第一层是按日期整理的每日日志,记录每次会话发生了什么、做了什么决策;第二层是 MEMORY.md 本身,作为精选长期存储,放长期重要的决策、持续的项目背景,以及对你纠正过的错误的记录。
关键取舍是:不要记录一切。全量记录会让每次会话加载上下文时消耗更多 Token,杂音还会淹没相关信息,响应质量反而下降。可行做法是让代理建立重要性评分,只把超过阈值的写进长期层。另一个习惯是,当你觉得某件事值得记,直接说“把这个记进 memory.md”,五秒钟省掉无数次重复解释。
2.4 Heartbeat 与 Cron 决定代理何时自己动
这两个系统让代理从被动工具变成后台协作伙伴。Heartbeat 是固定间隔自主醒来,检查你让它监控的任务清单,判断是否值得通过消息平台联系你。Cron 处理需要精确时间点的任务,比如每周一早上汇总。区别在于:Heartbeat 是周期性意识检查,Cron 是特定时间点触发,不要在该用心跳的地方用 Cron。
心跳指令的价值依赖核心文件。“检查紧急邮件”只有在 USER.md 里定义了什么叫“紧急”时才有意义;“提醒日程事件”只有在 SOUL.md 定义了提前多久、用什么格式提醒时才成立。间隔太短、清单太长,代理就变成通知机器,所以目标是精简清单加匹配你工作节奏的间隔。
3. 可复制的 config.toml 骨架
下面这份骨架把三层文件和两个调度系统串起来。字段名按 OpenClaw 常见约定组织,实际以你安装版本的文档为准,重点是结构关系。
# config.toml —— OpenClaw 核心配置骨架 [agent] name = "claw" workspace = "/opt/openclaw/workspace" # 三层 Markdown 文件路径,代理启动时按顺序加载 [agent.files] soul = "/opt/openclaw/workspace/SOUL.md" user = "/opt/openclaw/workspace/USER.md" memory = "/opt/openclaw/workspace/MEMORY.md" [memory] enabled = true # 持久记忆默认关闭,必须显式开启 daily_log_dir = "/opt/openclaw/workspace/memory/daily" long_term_file = "/opt/openclaw/workspace/MEMORY.md" importance_threshold = 0.6 # 低于该分数只进每日日志,不进长期层 max_context_tokens = 4000 # 每次会话注入记忆的 token 上限 [heartbeat] enabled = true interval = "3h" # 心跳间隔,按你的工作节奏调整 quiet_hours = ["23:00", "08:00"] # 静默时段,避免半夜打扰 tasks = [ "检查收件箱中标记为紧急的邮件", "查看项目看板是否有阻塞项超过 24 小时", ] [cron] enabled = true [[cron.jobs]] name = "weekly-digest" schedule = "0 9 * * 1" # 每周一 09:00 prompt = "汇总上周 MEMORY.md 中新增的决策,输出三条要点" [[cron.jobs]] name = "daily-standup" schedule = "30 8 * * 1-5" # 工作日 08:30 prompt = "根据 USER.md 中的当前项目,生成今日待办草稿"几个容易踩的点:importance_threshold设太低会让长期记忆膨胀,设太高会漏掉重要背景,0.5 到 0.7 之间比较稳;max_context_tokens要和模型上下文窗口匹配,别把窗口全喂给记忆;quiet_hours一定要配,否则心跳会在你睡觉时发消息。
4. settings.json 配置片段与主动机制参数
settings.json负责运行时行为,和config.toml的分工是:前者管调度与记忆策略,后者管模型接入与请求参数。下面这段可以直接作为起点。
{ "model": { "provider": "openai-compatible", "base_url": "https://taotoken.net/api", "model": "claude-sonnet-4-5", "api_key_env": "TAOTOKEN_API_KEY", "max_tokens": 4096, "temperature": 0.7 }, "memory": { "write_mode": "scored", "score_model": "claude-haiku-4-5", "dedupe": true, "daily_retention_days": 30 }, "heartbeat": { "notify_channel": "telegram", "min_interval_between_notifications": "45m", "escalate_after": 3 }, "cron": { "timezone": "Asia/Shanghai", "catch_up_missed": true } }write_mode设为scored时,代理会先用一个便宜的小模型给每条候选记忆打分,再决定是否写入长期层,这就是前面说的重要性评分落地方式。min_interval_between_notifications是心跳的节流阀,防止短时间内连续打扰。catch_up_missed让 Cron 在服务重启后补跑错过的任务,对长期运行的代理很实用。
模型接入这里用的是 OpenAI 兼容协议,base_url指向https://taotoken.net/api,API Key 通过环境变量注入,不要硬编码进文件:
export TAOTOKEN_API_KEY="sk-你的密钥"密钥在控制台的 API Keys 页面创建,接入细节看接入文档。
5. 验证主动机制触发与记忆读写
配置写完不算完,要验证三件事:记忆是否真的写入、心跳是否按间隔触发、Cron 是否在正确时间点执行。
先验证记忆写入。手动触发一次会话,明确要求记录:
openclaw chat --message "把这个记进 memory.md:项目 X 的截止日期改到 3 月 20 日"然后检查长期记忆文件是否新增条目:
grep -n "3 月 20 日" /opt/openclaw/workspace/MEMORY.md tail -n 20 /opt/openclaw/workspace/memory/daily/$(date +%F).md如果长期文件没有、每日日志有,说明分数没过阈值,可以临时把importance_threshold调到 0.4 再试一次,确认链路通了再调回去。
再验证心跳。把间隔临时改成 1 分钟,观察日志:
openclaw heartbeat --status openclaw logs --follow --component heartbeat正常输出会显示每次唤醒的时间戳、检查的任务数、是否触发通知。如果只唤醒不通知,检查quiet_hours是否覆盖了当前时间,以及任务描述是否足够具体到能判定“值得联系”。
最后验证 Cron:
openclaw cron list openclaw cron run weekly-digest --dry-run--dry-run会立即执行一次但不发送通知,用来确认 prompt 和输出格式符合预期。确认无误后等真实时间点触发即可。
6. 常见报错与排查
记忆不写入:先确认config.toml里memory.enabled = true,默认是关闭的。再看daily_log_dir目录是否存在且可写,权限不对会静默失败。如果每日日志有、长期文件没有,就是阈值问题。
心跳不触发:检查heartbeat.enabled和interval格式,"3h"合法,"3"不合法。再看quiet_hours是否把当前时间整个盖住了。日志里如果显示唤醒但任务列表为空,说明tasks数组没被正确解析。
Cron 时间不对:settings.json里的timezone必须显式设置,不设会跟随系统时区,容器里通常是 UTC,导致你以为的早上九点实际是下午五点。
模型请求 401:api_key_env指向的环境变量没导出,或者导出在了另一个 shell 会话里。用echo $TAOTOKEN_API_KEY确认当前会话能读到。
回复风格不对:回到 SOUL.md,检查负面约束是否写清楚。语气问题几乎都能在 SOUL 前半部分找到答案,不要试图在 settings.json 里调 temperature 解决。
7. 把配置跑通之后
三层文件加两个调度系统,本质是把“代理知道什么、为谁工作、记得什么、何时行动”拆成可独立维护的部件。SOUL 和 USER 要对齐,MEMORY 要跟着优先级更新,Heartbeat 的监控清单要匹配你真实的工作节奏。局部配置效果差,通常不是缺文件,而是文件之间不匹配。
验证环节别省。记忆写入、心跳触发、Cron 执行这三条链路各自跑通一次,后面出问题你才知道该看哪个日志。密钥和接入参数统一走环境变量,模型对话可以在模型对话页面直接试,长期跑编码和 Agent 任务可以看 Coding Plan,密钥管理在 API Keys,接入细节查接入文档。把配置骨架复制过去,改掉路径和阈值,先跑通再优化。