Skip to content

第三章 提示词系统——Agent 为什么不会每次都从零开始

核心问题:OpenClaw 是如何组装提示词的?


上一章讲的是 Agent Loop:一件事怎么被一轮一轮推进下去。

但只会“循环推进”还不够。因为如果 Agent 每次开始前都像重新出生一样,不知道自己是谁、不知道该怎么做,也不知道你是谁,那这个循环再聪明,也还是会不断从零开始。

这就是第三章真正要讲的东西:OpenClaw 为什么不会把提示词只当成一段临时文案,而是把它变成了工作区里的长期配置。

这里先提前说一句很重要的话:这一章讲的不是“怎么写一句更厉害的 Prompt”,而是系统怎样决定,哪些信息应该常驻,哪些只在特定时机出现,哪些应该按需读取,哪些干脆不该一直塞在上下文里。


第一节 为什么提示词要写进文件

这一节只回答一个问题:OpenClaw 为什么不把 Agent 的规则继续留在对话里,而是要把它们写成文件。

1.1 对话里的 Prompt,天然是不稳的

把提示词写在对话里,最大的优点是快。你想临时改一下口吻、规则、偏好,打一段话就行。

但它的问题也非常明显:它和这次对话活在同一个生命周期里。 对话结束,它也就结束了。 窗口一关,下次重新开始,系统又会回到默认状态。

这会带来三个直接问题:

问题表面现象本质原因
不持久今天调好的风格,明天又没了提示词跟着会话一起消失
不可维护说不清到底哪句话起了作用一切混在同一段临时文本里
不可协作团队里很难复用,也很难追溯没有稳定载体,也没有版本历史

所以,只要提示词仍然是一次性对话内容,它就很难变成真正可积累、可维护、可复用的系统配置。

1.2 OpenClaw 的解法,是让工作区变成 Agent 的“家”

OpenClaw 官方把这一套叫做 Agent Workspace。 你可以把它理解成:Agent 在磁盘上的固定住处。

它和普通聊天窗口最大的区别在于,很多本来会随会话消失的东西,现在有了落点:

  • 角色和性格,不再只靠一段系统提示词临时维持;
  • 用户画像和偏好,不再只靠模型从聊天历史里“猜”;
  • 做事流程和环境说明,不再每次都要重新交代;
  • 长期记忆和日常记录,也不再只是上下文里的一段旧消息。

这也是为什么 OpenClaw 官方文档一直把 workspace 看得很重。

因为从这一刻开始,Agent 的“默认状态”不再只是模型初始化时的一段字符串,而是一组放在磁盘上、可直接编辑、可用 Git 管理的真实文件。

1.3 这些文件,到底各自管什么

第一次看 OpenClaw 的工作区,很多人会觉得文件有点多。
但它的设计重点并不是“多”,而是分层

更准确地说,它是在回答四个不同的问题:

  1. 我是谁?
  2. 我怎么做事?
  3. 我记住了什么?
  4. 我在什么时机应该做什么?

可以先把常见文件分成下面几组来看:

分层文件 / 目录它更像什么主要负责什么
身份层SOUL.md IDENTITY.md USER.md人设、名片、用户档案定义 Agent 的角色、气质、称呼方式和服务对象
行为层AGENTS.md TOOLS.md HEARTBEAT.md操作手册、环境备忘录、短巡检单约束默认工作流,补充本地环境和工具使用说明;HEARTBEAT.md 也属于 workspace file,只是对 heartbeat runs 尤其重要
记忆层MEMORY.md memory/精选笔记、日记本前者更像长期记忆文件,后者更像按天积累的记录层
生命周期层BOOTSTRAP.md BOOT.md / hooks首次引导、启动/事件钩子分别对应 brand-new workspace,以及启动或其他事件触发
能力层skills/技能卡片告诉 Agent 遇到某类任务时,该去哪读哪份 SKILL.md

