Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第12章:Services 服务层

本章介绍 Claude Code 的 Services 服务层设计,包括 API 客户端、MCP 协议实现、OAuth 认证等核心服务。

12.1 Services 目录结构

服务层位于 src/services/ 目录,包含多个子模块:

src/services/
├── api/                  # API 客户端
│   ├── client.ts         # Anthropic API 客户端
│   ├── claude.ts         # Claude API 封装
│   ├── errors.ts         # 错误处理
│   ├── errorUtils.ts     # 错误工具
│   ├── withRetry.ts      # 重试机制
│   ├── usage.ts          # 使用量追踪
│   └── filesApi.ts       # Files API
│
├── mcp/                  # MCP 协议实现
│   ├── client.ts         # MCP 客户端
│   ├── config.ts         # MCP 配置解析
│   ├── auth.ts           # MCP OAuth
│   ├── types.ts          # MCP 类型定义
│   ├── utils.ts          # MCP 工具函数
│   └ normalization.ts  # 数据规范化
│
├── oauth/                # OAuth 认证
│   ├── client.ts         # OAuth 客户端
│   └ auth-code-listener.ts # Auth Code 监听
│
├── analytics/            # 分析服务
│   ├── index.ts          # 分析入口
│   ├── growthbook.ts     # GrowthBook 集成
│   ├── sink.ts           # 数据收集
│   └ datadog.ts        # DataDog 集成
│
├── compact/              # 上下文压缩
│   ├── compact.ts        # 压缩实现
│   ├── autoCompact.ts    # 自动压缩
│   └ microCompact.ts   # 微压缩
│
├── lsp/                  # LSP 服务
│   ├── LSPClient.ts      # LSP 客户端
│   ├── LSPServerManager.ts # LSP 服务器管理
│   └ config.ts           # LSP 配置
│
├── voice/                # 语音服务
│   ├── voice.ts          # 语音处理
│   ├── voiceStreamSTT.ts # 语音转文字
│
└── SessionMemory/        # 会话记忆
    ├── sessionMemory.ts  # 记忆实现
    └ prompts.ts        # 记忆提示词

12.2 API 客户端配置

12.2.1 多云服务商支持

Claude Code 支持多种 API 服务商:

graph TD
    A[API Client] --> B{Provider Detection}
    B --> C[Anthropic Direct]
    B --> D[AWS Bedrock]
    B --> D2[Azure Foundry]
    B --> E[Google Vertex AI]

    C --> F[ANTHROPIC_API_KEY]
    D --> G[AWS Credentials]
    D2 --> H[ANTHROPIC_FOUNDRY_API_KEY]
    E --> I[GCP Credentials]

Note

Claude Code 通过环境变量自动检测 API 服务商,无需手动配置切换。

12.2.2 环境变量配置

/**
 * 各服务商的环境变量配置:
 *
 * Direct API:
 * - ANTHROPIC_API_KEY: 直接 API 访问密钥
 *
 * AWS Bedrock:
 * - AWS credentials: 通过 aws-sdk 默认配置
 * - AWS_REGION / AWS_DEFAULT_REGION: 区域设置(默认 us-east-1)
 *
 * Azure Foundry:
 * - ANTHROPIC_FOUNDRY_RESOURCE: Azure 资源名称
 * - ANTHROPIC_FOUNDRY_API_KEY: Microsoft Foundry API Key
 * - 或使用 Azure AD DefaultAzureCredential
 *
 * Vertex AI:
 * - ANTHROPIC_VERTEX_PROJECT_ID: GCP 项目 ID
 * - CLOUD_ML_REGION: GCP 区域
 * - 标准 GCP credentials 配置
 */

12.2.3 客户端创建逻辑

function createAnthropicClient(): Anthropic {
  const provider = getAPIProvider()

  switch (provider) {
    case 'anthropic':
      return new Anthropic({
        apiKey: getAnthropicApiKey(),
        baseURL: process.env.ANTHROPIC_BASE_URL,
      })

    case 'bedrock':
      return createBedrockClient()

    case 'foundry':
      return createFoundryClient()

    case 'vertex':
      return createVertexClient()
  }
}

12.3 错误处理机制

12.3.1 错误类型定义

Claude Code 使用 Anthropic SDK 提供的错误类型:

// 从 SDK 导入的错误类型
import {
  APIConnectionError,       // 连接错误
  APIConnectionTimeoutError, // 连接超时
  APIError,                  // 通用 API 错误
  APIUserAbortError,         // 用户中止
} from '@anthropic-ai/sdk'

// 错误消息前缀
export const API_ERROR_MESSAGE_PREFIX = 'API Error'
export const PROMPT_TOO_LONG_ERROR_MESSAGE = 'Prompt is too long'

Note

