Claude Code拆解:提示词工程的36:1省钱密码 架构剖析Claude Code 的提示词工程——从模块拆解到动态组装的全链路解析引言为什么要把提示词拆成一块一块的大多数人写 System Prompt 的方式是打开一个文本框从头写到尾越写越长最后变成一坨谁都不敢动的“祖传配置”。改一个字就怕全崩了。Claude Code 不是这么干的。它的 System Prompt 是由 12 个独立函数动态拼装的每个函数负责生成一个片段最后像乐高一样组合成完整的 Prompt。但模块化只是表象。真正驱动这套架构的是钱的问题。在 Claude Code 的场景下单次请求的输入 Token 远大于输出。实测数据显示一次“修一个 bug”的请求System Prompt 工具定义约 3,200 TokenCLAUDE.md 约 800 Token历史消息约 8,500 Token当前文件内容约 2,000 Token——输入总计 14,550 Token输出仅约 400 Token输入输出比高达36:1。而 Prompt Cache 提供的折扣是90%——缓存命中的部分只收基础输入价的 10%。这不是“小幅优化”是数量级差异。这就是为什么 Claude Code 要把提示词拆成一块一块的。每一块的摆放位置都直接影响着你的账单。接下来我们将围绕下面这张架构蓝图逐块拆解每一个部分是怎么来的、长什么样、怎么加载的。一、整体架构从“巨无霸字符串”到“模块化数组”Claude Code 的提示词不是一条长长的文本而是一个字符串数组string[]。每个数组元素是一个独立的 Section分块可以独立缓存、独立替换、独立开关。整体架构遵循如下固定范式┌─────────────────────────────────────────────────────────┐ │ [静态区 – 全局可缓存] │ │ ├─ getSimpleIntroSection() // 1. 身份定义 │ │ ├─ getSimpleSystemSection() // 2. 系统行为规则 │ │ ├─ getSimpleDoingTasksSection() // 3. 任务执行规范 │ │ ├─ getActionsSection() // 4. 危险操作指南 │ │ ├─ getUsingYourToolsSection() // 5. 工具使用指南 │ │ ├─ getSimpleToneAndStyleSection() // 6. 语气风格 │ │ └─ getOutputEfficiencySection() // 7. 输出效率 │ ├─────────────────────────────────────────────────────────┤ │ [边界标记] SYSTEM_PROMPT_DYNAMIC_BOUNDARY │ ├─────────────────────────────────────────────────────────┤ │ [动态区 – 按会话/用户/项目变化] │ │ ├─ 会话元信息 (会话 ID, 当前时间, 工作目录) │ │ ├─ 用户记忆 (从 ~/.claude/memory.md 加载) │ │ ├─ 项目规范 (从 CLAUDE.md 加载的指令) │ │ ├─ 当前启用的 MCP 服务器指令 (若有) │ │ ├─ 功能开关 (如 token 预算警告、自动总结等) │ │ └─ 当前对话上下文摘要 (如上轮摘要) │ └─────────────────────────────────────────────────────────┘源码中getSystemPrompt()函数的返回值正是这样一个数组return[// --- 静态段落可全局缓存---getSimpleIntroSection(),// 1. 身份声明getSimpleSystemSection(),// 2. 系统规则getSimpleDoingTasksSection(),// 3. 任务执行准则getActionsSection(),// 4. 操作安全getUsingYourToolsSection(),// 5. 工具使用偏好getSimpleToneAndStyleSection(),// 6. 沟通风格getOutputEfficiencySection(),// 7. 输出效率// 缓存边界标记 SYSTEM_PROMPT_DYNAMIC_BOUNDARY,// --- 动态段落 ---...dynamicSections,].filter(ss!null)为什么要返回数组而不是字符串因为 API 调用时Anthropic 会把数组中的每个元素拼成最终的 System Prompt但缓存是按前缀匹配的——只要前面的片段不变就可以命中缓存后面片段怎么变都无所谓。返回数组意味着我们可以为每一个独立文本块精准设置cache_control元数据。二、静态区七层“混凝土”模块逐个拆解静态区包含所有用户共享、极少变化的核心规则。它们不依赖当前用户、项目目录、MCP 连接状态或本轮输入可以跨用户缓存。下面是每一个模块的具体内容。2.1 getSimpleIntroSection() —— 身份定义开门见山告诉模型“我是谁、我干什么”You are an interactive agent that helps users with software engineering tasks. IMPORTANT: Assist with authorized security testing... Refuse requests for destructive techniques... IMPORTANT: You must NEVER generate or guess URLs for the user unless you are confident...这一段开篇明义并注入强烈的安全约束防止越权或恶意利用。它是整个提示词的第一行也是缓存命中的最前端——只要这段不变所有后续请求都能复用缓存。2.2 getSimpleSystemSection() —— 系统行为规则定义 Claude Code 的基础行为框架包括如何处理多步骤任务如何与用户交互系统级别的边界约束这一层是整个 Agent 行为的“宪法”规定了它能做什么、不能做什么。2.3 getSimpleDoingTasksSection() —— 任务执行规范工程哲学的核心这是最长的 Section 之一体现了 Claude Code 的工程哲学# Doing tasks - In general, do not propose changes to code you havent read. If a user asks about or wants you to modify a file, read it first. - Do not create files unless theyre absolutely necessary... prefer editing an existing file... - If an approach fails, diagnose why before switching tactics... - The right amount of complexity is what the task actually requires— no speculative abstractions. - Three similar lines of code is better than a premature abstraction.翻译成人话先读代码再修改不要凭空提修改建议不要过度设计不添加未要求的特性、重构或改进不要过度防御编程不为不可能发生的场景添加错误处理三行相似代码优于过早抽象2.4 getActionsSection() —— 危险操作指南这一段定义了什么叫“三思而后行”# Executing actions with care Carefully consider the reversibility and blast radius of actions. Generally you can freely take local, reversible actions like editing files or running tests. But for actions that are hard to reverse... check with the user before proceeding. Examples: - Destructive operations: deleting files/branches, dropping database tables... - When you encounter an obstacle, do not use destructive actions as a shortcut...核心原则爆炸半径blast radius概念——操作的影响范围越大越需要用户确认。一次授权不等于永久授权授权范围要明确。2.5 getUsingYourToolsSection() —— 工具使用指南Claude Code 希望你用专用工具而不是 bash 万能命令专用工具替代命令理由FileReadToolcat, head, tail可追踪、可 reviewFileEditToolsed, awk结构化编辑FileWriteToolcat/heredoc意图明确核心思想Agent 不是黑盒用户应该能理解 Agent 的每一步操作。2.6 getSimpleToneAndStyleSection() —— 沟通风格定义 Claude 与用户交流的语气、格式和风格规范比如使用清晰、直接的语言适当使用 Markdown 格式保持专业但友好的态度2.7 getOutputEfficiencySection() —— 输出效率约束输出的长度和效率避免冗长、重复或无关的输出内容确保每次回复都精准、高效。三、边界标记守护缓存的“逻辑柏林墙”在静态区与动态区之间横亘着一条分界线SYSTEM_PROMPT_DYNAMIC_BOUNDARY源码里有一段非常严肃的注释WARNING: Do not remove or reorder this marker without updating cache logic.Everything BEFORE this marker can use scope: ‘global’.Everything AFTER contains user/session-specific content and should not be cached globally.翻译过来就是不要动这条线。前面的可以全局缓存后面的不能。这不是一句玩笑。Anthropic 的 API 按输入 Token 计费Prompt 缓存能节省 90% 的输入成本。如果你不小心把一个动态片段比如用户名挪到了分界线上面所有用户的缓存全部失效每月可能多花几万美元。这条线的实际作用在promptCacheBreakDetection.ts缓存破裂检测模块中系统只计算边界标记之前内容的哈希值。只要静态区不变无论边界后面的项目目录、用户记忆怎么变缓存哈希永远不变。四、动态区六个“活细胞”的完整拆解动态区的内容每一轮都可能变化它们被放在边界标记之后不会破坏静态前缀的缓存。4.1 会话元信息Session Meta来源由systemPromptSection(session_guidance, ...)在每次组装时动态计算。内容示例Session ID: sess_abc123 Current date: 2026-07-02 (fixed for this session) Working directory: /home/user/project/my-app Model: claude-opus-4-2026-05-01关键设计getSessionStartDate()函数使用了memoization记忆化——在用户输入claude命令启动会话的那一刻定格时间整个会话生命周期内不再改变。这避免了每次请求都刷新时间戳导致动态区缓存频繁破裂。4.2 用户记忆User Memory来源从~/.claude/memory.md文件加载。加载机制Claude Code 会自动读取用户主目录下的memory.md文件将其内容注入到系统提示词中。这是一个跨会话持久的用户偏好存储机制。内容示例User preferences: - 偏好使用 TypeScript 严格模式 - 测试框架使用 Jest - 优先使用 pnpm 而非 npm - 代码注释使用中文加载时机每次会话启动时加载/clear或/compact后会重新从磁盘读取。4.3 项目规范Project Rules / CLAUDE.md来源从项目根目录的CLAUDE.md文件加载。加载机制CLAUDE.md 是 Claude Code 在每次会话启动时读取的配置文件在用户发送第一条消息之前就被加载到系统提示词中。它充当项目级的长效记忆让 Claude 在开口前就知道项目的组织方式、约定和规范。多层加载顺序Global 范围~/.claude/CLAUDE.md全局用户配置Organization 范围组织级配置Project 范围项目根目录的CLAUDE.mdLocal 范围当前工作目录的CLAUDE.mdSubdirectory 范围子目录的CLAUDE.md按需加载内容示例# Project: MyApp ## Tech Stack - TypeScript 5.0 - React 18 - Tailwind CSS ## Conventions - All new features must include unit tests - No direct commits to main branch, use PRs - Use ESLint Prettier (config in .eslintrc.js) - API routes follow RESTful conventions ## Development Workflow - Run pnpm dev for local development - Run pnpm test before committing - Use conventional commits format关键特性/compact上下文压缩之后CLAUDE.md 会从磁盘重新加载——这意味着它是唯一能跨会话持久传递项目上下文的机制。4.4 MCP 服务器指令MCP Server Instructions来源通过 MCPModel Context Protocol服务器动态注入。加载机制Claude Code 在启动时会扫描配置的 MCP 服务器通过.mcp.json或~/.claude.json中的mcpServers配置将每个已连接 MCP 服务器的指令注入到提示词中。MCP 是什么MCP 是一个标准化协议让 AI 助手能够连接到外部数据源和工具。比如连接到 Jira、GitHub、Slack 等。内容示例MCP Servers: - Jira: Connected. You can reference ticket IDs in descriptions. - GitHub: Connected. Can create PRs, review code, manage issues. - Slack: Connected. Can send notifications to #dev channel.动态特性MCP 服务器的连接状态每一轮都可能变化——上一轮还连着 3 个 MCP Server这一轮可能断了一个。因此它必须被放在动态区。4.5 功能开关Feature Flags来源来自用户配置、A/B 测试或系统状态。加载机制在getSystemPrompt()组装时根据当前的配置状态条件性地注入对应的提示词片段。内容示例Token Budget Warning: ENABLED (warn at 80%, stop at 95%) Auto-Summarization: ENABLED (summarize when context exceeds 80%) Ultracode Mode: DISABLED为什么放在动态区功能开关的开启/关闭不应该污染全局共享的静态缓存。放在动态区既能灵活控制单个用户的模型行为又不会因为开关变化导致缓存失效。4.6 当前对话上下文摘要Context Summary来源从当前会话的对话历史中提取或压缩生成。加载机制当对话历史过长时Claude Code 会进行上下文压缩/compact将历史对话摘要后重新注入。内容示例Previous conversation summary: - User asked about refactoring the authentication module - Agent suggested using JWT with refresh tokens - User agreed and asked for implementation details - Agent provided code for the token generation service - Current task: Implement the refresh token rotation logic关键特性这个摘要随对话推进不断更新是典型的动态内容必须放在边界之后。五、组装引擎getSystemPrompt()的完整执行流程现在我们把所有模块串起来看完整的组装流程exportasyncfunctiongetSystemPrompt(tools:Tool[],model:string,context:SessionContext):Promisestring[]{// 1. 收集动态注册的片段constdynamicSections[systemPromptSection(session_guidance,()getSessionSpecificGuidanceSection(context)),systemPromptSection(memory,()loadMemoryPrompt()),// 从 ~/.claude/memory.md 加载systemPromptSection(project_rules,()loadProjectRules(context.cwd)),// 从 CLAUDE.md 加载systemPromptSection(env_info_simple,()computeSimpleEnvInfo(model,context)),systemPromptSection(mcp_instructions,()loadMCPInstructions()),// 从 MCP 服务器加载systemPromptSection(feature_flags,()getFeatureFlags(context)),// ... 其他动态注册块];// 2. 按严格顺序返回数组return[// --- 静态段落7个模块---getSimpleIntroSection(),getSimpleSystemSection(),getSimpleDoingTasksSection(),getActionsSection(),getUsingYourToolsSection(),getSimpleToneAndStyleSection(),getOutputEfficiencySection(),// --- 缓存边界标记 ---...(shouldUseGlobalCacheScope()?[SYSTEM_PROMPT_DYNAMIC_BOUNDARY]:[]),// --- 动态段落展开所有动态片段---...dynamicSections,].filter(ss!null);}关于systemPromptSection工厂函数exportfunctionsystemPromptSection(name:string,compute:ComputeFn,):SystemPromptSection{return{name,compute,cacheBreak:false}}每个动态模块有一个名字和一个计算函数。名字用来做跨回合缓存——同一个会话中如果这个模块上一轮已经算过了这一轮就直接读缓存不重复计算。只有在/clear或/compact时才清空缓存重新算。但有些模块比较特殊它的值每一轮都可能变——比如 MCP 服务器的连接状态。对于这种情况Claude Code 用了另一个函数来标记cacheBreak: true强制每轮重新计算。优先级仲裁在最终组装前buildEffectiveSystemPrompt()会根据优先级处理冲突Override prompt最高优先级绝对接管Coordinator prompt协调者模式专用人格Agent prompt主线程 Agent 的专属提示词Custom system prompt用户通过 CLI 传入的自定义规则Default system prompt上述皆无时采用的默认底座例如如果用户在CLAUDE.md中写了“禁止使用 grep”而静态区的getUsingYourToolsSection()说“优先使用 grep”系统会保留用户定义动态覆盖静态。六、缓存策略经济引擎如何运转6.1 前缀匹配原理Anthropic 服务端会保存你最近发送的 prompt 前缀。下次请求时只要前缀从第一个 token 开始完全一致就从缓存读取跳过重新计算。关键约束前缀任何一处变化后面所有内容的缓存全部失效。举例说明请求1[Sys][Tools][CLAUDE.md v1][对话1-5][新消息A]→ 缓存写入请求2[Sys][Tools][CLAUDE.md v1][对话1-5][新消息B]→ ✅ 命中缓存A 之前部分按 0.1× 计费请求3[Sys][Tools][CLAUDE.md v2][对话1-6][新消息C]→ ❌ CLAUDE.md 改了一行从 CLAUDE.md 开始包括对话 1-5之前已缓存的部分全部失效全部按 1.0× 重新计算6.2 cache_control 的实际放置Anthropic API 的cache_control标记是放在 message 块上的。Claude Code 的实际请求体大致长这样{model:claude-opus-4-2026-05-01,system:[{type:text,text:You are Claude Code...,cache_control:{type:ephemeral}}],tools:[...],messages:[{role:user,content:[{type:text,text:system-reminderCLAUDE.md content.../system-reminder,cache_control:{type:ephemeral}}]}]}注意两个cache_control标记位置——一个在 system prompt 末尾一个在 CLAUDE.md 上。6.3 缓存分区全景区块内容Cache Control 作用域命中率块1静态区7个静态模块 边界标记scope: global跨组织、跨用户共享块2会话元信息会话 ID、日期、工作目录scope: org组织内共享块3用户记忆~/.claude/memory.mdscope: org组织内共享块4项目规范CLAUDE.mdscope: org组织内共享块5MCP 指令MCP 服务器指令null不缓存每轮重新计算块6功能开关Feature flagsnull不缓存每轮重新计算scope: global真的能跨组织命中吗是的。在 Anthropic 的 API 设计中global作用域意味着字符串前缀在所有客户、所有租户之间共享缓存。Claude Code 官方为“身份定义 工具规范”这套数万 Token 的通用规则在全球范围内仅需支付一次计算费用。为什么动态区不用global而用org因为动态区包含用户记忆和项目路径这些内容涉及隐私和数据隔离。org作用域将缓存限制在同一组织内确保数据隔离安全。6.4 五大缓存失效陷阱CLAUDE.md 中途修改项目规则文件变化会破坏缓存动态时间戳如果日期被放在静态区每天凌晨缓存失效模型切换切换模型会改变请求前缀工具 schema 变化工具定义变化会导致前缀缓存失效功能开关变化如果开关被错误地放在静态区七、总结对 AI 应用开发的启示Claude Code 的这套提示词治理方案为构建大规模 AI 应用提供了极具价值的范式参考缓存是“一等公民”在设计阶段就应将 API 的缓存特性作为核心约束而非后期优化。数据结构与流程都必须为缓存效率让路。模块化与开闭原则通过 12 个独立函数和注册机制系统实现了高度的内聚与松耦合。新增工具支持或 MCP 集成无需改动核心组装逻辑。约束胜于鼓励提示词的主体是约束规则——压制幻觉、防止过度工程、确保安全。这种务实的策略让模型行为更加可靠。可观测性必不可少专门的缓存破裂检测机制确保生产环境的稳定性防止因团队协作中的疏忽导致性能退化。静态/动态分离是核心把所有不变的放在前面享受全球缓存把所有变化的放在后面保持灵活性。静态部分节省约 80% 的 Token动态部分保证每次对话都能感知当前环境。将“写提示词”升级为“构建提示词系统”或许正是下一代 AI 应用走向成熟的必经之路。