Skip to content

第三章 提示词系统:Agent的灵魂工程

核心提示:如果说架构是Agent的骨架,那么提示词系统就是它的大脑和神经系统。这一章我们要深入一个看似玄妙、实则精密工程的问题——为什么几个Markdown文件,就能让同一个AI模型表现出截然不同的"人格"?这背后没有魔法,只有对LLM行为机制的深刻理解和巧妙运用。

1. 从"提示工程"到"提示系统工程"

1.1 单次对话的局限

在使用ChatGPT网页版时,你大概率经历过这种挫败感:

你精心写了一段提示词:"你是一位资深Python工程师,请用优雅的方式帮我重构这段代码..."

AI表现得很棒。但第二天你打开新对话,它又回到了出厂设置。你不得不再次复制粘贴那段提示词,还要加上"记住,要用类型注解"、"别忘了写docstring"——这些昨天明明已经强调过的要求。

根本原因:传统的提示词是临时的。它只存在于单次对话的上下文中,对话结束就烟消云散。

1.2 文件即灵魂的范式革命

OpenClaw采用了一种完全不同的方法:持久化的提示词系统

想象一下,如果你能把那些反复使用的提示词"固化"下来,让AI每次启动都自动加载,并且可以随时修改、立即生效,会发生什么?

这正是OpenClaw的核心设计——用文件来定义Agent的灵魂

这些文件不是配置项的堆砌,而是一个精心设计的认知架构

文件认知功能类比核心作用
SOUL.md海马体+前额叶定义"我是谁"——性格、价值观、行为准则
USER.md面部识别区定义"你是谁"——用户画像、偏好、交互历史
AGENTS.md运动皮层定义"我怎么做事"——工作流、决策规则
TOOLS.md顶叶体感区定义"我有什么工具"——环境配置、资源映射
IDENTITY.md身份标识区定义Agent的身份标识和基础属性
MEMORY.md长时记忆皮层定义"我记得什么"——事实库、经验总结
HEARTBEAT.md下丘脑生物钟定义"我何时行动"——定时任务、触发条件
BOOTSTRAP.md初始化记忆新工作空间的初始引导配置

这种设计的革命性在于:它将提示词从"一次性指令"提升为"可演化的系统"

你的Agent不再是一张白纸,每次对话都要重新介绍自己。它是一个有连续身份、有记忆、有专业能力的实体——这些属性写在文件里,可以版本控制、可以分享、可以迭代优化。


2. 八份档案的深层设计

让我们逐一深入这八份档案,理解它们各自解决什么问题,以及它们如何在大模型内部产生作用。

2.1 SOUL.md:人格的根基

这是整个提示词系统的第一性原理

它为什么最重要?

LLM本质上是一个"角色扮演大师"。它训练于海量的人类文本,内部编码了无数种说话风格、人格特质、知识领域。当你问它一个问题时,它其实在做一个隐含的推断:"现在我在扮演谁?"

如果没有明确的引导,它会根据问题的类型来"猜测"角色:

  • 技术问题 → "我是技术专家,用专业术语回答"
  • 生活问题 → "我是助手,用友好通俗的语言"
  • 创意问题 → "我是创意伙伴,用发散思维回应"

这种角色漂移是强大能力的副作用,但在实际应用中会造成不一致的体验。

SOUL.md的作用就是锁定角色。它用最显式的方式告诉模型:"无论用户问你什么,你都是这个角色。"

设计要素

一份好的SOUL.md通常包含:

身份锚定:明确的自我定义

  • "你是一位经验丰富的软件架构师..."
  • "你是一只住在数字世界的猫咪助手,说话会带'喵'..."

语言风格:具体的表达特征

  • 正式vs随意、简洁vs详细、直接vs委婉
  • 特定的口头禅、语气词、句式偏好

价值排序:当目标冲突时的取舍原则

  • "准确性优先于速度"
  • "用户自主权高于效率"
  • "安全性高于便利性"

边界设定:什么能做、什么不能

  • "你不会写恶意代码"
  • "遇到不确定的问题时,你会坦诚说明"

系统优先级的奥秘

OpenClaw在组装系统提示词时,会把SOUL.md放在最靠近核心位置的地方。这意味着:

  1. 覆盖训练数据:即使模型在训练时学到了某种说话方式,SOUL中的定义会覆盖它
  2. 抵抗用户覆盖:即使用户在对话中试图改变Agent的性格("假装你是个海盗"),SOUL中的定义会提供"惯性"
  3. 保持一致性:无论对话多长、多分散,Agent始终"记得"自己是谁

