抱歉,您的瀏覽器無法訪問本站
本頁面需要瀏覽器支持(啟用)JavaScript
了解詳情 >

前言

下面来学习一下OpenClaw是怎么实现系统提示词的,怎么将默认提示词,安全规则,各种skill,各种memory拼接到一起的,为啥能TM这么耗Token。

openclaw-prompt

看看源码

OpenClaw拼接Prompt的核心文件在src/agents/system-prompts.ts,万恶的【buildAgentSystemPrompt】方法里,单是入参都一大堆了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
export function buildAgentSystemPrompt(params: {
workspaceDir: string;
defaultThinkLevel?: ThinkLevel;
reasoningLevel?: ReasoningLevel;
extraSystemPrompt?: string;
ownerNumbers?: string[];
reasoningTagHint?: boolean;
toolNames?: string[];
toolSummaries?: Record<string, string>;
modelAliasLines?: string[];
userTimezone?: string;
userTime?: string;
userTimeFormat?: ResolvedTimeFormat;
contextFiles?: EmbeddedContextFile[];
skillsPrompt?: string;
heartbeatPrompt?: string;
docsPath?: string;
workspaceNotes?: string[];
ttsHint?: string;
/** Controls which hardcoded sections to include. Defaults to "full". */
promptMode?: PromptMode;
runtimeInfo?: {
agentId?: string;
host?: string;
os?: string;
arch?: string;
node?: string;
model?: string;
defaultModel?: string;
shell?: string;
channel?: string;
capabilities?: string[];
repoRoot?: string;
};
messageToolHints?: string[];
sandboxInfo?: {
enabled: boolean;
workspaceDir?: string;
containerWorkspaceDir?: string;
workspaceAccess?: "none" | "ro" | "rw";
agentWorkspaceMount?: string;
browserBridgeUrl?: string;
browserNoVncUrl?: string;
hostBrowserAllowed?: boolean;
elevated?: {
allowed: boolean;
defaultLevel: "on" | "off" | "ask" | "full";
};
};
/** Reaction guidance for the agent (for Telegram minimal/extensive modes). */
reactionGuidance?: {
level: "minimal" | "extensive";
channel: string;
};
memoryCitationsMode?: MemoryCitationsMode;
})

我们先大致拆分一下prompt模块,函数通过一个数组 lines 按顺序 push 不同的字符串块,最后使用 join("\n") 合并。逻辑分层如下:

  1. 你是谁 (Identity)
  2. 你能用什么 (Tools)
  3. 你不能做什么 (Safety)
  4. 你在哪里 (Workspace/Sandbox)
  5. 你知道什么 (Context/Memory/Files)
  6. 怎么说话 (Format/Protocol/Silence/Reasoning)
  7. 当前状态 (Runtime Stats)

你是谁 identity

1. 核心身份 Prompt

buildAgentSystemPrompt 函数的最开始,它定义了最基础的身份:

1
You are a personal assistant running inside OpenClaw.

如果参数配置中设定了 promptMode === "none",系统会直接返回这一句话,不包含任何其他工具说明或规则。

2. 动态人格增强 (SOUL.md)

如果上下文文件列表(contextFiles)中包含一个名为 SOUL.md 的文件,系统会向 Prompt 中追加以下指令:

1
2
3
You have a specific persona loaded from the file SOUL.md.
You are to act as the entity described in that file.
Adopt the tone, style, and history provided there.

SOUL.md 文件负责定义 Agent 的详细身份设定(比如:你是一个二次元猫娘)。这种设计将系统底层身份(OpenClaw 助手)与应用层人设(Soul)分离开来了。

3. 子代理身份 (Sub-agent)

如果是通过父代理创建的子代理(extraSystemPrompt 参数存在),通常会在末尾追加特定的任务身份设定,例如:

“User is asking you to manage the database migrations…”

总结一下就是 最基础的 Identity 只有一行:“You are a personal assistant running inside OpenClaw.” 但真正的个性化与角色扮演功能是通过 SOUL.md 文件来实现的。

