Skip to content

Commit 73a18c3

Browse files
docs: 完善上下文工程核心定义与架构说明(docs/context) Provider 系统、Boundary 条件及兼容层说明 (#204)
- system-prompt.mdx: 新增 Provider 概述(1P/3P)与 Boundary 插入条件 - system-prompt.mdx: 新增 OpenAI/Gemini 兼容层章节 - compaction.mdx: 修正 COMPACTABLE_TOOLS 示例并补充 Microcompact 类型 - token-budget.mdx: 补充 3P Provider Token 计数差异说明
1 parent ae6ae6c commit 73a18c3

3 files changed

Lines changed: 177 additions & 8 deletions

File tree

docs/context/compaction.mdx

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,16 @@ const messagesForCompact = microcompactResult.messages
4848
MicroCompact 不压缩整个对话,而是**清除旧工具输出的内容**。它维护一个白名单:
4949

5050
```typescript
51+
// src/services/compact/microCompact.ts:41-48
5152
const COMPACTABLE_TOOLS = new Set([
52-
'Read', // 文件读取
53-
'Bash', // 命令输出
54-
'Grep', // 搜索结果
55-
'Glob', // 文件列表
56-
'WebSearch', // 搜索结果
57-
'WebFetch', // 网页内容
58-
'Edit', // 编辑输出
59-
'Write', // 写入输出
53+
FILE_READ_TOOL_NAME, // 'Read' - 文件读取
54+
...SHELL_TOOL_NAMES, // 'Bash' - 命令输出
55+
GREP_TOOL_NAME, // 'Grep' - 搜索结果
56+
GLOB_TOOL_NAME, // 'Glob' - 文件列表
57+
WEB_SEARCH_TOOL_NAME, // 'WebSearch' - 搜索结果
58+
WEB_FETCH_TOOL_NAME, // 'WebFetch' - 网页内容
59+
FILE_EDIT_TOOL_NAME, // 'Edit' - 编辑输出
60+
FILE_WRITE_TOOL_NAME, // 'Write' - 写入输出
6061
])
6162
```
6263

@@ -201,6 +202,31 @@ boundaryMarker.compactMetadata.preservedSegment = {
201202

202203
这在会话恢复时帮助加载器正确重建消息链,避免重复压缩已保留的消息。
203204

205+
### Microcompact Boundary
206+
207+
Microcompact 操作使用单独的 boundary 类型,与全量压缩的 `compact_boundary` 不同:
208+
209+
```typescript
210+
// src/utils/messages.ts:4599-4614
211+
type SystemMicrocompactBoundaryMessage = {
212+
type: 'system'
213+
subtype: 'microcompact_boundary'
214+
content: 'Context microcompacted'
215+
compactMetadata: {
216+
trigger: 'auto' // Microcompact 只有自动触发
217+
preTokens: number // 压缩前 token 数
218+
tokensSaved: number // 节省的 token 数
219+
compactedToolIds: string[] // 被压缩的工具 ID 列表
220+
clearedAttachmentUUIDs: string[] // 被清除的附件 UUID
221+
}
222+
}
223+
```
224+
225+
`compact_boundary` 的区别:
226+
- **保留原始消息**:Microcompact 仅清除工具输出内容,不删除消息本身
227+
- **可追溯性**:`compactedToolIds` 记录了哪些工具结果被清除
228+
- **轻量级**:不生成摘要,不调用 API
229+
204230
## PTL 紧急降级:Prompt Too Long
205231
206232
当压缩后仍然超出 token 限制(`PROMPT_TOO_LONG` 错误),系统会进入紧急降级路径:

docs/context/system-prompt.mdx

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,36 @@ DANGEROUS_uncachedSystemPromptSection(
8888

8989
`appendSystemPrompt` 始终追加到末尾(Override 除外)。
9090

91+
## Provider 系统概述
92+
93+
Claude Code 支持多种 API 提供商,分为两大类:
94+
95+
| 类别 | Provider | 环境变量 | 说明 |
96+
|------|----------|---------|------|
97+
| **1P (First Party)** | `firstParty` | 默认 | Anthropic 官方 API 直连 |
98+
| **3P (Third Party)** | `bedrock` | `CLAUDE_CODE_USE_BEDROCK=1` | AWS Bedrock 托管服务 |
99+
| **3P** | `vertex` | `CLAUDE_CODE_USE_VERTEX=1` | Google Vertex AI |
100+
| **3P** | `openai` | `CLAUDE_CODE_USE_OPENAI=1` | OpenAI 兼容层(Ollama/DeepSeek/vLLM) |
101+
| **3P** | `gemini` | `CLAUDE_CODE_USE_GEMINI=1` | Google Gemini API |
102+
| **3P** | `grok` | `CLAUDE_CODE_USE_GROK=1` | xAI Grok |
103+
104+
Provider 决定了:
105+
- **可用的 beta headers**:部分 beta 功能仅限 1P 用户
106+
- **缓存策略**:全局缓存 `scope: 'global'` 仅 1P 可用
107+
- **Token 计数方式**:Bedrock 有独立的 countTokens 端点,OpenAI/Gemini 依赖估算
108+
109+
```typescript
110+
// src/utils/model/providers.ts:5-13
111+
export type APIProvider =
112+
| 'firstParty' // 1P - Anthropic 直连
113+
| 'bedrock' // 3P - AWS Bedrock
114+
| 'vertex' // 3P - Google Vertex
115+
| 'foundry' // 3P - Anthropic Foundry
116+
| 'openai' // 3P - OpenAI 兼容层
117+
| 'gemini' // 3P - Google Gemini
118+
| 'grok' // 3P - xAI Grok
119+
```
120+
91121
## 缓存策略:分块、标记、命中
92122
93123
这是 System Prompt 设计中最精密的部分。
@@ -121,6 +151,30 @@ MCP 工具列表在会话中可能变化(连接/断开),破坏了跨组织
121151
122152
这是缓存效率最高的模式。`SYSTEM_PROMPT_DYNAMIC_BOUNDARY` 之前的静态内容(Intro、Rules、Tone & Style 等)对所有用户相同,可跨组织缓存。
123153
154+
### Boundary 插入条件
155+
156+
`SYSTEM_PROMPT_DYNAMIC_BOUNDARY` 标记**仅在特定条件**下插入:
157+
158+
```typescript
159+
// src/utils/betas.ts:226-229
160+
export function shouldUseGlobalCacheScope(): boolean {
161+
return (
162+
getAPIProvider() === 'firstParty' &&
163+
!isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS)
164+
)
165+
}
166+
```
167+
168+
```typescript
169+
// src/constants/prompts.ts:574
170+
...(shouldUseGlobalCacheScope() ? [SYSTEM_PROMPT_DYNAMIC_BOUNDARY] : []),
171+
```
172+
173+
这意味着:
174+
- **3P 用户(Bedrock/Vertex/OpenAI/Gemini)**:Boundary 永远不存在,始终使用模式 3
175+
- **1P 用户禁用实验性功能**:设置 `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1`,Boundary 不插入
176+
- **1P 用户默认**:Boundary 存在,使用模式 2(最高缓存效率)
177+
124178
#### 模式 3:默认(3P 提供商 或 Boundary 缺失)
125179

126180
```
@@ -250,3 +304,65 @@ Header 始终 `cacheScope: null`——它因版本和指纹不同而变化,不
250304
4. `SYSTEM_PROMPT_DYNAMIC_BOUNDARY` 标记允许 `splitSysPromptPrefix()` 精确地将静态区标记为 `scope: 'global'`,动态区不标记或标记为 `scope: 'org'`
251305

252306
这是 Claude Code 在 token 成本优化上的核心设计——一次典型的 System Prompt 约 20K+ tokens,通过缓存分块可以节省 30-50% 的输入 token 费用。
307+
308+
## 兼容层:OpenAI 与 Gemini
309+
310+
Claude Code 提供了 OpenAI 和 Gemini 协议的兼容层,允许使用非 Anthropic 端点。
311+
312+
### OpenAI 兼容层
313+
314+
通过 `CLAUDE_CODE_USE_OPENAI=1` 启用,支持任意 OpenAI Chat Completions 协议端点(Ollama、DeepSeek、vLLM 等)。
315+
316+
实现采用**流适配器模式**
317+
1. 将 Anthropic 格式请求转换为 OpenAI 格式
318+
2. 调用 OpenAI 兼容端点
319+
3. 将 SSE 流转换回 `BetaRawMessageStreamEvent`
320+
4. 下游代码完全无感知
321+
322+
```
323+
src/services/api/openai/
324+
├── client.ts # OpenAI 客户端配置
325+
├── convertMessages.ts # 消息格式转换(Anthropic → OpenAI)
326+
├── convertTools.ts # 工具定义转换
327+
├── streamAdapter.ts # SSE 流适配(OpenAI → Anthropic)
328+
├── modelMapping.ts # 模型名称映射
329+
└── index.ts # 入口函数 queryModelOpenAI()
330+
```
331+
332+
关键环境变量:
333+
- `CLAUDE_CODE_USE_OPENAI=1` — 启用 OpenAI provider
334+
- `OPENAI_API_KEY` — API 密钥
335+
- `OPENAI_BASE_URL` — API 端点(默认 `https://api.openai.com/v1`
336+
- `OPENAI_MODEL` — 直接指定模型名
337+
338+
### Gemini 兼容层
339+
340+
通过 `CLAUDE_CODE_USE_GEMINI=1` 启用,支持 Google Gemini API。
341+
342+
```
343+
src/services/api/gemini/
344+
├── client.ts # Gemini 客户端配置
345+
├── convertMessages.ts # 消息格式转换
346+
├── convertTools.ts # 工具定义转换
347+
├── streamAdapter.ts # 流适配
348+
├── modelMapping.ts # 模型名称映射
349+
├── types.ts # 类型定义
350+
└── index.ts # 入口函数
351+
```
352+
353+
关键环境变量:
354+
- `CLAUDE_CODE_USE_GEMINI=1` — 启用 Gemini provider
355+
- `GEMINI_API_KEY` — API 密钥
356+
- `GEMINI_BASE_URL` — API 端点(默认 `https://generativelanguage.googleapis.com/v1beta`
357+
- `GEMINI_MODEL` — 直接指定模型名
358+
- `GEMINI_DEFAULT_SONNET_MODEL` / `GEMINI_DEFAULT_OPUS_MODEL` — 按能力级别映射
359+
360+
### 兼容层的限制
361+
362+
使用 3P 兼容层时,部分功能受限:
363+
- **无精确 token 计数**:系统退回到近似估算,影响自动压缩触发时机
364+
- **无全局缓存**:只能使用组织级缓存 `scope: 'org'`
365+
- **部分 beta 功能不可用**:依赖 Anthropic 特有 beta headers 的功能受限
366+
367+
详见 `docs/plans/openai-compatibility.md``CLAUDE.md` 中的相关章节。
368+

docs/context/token-budget.mdx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,33 @@ function roughTokenCountEstimation(content: string, bytesPerToken = 4): number {
6464

6565
精确计数在关键决策点使用(压缩前后对比、warning 判断),近似估算在热路径使用(每轮循环的 shouldAutoCompact 检查)。
6666

67+
### 3P Provider 的 Token 计数差异
68+
69+
不同 Provider 的精确 token 计数实现方式不同,部分 provider 甚至不支持精确计数:
70+
71+
| Provider | 计数方式 | 注意事项 |
72+
|----------|---------|---------|
73+
| **Anthropic 直连** | `anthropic.beta.messages.countTokens()` | 标准 API,最准确 |
74+
| **AWS Bedrock** | `CountTokensCommand` | 需要动态加载 279KB AWS SDK |
75+
| **Google Vertex** | Anthropic SDK + beta 过滤 | 需要特定 beta headers |
76+
| **OpenAI 兼容层** | 无精确计数 | **退回到近似估算** |
77+
| **Gemini 兼容层** | 无精确计数 | **退回到近似估算** |
78+
| **Bedrock 不支持时** | 用 Haiku 发送 `max_tokens=1` 请求 | 读取 `usage.input_tokens` |
79+
80+
OpenAI 和 Gemini 兼容层**不支持精确 token 计数**,系统会退回到近似估算。这会影响:
81+
- **自动压缩触发时机**:可能略有偏差
82+
- **压缩前后 token 对比**:仅为估算值,非精确
83+
- **Warning/Error 阈值判断**:基于估算而非精确计数
84+
85+
```typescript
86+
// src/services/tokenEstimation.ts - 近似估算函数
87+
function roughTokenCountEstimation(content: string, bytesPerToken = 4): number {
88+
return Math.round(content.length / bytesPerToken)
89+
}
90+
```
91+
92+
源码路径:`src/services/tokenEstimation.ts`
93+
6794
## 自动压缩的触发阈值
6895

6996
```

0 commit comments

Comments
 (0)