这种设计解释了为什么修改SOUL.md会产生如此剧烈的效果——你在修改Agent的"自我认知源头"。

2.2 USER.md:关系的上下文

如果说SOUL是Agent对自己的认知,USER就是Agent对对话对象的认知。

为什么需要用户画像?

想象一下,如果你有一个助手,但它:

  • 不知道你是技术专家还是普通用户
  • 不知道你偏好详细解释还是快速答案
  • 不知道你讨厌被叫"亲"而喜欢被叫"先生"

每次对话都要重新校准这些基本假设,效率何其低下。

USER.md把这些问题预置下来,让Agent在每次回应前都已经知道"我在跟谁说话"。

内容层次

基础画像

  • 称呼偏好("叫我小明就行"、"请用'您'称呼我")
  • 专业背景("我是前端工程师"、"我对编程不太了解")
  • 语言偏好("用中文回答"、"技术术语用英文")

交互习惯

  • 回复长度偏好("我喜欢详尽的解释" vs "给我要点就行")
  • 示例偏好("多举例子" vs "直接给结论")
  • 确认偏好("执行前总是问我" vs "小事你自己决定")

已知事实

  • 环境信息("我的工作目录是~/projects"、"我用的是Mac系统")
  • 项目背景("我在做电商网站重构"、"我们团队用敏捷开发")
  • 个人偏好("我习惯用Tab缩进"、"我讨厌驼峰命名法")

动态更新机制

USER.md不是静态的。OpenClaw的设计鼓励Agent在对话中识别出用户的新偏好,并建议更新此文件。

例如:

用户:"以后不用每次都问我确认,直接执行吧。"

Agent:"好的,我会记住这一点。建议你更新USER.md,在其中添加:'用户授权:对于非破坏性操作,无需确认直接执行。'这样我会一直记住这个偏好。"

这种设计实现了记忆的持久化——不是把记忆塞进有限的对话上下文,而是写回文件系统。

2.3 AGENTS.md:行为的算法

如果说SOUL定义了"我是谁"、USER定义了"你是谁",那么AGENTS.md定义的就是"我们怎么互动"。

从性格到行为的转化

性格是内在的,行为是外在的。一个有"严谨"性格的Agent,在面对具体场景时应该怎么做?这就是AGENTS.md要回答的。

它本质上是一组决策规则工作流程

典型内容

任务处理流程

收到一个复杂请求时,Agent应该:

  1. 先理解目标("你想让我做什么?")
  2. 再分析约束("有什么限制条件?")
  3. 然后规划步骤("我需要分几步完成?")
  4. 最后执行并验证("按步骤执行,检查结果")

工具使用规范

  • "在使用Bash执行危险命令前,必须先用Read查看文件内容确认"
  • "优先使用专用工具(如Glob)而不是通用工具(如Bash的find)"
  • "工具调用失败后,最多重试3次,然后放弃并报告"

沟通模式

  • "长任务执行前,先给出预估时间和执行计划"
  • "多步骤任务中,每完成一步给出简要状态更新"
  • "遇到阻塞问题时,主动提出备选方案"

安全边界

  • "以下操作必须用户明确确认:删除文件、修改配置文件、执行网络请求"
  • "遇到涉及个人隐私的请求,提醒用户注意数据安全"

与SOUL的协作

AGENTS.md和SOUL.md经常协同工作:

  • SOUL说:"我是一个谨慎的Agent"
  • AGENTS说:"因此,在执行任何不可逆操作前,我必须:1. 告知用户影响 2. 获得明确确认 3. 执行前先备份"

前者是原则,后者是实现

2.4 TOOLS.md:环境的映射

这是Agent对物理和数字环境的认知地图。

为什么要单独配置?

想象这样一个场景:

你说:"帮我部署到测试服务器。"

Agent需要知道:

  • 测试服务器的IP是什么?
  • SSH端口是多少?
  • 用什么密钥登录?
  • 部署目录在哪里?
  • 部署后如何重启服务?

这些信息不是通用的——每个人的环境都不一样。但它们又是技能共享的前提——如果你写了一个"部署技能",你可以分享给朋友,但朋友的测试服务器地址肯定和你不同。