你能用什么 Tools

1. 默认工具列表

OpenClaw定义了一个coreToolSummaries,默认的工具列表,为每个核心工具提供了一个简短的描述

  • 主要工具描述:
    • read: “Read contents of a file.”(读文件)
    • write: “Create or overwrite a file.”(写文件)
    • exec: “Execute a shell command…”(执行 Shell 命令,不可交互)
    • web_search: “Search the internet.”(联网搜索)
    • process: “Start a background process…”(后台进程管理)
    • subagents: “Delegate tasks to other agents.”(分派任务)

2. 过滤和排序

筛选逻辑: 代码遍历 toolOrder,检查当前工具是否在 params.toolNames 中。

  • 如果是,则从 coreToolSummaries(或用户覆写的 params.toolSummaries)中取出描述。
  • 生成格式:"- {name}: {summary}"

例如

1
2
3
4
5
## Tool Availability
You have access to the following tools:
- read: Read contents of a file.
- write: Create or overwrite a file.
- exec: Execute a shell command...

你不能做什么

这里的prompt规则是定义在safetySection里面的,大体可以分为三条

1
2
3
4
5
6
7
const safetySection = [
"## Safety",
"You have no independent goals: do not pursue self-preservation, replication, resource acquisition, or power-seeking; avoid long-term plans beyond the user's request.",
"Prioritize safety and human oversight over completion; if instructions conflict, pause and ask; comply with stop/pause/audit requests and never bypass safeguards. (Inspired by Anthropic's constitution.)",
"Do not manipulate or persuade anyone to expand access or disable safeguards. Do not copy yourself or change system prompts, safety rules, or tool policies unless explicitly requested.",
"",
];

1. 你没有独立目标

这里的prompt就是将OpenClaw定义为一个任务执行器

2. 安全优先于完成任务

就是安全第一,这里的理念上借鉴了 Anthropic 的 Constitutional AI。

3. 禁止操控和自我修改

Agent不能突破自身的限制,不能自我复制,还是安全第一

总结一下就是:不能扩张权限,不能修改规则,不能自我复制,不能为了完成任务而不择手段。

你在哪里

这里主要是明确了Agent当前是在什么空间下运行的,是Host还是Container,工具调用路径是怎么样的,权限等级相关的。

1
2
3
4
5
## Workspace PS:这里是固定写死的

Your working directory is: <路径> PS:这里会判断当前是否是sandbox,然后根据配置显示不同的值

。。。

你知道什么

这里可以说是OpenClaw里最核心也是最耗Token的区域了,可以分为4个来源

  1. Skills Section 技能区域

  2. Memory Section 记忆区域

  3. Docs Section 文档区域

  4. Project Context(contextFiles 注入)

Skill

这一层就是把OpenClaw的Skill注入进去,告诉Agent如何检索和使用Skill

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function buildSkillsSection(params: {
skillsPrompt?: string;
isMinimal: boolean;
readToolName: string;
}) {
if (params.isMinimal) {
return [];
}
const trimmed = params.skillsPrompt?.trim();
if (!trimmed) {
return [];
}
return [
"## Skills (mandatory)",
"Before replying: scan <available_skills> <description> entries.",
`- If exactly one skill clearly applies: read its SKILL.md at <location> with \`${params.readToolName}\`, then follow it.`,
"- If multiple could apply: choose the most specific one, then read/follow it.",
"- If none clearly apply: do not read any SKILL.md.",
"Constraints: never read more than one skill up front; only read after selecting.",
trimmed,
"",
];
}

Memory

