---
title: "系统提示词"
description: "系统提示词不是一段写死的文本，而是一个动态组装、分块缓存的数组。理解三阶段管道、缓存分界标记和多级优先级选择的设计。"
keywords: ["系统提示词", "System Prompt", "动态组装", "Prompt Cache", "缓存策略"]
---

## 核心问题

AI 的行为由系统提示词（System Prompt）决定。但一个编程助手的系统提示词远不止一句"你是一个有用的助手"——它需要包含工具使用规则、安全策略、项目上下文、用户偏好等大量动态内容。

挑战在于：**这些内容每次请求都要发送，而且大部分是不变的。** 如何在保持动态性的同时最小化 token 成本？

## 从文本到数组：缓存驱动的架构选择

系统提示词不是单个字符串，而是一个 **字符串数组**。

### 为什么是数组？

Anthropic 的 Prompt Cache 以**内容块**为单位缓存。将提示词拆为多个块，不变的部分可以获得独立的缓存命中。如果是一个单字符串，任何一个字符变化（如日期更新）都会导致整个提示词的缓存失效。

一个典型的系统提示词约 20K+ tokens，通过缓存分块可以节省 30-50% 的输入 token 费用。

### 品牌类型保证

系统使用品牌类型（branded type）防止普通字符串数组被意外传入 API 调用——只有通过显式转换才能获得系统提示词类型。这是零开销的编译时安全保证。

## 三阶段组装管道

```
收集内容 → 选择优先级 → 分块 + 缓存标记
```

### 第一阶段：内容收集

系统提示词的内容分为两个区域：

| 区域 | 内容 | 特点 |
|------|------|------|
| **静态区** | 工具使用规则、安全策略、输出格式规范 | 所有用户相同 |
| **动态区** | 记忆、MCP 指令、模型覆盖、语言偏好 | 因用户/会话而异 |

两个区域之间用一个特殊的**分界标记**分隔。这个标记永远不会发送给 AI——它只是告诉缓存系统："到这里为止是静态的，从这里开始是动态的"。

### 第二阶段：优先级选择

最终使用哪个提示词取决于五级优先级：

| 优先级 | 来源 | 场景 |
|--------|------|------|
| **Override** | 外部覆盖 | SDK 集成、自动化测试 |
| **Coordinator** | 协调者模式 | 多 Agent 编排 |
| **Agent** | Agent 定义 | 自定义 Agent |
| **Custom** | 命令行参数 | 用户的自定义提示词 |
| **Default** | 完整组装 | 正常使用 |

**设计考量**：Override 级别完全替换默认提示词（包括安全规则），这是危险的但必要的——自动化测试和 SDK 集成需要完全控制。其他级别则在默认提示词基础上追加或替换。

### 第三阶段：分块与缓存标记

分块策略根据条件选择三种模式：

**模式 1：全局缓存（1P 用户默认）**
```
[归属头]        → 不缓存
[提示词前缀]    → 不缓存
[静态内容]      → 全局缓存（跨组织共享）
[动态内容]      → 不缓存
```

**模式 2：组织缓存（MCP 工具存在时）**
```
[归属头]        → 不缓存
[提示词前缀]    → 组织缓存
[其余内容]      → 组织缓存
```

**模式 3：组织缓存（3P 用户）**
```
[归属头]        → 不缓存
[提示词前缀]    → 组织缓存
[其余内容]      → 组织缓存
```

**为什么 MCP 工具会降级缓存**？MCP 工具列表在会话中可能变化（连接/断开），这会改变提示词内容，破坏跨组织缓存的基础。因此当 MCP 工具存在时，只能使用组织级缓存。

### 缓存破坏的防御

动态区的某些内容（如会话特定的工具集）必须严格放在分界标记之后。如果错误地放在静态区，每个运行时条件的组合会产生 2^N 种不同的哈希值（N = 条件数量），完全破坏缓存命中率。

系统对"每轮都重新计算"的 Section 使用专门的危险标记——开发者必须给出破坏缓存的理由才能使用它。

## 上下文注入：两条独立管道

系统提示词本身不包含运行时上下文。上下文通过两条独立管道注入：

### System Context（会话级不变）

- Git 分支和状态
- 最近的提交记录
- 计算一次，整个会话期间缓存

### User Context（动态变化）

- 合并后的 CLAUDE.md 内容
- 当前日期

**为什么 User Context 不放在 System Prompt 中**？因为 User Context 作为用户消息发送，可以利用 Prompt Cache 的前缀共享——系统提示词是所有用户共享的前缀，User Context 是每个用户的变化部分。这种分层让缓存命中率最大化。

## CLAUDE.md：项目级知识注入

这是 Claude Code 最巧妙的设计之一。在项目目录中放一个 `CLAUDE.md` 文件，就能让 AI "理解"项目。

### 多级合并

```
~/.claude/CLAUDE.md              ← 用户全局（个人偏好）
  └── /project/CLAUDE.md         ← 项目根目录（团队共享）
        └── /project/src/CLAUDE.md  ← 子目录（模块特定）
```

系统从当前工作目录向上遍历，合并所有匹配的 CLAUDE.md 文件。子目录的 CLAUDE.md 可以覆盖或补充父目录的规则。

**设计哲学**：项目知识应该由团队成员维护、随代码演进、可通过 git 追踪。CLAUDE.md 本质上是"给人读的项目文档，恰好 AI 也能读"。

### 安全考量

项目级 CLAUDE.md 可以被仓库中的任何人修改（包括恶意贡献者）。系统因此限制了项目级 CLAUDE.md 的影响范围——它们不能覆盖安全关键设置，也不能修改权限模型。

## Provider 差异与缓存

不同的 API Provider 有不同的缓存能力：

| Provider | 全局缓存 | 精确 Token 计数 | 特殊 Beta 功能 |
|----------|:--------:|:---------------:|:--------------:|
| Anthropic 直连 | ✓ | ✓ | ✓ |
| AWS Bedrock | ✗ | ✓（独立端点） | 部分 |
| Google Vertex | ✗ | ✗ | 部分 |
| OpenAI 兼容 | ✗ | ✗ | ✗ |
| Gemini | ✗ | ✗ | ✗ |

3P 用户的系统提示词始终使用组织级缓存，因为没有全局缓存的 API 支持。这也意味着 token 计数依赖估算，影响自动压缩的触发时机。

## 最小化模式

环境变量 `CLAUDE_CODE_SIMPLE` 可以将整个系统提示词缩减为一行——跳过所有 Section 注册、缓存分块和动态组装。用于最小化 token 消耗的测试场景。

## 接下来

- **上下文压缩** — 理解当上下文增长超出限制时的压缩策略
- **令牌预算** — 了解 token 窗口的动态计算
- **Provider 系统** — 了解多 Provider 支持的架构设计
