From 73a18c30dbc6ffc08ba30763d0eb9b3f7b3a746b Mon Sep 17 00:00:00 2001 From: CyberScrubber Date: Wed, 8 Apr 2026 18:09:26 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E5=AE=8C=E5=96=84=E4=B8=8A=E4=B8=8B?= =?UTF-8?q?=E6=96=87=E5=B7=A5=E7=A8=8B=E6=A0=B8=E5=BF=83=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E4=B8=8E=E6=9E=B6=E6=9E=84=E8=AF=B4=E6=98=8E(docs/context)=20P?= =?UTF-8?q?rovider=20=E7=B3=BB=E7=BB=9F=E3=80=81Boundary=20=E6=9D=A1?= =?UTF-8?q?=E4=BB=B6=E5=8F=8A=E5=85=BC=E5=AE=B9=E5=B1=82=E8=AF=B4=E6=98=8E?= =?UTF-8?q?=20(#204)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - system-prompt.mdx: 新增 Provider 概述(1P/3P)与 Boundary 插入条件 - system-prompt.mdx: 新增 OpenAI/Gemini 兼容层章节 - compaction.mdx: 修正 COMPACTABLE_TOOLS 示例并补充 Microcompact 类型 - token-budget.mdx: 补充 3P Provider Token 计数差异说明 --- docs/context/compaction.mdx | 42 +++++++++--- docs/context/system-prompt.mdx | 116 +++++++++++++++++++++++++++++++++ docs/context/token-budget.mdx | 27 ++++++++ 3 files changed, 177 insertions(+), 8 deletions(-) diff --git a/docs/context/compaction.mdx b/docs/context/compaction.mdx index bfa66cabd..2b21197a2 100644 --- a/docs/context/compaction.mdx +++ b/docs/context/compaction.mdx @@ -48,15 +48,16 @@ const messagesForCompact = microcompactResult.messages MicroCompact 不压缩整个对话,而是**清除旧工具输出的内容**。它维护一个白名单: ```typescript +// src/services/compact/microCompact.ts:41-48 const COMPACTABLE_TOOLS = new Set([ - 'Read', // 文件读取 - 'Bash', // 命令输出 - 'Grep', // 搜索结果 - 'Glob', // 文件列表 - 'WebSearch', // 搜索结果 - 'WebFetch', // 网页内容 - 'Edit', // 编辑输出 - 'Write', // 写入输出 + FILE_READ_TOOL_NAME, // 'Read' - 文件读取 + ...SHELL_TOOL_NAMES, // 'Bash' - 命令输出 + GREP_TOOL_NAME, // 'Grep' - 搜索结果 + GLOB_TOOL_NAME, // 'Glob' - 文件列表 + WEB_SEARCH_TOOL_NAME, // 'WebSearch' - 搜索结果 + WEB_FETCH_TOOL_NAME, // 'WebFetch' - 网页内容 + FILE_EDIT_TOOL_NAME, // 'Edit' - 编辑输出 + FILE_WRITE_TOOL_NAME, // 'Write' - 写入输出 ]) ``` @@ -201,6 +202,31 @@ boundaryMarker.compactMetadata.preservedSegment = { 这在会话恢复时帮助加载器正确重建消息链,避免重复压缩已保留的消息。 +### Microcompact Boundary + +Microcompact 操作使用单独的 boundary 类型,与全量压缩的 `compact_boundary` 不同: + +```typescript +// src/utils/messages.ts:4599-4614 +type SystemMicrocompactBoundaryMessage = { + type: 'system' + subtype: 'microcompact_boundary' + content: 'Context microcompacted' + compactMetadata: { + trigger: 'auto' // Microcompact 只有自动触发 + preTokens: number // 压缩前 token 数 + tokensSaved: number // 节省的 token 数 + compactedToolIds: string[] // 被压缩的工具 ID 列表 + clearedAttachmentUUIDs: string[] // 被清除的附件 UUID + } +} +``` + +与 `compact_boundary` 的区别: +- **保留原始消息**:Microcompact 仅清除工具输出内容,不删除消息本身 +- **可追溯性**:`compactedToolIds` 记录了哪些工具结果被清除 +- **轻量级**:不生成摘要,不调用 API + ## PTL 紧急降级:Prompt Too Long 当压缩后仍然超出 token 限制(`PROMPT_TOO_LONG` 错误),系统会进入紧急降级路径: diff --git a/docs/context/system-prompt.mdx b/docs/context/system-prompt.mdx index bc6e3deff..52516174e 100644 --- a/docs/context/system-prompt.mdx +++ b/docs/context/system-prompt.mdx @@ -88,6 +88,36 @@ DANGEROUS_uncachedSystemPromptSection( `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 设计中最精密的部分。 @@ -121,6 +151,30 @@ MCP 工具列表在会话中可能变化(连接/断开),破坏了跨组织 这是缓存效率最高的模式。`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 缺失) ``` @@ -250,3 +304,65 @@ Header 始终 `cacheScope: null`——它因版本和指纹不同而变化,不 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` 中的相关章节。 + diff --git a/docs/context/token-budget.mdx b/docs/context/token-budget.mdx index ca1bdbaf0..a438a4a14 100644 --- a/docs/context/token-budget.mdx +++ b/docs/context/token-budget.mdx @@ -64,6 +64,33 @@ function roughTokenCountEstimation(content: string, bytesPerToken = 4): number { 精确计数在关键决策点使用(压缩前后对比、warning 判断),近似估算在热路径使用(每轮循环的 shouldAutoCompact 检查)。 +### 3P Provider 的 Token 计数差异 + +不同 Provider 的精确 token 计数实现方式不同,部分 provider 甚至不支持精确计数: + +| Provider | 计数方式 | 注意事项 | +|----------|---------|---------| +| **Anthropic 直连** | `anthropic.beta.messages.countTokens()` | 标准 API,最准确 | +| **AWS Bedrock** | `CountTokensCommand` | 需要动态加载 279KB AWS SDK | +| **Google Vertex** | Anthropic SDK + beta 过滤 | 需要特定 beta headers | +| **OpenAI 兼容层** | 无精确计数 | **退回到近似估算** | +| **Gemini 兼容层** | 无精确计数 | **退回到近似估算** | +| **Bedrock 不支持时** | 用 Haiku 发送 `max_tokens=1` 请求 | 读取 `usage.input_tokens` | + +OpenAI 和 Gemini 兼容层**不支持精确 token 计数**,系统会退回到近似估算。这会影响: +- **自动压缩触发时机**:可能略有偏差 +- **压缩前后 token 对比**:仅为估算值,非精确 +- **Warning/Error 阈值判断**:基于估算而非精确计数 + +```typescript +// src/services/tokenEstimation.ts - 近似估算函数 +function roughTokenCountEstimation(content: string, bytesPerToken = 4): number { + return Math.round(content.length / bytesPerToken) +} +``` + +源码路径:`src/services/tokenEstimation.ts` + ## 自动压缩的触发阈值 ```