SDK 提供的错误类型已覆盖大多数场景,Claude Code 主要处理错误消息的格式化和展示,而非自定义错误类。

12.3.2 重试机制

withRetry.ts 实现智能重试策略,使用 AsyncGenerator 模式:

flowchart TD
    A[API Call] --> B{Success?}
    B -->|Yes| C[Yield Result]
    B -->|No| D{529 Error?}
    D -->|Yes| E{Foreground Source?}
    E -->|Yes| F[Retry with Backoff]
    E -->|No| G[Bail Out]
    D -->|No| H{Other Retryable?}
    H -->|Yes| I[Retry]
    H -->|No| G
    F --> A
    I --> A
// 重试配置常量
const DEFAULT_MAX_RETRIES = 10
const BASE_DELAY_MS = 500

// 前台查询源(用户正在等待结果,会重试 529)
const FOREGROUND_529_RETRY_SOURCES = new Set([
  'repl_main_thread',
  'sdk',
  'agent:custom',
  'compact',
  // ... 更多前台源
])

// AsyncGenerator 模式支持流式错误消息
export async function* withRetry<T>(
  getClient: () => Promise<Anthropic>,
  operation: (client, attempt, context) => Promise<T>,
  options: RetryOptions,
): AsyncGenerator<SystemAPIErrorMessage, T>

Tip

AsyncGenerator 模式允许在重试过程中实时输出错误消息,用户可以看到「正在重试...」等状态更新。

12.4 MCP 协议实现

12.4.1 MCP 配置解析

mcp/config.ts 解析 MCP 服务器配置:

// MCP 服务器配置格式
export type McpServerConfig = {
  command?: string        // Stdio 启动命令
  args?: string[]         // 命令参数
  url?: string            // HTTP/SSE URL
  transport?: 'stdio' | 'sse' | 'http'
  env?: Record<string, string>
  capabilities?: {
    tools?: boolean
    resources?: boolean
    prompts?: boolean
  }
}

12.4.2 MCP 客户端初始化

sequenceDiagram
    participant Claude as Claude Code
    participant Client as MCP Client
    participant Server as MCP Server

    Claude->>Client: createMcpClient(config)
    Client->>Server: connect (stdio/sse/http)
    Server-->>Client: connected
    Client->>Server: initialize
    Server-->>Client: capabilities
    Client->>Server: listTools
    Server-->>Client: tools list
    Client->>Claude: register tools
export async function initializeMcpClient(
  config: McpServerConfig
): Promise<Client> {
  const client = new Client(
    { name: 'claude-code', version: '1.0.0' },
    { capabilities: { tools: {}, resources: {}, prompts: {} } }
  )

  // 创建传输层
  let transport: Transport
  if (config.transport === 'stdio') {
    transport = new StdioClientTransport({
      command: config.command!,
      args: config.args ?? [],
      env: config.env,
    })
  } else if (config.transport === 'sse') {
    transport = new SSEClientTransport(new URL(config.url!))
  } else {
    transport = new StreamableHTTPClientTransport(new URL(config.url!))
  }

  await client.connect(transport)
  return client
}

12.4.3 MCP Tool 调用

export async function callMcpTool(
  client: Client,
  toolName: string,
  args: Record<string, unknown>
): Promise<CallToolResult> {
  const result = await client.request(
    { method: 'tools/call', params: { name: toolName, arguments: args } },
    CallToolResultSchema
  )

  return result
}

12.4.4 MCP OAuth 认证

mcp/auth.ts 处理 MCP 服务器的 OAuth 认证流程:

sequenceDiagram
    participant Claude as Claude Code
    participant MCP as MCP Client
    participant Auth as Auth Server
    participant User as 用户

    MCP->>Claude: 需要认证
    Claude->>Auth: 获取 OAuth URL
    Auth-->>Claude: auth_url
    Claude->>User: 打开浏览器
    User->>Auth: 授权
    Auth-->>Claude: callback (auth_code)
    Claude->>Auth: exchange code for token
    Auth-->>Claude: access_token
    Claude->>MCP: 提供 token
    MCP->>MCP Server: 认证完成

12.5 OAuth 认证服务

12.5.1 OAuth 客户端

oauth/client.ts 实现 OAuth 2.0 流程,配置来自 constants/oauth.ts

// Claude.ai OAuth scopes - 用于 Claude.ai 订阅用户
export const CLAUDE_AI_OAUTH_SCOPES = [
  'user:profile',           // 用户基本信息
  'user:inference',         // API 调用权限
  'user:sessions:claude_code', // Claude Code 会话
  'user:mcp_servers',       // MCP 服务器管理
  'user:file_upload',       // 文件上传
]

// OAuth 配置结构
type OauthConfig = {
  BASE_API_URL: string
  CONSOLE_AUTHORIZE_URL: string
  CLAUDE_AI_AUTHORIZE_URL: string
  TOKEN_URL: string
  CLIENT_ID: string
  // ...更多配置
}

