呕心沥血肝出来的,奉献给你们的龙虾了:OpenClaw Agent System Prompt 架构详解(9层)

0 阅读11分钟

整体架构图

image.png

快速导航(TL;DR)

新手必读:

  1. Layer 7(Workspace Files)- 你能直接编辑的配置文件
  2. Layer 8(Bootstrap Hook)- 你能写脚本动态注入内容
  3. 其他层都是框架自动生成的,了解即可

常见需求:

  • 想定义 Agent 身份?→ 编辑 Layer 7 的 IDENTITY.md
  • 想添加项目文档?→ 使用 Layer 8 的 bootstrap-extra-files Hook
  • 想注入实时上下文?→ 使用 Layer 8 的 before_prompt_build Hook
  • 想控制文件大小?→ 调整 bootstrapMaxChars 配置

Layer 1: OpenClaw Framework Core(框架核心层)

比喻

就像一本操作手册的"使用说明"部分——告诉 LLM 你是谁、能做什么、应该怎么回应

组成内容

image.png

实际示例

你正在以「创意伙伴」身份运行,这是一个 AI 内容创作专家 Agent。 当前时间:2026-03-05 14:37:00 CST 运行环境:agent=creative | host=黄宗宁的MacBook Air === 工具调用规范 === - 使用 XML 风格的工具调用格式 - 每个工具调用必须包含唯一的 tool_call_id - 工具结果通过 <tool_result> 标签返回 - 执行工具时考虑 AbortSignal 以支持取消操作 === 安全边界 === - 严禁执行 destructive 操作(rm -rf、格式化等) - 处理用户敏感信息时必须加密存储 - 禁止向未授权的渠道发送消息

设计权衡

为什么这样设计?

  • 权衡: 灵活性 vs 一致性
  • 决策: 框架层统一生成,保证所有 Agent 的基础行为一致
  • 好处:用户不需要为每个 Agent 重复配置基础规则 框架升级时所有 Agent 自动获得新能力 降低配置错误的风险
  • 代价:用户无法修改这些核心规则 如果需要特殊行为,只能通过 Layer 7/8 间接实现

Layer 2: Tool Definitions(工具定义层)

比喻

就像一把瑞士军刀的工具清单——告诉 LLM 你有哪些工具、每个工具是干什么用的、怎么用

组成内容

image.png

工具定义示例

{ "name": "read", "description": "读取文件内容。支持文本文件和图片(jpg/png/gif/webp)。图片会作为附件发送。文本文件输出限制为2000行或50KB。", "parameters": { "type": "object", "properties": { "path": { "type": "string", "description": "文件路径(相对或绝对)" }, "offset": { "type": "number", "description": "起始行号(1-indexed)" }, "limit": { "type": "number", "description": "最大读取行数" } }, "required": ["path"] } }

设计权衡

为什么用 JSON Schema?

  • 权衡: 灵活性 vs 类型安全
  • 决策: 使用严格的 JSON Schema 定义工具参数
  • 好处:LLM 能更准确地理解工具用法 框架可以在调用前验证参数 自动生成文档和类型定义
  • 代价:添加新工具需要编写完整的 Schema 无法支持完全动态的参数结构

Layer 3: Skills Registry(技能注册表)

比喻

就像一家餐厅的"特色菜谱"——告诉 LLM 有哪些专业领域的"配方"可以调用

设计权衡

为什么用目录扫描而不是手动注册?

  • 权衡: 灵活性 vs 维护成本
  • 决策: 自动扫描 ~/development/openclaw/skills/ 目录
  • 好处:添加新 Skill 只需放入目录,无需修改配置 所有 Agent 自动获得新 Skill 降低配置错误风险
  • 代价:无法精确控制每个 Agent 可用的 Skill 所有 Skill 都会被注入 System Prompt(增加 token 消耗)

组成内容

image.png

Layer 4: Model Aliases(模型别名层)

比喻

就像"快捷键"——给复杂的模型路径起个简短的别名,方便调用

设计权衡

为什么需要模型别名?

  • 权衡: 灵活性 vs 可读性
  • 决策: 允许用户为常用模型定义简短别名
  • 好处:简化模型调用(glm-5 代替 zhipu/glm-5) 支持多 Provider 切换(同一别名可映射不同 Provider) 便于 A/B 测试和模型迁移
  • 代价:需要维护别名配置文件 可能造成混淆(不同 Agent 的同一别名可能指向不同模型)

组成内容

image.png

实际示例

在 System Prompt 中,模型别名会被展示为:

Model Aliases - GLM-5: zhipu/glm-5 - Opus 4.6: xiaowang886/claude-opus-4-6-thinking - Sonnet 4.5: xiaowang886/claude-sonnet-4-5

LLM 可以使用别名来切换模型:/model glm-5

Layer 5: Protocol Specifications(协议规范层)

比喻

就像"交通规则"——定义 Agent 与系统交互的标准协议

设计权衡

为什么需要协议规范?

  • 权衡: 自由度 vs 一致性
  • 决策: 定义标准化的交互协议(Silent Replies、Heartbeats、Reply Tags 等)
  • 好处:保证所有 Agent 行为一致 支持自动化监控和健康检查 简化多 Agent 协作
  • 代价:限制了 Agent 的自由表达 需要 LLM 严格遵守协议(可能被忽略)

