news 2026/4/28 15:01:42

Claude Code 源码笔记 -- State状态流转

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Claude Code 源码笔记 -- State状态流转

State 是 queryLoop 唯一的跨轮可变量,所有"记忆"都在这里:

typeState={// 完整消息历史messages:Message[]// 工具上下文,包含 AbortController、工具列表、agentId 等,迭代内可能被更新toolUseContext:ToolUseContext// 自动压缩跟踪autoCompactTracking:AutoCompactTrackingState|undefined// max_output_tokens 恢复重试次数(上限3)maxOutputTokensRecoveryCount:number// 是否已尝试,防止 reactive compact 陷入无限循环的守卫位hasAttemptedReactiveCompact:boolean// 临时 token 上限覆盖,设置后下一轮将以 64k token 上限重试maxOutputTokensOverride:number|undefined// 异步预生成的工具摘要,上一轮工具调用摘要的异步 Promise,下一轮 yield 给前端pendingToolUseSummary:Promise<ToolUseSummaryMessage|null>|undefined// stop hook 是否活跃(防止 hook 错误触发死循环)stopHookActive:boolean|undefined// 当前轮次,用于 maxTurns 限制检查turnCount:number// 上一轮 continue 的原因transition:Continue|undefined}

迭代内临时变量

这些变量每轮重新声明,相当于当前轮的"草稿纸":

// 流式收集本轮模型产生的所有 assistant 消息(包括思考、文本、tool_use)constassistantMessages:AssistantMessage[]=[]// 工具执行完毕后的结果消息,将作为下一轮模型的输入consttoolResults:(UserMessage|AttachmentMessage)[]=[]// 从流中提取的所有 tool_use 块,决定本轮需要调用哪些工具consttoolUseBlocks:ToolUseBlock[]=[]// 只要流中出现了 tool_use 块就置为 true,是"有工具要执行"的信号letneedsFollowUp=false

迭代末尾,这些"草稿"被合并进持久状态:

state.messages=[...messagesForQuery,...assistantMessages,...toolResults]

状态枚举:继续循环

以下场景触发state = next; continue,即不退出,开始下一轮:

  1. next_turn—— 正常推进
    触发条件:模型输出了 tool_use,工具执行完毕,一切正常。 这是最常见的 continue 原因,代表 agent 正在正常工作中。工具结果被追加到 messages 后进入下一轮,让模型基于结果继续推理。
  2. collapse_drain_retry—— 上下文折叠恢复
    触发条件:收到 HTTP 413(prompt too long),且 context collapse 功能开启,且本轮并非已经从 collapse 中恢复过。 做法是将部分上下文"折叠压缩"释放空间,然后用更短的 messages 重新请求模型,不增加 turnCount。
  3. reactive_compact_retry—— 响应式压缩恢复
    触发条件:收到 413 或媒体大小错误,尝试对整个对话做一次 compact(生成摘要替换历史)。hasAttemptedReactiveCompact被设为 true,确保此路径只走一次,防止无限压缩。
  4. max_output_tokens_escalate—— 提升 token 上限
    触发条件:模型输出被max_output_tokens截断,且本轮还没有尝试过提升上限。 下一轮将以 64k tokens 的上限重试同样的请求。此路径只触发一次(由maxOutputTokensOverride === undefined守卫)。
  5. max_output_tokens_recovery—— 注入恢复提示
    触发条件:max_output_tokens 截断,且 escalate 也没有解决(或不适用)。 向对话注入一条 meta 消息,告知模型"输出被截断,直接继续,不要道歉",最多重试 3 次(由maxOutputTokensRecoveryCount < 3守卫)。
  6. stop_hook_blocking—— Stop Hook 阻塞重试
    触发条件:模型给出了正常响应(非 API 错误),stop hook 执行后发现有阻塞性错误需要反馈给模型。 将 hook 产生的错误消息追加到 messages,让模型看到并修正。stopHookActive 被设为 true 以标记 hook 正在活跃。
  7. token_budget_continuation—— Token Budget 未耗尽
    触发条件:TOKEN_BUDGET 功能开启,模型给出了响应,但 budget 检查认为还有配额,应该继续。 向对话注入一条"nudge"消息引导模型继续输出,直到 budget 耗尽或任务完成。

状态枚举 退出循环

以下场景触发return { reason: '...' },循环终止:

  1. blocking_limit
    token 数量已经达到硬性上限,且用户关闭了 autocompact。此时不允许继续,输出错误消息后退出。这是一个"安全阀",为用户保留手动运行 /compact 的空间。
  2. model_error/image_error
    模型调用抛出了无法恢复的异常,或图片大小超限且无法压缩恢复。
  3. aborted_streaming
    用户在模型流式输出过程中按下了中断(Ctrl+C)。
  4. aborted_tools
    用户在工具执行过程中中断。
  5. hook_stopped
    某个工具的 hook 明确返回了"阻止继续"的指令shouldPreventContinuation = true
  6. prompt_too_long
    收到 413,且所有恢复手段(collapse drain + reactive compact)都已用尽,只能放弃。
  7. stop_hook_prevented
    stop hook 明确返回了preventContinuation: true,通常表示某个外部策略要求停止。
  8. completed
    正常完成。分两种情况:
    • 模型返回了 API 错误(非 tool_use)→ 上报 failure hook 后退出
    • 模型给出正常文本响应,stop hook 无异议,token budget 也耗尽或不需要继续 → 正常完成
  9. max_turns
    turnCount超过了调用方传入的 maxTurns 上限。
queryLoop 进入 │ ▼ 初始化 state(第268行) turnCount=1, transition=undefined │ ╔═════════════════════════════════════════════╗ ║ while(true) 循环体 ║ ║ ║ ║ Step 1: 消息预处理 ║ ║ snip(截断过长历史) ║ ║ → microcompact(轻量压缩) ║ ║ → contextCollapse(上下文折叠) ║ ║ → autoCompact(token超阈值时自动压缩) ║ ║ │ ║ ║ Step 2: blocking_limit 检查 ║ ║ token超限且autocompact关闭? ║ ║ 是 ──────────────────────────────► return ║ ║ │ 否 'blocking_ ║ ║ Step 3: callModel() 流式调用 limit' ║ ║ │ ║ ║ ┌─────▼──────────────────────┐ ║ ║ │ 内层 while(attemptWithFallback)│ ║ ║ │ 收集 assistantMessages │ ║ ║ │ 收集 toolUseBlocks │ ║ ║ │ 设置 needsFollowUp=true │ ║ ║ │ FallbackTriggeredError? │ ║ ║ │ → 切换模型,continue(内层) │ ║ ║ └─────────────────────────────┘ ║ ║ │ ║ ║ 其他异常 ──────────────────────► return ║ ║ │ 'model_error' ║ ║ 用户中断 ──────────────────────► return ║ ║ │ 'aborted_streaming' ║ ║ │ ║ ║ ┌──────▼──────────────────────────────┐ ║ ║ │ needsFollowUp == false? │ ║ ║ │ (模型没有产生 tool_use) │ ║ ║ └──────┬──────────────────────────┬───┘ ║ ║ true │(无工具) false │(有工具)║ ║ │ │ ║ ║ ┌───────▼──────────┐ ┌────────────▼──────┐ ║ ║ │ 停止条件分支 │ │ 工具执行分支 │ ║ ║ │ │ │ │ ║ ║ │ ①413恢复路径: │ │ runTools()执行 │ ║ ║ │ collapse_drain │ │ 所有 toolUseBlocks│ ║ ║ │ → continue │ │ │ ║ ║ │ reactive_compact│ │ 用户中断? │ ║ ║ │ → continue │ │ → return │ ║ ║ │ 都失败 → return │ │ 'aborted_tools' │ ║ ║ │ │ │ │ ║ ║ │ ②max_output截断: │ │ hook阻止? │ ║ ║ │ escalate │ │ → return │ ║ ║ │ → continue │ │ 'hook_stopped' │ ║ ║ │ recovery(×3) │ │ │ ║ ║ │ → continue │ │ maxTurns超限? │ ║ ║ │ 耗尽 → yield err │ │ → return │ ║ ║ │ │ │ 'max_turns' │ ║ ║ │ ③API error? │ │ │ ║ ║ │ → return │ │ 一切正常: │ ║ ║ │ 'completed' │ │ messages合并 │ ║ ║ │ │ │ turnCount++ │ ║ ║ │ ④stop hook检查: │ │ transition= │ ║ ║ │ prevented │ │ 'next_turn' │ ║ ║ │ → return │ │ state=next │ ║ ║ │ blocking │ │ → continue ────┐ │ ║ ║ │ → continue │ └────────────────│──┘ ║ ║ │ │ │ ║ ║ │ ⑤token budget: │ │ ║ ║ │ continue budget │ │ ║ ║ │ → continue │ │ ║ ║ │ done │ │ ║ ║ │ → return │ │ ║ ║ │ 'completed' │ │ ║ ║ └──────────────────┘ │ ║ ║ │ return │ ║ ╚═════════╪═══════════════════════════════╪════╝ │ │ ▼ ┌──────────┘ 循环终止 │ 回到循环顶部 ▼ 解构新的 state 开始下一轮
函数触发的状态流转
callModel()驱动主循环,通过流产生assistantMessagestoolUseBlocks
runTools()执行工具,填充toolResults,可触发aborted_tools/hook_stopped
handleStopHooks()返回preventContinuation/blockingErrors,触发stop_hook_*系列转换
contextCollapse.recoverFromOverflow()触发collapse_drain_retry
reactiveCompact.tryReactiveCompact()触发reactive_compact_retry
checkTokenBudget()触发token_budget_continuationcompleted
calculateTokenWarningState()触发blocking_limit
isMaxOutputTokensTruncated()触发max_output_tokens_escalate/recovery
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/11 8:14:27

基于Verilog的以太网PHY芯片MDIO寄存器自动化测试方案

1. 从零理解MDIO接口的工作原理 MDIO&#xff08;Management Data Input/Output&#xff09;是以太网PHY芯片管理的核心接口&#xff0c;它就像PHY芯片的"控制面板"。想象一下&#xff0c;当你需要调整路由器参数时&#xff0c;会登录网页管理界面进行操作。MDIO就是…

作者头像 李华
网站建设 2026/4/11 8:14:23

模块指令与通信接口总结

核心理念&#xff1a;无论底层是 I2C、SPI 还是 UART/Wi-Fi&#xff0c;通信的本质只有两个字——“收”与“发”。如果收发不可靠&#xff0c;驱动就是空中楼阁。核心在于&#xff1a;可靠的物理层传输 严谨的应用层解析 闭环的应答机制。1. 物理层&#xff1a;收发的可靠性…

作者头像 李华
网站建设 2026/4/11 8:13:46

A01 - Web前端开发概述

一 网页的三个问题网页由那几部分组成?文字、图片、视频、音频、超链接...我们看到的网页&#xff0c;背后本质是什么?程序员写的前端代码前端代码如何转换成用户眼中的网页?通过浏览器转换成用户看到的网页。浏览器对代码进行解析渲染的部分&#xff0c;称为浏览器内核。二…

作者头像 李华
网站建设 2026/4/11 8:13:39

小红书无水印下载工具XHS-Downloader:3种高效采集方法全解析

小红书无水印下载工具XHS-Downloader&#xff1a;3种高效采集方法全解析 【免费下载链接】XHS-Downloader 小红书&#xff08;XiaoHongShu、RedNote&#xff09;链接提取/作品采集工具&#xff1a;提取账号发布、收藏、点赞、专辑作品链接&#xff1b;提取搜索结果作品、用户链…

作者头像 李华
网站建设 2026/4/11 8:12:29

Spring AI Alibaba 1.1.2.2 项目源码深度解析

1. 项目概述 1.1 项目简介 Spring AI Alibaba 是阿里云基于 Spring AI 框架开发的 AI 应用开发平台&#xff0c;提供了一整套用于构建 AI 应用的组件和工具。项目版本为 1.1.2.2&#xff0c;基于 Spring Boot 3.5.8 和 Spring AI 1.1.2 构建。 1.2 技术栈 组件版本说明Java…

作者头像 李华
网站建设 2026/4/11 8:09:22

.NET源码生成器基于partial范式开发和nuget打包衷

1 安装与初始化 # 全局安装 OpenSpec npm install -g fission-ai/openspeclatest # 在项目目录下初始化 cd /path/to/your-project openspec init 初始化时&#xff0c;OpenSpec 会提示你选择使用的 AI 工具&#xff08;Claude Code、Cursor、Trae、Qoder 等&#xff09;。 3 O…

作者头像 李华