这里有几个特别容易混淆的点,最好先分清:

  • AGENTS.md 讲的是“我怎么做事”,不是“我是谁”。
  • TOOLS.md 讲的是“环境和工具备注”,不是“给工具开权限”。
  • MEMORY.mdmemory/ 都是记忆层,但前者更像整理后的长期知识,后者更像按天积累的原始记录。
  • HEARTBEAT.md 名字里虽然有 heartbeat,但它本身仍属于会进入 Project Context 的 workspace file,只是对 heartbeat runs 更关键,而且应该保持很短。
  • BOOTSTRAP.mdBOOT.md / hooks 都和“时机”有关,但它们面对的是两种完全不同的触发条件。

所以 OpenClaw 的关键,不是“把一段大 Prompt 拆成八九个文件”这么简单,而是:它把原来混成一团的身份、规则、记忆和生命周期,拆成了几种职责完全不同的配置。

这一步一旦完成,Agent 的默认行为才第一次真正变得可定位、可修改、可积累。


第二节 提示词系统运行规则

这一节的核心问题在于:工作区里的这些文件,到底是通过什么机制进入一次 Agent 运行的?

2.1 system prompt 不是一段固定文案,而是每次 run 现拼的

OpenClaw 官方的 System Prompt 文档 和当前源码里的 system-prompt.ts 都在说明同一件事:OpenClaw 的 system prompt 不是一份写死的静态文本,而是每次 run 都会重新构建。

它大致是这样拼起来的:

text
固定系统区块
→ 工作区上下文(Project Context)
→ 当前会话历史、工具结果、附件
→ 模型看到这一轮真正的完整上下文

其中固定系统区块里,官方现在会放很多东西,例如:

  • Tooling:有哪些工具、怎么安全使用;
  • Safety:高风险操作的边界;
  • Skills:当前可用技能的索引;
  • Workspace / Documentation:当前工作区与文档提示;
  • Sandbox / Time / Runtime:沙箱、时间和运行时信息。

这件事特别重要,因为它告诉我们:

OpenClaw 并不是把“用户发来的那一句话”直接扔给模型,而是会先把这一轮工作的现场搭起来,再让模型开始判断。

也正因为如此,“提示词系统”在 OpenClaw 里其实不是某一段漂亮文案,而是一次运行开始前的上下文装配机制。

2.2 工作区里的东西,不是都走同一条路

这一点是很多初学者最容易搞混的地方。工作区里虽然有很多文件,但它们并不是都以同样的方式进入 prompt

从官方文档、源码和当前运行时设计来看,至少可以分成四条不同的路径:

内容进入方式为什么这样设计
AGENTS.md SOUL.md USER.md IDENTITY.md TOOLS.md HEARTBEAT.md 等工作区文件作为 Project Context 直接注入这是这轮运行默认就该带着走的规则和身份信息;HEARTBEAT.md 也在其中,只是应该特别短
skills/ 里的技能先注入紧凑索引,真正需要时再读 SKILL.md减少常驻上下文开销,避免几十个技能全文一起挤爆窗口
MEMORY.md作为 Project Context 的长期记忆文件直接注入让 Agent 默认带着最重要的长期事实与偏好工作
memory/作为 daily notes 和磁盘记忆层参与运行,近邻日期可能自动带入,其余更多依赖 memory 工具召回不把整段历史全文常驻,同时保留按需检索能力
BOOTSTRAP.md BOOT.md / hooks走不同的生命周期路径BOOTSTRAP.md 只在 brand-new workspace 时出现;BOOT.md 或其他 hooks 更像启动 / 事件触发入口,而不是每轮常驻 prompt

这四条路径背后,其实对应了四种完全不同的问题:

  • 哪些东西是每轮都要带着走的;
  • 哪些东西是先知道它存在,需要时再展开的;
  • 哪些东西是长期存着,等以后召回的;
  • 哪些东西是只在某个时刻触发一次的。

这里尤其要强调两点。

第一,memory 不是一股脑都常驻上下文。

OpenClaw 官方的 Memory 文档 把记忆讲得很清楚:

它的“真相”在磁盘上,而不在当前这次对话窗口里。

更稳的理解是:MEMORY.md 负责长期事实;memory/YYYY-MM-DD.md 负责 daily notes。官方概览页强调近邻日期的 notes 可能自动带入,而 system prompt 文档又明确说 daily files 不应被理解成和工作区常驻文件完全等价的“无条件注入全文”。
所以在写教程时,最不容易误导读者的说法是:不要把整个 memory/ 目录当成常驻大 prompt;更远的历史和更细的记录,仍主要依赖 memory 工具和召回机制。