组成内容

image.png

实际示例

Silent Replies 示例:

用户:收到 Agent:NO_REPLY

Heartbeats 示例:

System:[Heartbeat Poll] Agent:HEARTBEAT_OK

Reply Tags 示例:

Agent:[[reply_to_current]] 已完成任务 ✓

Layer 6: Runtime Info(运行时信息层)

比喻

就像"仪表盘"——告诉 LLM 当前运行环境的实时状态

设计权衡

为什么每次都注入运行时信息?

  • 权衡: Token 消耗 vs 上下文准确性
  • 决策: 每次请求都注入最新的运行时状态
  • 好处:LLM 知道当前时间(避免时间错乱) LLM 知道当前模型(避免能力误判) LLM 知道当前环境(避免路径错误)
  • 代价:每次请求消耗 ~2KB token 信息可能包含冗余

组成内容

image.png

实际示例

Runtime Runtime: agent=thinktank | host=黄宗宁的MacBook Air | repo=/Users/huangzongning/.openclaw/workspace-thinktank | os=Darwin 25.2.0 (arm64) | node=v25.5.0 | model=xiaowang886/claude-opus-4-6-thinking | default_model=xiaowang886/claude-opus-4-6-thinking | shell=zsh | channel=discord | capabilities=none | thinking=off

Layer 7: Workspace Files(工作区文件层)★ 用户可控

比喻

就像"你的工作笔记"——这是你可以直接编辑的静态配置文件

设计权衡

为什么只有这一层是静态可编辑的?

  • 权衡: 框架稳定性 vs 用户自由度
  • 决策: 把"变"和"不变"分离,框架层保证一致性,用户层允许个性化
  • 好处:用户可以定义 Agent 身份、工作规范、记忆 框架升级不会破坏用户配置 配置文件可以版本管理、备份、共享
  • 代价:用户无法修改框架核心行为 需要学习 TELOS 框架和文件结构

核心文件

image.png

Layer 8: Bootstrap Hook System(动态注入层)★ 用户可控

比喻

就像"可编程的注射器"——你可以写脚本在运行时动态注入内容到 System Prompt

设计权衡

为什么需要 Hook 系统?

  • 权衡: 静态配置的简单性 vs 动态注入的灵活性
  • 决策: 在静态 Workspace Files 之外,提供动态 Hook 机制
  • 好处:可以根据上下文(channel、sender、时间)动态调整注入内容 可以执行 shell 命令并注入输出(如当前天气、Git 状态) 可以读取外部文件并注入(如项目文档、API 文档) 支持条件判断(if/else)
  • 代价:需要学习 Hook 系统的语法和触发机制 Hook 脚本错误可能导致 System Prompt 异常 增加了系统复杂度

四种 Hook 机制

  1. agent:bootstrap Hook(内部 Hook 系统)

触发位置: bootstrap-hooks.ts 的 applyBootstrapHookOverrides()

能力:

  • 完全控制 bootstrapFiles 数组
  • 可以增删改文件
  • 可以重排序
  • 可以修改文件内容

谁可以注册:

  • OpenClaw 插件
  • Workspace Hooks(~/.openclaw/workspace-*/hooks/ 目录)
  • 内部模块

代码示例:

