本文档详细拆解 OpenClaw Agent 发送给 LLM 的完整 System Prompt 的组成结构**版本:**v2.1
**更新时间:**2026-03-05
整体架构图

快速导航(TL;DR)
新手必读:
- Layer 7(Workspace Files)- 你能直接编辑的配置文件
- Layer 8(Bootstrap Hook)- 你能写脚本动态注入内容
- 其他层都是框架自动生成的,了解即可
常见需求:
- 想定义 Agent 身份?→ 编辑 Layer 7 的 IDENTITY.md
- 想添加项目文档?→ 使用 Layer 8 的 bootstrap-extra-files Hook
- 想注入实时上下文?→ 使用 Layer 8 的 before_prompt_build Hook
- 想控制文件大小?→ 调整 bootstrapMaxChars 配置
Layer 1: OpenClaw Framework Core(框架核心层)
比喻
就像一本操作手册的"使用说明"部分——告诉 LLM 你是谁、能做什么、应该怎么回应
组成内容

实际示例
你正在以「创意伙伴」身份运行,这是一个 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 你有哪些工具、每个工具是干什么用的、怎么用
组成内容

工具定义示例
{
"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 消耗)
组成内容

Layer 4: Model Aliases(模型别名层)
比喻
就像"快捷键"——给复杂的模型路径起个简短的别名,方便调用
设计权衡
为什么需要模型别名?
- **权衡:**灵活性 vs 可读性
- **决策:**允许用户为常用模型定义简短别名
- **好处:**简化模型调用(glm-5 代替 zhipu/glm-5)
支持多 Provider 切换(同一别名可映射不同 Provider)
便于 A/B 测试和模型迁移 - **代价:**需要维护别名配置文件
可能造成混淆(不同 Agent 的同一别名可能指向不同模型)
组成内容

实际示例
在 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 严格遵守协议(可能被忽略)
组成内容

实际示例
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
信息可能包含冗余
组成内容

实际示例
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 框架和文件结构
核心文件

Layer 8: Bootstrap Hook System(动态注入层)★ 用户可控
比喻
就像"可编程的注射器"——你可以写脚本在运行时动态注入内容到 System Prompt
设计权衡
为什么需要 Hook 系统?
- **权衡:**静态配置的简单性 vs 动态注入的灵活性
- **决策:**在静态 Workspace Files 之外,提供动态 Hook 机制
- **好处:**可以根据上下文(channel、sender、时间)动态调整注入内容
可以执行 shell 命令并注入输出(如当前天气、Git 状态)
可以读取外部文件并注入(如项目文档、API 文档)
支持条件判断(if/else) - **代价:**需要学习 Hook 系统的语法和触发机制
Hook 脚本错误可能导致 System Prompt 异常
增加了系统复杂度
四种 Hook 机制
- 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: "自定义内容" }
];
});
- 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 文件
- 需要动态加载额外文档
- 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
- 需要注入实时上下文(如当前时间、天气)
- 需要完全替换系统提示词
- 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
对话历史可能包含噪音信息
组成内容

完整 System Prompt 组装流程



用户可控层总结
OpenClaw 提供了 3 种用户可控机制:
- Layer 7(Workspace Files)- 静态配置文件适用场景:定义 Agent 身份、工作规范、记忆
优点:简单直观,易于版本管理
缺点:无法动态调整 - Layer 8(Bootstrap Hook System)- 动态注入脚本适用场景:根据上下文动态注入内容、执行命令、读取外部文件
优点:灵活强大,支持条件判断和命令执行
缺点:需要学习 Hook 系统,脚本错误可能导致异常 - 间接控制 Layer 9(Inbound Context)- 通过发送消息影响上下文适用场景:通过对话历史、引用消息影响 LLM 行为
优点:无需配置,自然交互
缺点:无法精确控制
大小对比表
⚠️ 注意:以下数据为估算值,实际大小会因配置和运行时上下文而变化。框架层(Layer 1-6 + 9)理论上应该相同,但实际可能因工具定义、Skills 加载、运行时信息等差异而略有不同。

说明:
- Layer 7 和 Layer 8 是用户可控层,大小因 Agent 配置而异
- 其他层由框架自动生成,理论上所有 Agent 应该相同
- 实际测量时可能因工具可用性、Skills 加载、运行时上下文等因素产生差异
优化建议
- 用户可控部分优化(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 中使用不稳定的外部依赖(会导致启动失败)
- 提示词裁剪策略
如果 System Prompt 过大,可以考虑:

总结
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 的配置能力。