第二,skills 也不是常驻全文。

官方 Skills 文档 和当前源码里的 skills/workspace.ts 都说明了这一点:

系统会先把当前可用技能整理成紧凑列表注入 prompt,模型判断需要某个技能时,再去读那份 SKILL.md

这其实是一个非常工程化的决定。 因为 skill 的价值本来就是“低频但专业”。如果每次都把所有技能全文塞进 prompt,窗口很快就会被低频内容挤满。

2.3 不是所有 run,看到的都是同一套 prompt

如果 OpenClaw 把所有内容在任何场景下都一股脑塞进去,系统会很快变得又重又慢。

所以官方运行时还做了另一层处理:不同 run 会有不同强度的 prompt。

文档里把它叫做 promptMode,当前正式可见的主要是 fullminimalnone 这几类模式。
你不用死记每一类到底保留了哪些小块,但需要理解它背后的原则:

模式 / 场景设计原则
full给足上下文,让主会话有完整身份、规则和工作现场
minimal常见于子 Agent,尽量变轻,只保留完成局部任务真正需要的信息
none极简模式,只保留最基础的身份线

这也是为什么你会看到:

  • 子 Agent 的 prompt 通常比主会话更轻;
  • HEARTBEAT.md 虽然经常在 heartbeat 场景里被提起,但它本身也是 workspace file;最佳实践一直都是“短”,而在轻量 prompt 或特殊场景里,它可能再被进一步弱化;
  • BOOTSTRAP.md 用完就该退场,而不是永远留在默认上下文里;
  • BOOT.md 更像开机时的内部检查清单,而不是会话里的常驻人格说明。

从源码角度看,这件事也能对上:当前实现里,workspace 文件、skills 列表和 system prompt 各区块都会根据运行模式和 session 类型做筛选。

具体保留哪些小块,未来版本可能会继续微调,但“主会话更完整、特殊场景更轻量”这个原则是稳定的。

2.4 prompt 的真正成本,常常不是你以为的那一部分

很多人第一次遇到上下文压力时,直觉都会觉得:“是不是我某个 Markdown 文件写太长了?”

这当然有可能,但 OpenClaw 官方的 Context 文档 提醒了另一件更重要的事:

一次 run 的上下文成本,从来不只来自工作区文件。

它至少还包括:

  • 当前 session 的历史消息;
  • 工具调用和工具结果;
  • 附件与外部读入内容;
  • skills 列表;
  • 工具的文字说明;
  • 工具的 schema 开销。

最后这一点尤其容易被低估。因为工具不只是“提示词里那几行说明”,它背后还有给模型看的结构化 schema。很多时候,真正吃上下文的并不是你眼前看到的几句话,而是这些你平时没直接看见的部分。

所以 OpenClaw 才给了几套非常实用的观察工具:

  • /status:看当前会话和窗口压力;
  • /context list:看这一轮上下文里到底装了哪些东西;
  • /context detail:看更细的拆分,包括不同区块、文件和工具成本;
  • /compact:把旧历史压成摘要,给后面的运行腾位置。

另外,workspace 文件本身也不是毫无限制地注入。官方文档和当前实现里都明确有单文件预算总量预算;超长内容会被截断,缺失文件会被标记出来。

所以这一节想让大家真正明白的,不是“Prompt 会被注入”,而是:

OpenClaw 一直在做一件更复杂的事:在准确性、可维护性和上下文成本之间,找到一个平衡点。


第三节 知道机制以后,我们应该怎么写这套配置

前两节已经讲清楚了“它为什么存在”和“它怎么运转”。
接下来更实际的问题是:如果你真的要开始写自己的工作区文件,到底应该怎么写,才不会把这套系统用歪。

3.1 第一步,不是多写,而是先分清“这句话该写在哪”

很多初学者第一次配工作区,最容易犯的错误不是写少,而是乱写

比如:

  • 人格和语气写进 AGENTS.md
  • 工具路径写进 SOUL.md
  • 临时项目任务塞进 USER.md
  • 一次性的初始化说明永远留在常驻文件里。