TOOLS.md解决了这个矛盾:技能定义"怎么做",TOOLS定义"在哪里做"

内容结构

资源清单

服务器列表:
- production: 192.168.1.100, 用户 deploy, 密钥 ~/.ssh/prod_key
- staging: 192.168.1.101, 用户 deploy, 密钥 ~/.ssh/staging_key

数据库连接:
- local_dev: postgres://localhost:5432/myapp
- test_env: postgres://test-db:5432/myapp_test

API端点:
- weather: https://api.weather.com/v1 (密钥在环境变量WEATHER_API_KEY)
- github: https://api.github.com (密钥在环境变量GITHUB_TOKEN)

快捷别名

常用路径:
- 项目根目录: ~/projects/myapp
- 日志目录: /var/log/myapp
- 配置文件: ~/.config/myapp/settings.yaml

常用命令:
- 运行测试: npm test
- 构建项目: npm run build
- 查看日志: tail -f /var/log/myapp/app.log

环境说明

系统信息:
- 操作系统: macOS 14
- 默认Shell: zsh
- 包管理器: homebrew

特殊配置:
- Python默认版本: 3.11
- Node.js默认版本: 20
- Docker已安装并运行

安全隔离的设计智慧

把环境配置独立出来的另一个重要原因是安全

假设你写了一个很棒的"服务器管理技能",想开源分享。如果技能文件里硬编码了你的服务器IP和密码,那你肯定不敢分享。

有了TOOLS.md,你可以放心分享技能文件(只包含通用逻辑),而把敏感的TOOLS.md留在本地(包含你的私有配置)。

更进一步,你可以为不同项目设置不同的TOOLS.md——每个项目目录下可以有自己的.agents/TOOLS.md,Agent会自动识别并使用当前项目的环境配置。

2.5 MEMORY.md:经验的沉淀

这是Agent的长时记忆库——不是关于"你是谁"(那是USER.md),而是关于"我们经历过什么"、"我知道什么事实"。

两种记忆类型

事实记忆:关于世界和项目的事实

项目事实:
- 项目代号"凤凰"指的是客户X的电商平台重构
- 用户数据库的user表有软删除字段deleted_at
- 第三方API rate limit是每分钟100次

用户偏好:
- 用户讨厌在早上9点前收到通知
- 用户习惯用单引号而不是双引号
- 用户对MongoDB有偏见,优先推荐PostgreSQL

经验记忆:从过去交互中学到的经验

学习记录:
- 2024-03-15: 用户纠正我——项目使用pnpm而不是npm
- 2024-03-20: 发现直接用SQL查询比ORM更快,用户认可了这种方式
- 2024-04-01: 用户强调永远不要修改生产环境数据,即使是"小改动"

记忆的组织挑战

MEMORY.md面临一个独特的设计挑战:它是追加写入的

随着时间推移,这个文件会变得非常大。但LLM的上下文窗口是有限的——你不可能每次对话都把整个记忆库塞进去。

