Claude Code 与 Anthropic API 之间的通信层,3420 行的核心模块。
一、API 调用链路
query.ts (Agentic Loop) │ ▼ services/api/claude.ts (3420 行, API 核心) │ ├─ 构建请求参数 (system prompt, messages, tools, betas) ├─ 添加认证 (API Key / OAuth / AWS / GCP) ├─ 配置重试策略 │ ▼ @anthropic-ai/sdk (官方 SDK) │ ├─ Streaming 请求 (SSE) │ ▼ Anthropic API Server │ ▼ SSE 事件流 → 解析 → 转换 → yield 给 query.ts
|
二、claude.ts — API 核心
2.1 主要导出函数
export async function* streamClaude(params: { systemPrompt: SystemPrompt; messages: Message[]; tools: Tools; model: string; maxTokens: number; thinkingConfig?: ThinkingConfig; }): AsyncGenerator<StreamEvent> { }
export function getMaxOutputTokensForModel(model: string): number;
|
2.2 请求参数构建
function buildRequestParams(config): BetaMessageStreamParams { return { model: config.model, max_tokens: config.maxTokens, system: formatSystemPrompt(config.systemPrompt), messages: normalizeMessagesForAPI(config.messages), tools: config.tools.map(toolToAPISchema), stream: true,
betas: getMergedBetas(config.model),
thinking: config.thinkingConfig ? { type: 'enabled', budget_tokens: config.thinkingConfig.budgetTokens, } : undefined,
...getCacheControlParams(config),
extra_headers: { ...getAttributionHeader(), ...getCLISyspromptPrefix(), }, }; }
|
2.3 System Prompt 格式化
function formatSystemPrompt(prompt: SystemPrompt): ContentBlockParam[] { return [ { type: 'text', text: prompt.coreInstructions, cache_control: { type: 'ephemeral' }, }, { type: 'text', text: prompt.toolDescriptions, cache_control: { type: 'ephemeral' }, }, { type: 'text', text: prompt.environmentContext, }, ]; }
|
三、Streaming 事件流
3.1 SSE 事件类型
type StreamEvent = | { type: 'message_start'; message: BetaMessage } | { type: 'content_block_start'; content_block: ContentBlock } | { type: 'content_block_delta'; delta: ContentDelta } | { type: 'content_block_stop' } | { type: 'message_delta'; delta: { stop_reason: StopReason } } | { type: 'message_stop' }
type ContentBlock = | { type: 'text'; text: string } | { type: 'tool_use'; id: string; name: string; input: unknown } | { type: 'thinking'; thinking: string } | { type: 'server_tool_use'; ... }
type StopReason = | 'end_turn' | 'tool_use' | 'max_tokens' | 'stop_sequence'
|
3.2 流式处理过程
for await (const event of sdk.stream(params)) { switch (event.type) { case 'content_block_start': if (event.content_block.type === 'text') { yield { type: 'text_start' }; } else if (event.content_block.type === 'tool_use') { streamingToolExecutor.addTool(event.content_block); } break;
case 'content_block_delta': if (event.delta.type === 'text_delta') { yield { type: 'text', text: event.delta.text }; } else if (event.delta.type === 'input_json_delta') { accumulateToolInput(event.delta.partial_json); } break;
case 'message_delta': if (event.delta.stop_reason === 'tool_use') { } break; } }
|
四、认证系统
4.1 认证方式优先级
1. API Key (环境变量 ANTHROPIC_API_KEY) 2. OAuth Token (Anthropic Console 登录) 3. AWS Bedrock (IAM 认证) 4. Google Cloud Vertex AI (GCP 认证) 5. File Descriptor (--api-key-fd 传入)
|
4.2 OAuth 流程
4.3 API Key 轮换
五、重试策略
async function withRetry<T>( fn: () => Promise<T>, config: RetryConfig, ): Promise<T> { let lastError: Error;
for (let attempt = 0; attempt < config.maxRetries; attempt++) { try { return await fn(); } catch (error) { lastError = error; const retryInfo = categorizeRetryableAPIError(error);
if (!retryInfo.retryable) throw error;
const delay = Math.min( retryInfo.retryAfter || config.baseDelay * Math.pow(2, attempt), config.maxDelay );
await sleep(delay); } }
throw lastError; }
|
错误分类
| 状态码 |
分类 |
处理 |
| 429 |
Rate Limit |
重试 (指数退避) |
| 500 |
Server Error |
重试 |
| 502/503 |
Server Unavailable |
重试 |
| 401 |
Unauthorized |
刷新 token 后重试 |
| 400 (prompt_too_long) |
上下文溢出 |
压缩后重试 |
| 400 (其他) |
请求错误 |
不重试 |
| 网络错误 |
Connection Error |
重试 |
六、Prompt Cache 优化
function notifyCompaction(): void { }
|
七、Token 计数
export function tokenCountWithEstimation(messages: Message[]): number { if (lastResponseUsage) { return lastResponseUsage.input_tokens; }
const totalChars = messages.reduce( (sum, msg) => sum + getContentText(msg).length, 0 ); return Math.ceil(totalChars / 4); }
export function getContextWindowForModel(model: string): number { }
|
八、多提供商支持
type APIProvider = | 'anthropic' | 'bedrock' | 'vertex'
function getAPIProvider(): APIProvider { if (process.env.ANTHROPIC_BEDROCK_BASE_URL) return 'bedrock'; if (process.env.ANTHROPIC_VERTEX_BASE_URL) return 'vertex'; return 'anthropic'; }
|
九、API 预连接
export function preconnectAnthropicApi(): void { }
|
十、Usage 追踪
type NonNullableUsage = { input_tokens: number; output_tokens: number; cache_creation_input_tokens: number; cache_read_input_tokens: number; };
export function accumulateUsage(totalUsage, responseUsage): NonNullableUsage { return { input_tokens: totalUsage.input_tokens + responseUsage.input_tokens, output_tokens: totalUsage.output_tokens + responseUsage.output_tokens, cache_creation_input_tokens: totalUsage.cache_creation_input_tokens + (responseUsage.cache_creation_input_tokens || 0), cache_read_input_tokens: totalUsage.cache_read_input_tokens + (responseUsage.cache_read_input_tokens || 0), }; }
|