Note

OAuth 使用 platform.claude.com 作为认证平台,claude.ai 作为用户界面入口。

生产环境配置

const PROD_OAUTH_CONFIG = {
  BASE_API_URL: 'https://api.anthropic.com',
  CONSOLE_AUTHORIZE_URL: 'https://platform.claude.com/oauth/authorize',
  CLAUDE_AI_AUTHORIZE_URL: 'https://claude.com/cai/oauth/authorize',
  TOKEN_URL: 'https://platform.claude.com/v1/oauth/token',
  CLIENT_ID: '9d1c250a-e61b-44d9-88ed-5944d1962f5e',
}

获取组织 UUID

export async function getOrganizationUUID(): Promise<string | null> {
  const tokens = getClaudeAIOAuthTokens()
  if (!tokens) return null

  const response = await fetch(`${OAUTH_API_URL}/organizations`, {
    headers: { Authorization: `Bearer ${tokens.accessToken}` },
  })

  if (!response.ok) return null
  const data = await response.json()
  return data.id
}

12.5.2 Token 管理

export async function checkAndRefreshOAuthTokenIfNeeded(): Promise<boolean> {
  const tokens = getClaudeAIOAuthTokens()

  if (!tokens) return false

  // 检查是否即将过期
  const expiry = decodeJwtExpiry(tokens.accessToken)
  if (!expiry) return false

  const now = Math.floor(Date.now() / 1000)
  const buffer = 5 * 60 // 5 分钟缓冲

  if (expiry - now < buffer) {
    // 需要刷新
    return await refreshAccessToken(tokens.refreshToken)
  }

  return true
}

12.6 上下文压缩服务

12.6.1 Compact 机制

当对话历史过长时,Claude Code 会自动压缩上下文:

flowchart TD
    A[对话历史增长] --> B{超过阈值?}
    B -->|No| C[继续对话]
    B -->|Yes| D[触发 Compact]
    D --> E[提取关键信息]
    E --> F[生成摘要]
    F --> G[替换历史]
    G --> H[继续对话]
export async function compactConversation(
  messages: MessageParam[]
): Promise<MessageParam[]> {
  // 1. 分析消息结构
  const groups = groupMessagesByTopic(messages)

  // 2. 提取关键信息
  const keyPoints = extractKeyPoints(groups)

  // 3. 生成压缩摘要
  const summary = await generateCompactSummary(keyPoints)

  // 4. 构建新的消息列表
  return [
    { role: 'user', content: `[Context Summary]\n${summary}` },
    { role: 'assistant', content: 'I understand the context. Let\'s continue.' },
    ...messages.slice(-10)  // 保留最近的 10 条消息
  ]
}

12.6.2 Micro Compact

微压缩用于快速清理低价值内容:

export function microCompact(messages: MessageParam[]): MessageParam[] {
  return messages.map(msg => {
    if (msg.role === 'assistant') {
      // 移除冗长的确认回复
      if (isVerboseConfirmation(msg.content)) {
        return { ...msg, content: 'Done.' }
      }
    }
    return msg
  })
}

12.7 辅助服务

12.7.1 Analytics 服务

// 分析事件类型
export type AnalyticsEvent =
  | 'session_start'
  | 'session_end'
  | 'tool_call'
  | 'api_request'
  | 'error_occurred'

// 发送分析数据
export function logEvent(event: AnalyticsEvent, data: Record<string, unknown>) {
  sink.send({
    event,
    timestamp: Date.now(),
    sessionId: getSessionId(),
    ...data,
  })
}

12.7.2 LSP 服务

// LSP 客户端管理
export class LSPServerManager {
  private servers: Map<string, LSPServerInstance> = new Map()

  async startServer(languageId: string, config: LSPConfig): Promise<void> {
    const instance = new LSPServerInstance(languageId, config)
    await instance.start()
    this.servers.set(languageId, instance)
  }

  async getDiagnostics(filePath: string): Promise<Diagnostic[]> {
    const languageId = detectLanguage(filePath)
    const server = this.servers.get(languageId)
    if (!server) return []
    return server.getDiagnostics(filePath)
  }
}

本章小结

Services 服务层是 Claude Code 的后端支撑系统,主要特点:

  1. 多云服务商支持:Anthropic、AWS Bedrock、Azure Foundry、Vertex AI
  2. MCP 协议完整实现:支持 Stdio、SSE、HTTP 三种传输
  3. 智能错误处理:指数退避重试、错误分类处理
  4. 上下文管理:自动压缩、微压缩、会话记忆

通过本章的学习,读者可以深入了解 Claude Code 如何与各种后端服务集成,以及如何实现稳定的 API 调用和智能的上下文管理。