【免费下载链接】claude-code-sourcemap
claude-code full original source code from source maps
本文带你深入 Claude Code 的完整原始源码(claude-code-sourcemap,基于 source map 还原的 0.2.8 版本),用通俗易懂的方式解析其 Agent 主循环核心函数query()如何借助 TypeScript 的 AsyncGenerator 实现"模型调用 → 工具执行 → 递归追问"的自动循环。无需深厚背景,看完你就懂 AI 编程 Agent 是怎么"自己干活"的。
一张图看懂 Agent 主循环
先用一张流程概览,把 src/query.ts 里query()的主循环逻辑浓缩成 5 个环节:
用户消息 │ ▼ ① 组装系统提示词 ──► ② 调用模型(querySonnet) │ │ │ ▼ │ ③ 从回复里提取 tool_use 块 │ │ │ 没有工具调用?──► 结束(本轮对话完成) │ │ 有 ▼ ▼ ⑤ 把 [历史 + 助手消息 + 工具结果] 递归传回 query() ◄── ④ 权限校验 + 执行工具这个循环就是所有"Agentic Coding"工具的灵魂:模型想干什么就调什么工具,工具结果再喂回给模型,直到它认为任务完成、不再请求工具为止。
什么是 AsyncGenerator?为什么 Agent 框架偏爱它
AsyncGenerator(异步生成器)是 JavaScript/TypeScript 的一个语言特性:函数用async function*声明,就能一边"暂停"一边"吐出"数据。对 Agent 框架来说它几乎是完美方案,原因有三:
- 流式推送:模型每回复一条消息、工具每产出一个进度,就能立刻
yield给界面,终端不用干等; - 天然挂起等待用户:执行写文件这类危险操作前,权限检查可以在生成器内部"卡住"等用户点确认,其余代码无需轮询;
- 递归无栈风险:
query()通过yield*递归调用自己(src/query.ts#L234-L241),因为每层都是生成器而非常规函数调用栈,"模型 ↔ 工具"可以无限来回而不爆栈。
query()的函数签名非常直观,返回类型就是AsyncGenerator<Message, void>(src/query.ts#L124-L134):
| 参数 | 作用 |
|---|---|
messages | 迄今为止的完整对话历史 |
systemPrompt+context | 系统提示词与附加上下文,由formatSystemPromptWithContext合并 |
canUseTool | 权限钩子,决定"这个工具让不让用" |
toolUseContext | 运行环境:工具列表、中止信号、思考 token 上限等 |
它吐出的Message共有三种形态(src/query.ts#L35-L66):
| 类型 | 含义 | 用途 |
|---|---|---|
UserMessage | 工具执行结果(tool_result) | 拼回对话历史,喂给下一轮模型 |
AssistantMessage | 模型回复,含costUSD成本与耗时 | 展示给用户 |
ProgressMessage | 工具执行中的中间进度 | 仅供 UI 实时展示,不进入对话历史 |
四步拆解:一次 query() 的完整旅程
第 1 步:请求模型
query()内部定义了getAssistantResponse(),它调用 querySonnet(),把归一化后的消息、系统提示词、思考 token 上限和工具列表发给 Anthropic API。注意一个细节:请求会被 VCR(录像回放中间件)包一层,方便离线测试。
第 2 步:判断"是否还要用工具"
模型回复后,代码直接过滤出所有tool_use类型的 content 块(src/query.ts#L171-L178):
源码注释特意提醒:
stop_reason === 'tool_use'不可靠,不能总被正确设置——所以官方选择"看实际内容"而不是"看状态码",这是实战踩坑经验的直接体现。
如果没有任何tool_use,函数直接return,本轮结束。
第 3 步:权限校验 + 执行工具
每个tool_use都会走 checkPermissionsAndCallTool() 的完整流水线:
- Schema 校验:用 Zod 验证模型生成的入参。源码里有一句幽默的注释——"surprisingly, the model is not great at generating valid input"(出乎意料地,模型生成合法入参的能力并不好),校验失败会把
InputValidationError作为错误结果返回给模型,让它自我修正; - 业务校验:各工具自己的
validateInput(); - 权限询问:调用
canUseTool,它背后是 useCanUseTool 钩子,会弹出终端确认框;用户按 Esc 取消时会触发abortController.abort(),一次性中止所有挂起的工具调用; - 真正执行:
tool.call()本身也是一个异步生成器,result表示最终结果,progress表示中间进度,两者分别包装成UserMessage和ProgressMessage向外吐出。
第 4 步:排序结果,递归再问
所有工具执行完后,toolResults会按与tool_use请求相同的顺序排序(API 要求 tool_result 与 tool_use 一一对应,src/query.ts#L223-L232),然后执行最精妙的一行:
yield* await query([历史, 助手消息, 工具结果...], ...)yield*把子生成器的每一条输出原样转发给上层,对话历史不断累积,循环就这样一轮一轮推进,直到模型交卷。
并行与串行:MAX_TOOL_USE_CONCURRENCY 的策略
模型常常一条回复里同时请求多个工具。query()的策略是(src/query.ts#L182-L216):
- 全部是只读工具(如文件读取、grep 搜索)→ 走
runToolsConcurrently并行执行,上限由 MAX_TOOL_USE_CONCURRENCY = 10 控制; - 只要有一个非只读工具(如改文件、跑 shell)→ 降级为
runToolsSerially串行执行,避免并发改坏状态。
并行能力来自 utils/generators.ts 的 all():它用Promise.race从一批生成器中"谁先吐数据就先转发谁",实现带并发上限的合流,是 AsyncGenerator 编程的教科书级用法。
顺带一提,Agent 可用工具全集在 src/tools.ts 中注册,包括BashTool、FileEditTool、GrepTool、AgentTool(子 Agent)等十余种。
消息流如何驱动终端 UI
生成器是"发动机",而 REPL 界面 是"仪表盘"。用户提交消息后,onQuery只做一件事:
for await (const message of query(...)) { setMessages(old => [...old, message]) // 每来一条就渲染一条 }模型回复、工具进度、执行结果逐条到达,React 状态逐条追加——你在终端里看到的"实时打字 + 工具执行动画",本质上就是这个for await循环在消费 AsyncGenerator。这也解释了为什么 Claude Code 支持随时 Esc 中断:中止信号贯穿整条消息链,任何一环都能立刻"刹车"。
源码速查表:跟着 Agent 主循环读代码
| 想了解什么 | 去哪里看 |
|---|---|
| Agent 主循环与递归逻辑 | src/query.ts |
工具并发合流all() | src/utils/generators.ts |
| 模型 API 请求封装 | src/services/claude.ts |
| 权限确认钩子 | src/hooks/useCanUseTool.ts |
| 消息类型定义 | src/utils/messages.tsx |
| 工具注册表 | src/tools.ts |
| UI 消费端 REPL | src/screens/REPL.tsx |
小结
Claude Code 的query()用一个不到 120 行的 AsyncGenerator 递归函数,搭起了整个 Agent 的骨架:生成器负责流式产出消息,递归负责"模型—工具"无限循环,yield*负责层层透传,AbortController负责人类随时叫停。理解了这套模式,你再看任何 AI Agent 框架的 ReAct 循环、工具调用管线,都会发现殊途同归。
💡 延伸建议:先通读
query()全文(约 516 行),再对照all()与checkPermissionsAndCallTool(),是掌握 Agent 主循环源码的最佳阅读路径。
【免费下载链接】claude-code-sourcemap
claude-code full original source code from source maps
相关推荐
揭秘Claude Code Agent循环系统:智能编程助手的核心引擎如何工作
揭秘Claude Code Agent循环系统:智能编程助手的核心引擎如何工作 Claude Code是Anthropic公司开发的官方CLI工具,实现了一个完
示例工程教程人工智能AI Agent代码智能体DouK-Downloader:3 步拿到作品原声,免转码的抖音音频提取指南
DouK Downloader:3 步拿到作品原声,免转码的抖音音频提取指南 晚上十点,剪视频前发现想要的 BGM 藏在一个抖音作品里:长按保存只能拿到带画面的
网页爬虫CLI短视频Claude Code Agent 框架深度解析:从源码拆解核心循环、提示词工程、工具系统与上下文压缩
Claude Code Agent 框架深度解析:从源码拆解核心循环、提示词工程、工具系统与上下文压缩 导读 本文基于当前开源仓库(cc haha 工作区)中的
AI 应用桌面应用AI AgentAI 技能即时通讯GUI 自动化
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考