docs: 完善上下文工程核心定义与架构说明(docs/context) Provider 系统、Boundary 条件及兼容层说明

- system-prompt.mdx: 新增 Provider 概述(1P/3P)与 Boundary 插入条件
- system-prompt.mdx: 新增 OpenAI/Gemini 兼容层章节
- compaction.mdx: 修正 COMPACTABLE_TOOLS 示例并补充 Microcompact 类型
- token-budget.mdx: 补充 3P Provider Token 计数差异说明
This commit is contained in:
CyberScrubber
2026-04-08 17:35:07 +08:00
parent d52300ff44
commit 3ec5675fe7
3 changed files with 177 additions and 8 deletions

View File

@@ -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` 错误),系统会进入紧急降级路径:

View File

@@ -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` 中的相关章节。

View File

@@ -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`
## 自动压缩的触发阈值
```