registerInternalHook("agent:bootstrap", (event) => { const context = event.context as AgentBootstrapHookContext; // 完全控制 bootstrapFiles 数组 context.bootstrapFiles = [ { path: "CUSTOM.md", content: "自定义内容" } ]; });

  1. bootstrap-extra-files Hook(Bundled Hook)

触发位置: hooks/bundled/bootstrap-extra-files/handler.ts

能力:

  • 只追加文件,不修改现有文件
  • 通过配置文件指定额外文件

配置示例:

{ "hooks": { "bootstrap-extra-files": { "enabled": true, "paths": ["extra/*.md", "docs/CONTEXT.md"] } } }

适用场景:

  • 需要注入项目特定的上下文文件
  • 不想修改默认的 8 个 Bootstrap 文件
  • 需要动态加载额外文档
  1. before_prompt_build Hook(Plugin Hook)

触发位置: attempt.ts 的 runBeforePromptBuild()

能力:

  • 修改最终 prompt(在系统提示词构建后、发送给 LLM 前)
  • 可以 prepend context(在 prompt 前添加内容)
  • 可以覆盖 systemPrompt

事件数据:

{ prompt: string; // 用户输入 messages: unknown[]; // Session 消息历史 }

返回值:

{ prependContext?: string; // 在 prompt 前添加的内容 systemPrompt?: string; // 覆盖系统提示词 }

适用场景:

  • 需要根据 session 历史动态调整 prompt
  • 需要注入实时上下文(如当前时间、天气)
  • 需要完全替换系统提示词
  1. bootstrapMaxChars / bootstrapTotalMaxChars(配置项)

类型: 配置项(不是 hook)

能力:

  • 控制字符预算
  • 单文件默认 20K
  • 总计默认 150K
  • 超出部分按头 70% + 尾 20% 截断

配置位置:

{ "agents": { "defaults": { "bootstrapMaxChars": 20000, "bootstrapTotalMaxChars": 150000 } } }

实战建议

场景 1:我想添加项目文档

推荐方案:bootstrap-extra-files

{ "hooks": { "bootstrap-extra-files": { "enabled": true, "paths": ["docs/API.md", "docs/ARCHITECTURE.md"] } } }

场景 2:我想根据任务类型动态加载文件

推荐方案:自定义 agent:bootstrap Hook

registerInternalHook("agent:bootstrap", (event) => { const context = event.context as AgentBootstrapHookContext; const sessionKey = context.sessionKey; // 根据 session 类型加载不同文件 if (sessionKey.includes("coding")) { context.bootstrapFiles.push({ path: "CODING_GUIDELINES.md", content: fs.readFileSync("...").toString() }); } });

场景 3:我想注入实时上下文(如当前时间)

推荐方案:before_prompt_build Hook

on("before_prompt_build", (event, ctx) => { return { prependContext: 当前时间:${new Date().toISOString()} }; });

Layer 9: Inbound Context(入站上下文层)

比喻

就像"实时路况信息"——每次请求都会动态注入当前对话的上下文信息

设计权衡

为什么每次都注入上下文?

  • 权衡: Token 消耗 vs 对话连贯性
  • 决策: 每次请求都注入最新的消息元信息、发送者信息、对话历史
  • 好处:LLM 知道当前是谁在说话(避免混淆发送者) LLM 知道对话历史(保持上下文连贯) LLM 知道是否被 @(决定是否响应)
  • 代价:每次请求消耗 ~3KB token 对话历史可能包含噪音信息

组成内容

image.png

完整 System Prompt 组装流程

image.png image.png

image.png

用户可控层总结

OpenClaw 提供了 3 种用户可控机制:

  1. Layer 7(Workspace Files) - 静态配置文件适用场景:定义 Agent 身份、工作规范、记忆 优点:简单直观,易于版本管理 缺点:无法动态调整
  2. Layer 8(Bootstrap Hook System) - 动态注入脚本适用场景:根据上下文动态注入内容、执行命令、读取外部文件 优点:灵活强大,支持条件判断和命令执行 缺点:需要学习 Hook 系统,脚本错误可能导致异常
  3. 间接控制 Layer 9(Inbound Context) - 通过发送消息影响上下文适用场景:通过对话历史、引用消息影响 LLM 行为 优点:无需配置,自然交互 缺点:无法精确控制

大小对比表

⚠️ 注意:以下数据为估算值,实际大小会因配置和运行时上下文而变化。框架层(Layer 1-6 + 9)理论上应该相同,但实际可能因工具定义、Skills 加载、运行时信息等差异而略有不同。

image.png

说明:

  • Layer 7 和 Layer 8 是用户可控层,大小因 Agent 配置而异
  • 其他层由框架自动生成,理论上所有 Agent 应该相同
  • 实际测量时可能因工具可用性、Skills 加载、运行时上下文等因素产生差异

优化建议

  1. 用户可控部分优化(Layer 7 + 8)

由于 Layer 7 和 8 是用户可以控制的,以下是优化策略:

Layer 7(静态文件)优化:

✅ 推荐的精简策略:

  • IDENTITY.md:保留核心 TELOS 框架,删除冗余描述,使用表格代替段落
  • AGENTS.md:使用 checklist 代替长段落,用代码块展示命令,删除重复的规则说明
  • MEMORY.md:依赖 MemOS 自动导出,不要手动添加内容,让系统自动维护

❌ 避免的做法:

  • 不要重复描述 OpenClaw 框架已经知道的事情
  • 不要把 Skills 的详细说明复制到 Workspace Files
  • 不要使用过多的修辞和装饰性语言

Layer 8(Hook 系统)优化:

✅ 推荐的使用策略:

  • 优先使用 bootstrap-extra-files(简单场景)
  • 需要条件判断时使用 agent:bootstrap(复杂场景)
  • 需要实时上下文时使用 before_prompt_build(动态场景)

❌ 避免的做法:

  • 不要在 Hook 中执行耗时操作(会阻塞 System Prompt 生成)
  • 不要在 Hook 中注入过多内容(会超出 token 限制)
  • 不要在 Hook 中使用不稳定的外部依赖(会导致启动失败)
  1. 提示词裁剪策略

如果 System Prompt 过大,可以考虑:

image.png

总结

OpenClaw 的 System Prompt 不是一个单一的文件,而是 9 层架构的精心编排:

  • Layer 1-6:框架自动生成,保证一致性和稳定性
  • Layer 7:用户可编辑的静态配置文件(IDENTITY.md、AGENTS.md 等)
  • Layer 8:用户可编程的动态注入脚本(Bootstrap Hook System)
  • Layer 9:框架自动注入的实时上下文(Inbound Context)

用户可控的层有 2 个(Layer 7 + 8),而不是之前错误说的"只有 Layer 7"。

理解这些层的区别和联系,才能真正掌握 OpenClaw 的配置能力。