读懂 Claude Code 源码,Agent 的核心难点从来不是工具调用,而是持续运行

做过 AI Agent 开发的人,大概率都有过这样的困惑,自己手写的 Agent demo,单次工具调用、单次问答都能正常跑,可一旦放到复杂的长任务里,就频繁出问题。要么中途莫名终止,要么重复执行工具,要么上下文错乱导致逻辑跑偏,偶尔还会直接接口报错、任务卡死。
很长一段时间里,我和绝大多数开发者一样,默认 Agent 的核心能力是工具调用。只要模型能精准识别调用工具、正确传参、获取结果,就能完成自动化任务。直到我深入研读了 Claude Code 的 query.ts 和 QueryEngine.ts 核心源码,才彻底推翻了这个认知。
工具调用只是 Agent 最基础的“肢体动作”,是表层能力。真正决定一个 Agent 能不能稳定跑长任务、能不能容错恢复、能不能持续迭代推进工作的核心,是一套严谨的轮次继续逻辑。简单来说,Agent 开发的真正难点,从来不是“怎么调用工具”,而是工具执行完毕后,下一轮到底该怎么继续。
市面上绝大多数入门级 Agent demo,都套用一套极简的循环逻辑,看似逻辑闭环,实则完全经不起真实场景的打磨。但成熟的工业级 Agent,本质是一套精密的状态调度系统和交通规则,精准管控着模型输出、工具执行、上下文更新、任务终止的每一个节点。今天我结合源码拆解和实战开发经验,聊聊真正专业的 Agent 主循环到底强在哪,以及普通开发者手搓 Agent 最容易踩的核心坑。
别混淆会话与轮次,这是 Agent 稳定的根基
新手开发 Agent 最致命的误区,就是把“整体会话状态”和“单轮执行状态”混为一谈,全部塞进同一个函数、同一个变量池里。短任务、简单对话完全看不出问题,可一旦任务需要十几轮、几十轮迭代,就会出现状态丢失、上下文混乱、恢复机制失效等一系列问题。
Claude Code 的源码设计,最值得借鉴的第一个亮点,就是清晰的分层架构,用两个核心模块,彻底切割开会话生命周期和单轮执行逻辑,分工明确、互不干扰,这也是它能稳定运行超长复杂任务的核心前提。
QueryEngine.ts 负责管控完整会话的生命周期,相当于整场任务的“大管家”。它存储的是跨轮次、长期有效的全局状态,不会随着单轮任务结束而清空。其中包含会话的全部消息历史、文件读取缓存状态、用户权限拒绝记录、token 用量统计、可恢复的任务日志等核心数据。每一次用户发起新指令、每一轮模型迭代,都会基于这套全局状态延续上下文,保证整场会话的连贯性。简单理解,QueryEngine 决定了一场 AI 任务能不能“活着、续上、恢复”。
而 query.ts 负责管控单轮任务的循环执行,是单轮迭代的“执行指挥官”。它只聚焦当前这一轮的逻辑,包括调用模型、接收流式输出、调度工具执行、更新本轮上下文、判断本轮任务是否结束、判定是否需要开启下一轮迭代。
这套分层设计解决了开发中最棘手的状态管理问题。长期会话的全局状态不需要频繁修改,只需要迭代更新;单轮执行的临时状态不需要全局存储,执行完毕后按需沉淀、按需清空。反观很多自研 Agent,之所以越迭代越乱,就是因为把全局状态和临时状态杂糅在一起,既不知道哪些数据需要跨轮保留,也不知道哪些数据是单次执行的临时冗余,最终导致整个系统失控。
成熟 Agent 的第一步,从来不是调用模型
我们看网上绝大多数的 Agent 开发教程,主循环逻辑都极其简单,一套通用模板贯穿始终。
while true:
调用大模型
如果模型输出工具调用指令:
执行对应工具
否则:
结束本轮任务
这套逻辑没有语法错误,入门开发完全够用,但这是典型的“理想态极简逻辑”,完全脱离了真实工程场景。真实线上环境中,影响 Agent 运行稳定性的从来不是模型能不能输出工具指令,而是上下文过载、内容冗余、窗口超限、数据异常等各类边缘问题。
这也是 query.ts 带给我最大的认知颠覆,工业级 Agent 的每一轮循环,第一件事绝对不是调用模型,而是校验和治理上下文。在发起模型推理之前,系统会优先完成一整套风险校验和优化操作,从根源上避免任务报错、卡死和失效。
具体来说,每一轮模型调用前,Claude Code 都会依次处理多项核心校验工作,检测当前会话消息是否超出上下文窗口上限,判断上一轮工具返回结果是否体量过大,是否需要精简替换,扫描历史对话是否存在冗余片段,是否需要执行微压缩、全局折叠等优化操作。同时还会动态更新 token 预算,抵扣上下文占用的额度,重构压缩后的消息队列,确保送入模型的上下文是干净、有效、合规的。
很多开发者做性能优化时,总习惯性把上下文压缩、冗余清理当成后置优化手段,觉得只要模型能跑出结果就无需处理。但真实落地后会发现,绝大多数 Agent 长任务崩盘的根源,都是上下文持续膨胀。每一轮工具执行、每一次模型输出都会叠加新内容,冗余信息不断堆积,最终导致推理变慢、窗口超限、模型理解偏差,最后任务彻底失控。
query.ts 的工程设计逻辑非常直白,长任务 Agent 的上下文管理,不是锦上添花的优化,而是保障任务持续运行的核心基础。没有前置的上下文治理,再精准的工具调用、再强大的大模型,都跑不稳复杂迭代任务。
别迷信 stop_reason,模型终止标识从来不可靠
在 Agent 开发的工程实践中,判断是否需要继续下一轮迭代,是一个极易被忽视的细节,却直接决定了任务的正确性。绝大多数新手代码,都会依赖模型返回的 stop_reason 字段做唯一判定。
简单的判定逻辑通俗易懂,如果stop_reason 等于 tool_use,就代表模型需要调用工具,系统继续执行循环,如果是其他终止状态,就判定任务完成,直接结束流程。
但在 Claude Code 的源码注释中,官方直接明确了一个核心结论,stop_reason === 'tool_use' 是不可靠的,绝对不能作为唯一判定依据。
这一点特别能体现顶级工程和入门 demo 的差距。大模型的流式输出存在极强的不确定性,网络波动、输出截断、字段延迟、格式异常等各类问题,都会导致 stop_reason 字段出现滞后、错误、缺失的情况。如果单纯依赖这个总结性字段判断任务状态,非常容易出现逻辑误判。
比如模型实际已经输出了工具调用代码块,但 stop_reason 还未同步更新,系统就会误判任务结束,直接截断工具执行,留下半截无效的工具调用上下文,下一轮迭代直接接口报错。反之,字段异常标记为工具调用,模型却没有输出有效指令,又会导致系统空跑、资源浪费。
Claude Code 采用了一套更稳妥的判定逻辑,放弃依赖后置总结字段,选择实时监听流式输出内容。系统会全程流式接收模型的回复,只要检测到有效 tool_use 代码块,就实时记录标记,开启后续工具执行流程,并主动标记 needsFollowUp = true,强制开启下一轮迭代。
说白了,成熟 Agent 的判定逻辑只相信“实际拿到的有效内容”,不相信“系统总结的状态字段”。这也是所有开发者手搓 Agent 必须避开的核心坑,不要让控制流被模型的返回字段绑架,一定要基于本地实际接收的有效信息做决策。
流式工具调度,平衡速度与正确性的核心设计
聊完状态判定,就不得不提 Claude Code 的 StreamingToolExecutor 流式工具执行器,这是它区别于普通 Agent 的又一核心亮点,完美解决了长任务“执行效率低”和“逻辑不安全”的矛盾。
普通 Agent 的工具执行逻辑非常保守,必须等待模型完整输出全部内容、本轮回复彻底结束后,再统一解析工具指令、批量执行工具。这种逻辑绝对安全,不会出现顺序错乱、状态混乱的问题,但缺点也极其明显,效率极低。
如果模型输出内容较长、工具指令较多,开发者需要全程等待输出完毕才能执行任务,大量时间都浪费在等待模型输出上,长任务的整体推进速度会被严重拖慢。
而 StreamingToolExecutor 采用了流式并行调度的思路,不需要等待模型输出完成,只要流式解析到完整可用的工具指令,就会立刻加入执行队列,提前启动工具调度。为了兼顾效率和安全性,它搭建了一套完善的状态机机制,严格遵循 queued 排队、executing 执行中、completed 执行完成、yielded 结果返回的状态流转逻辑。
同时系统定义了严格的执行约束,规避流式执行带来的风险。对于无状态、并发安全的工具,系统会直接并行执行,最大化提升效率。对于 Bash 命令、文件修改等有状态、非并发安全的工具,必须串行排队,等待上一个工具执行完毕再执行下一个,避免文件冲突、指令覆盖、权限错乱等问题。
更细节的容错设计让人印象深刻,如果批量执行的工具中,某一个 Bash 工具执行失败,系统会主动终止其他正在运行的同级工具,避免无效消耗资源。遇到用户手动中断、流式输出异常、工具执行报错等问题,系统不会直接崩溃,而是主动生成模拟的 synthetic tool_result 兜底结果,保证主循环不中断、上下文不缺失。
最关键的是,所有提前执行的工具结果,最终都会按照可控的固定顺序回流到主循环,不会因为流式并行执行打乱整体逻辑顺序。这套设计没有炫技的成分,完全是为了适配真实工程场景,在保证任务绝对正确的前提下,最大限度提升 Agent 的执行效率。
工具执行结束,不等于轮次任务结束
绝大多数新手 Agent 的逻辑都非常直白,工具执行完成、拿到返回结果后,直接把结果拼接进上下文,然后开启下一轮模型调用。这套极简逻辑可以跑通demo,但完全适配不了真实复杂任务。
看完 query.ts 的收口逻辑,我最大的感悟是,工具执行只是单次轮次的中间步骤,绝非收尾步骤。成熟的工业级 Agent,在工具执行完毕后,会做一整套的状态校验、数据清理、状态更新、容错兜底工作,这也是 demo 和线上稳定系统的核心差距。
工具执行完成后,Claude Code 不会直接进入下一轮循环,而是先完成一系列收口校验,检测本轮工具返回的结果体量是否过大,是否需要精简压缩,判断工具执行是否产生了新的附件、新的缓存数据,核查是否存在未执行的排队指令、待更新的工具状态。同时系统会更新全局记忆、刷新权限状态、统计本轮 token 消耗、更新任务迭代次数,甚至还会根据任务进度生成精简摘要,优化用户观感。
这些操作看起来琐碎冗余,却是 Agent 能够持续运行的关键。如果跳过这些收口步骤,每一轮产生的冗余数据、异常状态、未处理的缓存都会不断堆积,几轮迭代过后,就会出现上下文臃肿、状态错乱、工具失效等各类问题。
更反直觉的一个设计是,即便本轮没有检测到任何工具调用指令,Claude Code 也不会直接终止任务。在很多场景下,没有工具调用,只是模型没有发起新的执行动作,不代表本轮任务已经圆满完成。
如果本轮输出触发上下文超长限制,系统不会直接报错结束,会主动触发上下文折叠、消息压缩机制,清理冗余内容后重试本轮任务。如果模型输出触达 token 上限、内容被强制截断,系统会插入恢复提示消息,引导模型接续输出,避免任务半截终止。
除此之外,系统还会校验各类拦截钩子,即便模型看似正常结束,只要钩子检测到潜在问题、未完成任务,就会注入错误标识,强制主循环继续迭代。同时 token 预算机制会动态判定任务进度,主动推送提示信息,避免模型敷衍结束、提前终止未完成的工作。
这也就解释了,为什么很多自研 Agent 总是“假性完成”。任务看似正常结束,实则是被上下文上限、token 限制、钩子异常强制截断,并没有真正闭环。成熟 Agent 的终止逻辑极其严苛,必须同时满足无未完成工具、无上下文异常、无拦截错误、无进度遗留、无预算约束等所有条件,才能真正结束一轮任务。
Agent 的连续工作能力,是运行时拼出来的,不是模型自带的
很多人对大模型 Agent 有一个认知误区,觉得模型自带记忆和逻辑延续能力,能够自主承接上一轮任务、持续推进工作。但实际上,大模型本身没有任何天然的任务记忆和状态延续能力。
模型每一次推理,都是一次独立的计算过程,它之所以能实现连续工作、迭代推进任务,完全是因为 Agent 运行时,每一轮迭代结束后,都会精准拼接、还原完整的任务现场,为下一轮推理提供完整的上下文和状态数据。
在每一轮任务收尾阶段,query.ts 会完成最核心的状态拼接工作,整合本轮的查询消息、模型输出内容、全部工具执行结果,同步更新工具上下文、任务追踪数据、轮次统计数据,最终生成完整的状态快照,传递给下一轮迭代。
这套快照包含了整场任务的全部关键信息,上一轮模型输出的完整内容、发起的全部工具调用、工具的返回结果、系统补充的附件信息、更新后的工具状态、当前的迭代轮次、本轮任务的继续原因等等。
下一轮模型启动推理时,看到的不是零散的对话片段,而是一套完整、连贯、可追溯的任务现场。所谓的 Agent 连续工作能力,本质是运行时层层兜底、精准复刻状态的结果,而非模型的原生能力。
这也是 Agent 开发最核心的真相,工具调用只能让 Agent“动起来”,而一套完善的 Query 主循环状态调度逻辑,才能让 Agent“长久跑下去”。
新手自研 Agent,先做稳主循环,再谈功能迭代
读完 Claude Code 的核心源码,我对 Agent 开发的思路彻底改观。以前开发时,我总想着堆叠复杂功能、实现多样的工具调用,现在我更倾向于先搭建一套“丑陋但足够稳定”的主循环架构。
对于新手开发者来说,完全没必要一上来就追求并发调度、智能压缩、容错恢复等高级功能。优先搭建一套稳健的基础主循环,就能甩开市面上 80% 的劣质 Agent demo。
一套合格的基础主循环,必须做好几件核心事,严格区分全局会话状态和单轮临时状态,每轮推理前优先校验上下文合法性,不依赖单一字段判定任务状态,基于实际输出内容识别工具调用,工具执行后完成完整的收口和状态更新,兼容各类异常场景的容错兜底,严格校验终止条件、杜绝假性结束,精准拼接每一轮的任务状态快照。
这套架构没有酷炫的技术亮点,却是保障 Agent 可靠性的核心。Agent 开发的核心竞争力,从来不是单次动作的完美执行,而是无数轮迭代的稳定承接、异常恢复、持续推进。
这和我做内容自动化系统的思路不谋而合,完整的生产链路,从来不是靠单次完美的输出,而是靠每一步的容错、每一轮的接续、每一次异常的兜底。不怕迭代慢,就怕任务断,能够稳定跑完完整链路,远比单次华丽的输出更有价值。
写在最后
回头来看,大多数人对 Agent 的认知,都停留在表层的工具调用,却忽略了底层的控制流和状态调度。工具调用只是 Agent 的手脚,而 Query 主循环才是 Agent 的大脑和神经,管控着整个任务的生死和进度。
真正的工业级 Agent,不是简单的“大模型+工具函数”的拼接,而是一套精密复杂的状态管理系统、一套严谨完善的任务调度规则。手搓 Agent 的核心奥义,不是学会调用工具,而是学会管控轮次、承接状态、处理异常、延续任务。
未来的 Agent 竞争,早已不是工具丰富度的竞争,而是运行时稳定性、长任务持续能力、异常容错能力的竞争。吃透 Query 主循环的核心逻辑,才算真正入门 AI Agent 工程开发。
更多推荐



所有评论(0)