流式响应处理
概述
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 的渲染循环以固定帧率刷新,确保流式文本平滑显示。
下一步
- 工具注册与发现 — 工具系统概览