API 服务
概述
API 服务封装了对 Anthropic Messages API 的调用,是 Claude Code 与 AI 模型通信的桥梁。
目录结构
src/services/api/
├── claude.ts # 核心消息 API
├── logging.ts # 请求/响应日志
└── errors.ts # 错误处理与分类核心调用
流式消息
// services/api/claude.ts 核心逻辑
async function streamMessage(params: {
messages: Message[]
system: SystemPrompt
tools: ToolDefinition[]
model: string
maxTokens: number
thinking?: ThinkingConfig
}) {
const stream = anthropic.messages.stream({
model: params.model,
max_tokens: params.maxTokens,
system: params.system,
messages: params.messages,
tools: params.tools,
stream: true,
})
return stream
}API 参数构建
function buildAPIParams(options: QueryOptions) {
return {
model: options.model || 'claude-sonnet-4-6',
max_tokens: options.maxTokens || 16384,
// 系统提示词
system: buildSystemPrompt(options),
// 对话历史
messages: options.messages,
// 工具定义
tools: buildToolDefinitions(options.tools),
// Thinking 模式
...(options.thinking ? {
thinking: {
type: 'enabled',
budget_tokens: options.thinkingBudget,
}
} : {}),
// 流式
stream: true,
}
}Thinking 模式
Claude Code 支持 Extended Thinking 模式,让 AI 进行更深入的推理:
interface ThinkingConfig {
type: 'enabled'
budget_tokens: number // 推理 token 预算
}
// Thinking 的输出在响应中以 thinking 块呈现
// 折叠显示在终端中,用户可展开查看Thinking 预算
// 不同模型的默认 Thinking 预算
const THINKING_BUDGETS = {
'claude-opus-4-6': 10000,
'claude-sonnet-4-6': 8000,
'claude-haiku-4-5': 4000,
}用量追踪
Token 计数
// services/api/logging.ts
interface NonNullableUsage {
input_tokens: number
output_tokens: number
cache_creation_input_tokens: number
cache_read_input_tokens: number
}缓存策略
Claude Code 利用 Anthropic 的 Prompt Caching 降低成本:
// 系统提示词标记为缓存
system: [{
type: 'text',
text: systemPrompt,
cache_control: { type: 'ephemeral' } // 标记缓存
}]
// 工具定义标记为缓存
tools: toolDefs.map(tool => ({
...tool,
cache_control: { type: 'ephemeral' }
}))缓存命中时 cache_read_input_tokens > 0,成本显著降低。
错误处理
错误分类
// services/api/errors.ts
type ErrorCategory =
| 'rate_limit' // 速率限制
| 'overloaded' // 服务过载
| 'timeout' // 请求超时
| 'auth' // 认证失败
| 'other' // 其他错误
function categorizeRetryableAPIError(error: unknown): {
retryable: boolean
category: ErrorCategory
}重试策略
async function callWithRetry(fn: () => Promise<T>, options: RetryOptions) {
let attempt = 0
while (attempt < options.maxRetries) {
try {
return await fn()
} catch (error) {
const { retryable, category } = categorizeRetryableAPIError(error)
if (!retryable) throw error
const delay = getBackoffDelay(attempt, category)
await sleep(delay)
attempt++
}
}
throw new MaxRetriesExceededError()
}退避策略
| 错误类型 | 首次退避 | 最大退避 | 最大重试 |
|---|---|---|---|
| rate_limit | 1s | 60s | 5 |
| overloaded | 2s | 30s | 3 |
| timeout | 5s | 30s | 2 |
| auth | 不重试 | - | 0 |
模型选择
支持的模型
const SUPPORTED_MODELS = {
'claude-opus-4-6': { maxTokens: 32768, thinkingBudget: 10000 },
'claude-sonnet-4-6': { maxTokens: 16384, thinkingBudget: 8000 },
'claude-haiku-4-5': { maxTokens: 8192, thinkingBudget: 4000 },
}模型切换
// /model 命令切换模型
// 或通过设置配置默认模型
// settings.json: { "model": "claude-sonnet-4-6" }SSE 事件处理
Anthropic API 返回 Server-Sent Events 流:
// 事件类型映射
type SSEEvent =
| { type: 'message_start', message: Message }
| { type: 'content_block_start', index: number, content_block: ContentBlock }
| { type: 'content_block_delta', index: number, delta: Delta }
| { type: 'content_block_stop', index: number }
| { type: 'message_delta', delta: MessageDelta, usage: Usage }
| { type: 'message_stop' }
// Delta 类型
type Delta =
| { type: 'thinking_delta', thinking: string }
| { type: 'text_delta', text: string }
| { type: 'input_json_delta', partial_json: string }
| { type: 'signature_delta', signature: string }流式渲染
SSE 事件 → Ink 组件更新 → 终端渲染
thinking_delta → 折叠区域(默认收起)
text_delta → 实时 Markdown 渲染
input_json_delta → 工具参数实时显示
message_delta → 更新 token 统计Last updated on