AI 编程 Agent 究竟是如何工作的:一次源码深度剖析
我们追踪了 Amazon Q CLI 和 Claude Code 的源代码,深入理解 AI 编程 Agent 底层的真实运作方式。

Cursor、Claude Code、Amazon Q、Windsurf…… 到了 2026 年,AI 编程已经成为一片竞争白热化的红海。但你有没有想过:这些工具在底层究竟是怎么工作的?
本文基于两个开源项目的源代码 —— Amazon Q Developer CLI(用 Rust 实现)和 Claude Code(TypeScript + Python)—— 从最底层拆解 AI 编程 Agent 的核心架构。
先说清楚:AI 编程不是聊天机器人
很多人以为 AI 编程工具不过是给 ChatGPT 套了个 IDE 的外壳。这从根本上就错了。
聊天机器人只会说话,AI 编程 Agent 却能行动。区别在哪?工具使用(Tool Use,即 function calling)。
当你让 Claude Code 修一个 bug 时,幕后实际发生的是这样一串过程:
You: "Fix the bug in src/app.js"
LLM thinks: I need to read that file first
LLM output: tool_call → fs_read("src/app.js")
Agent: executes read → returns file content to LLM
LLM thinks: Found it — line 42 has the issue
LLM output: tool_call → fs_write("src/app.js", ...)
Agent: executes write → returns result
LLM: "Done. The problem was..."
这个过程被称为 Agent 循环(Agent Loop)—— 它是每一款 AI 编程工具中最重要的设计模式。
关键概念: LLM 从不直接操作你的机器。它发送结构化的 JSON 请求,告诉 Agent“我想做什么”,而 Agent 在真正代其执行之前会先校验权限。这让每一次操作都可审计、可拦截、可回滚。
Agent 循环:一台优雅的状态机
Amazon Q CLI 用 Rust 实现了一个显式的有限状态机来管理整个 Agent 循环。
这个状态机有六个状态:Idle → ExecutingRequest → ExecutingHooks → WaitingForApproval → ExecutingTools →(循环回到起点)
这台状态机有几处设计尤为精妙:
- 循环是自动的 —— LLM 调用工具后,结果会被重新注入对话中,并自动再次调用 LLM。
- 工具可以并行执行 —— LLM 可以在一次响应中返回多个
tool_use块,Agent 使用 Tokio 的FuturesUnordered来并发执行它们。 - 每一次工具调用都要经过权限检查 —— 没有例外。
工具系统:AI 的手和脚
一个 AI 编程 Agent 的能力上限,完全取决于它能访问哪些工具。
工具描述的艺术
工具的 description 不是写给人看的文档 —— 它是写给 LLM 看的行为指令。它的质量直接决定了 Agent 的表现好坏。
__tool_use_purpose:逼迫 AI 在动手前先思考
Amazon Q CLI 有一个优雅的设计细节:每一次工具调用都强制要求 LLM 填写一个 purpose 字段。这个看似不起眼的约束效果显著 —— 它迫使模型在调用工具之前先阐明为什么要调用它,从而减少了幻觉式或不必要的工具调用。
安全模型:四层纵深防御
AI 编程 Agent 能直接访问你的文件系统、终端和网络。安全不是可选项 —— 它是架构层面的问题。
Amazon Q CLI 实现了一套四层安全架构:Hook → 用户确认 → 路径权限 → 工具白名单
所有文件路径都会先经过 canonicalize 规范化处理,这能防止 ../ 之类的路径穿越攻击绕过权限边界。
Claude Code 则采取了另一种思路,使用 Hook 系统来实现声明式的安全策略,自动检测九类常见的安全风险。
上下文窗口管理:最稀缺的资源
在传统软件中,瓶颈是 CPU、内存和 I/O。而在 AI 编程中,瓶颈是上下文窗口。
每一个 token 都很重要。系统提示词、对话历史、工具描述、文件内容以及工具返回结果,都在争抢一个固定大小窗口中的空间。一旦超出限制,模型要么丢失关键上下文,要么请求彻底失败。
Amazon Q CLI 采用四种策略来管理它:
- 自动压缩(Auto-compaction) —— 当窗口被填满时,把 20 万 token 的对话压缩成约 2K token 的摘要。
- 消息截断 —— 读取大文件时,只保留前 10,000 个字符。
- 历史裁剪 —— 保留最近的消息,同时维护结构完整性(确保工具调用/结果成对匹配)。
- 资源文件上限 —— 自动纳入的资源文件(如
.qdeveloper配置)被限制在 10KB 以内。
MCP 协议:工具扩展的事实标准
两个项目都采用了 **MCP(Model Context Protocol,模型上下文协议)**作为它们的工具扩展协议。MCP 提供了一种标准化方式,可以在不修改 Agent 核心代码的前提下为其添加新工具 —— 工具被定义为通过明确定义的协议进行通信的外部服务器。
Amazon Q CLI 使用 Actor 模型来管理多个 MCP 服务器,其中每个 MCP 服务器都作为一个拥有独立生命周期的 actor 运行。这提供了天然的隔离性:如果某个 MCP 服务器崩溃,也不会拖垮其他服务器。
插件架构:Claude Code 的五维扩展模型
Claude Code 定义了五个正交的扩展点,让插件作者能对 Agent 行为的不同方面进行细粒度的控制。
最有意思的例子是 feature-dev 插件的七阶段工作流 —— 它会并行启动多个子 Agent,同时探索不同的代码路径。每个子 Agent 在自己的探索分支上运作,最终结果被综合成一份连贯的实现方案。这是一种真正的多 Agent 模式,而不只是顺序的工具调用。
架构对比
| 维度 | Amazon Q CLI | Claude Code |
|---|---|---|
| 语言 | Rust | TypeScript + Python |
| 架构 | 单体 Agent + Actor 并发 | 核心引擎 + 插件生态 |
| 并发 | Tokio 异步 + Actor 模型 | Node.js 事件循环 + 子进程 |
| 扩展 | MCP + Hook 脚本 | 五维插件系统 |
| 状态 | SQLite 持久化 | 文件系统 + 会话状态 |
| 优势 | 性能、类型安全 | 开发速度、丰富的生态 |
尽管存在这些表面上的差异,核心范式却是完全一致的:LLM Agent + 工具使用 + 流式输出 + 安全 + MCP。
这种趋同并非巧合。这些正是在真实世界的编程任务中经受住考验、存活下来的设计模式。每一款严肃的 AI 编程工具,无论用什么语言实现,最终都会以惊人相似的方式去解决同样的根本问题。
七条设计原则
在深入研究了这两个代码库之后,以下是定义现代 AI 编程 Agent 构建方式的七条原则:
- LLM 是大脑,工具是手脚。 模型负责推理和决策,工具负责执行。切勿混淆二者。
- 流式优先。 每一次交互都实时流式传输 token 和事件。批量式的请求-响应对开发者体验而言是行不通的。
- 安全是架构问题,而非一项功能。 权限检查、路径校验和用户确认被内建进 Agent 循环本身 —— 而不是事后再补上去的。
- 上下文窗口是最稀缺的资源。 每一项设计决策 —— 从工具结果的格式化到对话历史的管理 —— 都必须考虑上下文预算。
- 工具描述就是提示词。 工具 description 字段里的文字实际上就是系统提示词的一部分,要以同样的用心去撰写。
- MCP 标准化了工具生态。 一套共享协议意味着工具可以在不同 Agent 之间移植,正如 REST 标准化了 Web API 一样。
- 状态机驱动对话管理。 显式的状态转换让 Agent 循环变得可预测、可调试、更安全。
结语
AI 编程看起来像魔法。但把它拆开来看,本质却出奇地简单:一个循环、一组工具、一套权限系统。
循环调用 LLM,LLM 挑选一个工具,工具执行,结果再反馈回循环。如此反复,直到任务完成。所有的复杂性 —— 流式输出、安全、上下文管理、插件系统 —— 都不过是围绕这个核心循环的展开与精细化。
理解这些内部机制,不只是满足好奇心。它给了你一套框架,去评估该采用哪些工具、如何扩展它们,以及真正的技术护城河在哪里(提示:护城河更多不在于循环本身,而在于工具和提示词)。
参考项目:
- Amazon Q Developer CLI (Rust)
- Claude Code (TypeScript + Python)
参考资料
- Claude Code repository — GitHub
- Claude Code documentation — Anthropic
- Anthropic engineering blog — Anthropic
- Model Context Protocol — MCP Documentation