mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-15 12:55:51 +00:00
* docs: 修复文档巡检发现的 4 处错误 - daemon.md: 反映实际实现状态(supervisor/worker 已实现而非 stub) - bridge-mode.md: API 操作数量从 7 修正为 9 - web-search-tool.md: 文件路径从 src/tools/ 修正为 packages/builtin-tools/src/tools/ - remote-control-self-hosting.md: 补充缺失的 RCS_WS_IDLE_TIMEOUT 和 RCS_WS_KEEPALIVE_INTERVAL 配置项 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 修正 Safety 和 Context 文档中的代码引用和类型错误 - permission-model: 修正规则来源从"五层"到八层,优先级顺序对齐代码 - permission-model: PermissionUpdate 类型改为实际的 addRules/replaceRules 等 - permission-model: 补充 acceptEdits 和 dontAsk 两种权限模式 - permission-model: DENIAL_LIMITS 字段名对齐实际代码 - plan-mode: 工具路径从 src/tools/ 改为 packages/builtin-tools/src/tools/ - compaction: 修正 COMPACTABLE_TOOLS 和 POST_COMPACT_* 的行号 - project-memory: 修正 ENTRYPOINT_NAME 常量的行号 - system-prompt: 修正 SystemPrompt 类型定义文件路径和多个行号引用 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 修复 introduction 文档中的错误路径和行号引用 - why-this-whitepaper.mdx: BashTool 路径从 src/tools/ 修正为 packages/builtin-tools/src/tools/ - what-is-claude-code.mdx: 移除不存在的 Azure provider,改为实际的 7 种 provider - architecture-overview.mdx: State 类型行号从 204 修正为 207 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 修复 conversation/features 文档中的错误 - streaming.mdx: queryStreamRaw → queryModelWithStreaming 函数名修正 - streaming.mdx: Azure 提供商不存在,替换为实际 7 个提供商 - debug-mode.mdx: --inspect-wait 描述错误,实际使用 BUN_INSPECT 环境变量 - buddy.mdx: 补充缺失的 companionReact.ts、CompanionCard.tsx、index.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 修复文档巡检中的源码引用错误 - feature-flags.mdx: 修正 feature() 兜底描述,实际从 bun:bundle 导入而非 cli.tsx:3 内联 - feature-flags.mdx: 修正工具 require 路径为 @claude-code-best/builtin-tools 包路径 - ant-only-world.mdx: 修正 tools.ts 中 require 路径为包路径 - ant-only-world.mdx: 修正 INTERNAL_ONLY_COMMANDS 行号 (267-295) 和数量 (24+) - skills.mdx: 修正 COMMANDS memoize 行号 258 → 299 - mcp-protocol.mdx: 修正 fetchToolsForClient LRU 缓存上限 20 → 100 - streaming.mdx: 修正流式事件引用 - file-operations.mdx: 修正工具路径引用 - search-and-navigation.mdx: 修正搜索工具引用 - shell-execution.mdx: 修正 shell 工具引用 - buddy.mdx: 补充缺失的 frontmatter 字段 - debug-mode.mdx: 修正调试模式描述 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 修正 tools/agent 文档中的文件路径和行号引用 - 修正 TodoWriteTool、AgentTool、ToolSearchTool 等工具路径 src/tools/ → packages/builtin-tools/src/tools/ - 更新 Tool.ts、tools.ts、BashTool.tsx 中过时的行号引用 - 修正 WebSearchTool/WebFetchTool/EnterWorktreeTool/ExitWorktreeTool 路径 - 修正 AgentTool.tsx 中多行行号引用 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 修正 feature 文档中的文件路径和行号引用 - ultraplan.md: 更新文件行数(525/349/127) - fork-subagent.md: 路径迁移 src/tools/ → packages/builtin-tools/ - mcp-skills.md: 修正 getMcpSkillCommands 行号 547→604,client.ts 行号 117→129 - kairos.md: 修正 getBriefSection/getProactiveSection 行号 - proactive.md: 修正 getProactiveSection 行号 860→864 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 修正顶层文档中的路径迁移和行号引用 - auto-updater.md: config.ts 行号 1735→1737,标注未接入启动流程的函数 - external-dependencies.md: WebSearchTool/WebFetchTool 路径迁移到 builtin-tools 包,Vertex 行号修正 - lsp-integration.md: LSPTool 路径从 src/tools/ 迁移到 packages/builtin-tools/ - stub-recovery-design-1-4.md: 修正 Windows 绝对路径链接为标准代码引用 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 修正 task 文档中的文件扩展名和路径引用 - task-004: AssistantSessionChooser.ts → .tsx, assistant.ts → .tsx - task-003: cli.tsx 行号 249→272, markdownConfigLoader.ts 行号 29→35 - lan-pipes: SendMessageTool 路径迁移到 packages/builtin-tools/ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 补充 computer-use-tools-reference 缺失的 Windows 工具 添加遗漏的 open_terminal 和 activate_window 两个 Windows 专属工具, 修正工具总数 37→39,Windows 工具数 10→12。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 修正 audit/bash-classifier/token-budget/tree-sitter 文档 - feature-flags-audit: ScheduleCronTool 路径迁移、DAEMON 状态更新为 COMPLETE、assistant 文件标记已补全、UDS 标记已实现 - bash-classifier: BashPermissionRequest 文件路径修正、withRetry 行号移除 - token-budget: attachments.ts 行号范围修正 - tree-sitter-bash: bashPermissions.ts 路径迁移到 packages/builtin-tools Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 修正 langfuse-monitoring AgentTool 路径迁移 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 修正 bridgeApi 行号和 Tool.ts 行号引用 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 修正 Safety/Extensibility 文档中的工具路径迁移和行号引用 - sandbox.mdx: shouldUseSandbox.ts 和 bashPermissions.ts 路径迁移至 packages/builtin-tools - why-safety-matters.mdx: bashPermissions.ts 路径迁移(3 处) - plan-mode.mdx: EnterPlanModeTool/prompt.ts 路径迁移 - auto-mode.mdx: Auto mode 指令行号 3464→3481 - hooks.mdx: AgentTool/runAgent.ts 路径迁移 - skills.mdx: SkillTool.ts 路径迁移 - custom-agents.mdx: Agent built-in 目录和 exploreAgent.ts 路径迁移 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 修正 internals 文档引用计数和路径 - ant-only-world: USER_TYPE 引用计数 465→410+,工具路径迁移到 builtin-tools - growthbook-ab-testing: growthbook.ts 行数 1156→1258 - hidden-features: 语音模式状态更新(audio-napi 已恢复) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 修正工具文档中的行号引用 - sub-agents: AgentTool.call 入口行号 340→387 - shell-execution: ShellCommand onTimeout 行号 129→144 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 修正 feature 文档中的状态、路径和计数 - all-features-guide: 修正 feature flag 启用范围(dev only vs dev+build) - tier3-stubs: 大量状态修正(stub→已实现),缩减过时条目 - workflow-scripts: 路径迁移到 builtin-tools,状态更新 - web-browser-tool: 工具状态缺失→已实现,路径迁移 - context-collapse: CtxInspectTool 状态缺失→已实现 - computer-use: 行号引用更新,平台分发描述修正 - computer-use-tools-reference: 工具数 39→38 - voice-mode: voiceModeEnabled 行数 55→54 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 更新 the-loop 查询循环行号引用 query.ts 代码变更后终止原因行号整体偏移约 40 行 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 补充 feature-flags-audit 完整 build 默认 feature 列表 添加 ULTRATHINK/LODESTONE/ACP/DAEMON 等 19 个缺失的 build 默认 feature, 修正 dev-only 特征标注(UDS_INBOX/LAN_PIPES/BG_SESSIONS/TEMPLATES) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 修正 feature-flags-audit ConfigTool 路径迁移 ConfigTool 路径从 src/tools/ 迁移到 packages/builtin-tools/src/tools/ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 修正 feature-flags-audit BashTool 路径迁移 BashTool 路径从 src/tools/ 迁移到 packages/builtin-tools/src/tools/ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 修正 feature-flags-audit SkillTool 路径迁移 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 更新 feature-flags-audit WorkflowTool 状态为已实现 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
369 lines
16 KiB
Plaintext
369 lines
16 KiB
Plaintext
---
|
||
title: "System Prompt 动态组装 - AI 工作记忆构建"
|
||
description: "深入解析 Claude Code 的 System Prompt 动态组装过程:缓存策略、分界标记、Section 注册表、CLAUDE.md 多级合并,以及如何将零散上下文拼装为 API 可消费的缓存友好结构。"
|
||
keywords: ["System Prompt", "系统提示词", "动态组装", "CLAUDE.md", "Prompt Cache", "缓存策略"]
|
||
---
|
||
|
||
## 从数组到 API 调用:System Prompt 的完整链路
|
||
|
||
System Prompt 在 Claude Code 中不是一段写死的文本,而是一个 **`string[]` 数组**(品牌类型 `SystemPrompt`,定义于 `src/utils/systemPromptType.ts:8`),经过组装、分块、缓存标记后发送给 API。
|
||
|
||
### 三阶段管道
|
||
|
||
```
|
||
getSystemPrompt() → string[] (组装内容)
|
||
↓
|
||
buildEffectiveSystemPrompt() → SystemPrompt (选择优先级路径)
|
||
↓
|
||
buildSystemPromptBlocks() → TextBlockParam[] (分块 + cache_control 标记)
|
||
```
|
||
|
||
1. **`getSystemPrompt()`**(`src/constants/prompts.ts:444`)—— 收集静态段 + 动态段,插入 `SYSTEM_PROMPT_DYNAMIC_BOUNDARY` 分界标记
|
||
2. **`buildEffectiveSystemPrompt()`**(`src/utils/systemPrompt.ts:41`)—— 按 Override > Coordinator > Agent > Custom > Default 优先级选择
|
||
3. **`buildSystemPromptBlocks()`**(`src/services/api/claude.ts:3279`)—— 调用 `splitSysPromptPrefix()` 分块,为每个块附加 `cache_control`
|
||
|
||
## SystemPrompt 品牌类型
|
||
|
||
```typescript
|
||
// packages/@ant/model-provider/src/types/systemPrompt.ts:4
|
||
export type SystemPrompt = readonly string[] & {
|
||
readonly __brand: 'SystemPrompt'
|
||
}
|
||
export function asSystemPrompt(value: readonly string[]): SystemPrompt {
|
||
return value as SystemPrompt // 零开销类型断言
|
||
}
|
||
```
|
||
|
||
品牌类型(branded type)防止普通 `string[]` 被意外传入 API 调用——只有通过 `asSystemPrompt()` 显式转换才能获得 `SystemPrompt` 类型。
|
||
|
||
## getSystemPrompt():内容组装的全景
|
||
|
||
`src/constants/prompts.ts:444` 是 System Prompt 的核心工厂函数,返回一个有序数组:
|
||
|
||
| 阶段 | 内容 | 缓存策略 |
|
||
|------|------|----------|
|
||
| **静态区** | Intro Section、System Rules、Doing Tasks、Actions、Using Tools、Tone & Style、Output Efficiency | 可跨组织缓存(`scope: 'global'`) |
|
||
| **BOUNDARY** | `SYSTEM_PROMPT_DYNAMIC_BOUNDARY = '__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__'` | 分界标记(不发送给 API,仅用于分割静态区与动态区以实现全局缓存) |
|
||
| **动态区** | Session Guidance、Memory、Model Override、Env Info、Language、Output Style、MCP Instructions、Scratchpad、FRC、Summarize Tool Results、Token Budget、Brief | 每次会话不同(`scope: 'org'` 或无缓存) |
|
||
|
||
> **Boundary 是什么**:它把 System Prompt 分成"不变的静态区"和"因用户/会话而异的动态区"。静态区对所有用户相同,可获得 `scope: 'global'` 跨组织缓存;动态区每次不同,只能 `scope: 'org'` 或不缓存。它本身是一个特殊字符串,在发送给 API 前被移除,AI 永远看不到。
|
||
|
||
### 动态区的 Section 注册表
|
||
|
||
动态区通过 `systemPromptSection()` / `DANGEROUS_uncachedSystemPromptSection()` 注册,这两个工厂函数定义于 `src/constants/systemPromptSections.ts`:
|
||
|
||
```typescript
|
||
// 缓存式 Section:计算一次,/clear 或 /compact 后才重新计算
|
||
systemPromptSection('memory', () => loadMemoryPrompt())
|
||
|
||
// 危险:每轮重新计算,会破坏 Prompt Cache
|
||
DANGEROUS_uncachedSystemPromptSection(
|
||
'mcp_instructions',
|
||
() => isMcpInstructionsDeltaEnabled() ? null : getMcpInstructionsSection(mcpClients),
|
||
'MCP servers connect/disconnect between turns' // 必须给出破坏缓存的理由
|
||
)
|
||
```
|
||
|
||
`resolveSystemPromptSections()` 在每轮查询时解析所有 Section,对于 `cacheBreak: false` 的 Section,优先使用 `getSystemPromptSectionCache()` 中的缓存值。只有 MCP 指令等真正动态的内容使用 `DANGEROUS_uncachedSystemPromptSection`。
|
||
|
||
### `CLAUDE_CODE_SIMPLE` 快速路径
|
||
|
||
当环境变量 `CLAUDE_CODE_SIMPLE` 为真时,整个 System Prompt 缩减为一行:
|
||
|
||
```typescript
|
||
`You are Claude Code, Anthropic's official CLI for Claude.\n\nCWD: ${getCwd()}\nDate: ${getSessionStartDate()}`
|
||
```
|
||
|
||
跳过所有 Section 注册、缓存分块、动态组装——用于最小化 token 消耗的测试场景。
|
||
|
||
## buildEffectiveSystemPrompt():五级优先级
|
||
|
||
`src/utils/systemPrompt.ts:41` 决定最终使用哪个 System Prompt:
|
||
|
||
| 优先级 | 条件 | 行为 |
|
||
|--------|------|------|
|
||
| **0. Override** | `overrideSystemPrompt` 非空 | 完全替换,返回 `[override]` |
|
||
| **1. Coordinator** | `COORDINATOR_MODE` feature + 环境变量 | 使用协调者专用提示词 |
|
||
| **2. Agent** | `mainThreadAgentDefinition` 存在 | Proactive 模式:追加到默认提示词尾部;否则:替换默认提示词 |
|
||
| **3. Custom** | `--system-prompt` 参数指定 | 替换默认提示词 |
|
||
| **4. Default** | 无特殊条件 | 使用 `getSystemPrompt()` 完整输出 |
|
||
|
||
`appendSystemPrompt` 始终追加到末尾(Override 除外)。
|
||
|
||
## Provider 系统概述
|
||
|
||
Claude Code 支持多种 API 提供商,分为两大类:
|
||
|
||
| 类别 | Provider | 环境变量 | 说明 |
|
||
|------|----------|---------|------|
|
||
| **1P (First Party)** | `firstParty` | 默认 | Anthropic 官方 API 直连 |
|
||
| **3P (Third Party)** | `bedrock` | `CLAUDE_CODE_USE_BEDROCK=1` | AWS Bedrock 托管服务 |
|
||
| **3P** | `vertex` | `CLAUDE_CODE_USE_VERTEX=1` | Google Vertex AI |
|
||
| **3P** | `openai` | `CLAUDE_CODE_USE_OPENAI=1` | OpenAI 兼容层(Ollama/DeepSeek/vLLM) |
|
||
| **3P** | `gemini` | `CLAUDE_CODE_USE_GEMINI=1` | Google Gemini API |
|
||
| **3P** | `grok` | `CLAUDE_CODE_USE_GROK=1` | xAI Grok |
|
||
|
||
Provider 决定了:
|
||
- **可用的 beta headers**:部分 beta 功能仅限 1P 用户
|
||
- **缓存策略**:全局缓存 `scope: 'global'` 仅 1P 可用
|
||
- **Token 计数方式**:Bedrock 有独立的 countTokens 端点,OpenAI/Gemini 依赖估算
|
||
|
||
```typescript
|
||
// src/utils/model/providers.ts:5-13
|
||
export type APIProvider =
|
||
| 'firstParty' // 1P - Anthropic 直连
|
||
| 'bedrock' // 3P - AWS Bedrock
|
||
| 'vertex' // 3P - Google Vertex
|
||
| 'foundry' // 3P - Anthropic Foundry
|
||
| 'openai' // 3P - OpenAI 兼容层
|
||
| 'gemini' // 3P - Google Gemini
|
||
| 'grok' // 3P - xAI Grok
|
||
```
|
||
|
||
## 缓存策略:分块、标记、命中
|
||
|
||
这是 System Prompt 设计中最精密的部分。
|
||
|
||
### Anthropic Prompt Cache 基础
|
||
|
||
Anthropic API 的 Prompt Cache 允许跨请求复用相同的 System Prompt 前缀,按缓存命中量计费(远低于完整输入价格)。缓存键由内容的 Blake2b 哈希决定——任何字符变化都会导致缓存失效。
|
||
|
||
### `splitSysPromptPrefix()`:三种分块模式
|
||
|
||
`src/utils/api.ts:321` 是缓存策略的核心,根据条件选择三种分块模式:
|
||
|
||
#### 模式 1:MCP 工具存在时(`skipGlobalCacheForSystemPrompt=true`)
|
||
|
||
```
|
||
[attribution header] → cacheScope: null (不缓存)
|
||
[system prompt prefix] → cacheScope: 'org' (组织级缓存)
|
||
[everything else] → cacheScope: 'org' (组织级缓存)
|
||
```
|
||
|
||
MCP 工具列表在会话中可能变化(连接/断开),破坏了跨组织缓存的基础,因此降级为组织级。
|
||
|
||
#### 模式 2:Global Cache + Boundary 存在(1P 专用)
|
||
|
||
```
|
||
[attribution header] → cacheScope: null (不缓存)
|
||
[system prompt prefix] → cacheScope: null (不缓存)
|
||
[static content] → cacheScope: 'global' (全局缓存!跨组织共享)
|
||
[dynamic content] → cacheScope: null (不缓存)
|
||
```
|
||
|
||
这是缓存效率最高的模式。`SYSTEM_PROMPT_DYNAMIC_BOUNDARY` 之前的静态内容(Intro、Rules、Tone & Style 等)对所有用户相同,可跨组织缓存。
|
||
|
||
> **Boundary 插入条件**:`SYSTEM_PROMPT_DYNAMIC_BOUNDARY` 标记**仅在特定条件**下插入:
|
||
|
||
```typescript
|
||
// src/utils/betas.ts:226-229
|
||
export function shouldUseGlobalCacheScope(): boolean {
|
||
return (
|
||
getAPIProvider() === 'firstParty' &&
|
||
!isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS)
|
||
)
|
||
}
|
||
```
|
||
|
||
```typescript
|
||
// src/constants/prompts.ts:574
|
||
...(shouldUseGlobalCacheScope() ? [SYSTEM_PROMPT_DYNAMIC_BOUNDARY] : []),
|
||
```
|
||
|
||
这意味着:
|
||
- **3P 用户(Bedrock/Vertex/OpenAI/Gemini)**:Boundary 永远不存在,始终使用模式 3
|
||
- **1P 用户禁用实验性功能**:设置 `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1`,Boundary 不插入
|
||
- **1P 用户默认**:Boundary 存在,使用模式 2(最高缓存效率)
|
||
|
||
#### 模式 3:默认(3P 提供商 或 Boundary 缺失)
|
||
|
||
```
|
||
[attribution header] → cacheScope: null (不缓存)
|
||
[system prompt prefix] → cacheScope: 'org' (组织级缓存)
|
||
[everything else] → cacheScope: 'org' (组织级缓存)
|
||
```
|
||
|
||
### `getCacheControl()`:TTL 决策
|
||
|
||
`src/services/api/claude.ts:348` 生成的 `cache_control` 对象:
|
||
|
||
```typescript
|
||
{
|
||
type: 'ephemeral',
|
||
ttl?: '1h', // 仅特定 querySource 符合条件时
|
||
scope?: 'global', // 仅静态区
|
||
}
|
||
```
|
||
|
||
1 小时 TTL 的判定逻辑(`should1hCacheTTL()`,第 383 行):
|
||
- **Bedrock 用户**:通过环境变量 `ENABLE_PROMPT_CACHING_1H_BEDROCK` 启用
|
||
- **1P 用户**:通过 GrowthBook 配置的 `allowlist` 数组匹配 `querySource`,支持前缀通配符(如 `"repl_main_thread*"`)
|
||
- **会话级锁定**:资格判定结果在 bootstrap state 中缓存,防止 GrowthBook 配置中途变化导致同一会话内 TTL 不一致
|
||
|
||
### 缓存破坏:Session-Specific Guidance 的放置
|
||
|
||
`getSessionSpecificGuidanceSection()`(`src/constants/prompts.ts:354`)的内容必须放在 `SYSTEM_PROMPT_DYNAMIC_BOUNDARY` **之后**。因为它包含:
|
||
- 当前会话的 enabledTools 集合
|
||
- `isForkSubagentEnabled()` 的运行时判定
|
||
- `getIsNonInteractiveSession()` 的结果
|
||
|
||
这些运行时 bit 如果放在静态区,会产生 2^N 种 Blake2b 哈希变体(N = 运行时条件数),完全破坏缓存命中率。源码注释明确警告:
|
||
|
||
> Each conditional here is a runtime bit that would otherwise multiply the Blake2b prefix hash variants (2^N). See PR #24490, #24171 for the same bug class.
|
||
|
||
### `CLAUDE_CODE_SIMPLE` 模式
|
||
|
||
当设置了 `CLAUDE_CODE_SIMPLE` 环境变量时,整个系统提示词会大幅缩减:
|
||
|
||
```typescript
|
||
return [`You are Claude Code, Anthropic's official CLI for Claude.\n\nCWD: ${getCwd()}\nDate: ${getSessionStartDate()}`]
|
||
```
|
||
|
||
## 上下文注入:System Context 与 User Context
|
||
|
||
System Prompt 数组本身不包含运行时上下文(git 状态、CLAUDE.md 内容)。上下文通过两个独立的管道注入:
|
||
|
||
### System Context(`src/context.ts:116`)
|
||
|
||
```typescript
|
||
export const getSystemContext = memoize(async () => {
|
||
return {
|
||
gitStatus, // git 分支、状态、最近提交(截断至 MAX_STATUS_CHARS=2000)
|
||
cacheBreaker, // 仅 ant 用户的缓存破坏器
|
||
}
|
||
})
|
||
```
|
||
|
||
- 使用 `lodash.memoize` 缓存——**整个会话期间只计算一次**
|
||
- Git 状态快照包含 5 个并行 `git` 命令(branch、defaultBranch、status、log、userName)
|
||
- `status` 超过 2000 字符时截断并附加提示使用 BashTool 获取更多信息
|
||
- `systemPromptInjection` 变更时,通过 `getUserContext.cache.clear?.()` 清除所有上下文缓存
|
||
|
||
### User Context(`src/context.ts:155`)
|
||
|
||
```typescript
|
||
export const getUserContext = memoize(async () => {
|
||
return {
|
||
claudeMd, // 合并后的 CLAUDE.md 内容
|
||
currentDate, // "Today's date is YYYY-MM-DD."
|
||
}
|
||
})
|
||
```
|
||
|
||
- **CLAUDE.md 禁用条件**:`CLAUDE_CODE_DISABLE_CLAUDE_MDS` 环境变量,或 `--bare` 模式(除非通过 `--add-dir` 显式指定目录)
|
||
- `--bare` 模式的语义是"跳过我没要求的东西"而非"忽略所有"
|
||
|
||
### 注入位置
|
||
|
||
在 `src/query.ts:449`:
|
||
|
||
```typescript
|
||
// System Context 追加到 System Prompt 尾部
|
||
const fullSystemPrompt = asSystemPrompt(
|
||
appendSystemContext(systemPrompt, systemContext) // 简单拼接
|
||
)
|
||
```
|
||
|
||
User Context 通过 `prependUserContext()`(`src/utils/api.ts:449`)注入为 `<system-reminder>` 标签包裹的首条用户消息,放在所有对话消息之前。
|
||
|
||
## Attribution Header:计费与安全
|
||
|
||
每个 API 请求的 System Prompt 首块是 Attribution Header(`src/constants/system.ts:30`),包含:
|
||
- **`cc_version`**:Claude Code 版本 + 指纹
|
||
- **`cc_entrypoint`**:入口点标识(REPL / SDK / pipe 等)
|
||
- **`cch=00000`**(NATIVE_CLIENT_ATTESTATION 启用时):Bun 原生 HTTP 层在发送前将零替换为计算出的哈希值,服务器验证此 token 确认请求来自真实 Claude Code 客户端
|
||
|
||
Header 始终 `cacheScope: null`——它因版本和指纹不同而变化,不适合缓存。
|
||
|
||
## CLAUDE.md:项目级知识注入
|
||
|
||
这是 Claude Code 最巧妙的设计之一。在项目根目录放一个 `CLAUDE.md` 文件,就能让 AI "理解" 你的项目:
|
||
|
||
- **项目概述**:这个项目做什么、用了什么技术栈
|
||
- **开发约定**:代码风格、命名规范、分支策略
|
||
- **常用命令**:怎么构建、怎么测试、怎么部署
|
||
- **注意事项**:已知的坑、特殊的配置
|
||
|
||
系统会自动发现并合并多级 CLAUDE.md:
|
||
|
||
```
|
||
~/.claude/CLAUDE.md ← 用户全局(个人偏好)
|
||
└── /project/CLAUDE.md ← 项目根目录(团队共享)
|
||
└── /project/src/CLAUDE.md ← 子目录(模块特定)
|
||
```
|
||
|
||
加载逻辑在 `src/utils/claudemd.ts` 中的 `getClaudeMds()` 和 `getMemoryFiles()` 实现——从 CWD 向上遍历目录树,合并所有匹配的 CLAUDE.md 文件内容。
|
||
|
||
## 设计洞察:为什么是 `string[]` 而非单个 `string`
|
||
|
||
将 System Prompt 设计为数组而非单段文本,是为了 **缓存分块**:
|
||
|
||
1. Anthropic Prompt Cache 以 **内容块**(TextBlock)为缓存单位
|
||
2. 将 System Prompt 拆为多个块,可以让不变的部分(Intro、Rules)获得独立的缓存命中
|
||
3. 如果是单个 `string`,任何一个字符变化(如日期更新)都会导致整个 System Prompt 的缓存失效
|
||
4. `SYSTEM_PROMPT_DYNAMIC_BOUNDARY` 标记允许 `splitSysPromptPrefix()` 精确地将静态区标记为 `scope: 'global'`,动态区不标记或标记为 `scope: 'org'`
|
||
|
||
这是 Claude Code 在 token 成本优化上的核心设计——一次典型的 System Prompt 约 20K+ tokens,通过缓存分块可以节省 30-50% 的输入 token 费用。
|
||
|
||
## 兼容层:OpenAI 与 Gemini
|
||
|
||
Claude Code 提供了 OpenAI 和 Gemini 协议的兼容层,允许使用非 Anthropic 端点。
|
||
|
||
### OpenAI 兼容层
|
||
|
||
通过 `CLAUDE_CODE_USE_OPENAI=1` 启用,支持任意 OpenAI Chat Completions 协议端点(Ollama、DeepSeek、vLLM 等)。
|
||
|
||
实现采用**流适配器模式**:
|
||
1. 将 Anthropic 格式请求转换为 OpenAI 格式
|
||
2. 调用 OpenAI 兼容端点
|
||
3. 将 SSE 流转换回 `BetaRawMessageStreamEvent`
|
||
4. 下游代码完全无感知
|
||
|
||
```
|
||
src/services/api/openai/
|
||
├── client.ts # OpenAI 客户端配置
|
||
├── convertMessages.ts # 消息格式转换(Anthropic → OpenAI)
|
||
├── convertTools.ts # 工具定义转换
|
||
├── streamAdapter.ts # SSE 流适配(OpenAI → Anthropic)
|
||
├── modelMapping.ts # 模型名称映射
|
||
└── index.ts # 入口函数 queryModelOpenAI()
|
||
```
|
||
|
||
关键环境变量:
|
||
- `CLAUDE_CODE_USE_OPENAI=1` — 启用 OpenAI provider
|
||
- `OPENAI_API_KEY` — API 密钥
|
||
- `OPENAI_BASE_URL` — API 端点(默认 `https://api.openai.com/v1`)
|
||
- `OPENAI_MODEL` — 直接指定模型名
|
||
|
||
### Gemini 兼容层
|
||
|
||
通过 `CLAUDE_CODE_USE_GEMINI=1` 启用,支持 Google Gemini API。
|
||
|
||
```
|
||
src/services/api/gemini/
|
||
├── client.ts # Gemini 客户端配置
|
||
├── convertMessages.ts # 消息格式转换
|
||
├── convertTools.ts # 工具定义转换
|
||
├── streamAdapter.ts # 流适配
|
||
├── modelMapping.ts # 模型名称映射
|
||
├── types.ts # 类型定义
|
||
└── index.ts # 入口函数
|
||
```
|
||
|
||
关键环境变量:
|
||
- `CLAUDE_CODE_USE_GEMINI=1` — 启用 Gemini provider
|
||
- `GEMINI_API_KEY` — API 密钥
|
||
- `GEMINI_BASE_URL` — API 端点(默认 `https://generativelanguage.googleapis.com/v1beta`)
|
||
- `GEMINI_MODEL` — 直接指定模型名
|
||
- `GEMINI_DEFAULT_SONNET_MODEL` / `GEMINI_DEFAULT_OPUS_MODEL` — 按能力级别映射
|
||
|
||
### 兼容层的限制
|
||
|
||
使用 3P 兼容层时,部分功能受限:
|
||
- **无精确 token 计数**:系统退回到近似估算,影响自动压缩触发时机
|
||
- **无全局缓存**:只能使用组织级缓存 `scope: 'org'`
|
||
- **部分 beta 功能不可用**:依赖 Anthropic 特有 beta headers 的功能受限
|
||
|
||
详见 `docs/plans/openai-compatibility.md` 和 `CLAUDE.md` 中的相关章节。
|
||
|