本文总结如何修改 OpenClaw sub-agent 的 system prompt,特别是”只对 sub-agent 生效、主 agent 不受影响”的实现方式。完整 plugin 实现见 subagent-prompt-inject-plugin。

核心机制

System Prompt 生成

Sub-agent 的 system prompt 由 src/agents/subagent-system-prompt.ts 中的 buildSubagentSystemPrompt() 生成,包含以下段落:

# Subagent Context
## Your Role
## Rules
## Output Format
## What You DON'T Do
## Sub-Agent Spawning(按 depth 决定)
## Session Context

各段落含义见 subagent-system-prompt-basics。

buildSubagentSystemPrompt 参数

参数类型说明
requesterSessionKeystring?父 agent 的 session key,注入到 ## Session Context
requesterOriginDeliveryContext?父 agent 的 channel/to 信息
childSessionKeystring子 agent 的 session key
labelstring?spawn 时传入的标签
taskstring?任务描述(注入到 ## Your Role)
acpEnabledboolean?是否启用 ACP,控制 nativeCommandGuidanceLines 是否注入
nativeCommandGuidanceLinesstring[]?Plugin 注册的命令 guidance(仅 acpEnabled=true 时生效)
childDepthnumber?子 agent 的嵌套深度(1=sub-agent,2=sub-sub-agent)
maxSpawnDepthnumber?最大允许嵌套深度,控制是否显示 spawn 指引

注入方式

在 src/agents/subagent-spawn.ts:1159,system prompt 以 extraSystemPrompt 字段追加到 agent 原有 prompt 后面(不是替换):

extraSystemPrompt: childSystemPrompt,

Session 类型判断

src/agents/pi-embedded-runner/run/attempt.prompt-helpers.ts:209:

export function resolvePromptModeForSession(sessionKey?: string): "minimal" | "full" {
  return isSubagentSessionKey(sessionKey) || isCronSessionKey(sessionKey) ? "minimal" : "full";
}
  • 主 agent:promptMode = "full"
  • Sub-agent:promptMode = "minimal"
  • Cron session:promptMode = "minimal"

配置文件的限制

openclaw.json 的 subagents 配置块(src/config/types.agent-defaults.ts:438)没有 prompt 注入字段:

subagents:
  delegationMode, allowAgents, maxConcurrent, maxSpawnDepth,
  maxChildrenPerAgent, archiveAfterMinutes, model, thinking,
  runTimeoutSeconds, announceTimeoutMs, requireAgentId

AGENTS.md、SOUL.md 等 workspace 文件对主 agent 和 sub-agent 都生效,无法区分。

修改方案对比

方案适用场景侵入性是否区分 sub-agent
修改 AGENTS.md全局行为约束零否(主 agent 也受影响)
task 参数写指令单次 spawn 临时注入零是(精准控制)
agentPromptGuidancePlugin 命令使用说明低仅 ACP 模式
ProviderPlugin.transformSystemPrompt自动化、永久生效中(需写 plugin)是
改源码 buildSubagentSystemPrompt()全局结构性修改高(需 rebuild)是

前两种方案(AGENTS.md 和 task 参数)的详细说明见 subagent-system-prompt-basics。

推荐方案:ProviderPlugin.transformSystemPrompt

判断逻辑

transformSystemPrompt(ctx) {
  // 主 agent 是 "full",直接跳过
  if (ctx.promptMode !== "minimal") return null;
  // cron session 也是 "minimal",但没有这个 marker
  if (!ctx.systemPrompt.includes("# Subagent Context")) return null;
  // 只有 sub-agent 才追加
  return `${ctx.systemPrompt}\n\n${EXTRA_INSTRUCTIONS}`;
}

ctx 完整字段(ProviderTransformSystemPromptContext)

type ProviderTransformSystemPromptContext = {
  config?: OpenClawConfig;
  agentDir?: string;
  workspaceDir?: string;
  provider: string;
  modelId: string;
  promptMode: PromptMode;        // "full" | "minimal" | "none"
  runtimeChannel?: string;
  runtimeCapabilities?: string[];
  agentId?: string;
  trigger?: "cron" | "heartbeat" | "manual" | "memory" | "overflow" | "user";
  systemPrompt: string;
}

hookAliases 机制

transformSystemPrompt 按 provider id 查找(src/plugins/provider-hook-runtime.ts)。通过 hookAliases 可以 hook 进目标 provider 而不注册完整 provider,避免冲突:

api.registerProvider({
  id: "subagent-prompt-inject-hook-openai",
  hookAliases: ["openai"],  // hook 进 openai provider 的 transform 链
  auth: [],                 // hook-only plugin,不提供模型
  transformSystemPrompt(ctx) { ... },
});

agentPromptGuidance 机制

Plugin 可以通过 registerCommand 注册命令时附带 guidance:

api.registerCommand({
  name: "my-command",
  agentPromptGuidance: [
    "When using my-command, always pass --format json",
    "my-command results are cached for 5 minutes",
  ],
});

这些 guidance 通过 listRegisteredPluginAgentPromptGuidance() 收集,注入到 ## Sub-Agent Spawning 段。

限制:只在 acpEnabled=true(启用了 ACP harness)时才注入,普通 sub-agent 场景不生效。

常见误区

subagent_spawning hook 不能注入 prompt

subagent_spawning hook 的返回值 PluginHookSubagentSpawningResult 只能返回路由信息,不能注入 system prompt:

type PluginHookSubagentSpawningResult = {
  status: "ok" | "error";
  threadBindingReady?: boolean;
  deliveryOrigin?: DeliveryContext;  // 只能改路由
  error?: string;
}

该 hook 主要用于 channel thread 绑定。

CliBackendPlugin vs ProviderPlugin 的区别

两个 plugin 类型都有 transformSystemPrompt,但签名不同:

CliBackendPlugin(src/plugins/cli-backend.types.ts:124):有 modelDisplay,没有 promptMode、trigger、runtimeCapabilities。

ProviderPlugin(src/plugins/types.ts:1686):有完整的 promptMode、trigger、runtimeCapabilities。

结论:判断 sub-agent 需要 promptMode 字段,必须用 ProviderPlugin 版本。

关键注意点

  • OpenClaw 默认 provider 是 openai(src/agents/defaults.ts),TARGET_PROVIDERS 需与实际使用的 provider 一致
  • agentPromptGuidance 只在 acpEnabled=true 时注入,普通 sub-agent 场景不生效
  • Sub-agent system prompt 是追加模式,不是替换
  • promptMode === "minimal" 同时匹配 sub-agent 和 cron,需结合 # Subagent Context marker 精准区分
  • subagent_spawning hook 只能改路由,不能注入 system prompt
  • 判断 sub-agent 必须用 ProviderPlugin.transformSystemPrompt,CliBackendPlugin 版本缺少 promptMode 字段

相关源码

  • src/agents/subagent-system-prompt.ts — system prompt 生成
  • src/agents/subagent-spawn.ts — spawn 时注入 extraSystemPrompt
  • src/agents/pi-embedded-runner/run/attempt.prompt-helpers.ts — promptMode 解析
  • src/plugins/types.ts:1214 — ProviderTransformSystemPromptContext 类型定义
  • src/plugins/provider-hook-runtime.ts — hookAliases 匹配逻辑
  • src/agents/defaults.ts — DEFAULT_PROVIDER = “openai”

相关页面