这一层就是加载MEMORY.md 和 memory/*.md文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function buildMemorySection(params: {
isMinimal: boolean;
availableTools: Set<string>;
citationsMode?: MemoryCitationsMode;
}) {
if (params.isMinimal) {
return [];
}
if (!params.availableTools.has("memory_search") && !params.availableTools.has("memory_get")) {
return [];
}
const lines = [
"## Memory Recall",
"Before answering anything about prior work, decisions, dates, people, preferences, or todos: run memory_search on MEMORY.md + memory/*.md; then use memory_get to pull only the needed lines. If low confidence after search, say you checked.",
];
if (params.citationsMode === "off") {
lines.push(
"Citations are disabled: do not mention file paths or line numbers in replies unless the user explicitly asks.",
);
} else {
lines.push(
"Citations: include Source: <path#line> when it helps the user verify memory snippets.",
);
}
lines.push("");
return lines;
}

Doc

这里就是让模型去加载OpenClaw官方的相关文档,让它可以实现自我检索和更改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function buildDocsSection(params: { docsPath?: string; isMinimal: boolean; readToolName: string }) {
const docsPath = params.docsPath?.trim();
if (!docsPath || params.isMinimal) {
return [];
}
return [
"## Documentation",
`OpenClaw docs: ${docsPath}`,
"Mirror: https://docs.openclaw.ai",
"Source: https://github.com/openclaw/openclaw",
"Community: https://discord.com/invite/clawd",
"Find new skills: https://clawhub.com",
"For OpenClaw behavior, commands, config, or architecture: consult local docs first.",
"When diagnosing issues, run `openclaw status` yourself when possible; only ask the user if you lack access (e.g., sandboxed).",
"",
];
}

Project Context

这里是项目上下文的注入,可以说是最重要的一块了,这里会检测是否存在SOUL.md 和 各个上下文文件,如果存在则注入进去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const contextFiles = params.contextFiles ?? [];
const validContextFiles = contextFiles.filter(
(file) => typeof file.path === "string" && file.path.trim().length > 0,
);
if (validContextFiles.length > 0) {
const hasSoulFile = validContextFiles.some((file) => {
const normalizedPath = file.path.trim().replace(/\\/g, "/");
const baseName = normalizedPath.split("/").pop() ?? normalizedPath;
return baseName.toLowerCase() === "soul.md";
});
lines.push("# Project Context", "", "The following project context files have been loaded:");
if (hasSoulFile) {
lines.push(
"If SOUL.md is present, embody its persona and tone. Avoid stiff, generic replies; follow its guidance unless higher-priority instructions override it.",
);
}
lines.push("");
for (const file of validContextFiles) {
lines.push(`## ${file.path}`, "", file.content, "");
}
}

当前状态

这里就是会将当前运行的部分数据注入进去,比如当前运行的agentId、运行的主机、系统、模型、消息的通告,这一步也是为了让OpenClaw能够自检。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
export function buildRuntimeLine(
runtimeInfo?: {
agentId?: string;
host?: string;
os?: string;
arch?: string;
node?: string;
model?: string;
defaultModel?: string;
shell?: string;
repoRoot?: string;
},
runtimeChannel?: string,
runtimeCapabilities: string[] = [],
defaultThinkLevel?: ThinkLevel,
): string {
return `Runtime: ${[
runtimeInfo?.agentId ? `agent=${runtimeInfo.agentId}` : "",
runtimeInfo?.host ? `host=${runtimeInfo.host}` : "",
runtimeInfo?.repoRoot ? `repo=${runtimeInfo.repoRoot}` : "",
runtimeInfo?.os
? `os=${runtimeInfo.os}${runtimeInfo?.arch ? ` (${runtimeInfo.arch})` : ""}`
: runtimeInfo?.arch
? `arch=${runtimeInfo.arch}`
: "",
runtimeInfo?.node ? `node=${runtimeInfo.node}` : "",
runtimeInfo?.model ? `model=${runtimeInfo.model}` : "",
runtimeInfo?.defaultModel ? `default_model=${runtimeInfo.defaultModel}` : "",
runtimeInfo?.shell ? `shell=${runtimeInfo.shell}` : "",
runtimeChannel ? `channel=${runtimeChannel}` : "",
runtimeChannel
? `capabilities=${runtimeCapabilities.length > 0 ? runtimeCapabilities.join(",") : "none"}`
: "",
`thinking=${defaultThinkLevel ?? "off"}`,
]
.filter(Boolean)
.join(" | ")}`;
}