Skip to content

流式响应处理

概述

Claude Code 全程使用流式传输处理 API 响应。从 API 返回的每个事件都经过多层处理后最终渲染到终端。

端到端流程

流式事件处理 (query.ts)

Source: src/query.ts:708-866

在查询循环中,每个流式消息经过以下处理:

1. 降级重试检测

typescript
// 检测是否触发了降级
if (isFallbackMessage(message)) {
  // 切换到降级模型
  throw new FallbackTriggeredError(fallbackModel);
}

2. tool_use 输入回填

typescript
// 为 SDK 兼容性回填 tool_use 的 input 字段
backfillToolUseInputs(message, toolUseBlocks);

3. 可恢复错误扣留

typescript
// 扣留 413 (Prompt Too Long) 错误
if (is413Error(message)) {
  withheldError = message;
  continue;  // 不 yield 给调用者
}

// 扣留 max_output_tokens 错误
if (isMaxTokensError(message)) {
  withheldError = message;
  continue;
}

4. 正常消息分发

typescript
// 正常消息 yield 给调用者
yield message;

// 提取 tool_use 块
if (hasToolUse(message)) {
  toolUseBlocks.push(...extractToolUseBlocks(message));
}

5. 流式工具执行

typescript
// 喂给流式工具执行器(边解析边执行)
if (streamingToolExecutor) {
  streamingToolExecutor.feed(toolUseBlock);
  
  // yield 已完成的工具结果
  for (const result of streamingToolExecutor.getCompletedResults()) {
    yield result;
  }
}

流式工具执行器

StreamingToolExecutor 实现了边解析边执行的策略,减少总延迟:

优势:

  • 减少延迟 — 工具在流式传输期间就开始执行
  • 并行处理 — API 流式传输和工具执行同时进行

事件类型映射

SDK 事件内部处理
message_start初始化助手消息
content_block_start (text)开始文本块
content_block_delta (text_delta)追加文本内容
content_block_start (tool_use)开始工具调用块
content_block_delta (input_json_delta)追加工具输入 JSON
content_block_stop完成内容块
message_delta更新 stop_reason
message_stop消息完成

中断处理

用户可以在流式传输期间按 Ctrl+C 中断:

typescript
if (toolUseContext.abortController.signal.aborted) {
  // 消费剩余的流式工具结果
  // yield 中断消息
  return { reason: 'aborted_streaming' };
}

与 UI 的连接

流式事件最终通过 QueryEngine.submitMessage() 的 Generator yield 到 REPL 界面:

typescript
// REPL 消费流式事件
for await (const event of queryEngine.submitMessage(input)) {
  // 更新 AppState 中的消息列表
  // 触发 React 重新渲染
  // 消息内容实时显示在终端
}

终端 UI 通过 Ink 的渲染循环以固定帧率刷新,确保流式文本平滑显示。

下一步