这样做的问题不是“不优雅”,而是你以后根本没法维护。
更稳的思路应该是:先判断这句话属于哪一层,再决定它应该放哪。

可以先用下面这张速查表:

你想表达什么更适合写在哪
这个 Agent 的气质、边界、价值取向SOUL.md
名字、身份设定、基础角色信息IDENTITY.md
用户偏好、称呼、长期协作习惯USER.md
默认工作流、做事顺序、确认规则AGENTS.md
路径、项目说明、环境备注、常用命令提示TOOLS.md
长期有效的事实和经验MEMORY.md
按天记录的原始经历和事件memory/
第一次进入工作区时该完成什么BOOTSTRAP.md
Gateway 启动时要检查什么BOOT.md
定时巡检时要关注什么HEARTBEAT.md
某类低频但专业的流程skills/某技能/SKILL.md

这里还要单独提醒一句:

TOOLS.md 不是权限配置文件。
它适合写“在哪里做事、怎么更稳妥地用工具”,但它不负责真正的工具开关、审批和安全边界。

3.2 第二步,把真正长期有效的规则写进去

工作区文件最怕的不是短,而是把短期内容错当成长期规则

一个很简单的判断方法是:

如果一条信息满足下面两个条件,它才更适合进入常驻配置:

  1. 它会反复影响未来很多次运行;
  2. 它不该只存在于某一次具体任务里。

比如下面这种,就很适合写成常驻规则:

text
执行任何删除、发送、部署类操作前,先列出影响范围并等我确认。

因为它长期有效,而且未来很多任务都用得上。

但下面这种,就不应该直接写进常驻文件:

text
今天先帮我看 chapter3 的 rewrite 文档。

因为它只是当前任务,不是未来默认规则。

写这类文件时,还有三个很实用的原则:

  • 写具体,不写空话请谨慎行事 不如 删除前先列出文件并等确认
  • 写稳定,不写瞬时状态:今天临时要做的事,不要塞进永远常驻的文件。
  • 写必要,不写贪多:尤其是 HEARTBEAT.mdBOOT.md 或其他启动/事件 hook 里会被短暂读取的说明,越短越稳。

还有一点非常现实,也非常重要:

不要把密钥和敏感凭证写进工作区文件,更不要顺手提交到 Git。

OpenClaw 官方的 workspace 文档也反复提醒这一点。

配置可以版本化,秘密不该版本化。需要长期保存的敏感信息,应该放进 OpenClaw 的 credentials 体系,而不是 Markdown 文件。

3.3 第三步,用工程的方式维护,而不是靠记忆硬扛

只要你真的开始长期用 OpenClaw,很快就会发现:这套系统的价值,不在于“第一天配置得多漂亮”,而在于能不能越用越稳,而不是越用越乱。

更靠谱的维护方式通常有四条:

第一,把工作区配置当成资产管理。

能进 Git 的进 Git。
尤其是 AGENTS.mdSOUL.mdTOOLS.mdUSER.md 这种长期会迭代的文件,最好有提交历史。

第二,不要靠猜,要靠观察。

如果你发现 Agent 开始变慢、变散、变得不听话,不要先怀疑“模型怎么又抽风了”,先去看:

  • /context list:到底注入了什么;
  • /context detail:到底是谁把窗口撑大了;
  • /compact:是不是该把旧历史压掉了。

很多所谓“人格飘了”“规则没生效”,最后都不是玄学问题,而是上下文分配问题。

第三,改完以后,用新的运行去验证。

OpenClaw 的很多配置都和 session、prompt mode、skills 快照有关。有些变更下一轮就能体现,有些场景下重新开一个新会话会更稳、更容易观察。

所以更工程化的做法往往不是在当前对话里硬拗,而是:

text
改文件
→ 开一个干净的新会话
→ 看默认行为有没有按预期变化
→ 再决定要不要继续调

第四,把低频能力交给 skill,把高频规则留给常驻文件。

如果某个流程只是偶尔需要,但每次都很专业,比如部署、论文检索、代码审查模板,那更适合做成 skill。

