涉及文件 : QueryEngine.ts, queryContext.ts, query.ts, constants/prompts.ts, constants/system.ts, services/api/claude.ts, utils/api.ts
总览
System prompt 的构建分为 4 个阶段,跨越从用户输入到 API 调用的完整链路:
| 阶段 | 位置 | 产出 |
|---|---|---|
| Phase 1 基础构建 | fetchSystemPromptParts() + getSystemPrompt() |
原始 system prompt 字符串数组 |
| Phase 2 组装拼接 | QueryEngine.submitMessage() |
含用户自定义/追加内容的 system prompt |
| Phase 3 上下文注入 | queryLoop() → appendSystemContext() |
追加 currentDate 等动态 KV |
| Phase 4 运行时注入 + 缓存分块 | queryModel() → buildSystemPromptBlocks() |
最终 TextBlockParam[](含 cache_control) |
Phase 1:基础构建
入口
typescript
// QueryEngine.ts:288-300
const { defaultSystemPrompt, userContext, systemContext } =
await fetchSystemPromptParts({ tools, mainLoopModel, mcpClients, customSystemPrompt })
fetchSystemPromptParts()(queryContext.ts:44-74)
typescript
const [defaultSystemPrompt, userContext, systemContext] = await Promise.all([
customSystemPrompt !== undefined
? Promise.resolve([]) // SDK 模式:跳过,返回空数组
: getSystemPrompt(tools, model, ...), // 交互模式:生成默认 system prompt
getUserContext(), // 当前日期、CWD 等
customSystemPrompt !== undefined
? Promise.resolve({})
: getSystemContext(), // currentDate 等动态 KV
])
关键逻辑 :customSystemPrompt 参数决定是否执行 getSystemPrompt()
| 模式 | customSystemPrompt |
getSystemPrompt() |
getSystemContext() |
|---|---|---|---|
| 交互模式(print.ts) | undefined |
执行 → 生成完整默认 prompt | 执行 |
| SDK 模式(用户提供 system) | string |
跳过(返回 []) |
跳过(返回 {}) |
注意:
fetchSystemPromptParts不是 SDK 独有 的。print.ts:2147的交互模式通过ask()→QueryEngine.submitMessage()→fetchSystemPromptParts()同样走这条路径。
getSystemPrompt()(prompts.ts:444-577)的默认结构
scss
[0] getSimpleIntroSection() → "You are Claude Code..."
[1] getSimpleSystemSection() → 通用行为说明
[2] getSimpleDoingTasksSection() → 任务执行指南
[3] getActionsSection() → 操作说明
[4] getUsingYourToolsSection() → 工具使用说明
[5] getSimpleToneAndStyleSection() → 语气和风格
[6] getOutputEfficiencySection() → 输出效率要求
=== BOUNDARY MARKER === → 仅在全局缓存启用时插入
[7] session_guidance → 会话特定指导(动态)
[8] memory → MEMORY.md 内容(动态)
[9] ant_model_override → 模型覆盖说明(动态)
[10] env_info_simple → 环境信息(动态)
[11] language → 语言设置(动态)
[12] output_style → 输出风格配置(动态)
[13] mcp_instructions → MCP 服务器指令(动态,不缓存)
[14] scratchpad → Scratchpad 指令(动态)
[15] frc → 函数结果清理(动态)
[16] summarize_tool_results → 工具结果摘要说明(动态)
[17+] numeric_length_anchors / token_budget / brief(特性门控)
- 0-6 :静态内容,可在 API 侧全局缓存(
cache_control: { type: "global" }) - BOUNDARY MARKER :分隔静态/动态内容,仅在
shouldUseGlobalCacheScope()为 true 时插入 - 7+ :动态内容,通过
systemPromptSection()注册,支持按名称缓存/清除
Phase 2:组装拼接
typescript
// QueryEngine.ts:321-325
const memoryMechanicsPrompt =
customPrompt !== undefined && hasAutoMemPathOverride()
? await loadMemoryPrompt()
: null
const systemPrompt = asSystemPrompt([
...(customPrompt !== undefined ? [customPrompt] : defaultSystemPrompt),
...(memoryMechanicsPrompt ? [memoryMechanicsPrompt] : []),
...(appendSystemPrompt ? [appendSystemPrompt] : []),
])
| 输入 | 交互模式 | SDK 模式 |
|---|---|---|
customPrompt |
不使用 → 使用 defaultSystemPrompt(Phase 1 产出) |
使用 → 完全替换默认 prompt |
memoryMechanicsPrompt |
不注入(仅 SDK 且有路径覆盖时) | 有条件注入 |
appendSystemPrompt |
有条件追加(由 --append-system-prompt 传入) |
有条件追加 |
asSystemPrompt() 只是 branded type 转换,无运行时行为。
Phase 3:上下文注入
在 queryLoop()(query.ts)中,每次迭代将 systemContext 追加到 system prompt 末尾:
typescript
// query.ts:449-451
const fullSystemPrompt = asSystemPrompt(
appendSystemContext(systemPrompt, systemContext),
)
appendSystemContext()(api.ts:437-447)
typescript
return [
...systemPrompt,
Object.entries(context)
.map(([key, value]) => `${key}: ${value}`)
.join('\n'), // 如 "currentDate: 2026-06-04"
].filter(Boolean)
systemContext 典型值:{ currentDate: "2026-06-04" }(来自 getSystemContext())
注意:
userContext不走 system prompt,而是通过prependUserContext()注入为消息数组开头的system-reminder块。
Phase 4:运行时注入 + 缓存分块
queryModel() 是 system prompt 进入 API 前的最后一站。
4a. 运行时注入前缀(claude.ts:1357-1369)
typescript
systemPrompt = asSystemPrompt([
getAttributionHeader(fingerprint), // attribution 埋点
getCLISyspromptPrefix({...}), // CLI 角色前缀
...systemPrompt, // 来自 Phase 3 的完整 prompt
...(advisorModel ? [ADVISOR_TOOL_INSTRUCTIONS] : []),
...(injectChromeHere ? [CHROME_TOOL_SEARCH_INSTRUCTIONS] : []),
].filter(Boolean))
getCLISyspromptPrefix()(system.ts:30-46)
typescript
function getCLISyspromptPrefix(options?): CLISyspromptPrefix {
// Vertex → DEFAULT_PREFIX
// Non-interactive + appendSystemPrompt → AGENT_SDK_CLAUDE_CODE_PRESET_PREFIX
// Non-interactive(无 append) → AGENT_SDK_PREFIX
// 默认 → DEFAULT_PREFIX
}
// 三个可能的取值:
const DEFAULT_PREFIX = "You are Claude Code, Anthropic's official CLI for Claude."
const AGENT_SDK_CLAUDE_CODE_PRESET_PREFIX = "You are Claude Code, Anthropic's official CLI for Claude, running within the Claude Agent SDK."
const AGENT_SDK_PREFIX = "You are a Claude agent, built on Anthropic's Claude Agent SDK."
getAttributionHeader()(system.ts:73-95)
ini
x-anthropic-billing-header: cc_version={VERSION}.{fingerprint}; cc_entrypoint={entrypoint}; cch=00000; cc_workload={workload};
用于 API 调用方身份识别、fingerprint 验证和客户端 attestation。
4b. 构建 API system blocks + 缓存标记(claude.ts:1374-1379)
typescript
const system = buildSystemPromptBlocks(systemPrompt, enablePromptCaching, {
skipGlobalCacheForSystemPrompt: needsToolBasedCacheMarker,
querySource: options.querySource,
})
buildSystemPromptBlocks() → splitSysPromptPrefix()(api.ts:321-435)
核心逻辑:解析 system prompt 数组,分段并标记 cache_control。
场景 1:全局缓存 + 有 MCP 工具(needsToolBasedCacheMarker=true)
跳过 boundary marker,前缀和剩余内容标记为 org 级缓存,attribution header 无缓存:
typescript
[
{ text: attributionHeader, cacheScope: null }, // 不缓存
{ text: "You are Claude Code...", cacheScope: "org" },
{ text: "全部剩余内容(拼接后)", cacheScope: "org" },
]
场景 2:全局缓存 + 有 boundary marker(标准交互模式)
attribution header 和 CLI 前缀无缓存,静态块标记 global 级缓存,动态块不缓存:
typescript
[
{ text: attributionHeader, cacheScope: null }, // 不缓存
{ text: "You are Claude Code...", cacheScope: null }, // 不缓存
{ text: "静态内容([0]-[6] 拼接)", cacheScope: "global" }, // 全局缓存
{ text: "动态内容([7+] 拼接)", cacheScope: null }, // 不缓存
]
场景 3:无全局缓存
前缀和剩余内容标记 org 级缓存:
typescript
[
{ text: attributionHeader, cacheScope: null }, // 不缓存
{ text: "You are Claude Code...", cacheScope: "org" },
{ text: "全部剩余内容(拼接后)", cacheScope: "org" },
]
4c. 组装最终 API 参数(claude.ts:1699-1728)
typescript
return {
model: normalizeModelStringForAPI(options.model),
messages: addCacheBreakpoints(messagesForAPI, ...),
system, // ← 最终的 TextBlockParam[]
tools: allTools,
tool_choice: options.toolChoice,
betas: betasParams,
max_tokens: maxOutputTokens,
thinking,
temperature,
// ...
}
4d. 发送 API 请求(claude.ts:1822-1836)
typescript
const result = await anthropic.beta.messages
.create(
{ ...params, stream: true }, // params.system = 上述 system 字段
{ signal, headers: { ... } },
)
.withResponse()
全链路流程图
scss
print.ts / SDK
│
└─ ask() → QueryEngine.submitMessage()
│
├─ Phase 1: fetchSystemPromptParts()
│ ├─ customPrompt 有值?→ Promise.resolve([]) (跳过)
│ └─ customPrompt 无值?→ getSystemPrompt() (交互模式)
│ ├─ 静态 sections [0]-[6]
│ ├─ BOUNDARY MARKER(可选)
│ └─ 动态 sections [7+]
│
├─ Phase 2: 组装
│ [customPrompt/defaultSystemPrompt, memoryMechanicsPrompt, appendSystemPrompt]
│
└─ query() → queryLoop()
│
├─ Phase 3: appendSystemContext(systemPrompt, systemContext)
│ → 追加 "currentDate: ..." 等 KV
│
└─ queryModelWithStreaming() → queryModel()
│
├─ normalizeMessagesForAPI()
├─ ensureToolResultPairing()
├─ stripExcessMediaItems()
│
├─ Phase 4a: 运行时注入
│ ├─ getAttributionHeader() → 身份标识
│ ├─ getCLISyspromptPrefix() → 角色声明
│ ├─ advisor 指令
│ └─ Chrome 工具搜索指令
│
├─ Phase 4b: buildSystemPromptBlocks()
│ └─ splitSysPromptPrefix() → 分段 + cache_control
│
├─ Phase 4c: paramsFromContext()
│ └─ { system, messages, tools, ... }
│
└─ Phase 4d: anthropic.beta.messages.create({ system, ... })
关键设计点
-
分层构建:4 个阶段各司其职,基础内容 → 用户定制 → 动态上下文 → 运行时注入,避免耦合
-
Prompt 缓存优化 :
splitSysPromptPrefix通过 boundary marker 精确分离静态/动态内容,静态部分标记global或org级缓存,大幅减少 API 侧的缓存缺失 -
按需解析 :动态 sections 使用
systemPromptSection()注册工厂函数,首次访问时按需解析并缓存结果,后续使用直接返回缓存 -
双模式适配 :同一个
fetchSystemPromptParts同时服务交互和 SDK 模式,通过customSystemPrompt的有无决定是否需要生成默认 prompt -
可观测性 :
logAPIPrefix(systemPrompt)在发送前记录完整 system prompt 内容,便于调试