System Prompt 组装
system prompt 是每次 Claude Code API 调用中最关键的 context 部分。它定义了 Claude 的身份、能力、行为约束和环境感知。src/constants/prompts.ts 中的组装过程是一条精心设计的分层流水线,在 cache 效率与每 session 动态性之间取得平衡。
system prompt 由一个边界标记分为两个区域:
export const SYSTEM_PROMPT_DYNAMIC_BOUNDARY = '__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__'graph TD
subgraph "Static Zone (cross-org cacheable)"
A[Identity & Introduction]
B[System Information]
C[Coding Instructions]
D[Actions Section]
E[Tool Usage Guide]
F[Tone & Style]
G[Output Efficiency]
end
H["__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__"]
subgraph "Dynamic Zone (per-session)"
I[Environment Info]
J[Memory Prompt]
K[Language Preference]
L[Output Style Config]
M[MCP Instructions]
N[Scratchpad Instructions]
O[Function Result Clearing]
P[Token Budget]
end
A --> B --> C --> D --> E --> F --> G --> H --> I --> J --> K --> L --> M --> N --> O --> P
边界之前的所有内容可以使用 scope: 'global' cache——在所有用户和 session 中完全相同。边界之后的内容包含用户/session 特定信息,不得进行全局 cache。
getSystemPrompt() 函数
Section titled “getSystemPrompt() 函数”主入口是 src/constants/prompts.ts 中的 getSystemPrompt():
// src/constants/prompts.ts — simplified structureexport async function getSystemPrompt( tools: Tools, model: string, additionalWorkingDirectories?: string[], mcpClients?: MCPServerConnection[],): Promise<string[]> { // Early exit for --bare / SIMPLE mode if (isEnvTruthy(process.env.CLAUDE_CODE_SIMPLE)) { return [`You are Claude Code...\n\nCWD: ${getCwd()}\nDate: ${getSessionStartDate()}`] }
// Early exit for proactive/autonomous mode if (proactiveModule?.isProactiveActive()) { return [/* minimal autonomous prompt */] }
// Standard prompt: static sections + dynamic sections const dynamicSections = [ systemPromptSection('env_info', () => envInfo), systemPromptSection('memory', () => loadMemoryPrompt()), systemPromptSection('language', () => getLanguageSection(settings.language)), systemPromptSection('output_style', () => getOutputStyleSection(outputStyleConfig)), DANGEROUS_uncachedSystemPromptSection('mcp_instructions', ...), systemPromptSection('scratchpad', () => getScratchpadInstructions()), systemPromptSection('frc', () => getFunctionResultClearingSection(model)), // ... ]
return [ // --- Static content (cacheable) --- getSimpleIntroSection(outputStyleConfig), getSimpleSystemSection(), getSimpleDoingTasksSection(), getActionsSection(), getUsingYourToolsSection(enabledTools), getSimpleToneAndStyleSection(), getOutputEfficiencySection(), // === BOUNDARY MARKER === ...(shouldUseGlobalCacheScope() ? [SYSTEM_PROMPT_DYNAMIC_BOUNDARY] : []), // --- Dynamic content --- ...resolvedDynamicSections, ].filter(s => s !== null)}该函数返回字符串数组(各分区),而非单一字符串。这样可以将边界标记保留给下游 cache 逻辑使用。
function getSimpleIntroSection(outputStyleConfig: OutputStyleConfig | null): string { // "You are Claude Code, Anthropic's official CLI for Claude..." // Core identity, tool-using mandate, human-in-the-loop principle}function getSimpleDoingTasksSection(): string { // File editing rules, test/lint requirements // "When editing files: use Read before Edit" // "When writing tests: follow existing patterns"}Tool 使用指南
Section titled “Tool 使用指南”function getUsingYourToolsSection(enabledTools: Set<string>): string { // Conditional sections based on which tools are available // Includes explore agent usage tips when enabled // Includes fork agent instructions when FORK_SUBAGENT is active}两个变体——ant 内部版(更长,包含更细致的沟通准则)和外部版(简洁的”直入主题”指令):
function getOutputEfficiencySection(): string { if (process.env.USER_TYPE === 'ant') { return `# Communicating with the userWhen sending user-facing text, you're writing for a person, not logging to a console...` } return `# Output efficiencyIMPORTANT: Go straight to the point. Try the simplest approach first...`}动态分区通过注册系统(systemPromptSections.ts)管理:
// Two types of dynamic sectionssystemPromptSection('memory', () => loadMemoryPrompt())// ↑ Cached by the section registry — value stabilizes within a session
DANGEROUS_uncachedSystemPromptSection('mcp_instructions', () => getMcpInstructionsSection(...))// ↑ Recomputed every turn — changes between turns (e.g., MCP connect/disconnect)// Includes: CWD, date/time, git status, OS, model nameasync function computeEnvInfo( modelId: string, additionalWorkingDirectories?: string[],): Promise<string> { const [isGit, unameSR] = await Promise.all([getIsGit(), getUnameSR()]) // Builds environment string with all runtime context}Memory Prompt
Section titled “Memory Prompt”从自动 memory 系统(src/memdir/memdir.ts)加载。memory prompt 分区包含 MEMORY.md 内容、team memory 以及保存/调取指令。
function getLanguageSection(language?: string): string | null { if (!language) return null return `IMPORTANT: Always respond in ${language}.`}MCP Server 指令
Section titled “MCP Server 指令”当 MCP server 通过 client.instructions 提供自定义指令时,这些指令会被注入到 system prompt 中:
function getMcpInstructions(mcpClients: MCPServerConnection[]): string | null { const clientsWithInstructions = connectedClients.filter(c => c.instructions) // Returns "# MCP Server Instructions\n## server-name\n{instructions}"}Simple 模式(--bare)
Section titled “Simple 模式(--bare)”将 system prompt 精简至最小——仅保留身份、CWD 和日期:
if (isEnvTruthy(process.env.CLAUDE_CODE_SIMPLE)) { return [`You are Claude Code...\nCWD: ${getCwd()}\nDate: ${getSessionStartDate()}`]}Proactive 模式
Section titled “Proactive 模式”自主 agent 使用截然不同的 prompt,专注于持续的自我驱动工作,而非与人交互:
if (proactiveModule?.isProactiveActive()) { return [ `You are an autonomous agent. Use the available tools to do useful work.`, getSystemRemindersSection(), await loadMemoryPrompt(), envInfo, // ... minimal sections ]}Coordinator 模式
Section titled “Coordinator 模式”coordinator agent 使用 src/coordinator/coordinatorMode.ts 中的 getCoordinatorSystemPrompt()——一个完全独立的约 370 行 prompt,定义了编排协议(参见 Coordinator 模式)。
Prompt 大小预算
Section titled “Prompt 大小预算”system prompt 占据了 context window 的相当大比例。关键大小决策:
| 分区 | 相对大小 | 说明 |
|---|---|---|
| 编码指令 | 大 | 完整的文件编辑协议 |
| 输出效率 | 中 | ant 版本更长 |
| tool 使用指南 | 可变 | 随启用的 tool 数量增长 |
| memory | 有上限 | MEMORY.md:200 行,25KB 上限 |
| MCP 指令 | 可变 | 取决于已连接的 server |
| 环境信息 | 小 | 约 200 字符 |
双区拆分确保最大的分区(编码指令、tool 使用)位于静态区并被全局 cache,而较小的每 session 分区则占据动态区。