💓

QueryEngine 核心循环

Claude Code 的心脏 —— query() 无限循环如何驱动 AI 推理、工具执行与上下文管理

核心架构

QueryEngine 概述

驱动 Claude Code 的核心引擎

QueryEngine 是 Claude Code 最核心的类。它拥有整个查询生命周期和会话状态, 每次 submitMessage() 调用启动一个新的 turn,而内部的 query() 函数通过 while(true) 无限循环 实现多轮工具调用。

架构上分为两层:QueryEngine 类(会话管理、消息持久化、SDK 适配) 和 query() 函数(纯推理循环、上下文压缩、工具执行)。 依赖通过 QueryDeps 注入,便于测试。

QueryEngine 两层架构

streamexecuteif neededend_turnretryQueryEnginesubmitMessage()fetchSystemPrompt()processUserInput()query() while(true)handleStopHooks()callModel()runTools()autocompact()

8 步执行流程

query() 循环的完整生命周期

以下是 queryLoop() 每次迭代执行的 8 个核心步骤。点击自动播放可观看完整流程动画。

query() 核心循环 — 8 步流程
typescript
1// query.ts — queryLoop entry
2async function* queryLoop(params: QueryParams) {
3 const budgetTracker = feature('TOKEN_BUDGET')
4 ? createBudgetTracker() : null
5 const config = buildQueryConfig()
6 
7 // Fire-and-forget memory prefetch
8 using pendingMemoryPrefetch =
9 startRelevantMemoryPrefetch(messages, toolUseContext)
10 
11 while (true) {
步骤 1/8

Step 1: 初始化 — 创建 BudgetTracker、快照 QueryConfig(session ID、feature gates)、启动异步内存预取

执行流程全景图

从用户输入到最终结果的完整数据流

QueryEngine 完整执行流程图

压缩调用tool_use递归end_turn检查👤 用户输入QueryEngine.submitMessage()processUserInput()query() while(true)SnipMicrocompactAutocompactClaude API (streaming)assistant + tool_userunTools() / StreamingExecutortool_resultsStop HooksToken Budget✅ result
初始化阶段
  • 创建 BudgetTracker 和 QueryConfig
  • 启动内存预取 (pendingMemoryPrefetch)
  • 初始化 StreamingToolExecutor
上下文管理
  • Snip — 移除过期的僵尸标记
  • Microcompact — 去除冗余工具结果
  • Autocompact — 全量对话摘要压缩
推理与执行
  • 流式调用 Claude API
  • 收集 assistant 消息和 tool_use 块
  • 并行/串行执行工具调用
终止与检查
  • Stop Hooks — 后台钩子检查
  • Token Budget — 90% 阈值/边际递减
  • maxTurns / maxBudgetUsd 限制

Stop Hooks 中断机制

每次 turn 结束时的钩子系统

handleStopHooks() 在 Claude 完成回复后执行,可以阻止循环继续(preventContinuation)或注入阻塞错误(blockingErrors)触发重试。 它还异步触发 Prompt Suggestion、Memory Extraction、Auto Dream 等后台任务。

对于 Teammate(子智能体),还会额外运行 TaskCompleted TeammateIdle 钩子。

Stop Hooks 执行流程

有错误阻止通过Turn 结束 (needsFollowUp=false)后台任务 (async fire-and-forget)PromptSuggestionExtractMemoriesAutoDreamexecuteStopHooks()progress 消息结果检查blockingErrors → continue 重试preventContinuation → return 终止通过 → return completed
blockingErrors

钩子发现需要修正的问题(如代码规范违规),注入错误消息后 continue 重试,Claude 会在下一轮修正

preventContinuation

钩子判定应该终止循环(如前置条件不满足),立即 return,不再继续推理

后台任务

PromptSuggestion(生成后续建议)、ExtractMemories(提取对话记忆)、AutoDream(自动任务生成)异步执行,不阻塞主循环

Token Budget 动态分配

智能的 token 消耗控制策略

checkTokenBudget() 实现了双重停止条件:

  • 90% 阈值 — 当 token 消耗达到预算的 90% 时,注入 nudge 消息提示 Claude 尽快收尾
  • 边际递减检测 — 连续 3 次续接后,如果每轮新增 token < 500,判定为边际递减,提前终止

Token Budget 决策流程

checkTokenBudget()计算 pct = turnTokens / budget边际递减? (≥3次 & <500 tokens)pct < 90%?✅ continue 注入 nudge 消息⏹ stop 边际递减终止⏹ stop 预算耗尽
0.9 (90%)
COMPLETION_THRESHOLD

达到预算 90% 时注入收尾提示

500 tokens
DIMINISHING_THRESHOLD

每轮新增低于此值视为边际递减

3 次
最小续接次数

至少续接 3 次后才开始检测边际递减

BudgetTracker 状态

continuationCount
续接计数
lastDeltaTokens
上轮增量
lastGlobalTurnTokens
上轮总量
startedAt
起始时间
pct
当前百分比

依赖注入与配置

QueryDeps + QueryConfig 的设计哲学

query() 的核心依赖通过 QueryDeps 接口注入(callModel、microcompact、autocompact、uuid),不可变配置通过 QueryConfig 在循环开始时快照。这使得测试可以直接注入 mock,无需 spyOn。

QueryDeps — 可替换依赖

callModelqueryModelWithStreaming
microcompactmicrocompactMessages
autocompactautoCompactIfNeeded
uuidrandomUUID

QueryConfig — 不可变快照

sessionIdSessionId
gates
streamingToolExecution: boolean
emitToolUseSummaries: boolean
isAnt: boolean
fastModeEnabled: boolean

错误恢复机制

Prompt-Too-Long、Max-Output-Tokens、Model Fallback

query() 实现了多层错误恢复策略,通过 withhold 机制暂缓错误暴露,先尝试恢复:

Context Collapse Drainprompt_too_long (413)

排空所有 staged collapses,保留细粒度上下文而非全量摘要

Reactive Compactprompt_too_long / media_size_error

执行 reactive compact 压缩,单次尝试,避免死循环

Max Output Tokens Escalatemax_output_tokens (8k cap)

自动升级到 64k tokens 重试同一请求

Max Output Tokens Recoverymax_output_tokens (64k also hit)

注入恢复消息,最多重试 3 次(MAX_OUTPUT_TOKENS_RECOVERY_LIMIT)

Model FallbackFallbackTriggeredError

切换到 fallbackModel 重试,清理签名块(thinking blocks)

消息类型与流转

query() yield 的所有消息类型

query() 是一个 AsyncGenerator,通过 yield 向外推送多种消息类型。 QueryEngine.submitMessage() 负责将这些消息转换为 SDKMessage 格式并持久化到 transcript。

assistant

Claude 的回复(含 thinking/tool_use 块)

user

工具执行结果(tool_result)

progress

工具执行进度通知

attachment

文件变更、max_turns、structured_output

stream_event

message_start/delta/stop 事件

system

compact_boundary、api_error、warning

tombstone

标记待移除的消息(如 fallback 清理)

stream_request_start

API 请求开始信号

tool_use_summary

工具调用摘要(Haiku 生成)