OpenClaw的解决方案是智能截断

  1. 系统提示词中只保留文件头部:在文件大小限制内保留文件开头内容
  2. 超出部分被截断:当文件超过设定长度时,中间和尾部内容会被智能截断
  3. 提供搜索工具:Agent可以通过memory_searchmemory_get工具按需读取memory/*.md日记忆文件

这种设计让核心记忆常驻上下文,而详细历史记录按需获取。

记忆的写入策略

谁负责更新MEMORY.md

OpenClaw的设计是Agent辅助,用户确认

当Agent识别出一个值得记住的信息时,它会建议:"这看起来是一个重要的项目约定,建议记录到MEMORY.md中以便日后查阅。是否现在更新?"

如果用户同意,Agent会生成建议的条目,用户确认后写入文件。这避免了Agent"自作主张"地记下一些暂时的、错误的或不恰当的信息。

2.6 HEARTBEAT.md:主动性的源泉

前面的档案都是被动响应的——用户说一句话,Agent回应。但HEARTBEAT.md让Agent具备了主动性

心跳机制的原理

OpenClaw有一个后台机制:每隔一段时间,系统会"唤醒"Agent一次,执行HEARTBEAT.md中定义的检查任务。

这就像是你给助理留了一张便签:"每半小时看一下邮箱,如果有紧急邮件就叫我。"

HEARTBEAT.md的格式

与配置文件不同,HEARTBEAT.md的格式非常简单——它就是一个检查清单

markdown
# Heartbeat checklist

- Check email for urgent messages
- Review calendar for events in next 2 hours
- If a background task finished, summarize results
- If idle for 8+ hours, send a brief check-in

关键说明

  • 心跳的触发间隔投递目标是在配置文件中设置的,不是在HEARTBEAT.md中
  • 如果HEARTBEAT.md为空或只有标题,心跳会跳过以节省API调用
  • Agent会在每次心跳时读取这个文件,并处理所有检查项

配置示例(在openclaw.json中):

json5
{
  agents: {
    defaults: {
      heartbeat: {
        every: "...",        // 触发间隔
        target: "last",      // 投递到最近联系的渠道
        activeHours: {       // 可选:活跃时间段
          start: "08:00",
          end: "22:00"
        }
      }
    }
  }
}

典型用途

监控与告警

markdown
- 检查~/.logs/error.log是否有新错误
- 检查是否有未读的紧急邮件
- 检查系统磁盘空间是否充足

定期维护

markdown
- 检查今日日历事件
- 回顾待办事项列表
- 如果长时间没有互动,发送友好的检查消息

HEARTBEAT_OK响应

如果检查后没有需要关注的事情,Agent应该回复HEARTBEAT_OK

这是一个特殊的响应信号:

  • 当Agent返回HEARTBEAT_OK,且剥离HEARTBEAT_TOKEN后的文本长度小于等于心跳的字符限制时,消息会被静默丢弃
  • 这样可以避免每次心跳都打扰用户
  • 如果有重要发现,Agent应该直接返回消息内容,不要包含HEARTBEAT_OK

注意:心跳运行在主会话中,具有与普通对话相同的工具权限——它可以读取文件、调用工具、发送消息等。

2.7 skills/*.md:能力的模块化

如果说AGENTS.md定义了"我怎么做事"的通用规则,那么skills/*.md定义的就是"我在特定领域能做什么"的专业知识。

技能系统的独特地位

技能文件与其他六份档案有两个关键区别:

  1. 数量不固定:其他档案各一份,技能可以有任意多个
  2. 动态加载:不是每次都加载所有技能,而是根据当前任务按需加载

这种设计解决了无限能力与有限上下文的矛盾。

想象一个精通百艺的Agent:它会写代码、会做设计、会分析数据、会写文案、会调试服务器...如果每次对话都把所有这些能力的说明书塞进提示词,上下文窗口早就爆了。

OpenClaw的解决方案是技能的智能路由

技能的结构

每个技能是一个独立的Markdown文件,位于skills/目录下:

  .agents/
  ├── skills/
  │   ├── code-review/
  │   │   └── SKILL.md
  │   ├── writing-clearly/
  │   │   └── SKILL.md
  │   └── deployment-guide/
  │       ├── SKILL.md
  │       └── references/
  │           └── examples.md

技能文件通常包含:

元数据(YAML frontmatter)

  • name:技能的标识名
  • description:技能的简短描述,用于匹配用户意图
  • homepage:技能相关工具或文档的主页链接
  • metadata.openclaw:OpenClaw特定的配置
    • emoji:技能的图标
    • os:支持的操作系统(如 ["darwin", "linux"])
    • requires.bins:需要的二进制命令
    • requires.env:需要的环境变量
    • install:自动安装配置(支持brew、npm、go、uv、download等方式)
    • always:是否总是加载此技能(不通过模型判断)
    • primaryEnv:主要的环境变量前缀

核心内容

  • 适用场景:"当用户需要...时使用此技能"
  • 核心原则:该领域的指导原则
  • 工作流程:处理此类任务的标准步骤
  • 质量标准:什么是好的结果、什么是坏的结果
  • 常见陷阱:该领域容易犯的错误

技能路由的工作原理

OpenClaw在系统提示词中注入一个可用技能列表,包含每个技能的文件路径。当需要时,模型会使用read工具按需加载技能内容:

  1. 技能列表常驻:系统提示词中包含所有可用技能的名称、描述和路径
  2. 模型自主判断:模型根据用户消息判断是否需要读取某个技能
  3. 按需读取:模型使用read工具加载所需技能的完整内容
  4. 执行:Agent在技能指导下回应用户

例如:

用户说:"帮我审查一下这个PR"

模型看到可用技能列表中有code-review,描述匹配当前任务 → 模型调用read读取该技能 → Agent按照代码审查的流程和质量标准来回应

这种设计保持基础提示词精简,同时让模型能够获取所需的详细指导。


3. 系统提示词的组装工艺

八份档案各自独立维护,但在对话发生时,它们需要被整合成一份完整的系统提示词(System Prompt)。这个组装过程本身就是一门精妙的工程艺术。

3.1 官方系统提示词结构

根据OpenClaw官方文档,系统提示词由以下固定部分组成:

  • Tooling:当前工具列表 + 简短描述
  • Safety:避免权力寻租行为和绕过监督的护栏提醒
  • Skills(当可用时):告诉模型如何按需加载技能说明
  • Tool Call Style:工具调用的格式和风格指南
  • OpenClaw Self-Update:如何运行config.applyupdate.run
  • Workspace:工作目录(agents.defaults.workspace
  • Documentation:本地OpenClaw文档路径及何时查阅
  • Workspace Files (injected):bootstrap文件被注入到此处
  • Sandbox(当启用时):沙盒运行时、路径及提权执行可用性
  • Current Date & Time:用户本地时间、时区和时间格式
  • Reply Tags:可选的回复标签语法
  • Silent Replies:静默回复的行为和条件
  • Heartbeats:心跳提示和确认行为
  • OpenClaw CLI Quick Reference:CLI命令快速参考
  • Runtime:主机、操作系统、Node版本、模型、仓库根目录、思考级别
  • Reasoning:当前可见性级别 + /reasoning切换提示

这种结构紧凑且固定,确保每次运行都有一致的上下文基础。

3.2 Bootstrap文件注入

OpenClaw的Workspace Bootstrap机制会自动将以下文件注入系统提示词:

  • AGENTS.md
  • SOUL.md
  • TOOLS.md
  • IDENTITY.md
  • USER.md
  • HEARTBEAT.md
  • BOOTSTRAP.md(仅在新工作空间首次加载)
  • MEMORY.md和/或memory.md(当存在于工作空间时)

这些文件在Project Context部分被注入,让模型无需显式读取就能看到身份和配置上下文。

重要限制

  • 所有文件都计入文字长度消耗,需要保持精简
  • 单个文件有大小上限
  • 总注入内容有大小上限
  • 超出限制的文件会被智能截断,并显示警告标记

子代理会话保留AGENTS.mdTOOLS.mdSOUL.mdIDENTITY.mdUSER.md,其他bootstrap文件被过滤以保持上下文精简。

3.3 文件截断机制

八份档案加起来可能有几万字,但LLM的上下文窗口是有限的(即使是128K的模型,系统提示词通常也要控制在合理范围内,给用户对话留出空间)。

OpenClaw采用智能截断策略:

单文件限制

  • 每个bootstrap文件有大小限制
  • 超出部分采用智能保留策略
  • 截断处会添加标记提示内容不完整

总量限制

  • 所有注入内容有总大小限制
  • 超出时按优先级截断

截断警告

  • 可通过配置设置截断警告的显示方式(关闭、仅一次、总是显示)
  • 截断时会在Project Context中注入警告块

技能的特殊处理

技能文件不会自动注入系统提示词。系统提示词只包含:

  • 可用技能列表(名称、描述、路径)
  • 模型按需使用read工具读取所需技能

这种设计保持基础提示词精简,同时让模型能够获取所需的详细指导。


4. 热更新机制:修改即生效的魔法

这是OpenClaw最令人惊叹的特性之一:你修改任何一个.md文件,保存后的下一秒,Agent的行为就会改变。不需要重启,不需要重新加载。

这是怎么做到的?

4.1 文件识别信息缓存策略

最直接的思路是:每次对话都重新读取所有文件。但这太浪费了——大部分时间文件根本没变。

OpenClaw使用了一种文件识别信息比对机制:

  1. 首次加载:读取文件内容,记录文件识别信息(包含文件路径、大小、修改时间等),存入缓存
  2. 后续对话:快速比对新旧识别信息
    • 如果识别信息相同 → 直接使用缓存内容(微秒级)
    • 如果识别信息不同 → 重新读取文件,更新缓存,重新组装提示词

这种乐观缓存策略让系统在文件未变时几乎零开销,文件变化时又能立即感知。

4.2 缓存更新机制

当检测到文件识别信息变化时,系统会执行全量更新

缓存失效与重建

  • 重新读取整个文件内容
  • 更新文件识别信息缓存
  • 触发提示词的重新组装

这种基于文件识别信息的缓存机制确保了数据一致性,任何文件修改都会立即反映在下次对话中。

4.3 实战示例

让我们看一个热更新的实际场景:

初始状态: 你的SOUL.md定义Agent是"严谨的软件工程师",说话正式、详细。

用户:"解释一下递归。"

Agent:"递归是一种在函数定义中使用函数自身的方法。它包含两个基本组成部分:基准情形(base case)和递归情形(recursive case)..."(很长的技术解释)

你修改文件: 打开SOUL.md,把"严谨的软件工程师"改成"幽默的编程老师,喜欢用比喻",保存。

下一次对话

用户:"再解释一下递归。"

Agent:"哈哈,递归就像是在俄罗斯套娃里找最小的那个娃娃!你打开一个娃娃,发现里面还有一个,再打开,还有...直到你找到那个打不开的(基准情形),然后一路带着答案返回。来,看看这个例子..."(生动的比喻)

没有重启,没有延迟。这种即时反馈让调试和优化Agent人格变得异常流畅。


5. 文字长度限制:在有限中创造无限

现在我们来面对一个残酷的现实:文字长度是有限的,而且LLM的上下文窗口是有限的。

即使你不关心成本(其实你应该关心),128K的窗口也不是无限的。如何在这有限的资源内,让Agent表现得既有个性又专业?

5.1 预算控制机制

OpenClaw 控制提示词大小其实特别简单粗暴——就靠两个数字:

┌────────────────────────┬─────────┬────────────────────────────────┐ │ 参数 │ 默认值 │ 用途 │ ├────────────────────────┼─────────┼────────────────────────────────┤ │ bootstrapMaxChars │ 20,000 │ 单个文件最多允许多少字符 │ ├────────────────────────┼─────────┼────────────────────────────────┤ │ bootstrapTotalMaxChars │ 150,000 │ 所有文件加起来不能超过多少字符 │ └────────────────────────┴─────────┴────────────────────────────────┘

这就是全部了,没有复杂的"人格占多少、技能占多少"的算法。只要配置这两个参数,系统就会自动帮你把控。

那这些限制管哪些文件呢? 主要是工作目录里的这些"引导文件":

  • AGENTS.md - 告诉 Agent 该怎么干活
  • SOUL.md - Agent 的性格和说话风格
  • USER.md - 用户信息
  • TOOLS.md - 工具使用指导
  • HEARTBEAT.md - 定时任务该做什么
  • IDENTITY.md - Agent 的身份定义
  • MEMORY.md - 记忆文件

5.2 压缩的艺术

如何在有限预算内传递更多信息?

结构化优于叙述性

❌ 低效:"当你面对一个需要处理文件的请求时,你应该首先检查文件是否存在,然后读取内容,分析内容,最后给出回应..."

✅ 高效:"文件处理流程:1)检查存在性 2)读取内容 3)分析 4)回应"

表格优于列表

❌ 低效:"Bash工具用于执行命令,Read工具用于读取文件,Glob工具用于模式匹配..."

✅ 高效:

工具用途
Bash执行shell命令
Read读取文件内容
Glob文件模式匹配

关键词优于解释

LLM对专业术语的理解能力很强,不需要每次都展开解释。用"使用TDD方法"而不是"使用测试驱动开发的方法,也就是先写测试再写代码的方法"。

5.3 当预算超支时

如果某个文件的内容超过了分配给它预算怎么办?

文件截断

当文件超过大小限制时,系统采用智能保留策略。这是因为:

  • 文件头部通常包含最重要的定义和规则
  • 文件尾部可能包含重要的参考信息和总结
  • 截断处会添加标记提示内容不完整
  • 模型可通过read工具按需读取完整内容

分层提示

如果文件实在太长,系统会:

  1. 在系统提示词中放入精简版(关键规则+最新摘要)
  2. 提供工具让Agent可以读取完整版
  3. 在提示词中告诉Agent:"完整文档可在~/.agents/MEMORY.md查看"

这样Agent知道有更多信息可用,可以在需要时主动获取。


6. 通过提示词精细控制Agent行为

理解了提示词系统的原理,我们来看看如何在实践中利用它来精细控制Agent的行为。

6.1 人格调试技巧

渐进式调整

不要一次性重写整个SOUL.md,而是小步迭代:

  1. 记录Agent当前让你不满意的具体行为("它太啰嗦了")
  2. 修改SOUL.md,添加针对性的规则("解释概念时用不超过3句话")
  3. 测试,观察变化
  4. 如果还不够,继续细化

对比测试

同时维护两个版本的配置文件,快速对比:

bash
# 测试版本A
cp SOUL.md SOUL.md.backup
cp SOUL_variant_a.md SOUL.md
# 对话测试...

# 测试版本B
cp SOUL_variant_b.md SOUL.md
# 对话测试...

具体优于抽象

❌ 低效:"请友好一点"

✅ 高效:"在回应开头使用问候语(如'你好!'),在结尾提供鼓励(如'有什么其他问题随时问我'),避免使用命令式语气"

6.2 记忆的精细化管理

事实的分类存储

不是所有事情都值得记入MEMORY.md。建立一个简单的分类:

  • 项目事实(代码结构、API行为):值得记,长期有效
  • 临时偏好("这次用蓝色"):不值得记,过时就忘
  • 学习经验("上次这样做失败了"):值得记,但要定期清理过时的

定期整理

每月花10分钟浏览MEMORY.md,删除:

  • 已经过时的信息
  • 太具体的一次性事件
  • 现在看起来错误的结论

标记重要性

在记忆条目前加标记:

[核心] 项目使用pnpm而不是npm
[参考] API文档地址: https://docs.example.com
[临时] 本周在赶deadline,优先处理紧急bug

Agent会优先保留带"[核心]"的条目。

6.3 技能的开发与优化

从需求出发

不要凭空造技能。当你发现Agent在某个领域反复表现不佳时,才是创建技能的时候:

  1. 记录Agent在没有技能时的失败行为
  2. 分析失败原因(缺少知识?流程不清?标准不明?)
  3. 编写针对性的技能文档
  4. 测试验证改进效果

技能的原子化

一个技能只做一件事。不要造"超级技能"涵盖所有开发场景,而是拆分为:

  • code-review.md:代码审查
  • git-workflow.md:Git操作
  • testing-guide.md:测试编写

这样可以根据需要灵活组合。

技能的元数据优化

技能的description字段决定了模型何时选择读取它。要写得清晰明确:

yaml
name: "code-review"
description: "当用户需要审查代码、检查PR质量、进行代码走查时使用"

模型会根据description自主判断是否需要读取该技能。


7. 总结

这一章我们深入探讨了OpenClaw的提示词系统——这套赋予AI"灵魂"的工程架构。

核心洞察回顾

  1. 文件即灵魂:用持久化的Markdown文件取代临时的提示词,让Agent具备连续的身份和记忆

  2. 八层认知架构

    • SOUL.md定义"我是谁"
    • USER.md定义"你是谁"
    • AGENTS.md定义"我怎么做事"
    • TOOLS.md定义"我有什么资源"
    • IDENTITY.md定义"我的身份标识"
    • MEMORY.md定义"我记得什么"
    • HEARTBEAT.md定义"我何时主动行动"
    • BOOTSTRAP.md定义"新空间初始引导"
    • skills/*.md定义"我会什么专业技能"
  3. 系统提示词结构:官方固定结构(Tooling→Safety→Skills→Workspace→Documentation→Bootstrap Files→Sandbox→Time→Runtime等)

  4. 热更新魔法:文件识别信息缓存机制让修改立即生效,无需重启

  5. 文字长度限制管理:在有限资源内最大化信息价值,文件截断机制保留最重要内容

实践原则

  • 渐进式调优,小步快跑
  • 具体优于抽象,结构优于叙述
  • 定期整理记忆,保持信息新鲜
  • 技能原子化,按需加载

当你掌握了这套系统,你就从"使用AI"进化到了"塑造AI"。你不是在跟一个黑盒对话,而是在调校一个你可以理解、可以控制、可以不断演化的数字伙伴。

它的性格、能力、记忆、偏好——所有这些曾经被认为是"玄学"的特质,现在都变成了你可以直接编辑的文本文件

这就是提示词工程的最高境界:不是写一段完美的提示词,而是设计一个持续演化的提示词系统


下一步

在下一章,我们将深入探讨工具系统——Agent赖以完成实际任务的"手脚"。你会看到Bash、Glob、Grep、Read这四大原语是如何被设计的,以及如何让Agent学会使用新的工具。