Claude Code 0331 系统报告

第4章 · 查询引擎(QueryEngine)

第4章 · 查询引擎(QueryEngine)

4.1 query.ts:查询循环

query.ts(1,729行)实现了Claude Code的核心查询循环。它使用**异步生成器(AsyncGenerator)**模式,将每次与API的交互表示为一个可迭代的事件流:

async function* queryLoop(params: QueryParams): AsyncGenerator<QueryEvent> {
  while (true) {
    // 1. 构建API请求
    const request = buildRequest(messages, tools, systemPrompt);

    // 2. 发送请求并流式处理响应
    for await (const event of streamResponse(request)) {
      yield event; // 向上层传递流式事件
    }

    // 3. 处理工具调用
    if (hasToolCalls(lastResponse)) {
      const results = await executeTools(toolCalls);
      messages.push(...results);
      continue; // 继续循环
    }

    // 4. 无工具调用 = 模型完成
    break;
  }
}

这个设计的优雅之处在于:查询循环是一个无限生成器,每次 yield 一个事件,调用方可以按需消费。工具执行在循环内部完成,消息历史在迭代间保持。

4.2 QueryEngine.ts:状态管理与Token预算

QueryEngine.ts(1,295行)是查询系统的上层协调器,负责:

Token预算管理:维护一个动态的Token预算,计算方式为:

有效预算 = 模型上下文窗口 - 系统提示Token - 工具Schema Token - 安全缓冲区(13,000)

当消息历史的Token用量接近有效预算时,触发压缩。

系统提示构建:系统提示由多个动态Section组成,每个Section有独立的生成函数和缓存策略。Section包括:基础指令、工具描述、用户上下文(CLAUDE.md)、项目信息(Git状态)、Proactive指令、Brief指令等。

消息规范化:每次发送前,消息序列经过完整的规范化处理:

  1. 完整性检查(确保assistant/user交替)
  2. 缓存断点插入(在稳定内容处标记)
  3. 工具引用清理(移除已压缩消息的引用)
  4. Token计数更新

4.3 流式处理与工具并发

Claude Code的流式处理不是简单的"接收文本并显示"。它实现了一个 StreamingToolExecutor,允许在API仍在流式返回时就开始执行已完成的工具调用:

API流式返回: [文本块1][工具调用A开始][文本块2][工具调用A结束][工具调用B开始]...

                                    工具A已完整,立刻开始执行
                                    不等待流式传输结束

这个设计显著减少了总往返时间——工具执行和API流式传输并行进行。

4.4 错误恢复:三层策略

预测性恢复:在Token超限之前,主动触发自动压缩。压缩阈值为 有效窗口 - 13,000

响应式恢复:如果API返回 prompt-too-long 错误,立刻执行紧急压缩。紧急压缩比常规压缩更激进,同时缩减 maxOutputTokens

重试逻辑:网络错误和速率限制最多重试10次,容量错误最多3次。速率限制使用API返回的 retry-after 头进行精确等待。

断路器设计:如果连续3次压缩每次回收不到500个Token,压缩器自动禁用,避免无限循环。


On this page