第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指令等。
消息规范化:每次发送前,消息序列经过完整的规范化处理:
- 完整性检查(确保assistant/user交替)
- 缓存断点插入(在稳定内容处标记)
- 工具引用清理(移除已压缩消息的引用)
- 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,压缩器自动禁用,避免无限循环。