如果某条规则是每次做事都该带着的,比如确认边界、输出格式、沟通风格,那才更适合放进 AGENTS.mdSOUL.mdUSER.md

一句话说,就是:

不要让所有东西都争着常驻。

真正成熟的提示词系统,不是“尽量塞更多”,而是“让该常驻的常驻,该按需的按需,该退场的退场”。

3.4 第四步,先分清到底是谁在改这些文件

这里还有一个特别容易让初学者误会的问题:

这些 Markdown 文件,到底是我自己改,还是系统会自动改,还是我要命令 Agent 去改?

更准确的答案是:这三种情况都存在,但它们发生的条件完全不一样。

先说最常见、也最稳的一种:你自己手动改。

这些文件本来就是工作区里的普通文件,所以你完全可以像改别的 Markdown 一样,在编辑器里直接修改它们:

  • 想改默认流程,就改 AGENTS.md
  • 想改人格和语气,就改 SOUL.md
  • 想补环境说明,就改 TOOLS.md
  • 想整理长期规则和经验,就改 USER.mdMEMORY.mdmemory/

这也是最清楚、最可控的维护方式。

第二种是:你把“改配置”本身交给 Agent。

OpenClaw 本来就有读写和编辑文件的能力,所以只要权限允许,你也可以直接说:

text
把这条规则写进 AGENTS.md。
把我刚才说的偏好补到 USER.md。
把这件事记进 MEMORY.md。

这时候本质上不是“系统自己在偷偷改配置”,而是你明确把修改文件当成一个任务交给了 Agent。

第三种才是:系统在少数特定机制里自动写盘。

这一类不是“平时聊天时随时乱改”,而是只发生在几个明确入口:

  • 首次 bootstrapping:官方文档明确写着,首次引导会把信息写入 IDENTITY.mdUSER.mdSOUL.md,完成后再移除 BOOTSTRAP.md
  • memory 流程:如果你明确说“记住这件事”,Agent 应该把内容写入记忆;另外 memory 机制在接近压缩或切会话时,也可能通过官方 hook 把值得保留的信息落到磁盘;
  • 会话摘要 / memory hooks:如果你的部署启用了把会话摘要写回记忆的 hook,那么切会话、compaction 前后或其他触发点,也可能把内容落到 memory/;具体是否开启要看当前配置;
  • BOOT.md / 其他 hooks:如果启用了启动或事件钩子,系统会在这些触发点执行对应流程,但会不会真的改文件,还要看那份 BOOT.md 或 hook 本身写了什么。

所以更实用的理解可以压成下面这张表:

情况会不会改文件更像什么
你在编辑器里直接改手动维护配置
你命令 Agent 去改把“改配置”当成任务交给 Agent
普通聊天但你没要求它改通常不会主动乱改常驻文件正常对话,不等于默认自我改写
bootstrapping / memory / hooks 这类特定机制可能会有明确触发条件的自动写盘

如果把这一点收成一句话,就是:

默认把这些文件当成你自己维护的配置;需要时可以让 Agent 帮你改;只有少数官方定义好的流程,系统才会自动写入其中一部分文件。


本章小结

这一章其实就讲清楚了一件事:OpenClaw 的提示词系统,本质上不是“一段更高级的 Prompt”,而是一套围绕工作区、生命周期和上下文预算搭出来的运行机制。

它真正做的事情有三步:

  1. 把临时提示词搬出对话,变成工作区里的长期配置;
  2. 按“常驻注入、按需读取、生命周期触发、磁盘召回”几条不同路径,把这些内容带进一次运行;
  3. 再用 prompt mode、skills 索引、memory 召回和 context 预算,把整套系统控制在可运行的范围里。

所以 OpenClaw 看起来像是在“写很多 Markdown 文件”,但背后真正重要的是:

  • 什么该成为默认身份;
  • 什么该成为默认规则;
  • 什么该留在磁盘上等以后再读;
  • 什么只该在特定时机出现;
  • 什么根本不该一直占着 prompt。

如果把这一章压成一句话,就是:

OpenClaw 之所以不会每次都从零开始,不是因为它神奇地“记住了对话”,而是因为它把身份、规则、记忆和能力真正落到了文件和运行机制里。


第四章 工具系统