第 2 章:全局 Context Prompt — 系统提示的构建机制
源码位置:
src/utils/systemPrompt.ts、src/utils/attachments.ts、src/constants/prompts.ts
2.1 为什么系统提示很重要?
在 LLM 应用中,系统提示决定了 AI 的身份、能力边界和行为规范。Claude Code 的系统提示并非一成不变——它根据当前模式(普通模式 / Coordinator 模式 / Proactive 模式 / 自定义 Agent 模式)动态构建,并在每一轮 API 调用前组装。
2.2 系统提示的五个来源
优先级(从高到低):
0. Override 提示 ← loop 模式等特殊场景,完全替换所有其他提示
1. Coordinator 提示 ← 自主代理协调器模式(环境变量 CLAUDE_CODE_COORDINATOR_MODE=1)
2. Agent 提示 ← mainThreadAgentDefinition 定义的自定义代理
├── Proactive 模式:Agent 提示 "追加" 到 Default 之后
└── 普通模式:Agent 提示 "替换" Default
3. Custom 提示 ← 用户通过 --system-prompt CLI 参数传入
4. Default 提示 ← Claude Code 内置的标准提示
+ Append 提示 ← 始终追加在末尾(Override 除外)
2.3 核心函数:buildEffectiveSystemPrompt()
源码位置:src/utils/systemPrompt.ts:41
export function buildEffectiveSystemPrompt({
mainThreadAgentDefinition,
toolUseContext,
customSystemPrompt,
defaultSystemPrompt,
appendSystemPrompt,
overrideSystemPrompt,
}: {
mainThreadAgentDefinition: AgentDefinition | undefined
toolUseContext: Pick<ToolUseContext, 'options'>
customSystemPrompt: string | undefined
defaultSystemPrompt: string[]
appendSystemPrompt: string | undefined
overrideSystemPrompt?: string | null
}): SystemPrompt {
// 优先级 0:Override(直接返回,忽略所有其他提示)
if (overrideSystemPrompt) {
return asSystemPrompt([overrideSystemPrompt])
}
// 优先级 1:Coordinator 模式
// 注意:使用 lazy require 避免循环依赖
if (
feature('COORDINATOR_MODE') &&
isEnvTruthy(process.env.CLAUDE_CODE_COORDINATOR_MODE) &&
!mainThreadAgentDefinition
) {
const { getCoordinatorSystemPrompt } = require('../coordinator/coordinatorMode.js')
return asSystemPrompt([
getCoordinatorSystemPrompt(),
...(appendSystemPrompt ? [appendSystemPrompt] : []),
])
}
// 计算 Agent 提示(如果有自定义 Agent 定义)
const agentSystemPrompt = mainThreadAgentDefinition
? isBuiltInAgent(mainThreadAgentDefinition)
? mainThreadAgentDefinition.getSystemPrompt({ toolUseContext: { options: toolUseContext.options } })
: mainThreadAgentDefinition.getSystemPrompt()
: undefined
// 优先级 2(Proactive 模式):Agent 提示追加到 Default 之后
if (agentSystemPrompt && isProactiveActive_SAFE_TO_CALL_ANYWHERE()) {
return asSystemPrompt([
...defaultSystemPrompt,
`\n# Custom Agent Instructions\n${agentSystemPrompt}`,
...(appendSystemPrompt ? [appendSystemPrompt] : []),
])
}
// 优先级 2/3/4:Agent > Custom > Default,最后加 Append
return asSystemPrompt([
...(agentSystemPrompt
? [agentSystemPrompt]
: customSystemPrompt
? [customSystemPrompt]
: defaultSystemPrompt),
...(appendSystemPrompt ? [appendSystemPrompt] : []),
])
}
2.4 决策树图
调用 buildEffectiveSystemPrompt()
│
▼
overrideSystemPrompt 存在?
│ │
YES NO
│ │
▼ ▼
[Override] COORDINATOR_MODE 环境变量?
│ │
YES NO
│ │
▼ ▼
[Coordinator] mainThreadAgentDefinition 存在?
│ │
YES NO
│ │
▼ ▼
isProactiveActive()? customSystemPrompt 存在?
│ │ │ │
YES NO YES NO
│ │ │ │
▼ ▼ ▼ ▼
[Default [Agent只有] [Custom] [Default]
+ Agent]
│ │ │ │
└───────┴─────────────┴────────┘
│
▼
+ appendSystemPrompt(如果有)
2.5 Attachment Messages
除了系统提示,Claude Code 还向每轮 API 调用注入动态上下文。附件消息类型为 AttachmentMessage,在 normalizeMessagesForAPI() 时转换为 API 格式(通常是 <system-reminder> 包裹的 user message)。
getAttachmentMessages() 实际管理的附件类型超过 50 种,按触发场景分为以下几类(src/utils/attachments.ts:743):
用户输入相关(每次用户提交时处理)
| 附件类型 | 触发条件 |
|---|---|
skill_listing | 有新 skill 尚未告知 LLM(sentSkillNames 判断) |
skill_discovery | EXPERIMENTAL_SKILL_SEARCH 开启时,语义搜索结果 |
nested_memory | 用户 @-mention 文件时,自动加载该文件所在目录的条件 CLAUDE.md 规则 |
agent_mentions | 用户消息中提及了 @agent |
全局 Delta(有变化才注入,避免重复 token)
| 附件类型 | 触发条件 | 说明 |
|---|---|---|
deferred_tools_delta | 模型支持工具引用 + 工具搜索功能开启 | 告知 Claude 还有哪些工具可通过 ToolSearch 发现,不把所有工具塞入 tools 参数 |
agent_listing_delta | 可用 Agent 定义发生变化 | 告知 Claude 可以调用哪些 subagent_type |
mcp_instructions_delta | MCP 服务器连接后首次注入 | MCP 服务器的使用说明 |
date_change | 日期跨天 | 更新当前日期 |
plan_mode / plan_mode_exit | Plan 模式进入/退出 | |
todo_reminder / task_reminder | 有未完成任务 | 提醒 Claude 当前待办 |
teammate_mailbox | Coordinator 模式下有新邮件 |
主线程专属(IDE 集成等)
| 附件类型 | 触发条件 |
|---|---|
selected_lines_in_ide | IDE 中有选中代码 |
opened_file_in_ide | IDE 中打开了文件 |
critical_system_reminder | 有需要强提醒的系统消息 |
附件的关键设计
- Delta 模式:全局类附件只在内容发生变化时才注入,避免重复消耗 token
- AttachmentMessage 容器:统一的内部数据结构,不直接对应 API 格式;
normalizeMessagesForAPI()在每次 API 调用前将其转换 - relevant_memories 的异步注入:CLAUDE.md 相关记忆通过
startRelevantMemoryPrefetch()预取,在工具执行后消费(见第 1 章)
2.6 userContext 与 CLAUDE.md
userContext 是 { [k: string]: string } 键值对,由 getUserContext() 构建,包含两项:
return {
...(claudeMd && { claudeMd }), // CLAUDE.md 合并内容(见下)
currentDate: `Today's date is ${getLocalISODate()}.`,
}
userContext 不是 systemPrompt 的一部分,而是在 API 调用时通过 prependUserContext() 以 <system-reminder> user message 的形式插入到 messages 列表最前面(src/query.ts:660)。
CLAUDE.md 记忆文件的加载顺序
getMemoryFiles() 按以下顺序加载(src/utils/claudemd.ts:803):
1. Managed(企业策略)
/etc/claude-code/CLAUDE.md
~/.claude-code/rules/*.md
2. User(用户全局,若 userSettings 未禁用)
~/.claude/CLAUDE.md
~/.claude/rules/*.md
3. Project(从 Git 根目录向下遍历到 CWD,每个目录中按序)
CLAUDE.md ← 检入代码库的项目指令
.claude/CLAUDE.md
.claude/rules/*.md
CLAUDE.local.md ← 本地私有指令,不检入代码库
Git worktree 特殊处理:从 nested worktree 运行时,跳过主仓库的 Project 级文件,避免重复加载。
filterInjectedMemoryFiles 的实际作用
文档原来说"过滤已注入的(避免重复)"是错的。实际逻辑是:
export function filterInjectedMemoryFiles(files: MemoryFileInfo[]): MemoryFileInfo[] {
const skipMemoryIndex = getFeatureValue_CACHED_MAY_BE_STALE('tengu_moth_copse', false)
if (!skipMemoryIndex) return files // 默认:返回全部文件
return files.filter(f => f.type !== 'AutoMem' && f.type !== 'TeamMem')
}
默认情况下不过滤任何文件。只有 tengu_moth_copse feature flag 开启时,才过滤掉 AutoMem 和 TeamMem 类型(这两类通过 relevant_memories attachment 单独异步注入)。
条件规则(nested_memory)
当用户 @-mention 一个文件时,Claude Code 自动查找该文件所在目录的 CLAUDE.md,将其中匹配当前场景的条件规则作为 nested_memory attachment 注入。这是 CLAUDE.md "子目录级生效"的实现机制。
2.7 systemContext 与 git 状态
与 userContext 并列,systemContext 由 getSystemContext() 构建(src/context.ts:116),包含:
return {
...(gitStatus && { gitStatus }), // 当前 git 工作区状态(可选)
...(cacheBreaker && { cacheBreaker }), // 缓存破坏器,ant-only(可选)
}
systemContext 的注入方式与 userContext 不同——通过 appendSystemContext() 追加到 systemPrompt 数组末尾(src/query.ts:449),成为 system prompt 的一部分:
// src/utils/api.ts
export function appendSystemContext(
systemPrompt: SystemPrompt,
context: { [k: string]: string },
): string[] {
return [
...systemPrompt,
Object.entries(context)
.map(([key, value]) => `${key}: ${value}`) // 格式:"gitStatus: ..."
.join('\n'),
].filter(Boolean)
}
| userContext | systemContext | |
|---|---|---|
| 包含内容 | CLAUDE.md + 当前日期 | git 状态 + 缓存破坏器 |
| 注入方式 | prependUserContext() → messages 最前的 <system-reminder> | appendSystemContext() → 追加到 systemPrompt 末尾 |
| 缓存 | memoize,整个会话只加载一次 | memoize,整个会话只加载一次 |
2.8 系统提示的 Token 分析
上下文构建完成后,Claude Code 会分析 token 使用情况:
// src/utils/contextAnalysis.ts
analyzeContext(messages, systemPrompt)
// → tokenStatsToStatsigMetrics() 用于分析上报
这为 Auto Compaction(自动压缩,第 7 章)提供判断依据。
2.9 Coordinator 模式系统提示
Coordinator 模式是 Claude Code 的"自主代理编排"模式,此时系统提示完全不同:
// src/coordinator/coordinatorMode.ts
export function getCoordinatorSystemPrompt(): string {
// 返回协调器专用提示:
// - 如何分配任务给 worker 代理
// - 如何通过 mailbox 通信
// - 工具集限制(ASYNC_AGENT_ALLOWED_TOOLS)
// - 任务完成标准
}
export function isCoordinatorMode(): boolean {
return feature('COORDINATOR_MODE') &&
isEnvTruthy(process.env.CLAUDE_CODE_COORDINATOR_MODE)
}
Coordinator 也有自己的 Worker 上下文注入:
getCoordinatorUserContext()
// 将可用的 worker 工具列表注入到 user 消息中
// 让 coordinator 知道它能分配哪些能力给 worker
2.10 系统提示缓存优化
Claude API 支持 Prompt Cache(提示缓存)。Claude Code 通过以下方式最大化缓存命中:
- 系统提示内容稳定:尽量不在每次循环中改变系统提示内容
- Delta 附件模式:只在有变化时才追加新内容,避免整个消息列表发生变化
- Fork Subagent 字节级一致:子代理创建时传递"已渲染"的系统提示字节,而不是重新调用
getSystemPrompt()(可能因 GrowthBook 状态变化而产生不同结果)
源码位置:src/tools/AgentTool/forkSubagent.ts:56
// FORK_AGENT 定义:
// The getSystemPrompt here is unused: the fork path passes
// `override.systemPrompt` with the parent's already-rendered system prompt
// bytes, threaded via `toolUseContext.renderedSystemPrompt`.
// Reconstructing by re-calling getSystemPrompt() can diverge (GrowthBook
// cold→warm) and bust the prompt cache; threading the rendered bytes is
// byte-exact.
export const FORK_AGENT = {
// ...
getSystemPrompt: () => '', // 不使用,由 override 传递父代理的已渲染提示
}
小结
| 机制 | 作用 | 源码位置 |
|---|---|---|
buildEffectiveSystemPrompt() | 按优先级组合系统提示 | src/utils/systemPrompt.ts:41 |
userContext | CLAUDE.md + 当前日期,以 <system-reminder> 插入 messages 最前 | src/context.ts:155 |
systemContext | git 状态 + 缓存破坏器,追加到 systemPrompt 末尾 | src/context.ts:116 |
| Attachment Messages | 动态注入上下文(50+ 类型,按 Delta 模式避免重复) | src/utils/attachments.ts:743 |
| CLAUDE.md 记忆文件 | 多层级加载(managed → user → project),通过 userContext 注入 | src/utils/claudemd.ts:803 |
nested_memory | @-mention 文件时自动加载该目录的条件规则 | src/utils/attachments.ts |
| Coordinator 提示 | 自主代理编排模式 | src/coordinator/coordinatorMode.ts |
| Prompt Cache 优化 | Fork subagent 传递已渲染字节,保证字节级一致 | src/tools/AgentTool/forkSubagent.ts:56 |