我们将涵盖构建编码框架的所有内容:Agent 循环、规划、子 Agent、沙盒、记忆和检查点,逐步构建。
如果你曾经尝试构建自己的编码 Agent,你就会知道会发生什么。你把模型连接到文件工具和 Shell 上,把它指向一个真正的代码库,然后它往往在十几个工具调用之内就崩溃了。
它读取错误的文件,在半途中丢失目标,并用不再需要的输出填满自己的上下文。
然后,同样的任务经由 Claude Code 处理,却能干净利落地完成。一个简单的结论是,Anthropic 只是拥有更好的模型,而这个结论忽略了真正发生工作的环节。
区别在于框架。框架是包裹在模型周围的普通代码,它处理规划、工具执行、记忆和安全,而模型只决定下一步动作。
这是完全搭建好的框架画出来的样子:

GIF
这张图看起来很复杂,但它可以分解为四个部分:
- 记忆 为模型提供工作上下文以及跨会话学到的事实。
- 技能 编码了 Agent 应该如何运作,即它遵循的程序、约束和启发式规则。
- 协议 将 Agent 连接到用户、工具和其他 Agent。
- 框架核心 通过子 Agent 编排、沙盒、评估器、审批循环、可观测性和上下文压缩,将所有内容整合在一起。
Anthropic 将这种划分描述为大脑和双手。模型是选择每个动作的大脑,而框架是执行这些动作并保持运行在正轨上的双手。
所以,你的 Agent 和 Claude Code 之间的差距不在于模型,而在于模型周围的机制。
Claude Code 是目前生产环境中能力最强的框架之一,它由该插图中数量少得惊人的层构建而成。为了了解你需要自己构建多少这样的机制,我在 CrewAI(一个用于编排 Agent 的开源框架)中重建了它。
比我预想的更多功能映射到了内置特性上,而其余部分正是真正的工程所在。
让我们逐层构建,从核心循环开始,然后叠加规划、子 Agent、沙盒和记忆。在每一步,我们都会标记出框架的边界,以及你的工作从何开始。
Claude Code 框架的工作原理
Claude Code 的核心是一个简单的 Agent 循环。你向它发送一条消息,模型决定下一步做什么,然后它要么直接响应,要么请求一个工具。如果它请求工具,工具就会运行,结果会返回到对话中,然后模型再次决定。
这个循环会一直重复,直到模型返回一个最终答案,且不再进行任何工具调用。
在这个循环内部,模型会读取文件、编辑代码、运行 Shell 命令和执行测试。这些并不是独立的模式,它们只是同一个循环中的不同工具调用。
然而,仅靠循环本身不足以构建一个可靠的编码 Agent。Claude Code 在其周围添加了规划、文件工具、子 Agent、记忆以及权限和沙盒系统。这些层并不取代循环,而是使其足够安全可靠,以用于实际工作。

这就是我们将要重建的架构,首先是核心循环,然后在其上叠加每一层,并将每一层映射到处理它的 CrewAI 特性。
核心 Agent 循环
循环会重复执行相同的序列,直到任务完成:
- 要求模型执行任务。
- 模型直接响应,或请求一个或多个工具。
- 如果请求了工具,则运行它们并将结果返回给模型。
- 使用更新后的对话重复第 2 步。
- 当模型响应而未请求任何工具时,任务完成。

1while True:2 reply = model(messages, tools)3 calls = [b for b in reply if b.type == "tool_use"]4 if not calls: # 纯文本,无工具调用:任务完成5 return reply.text6 messages += [reply, run_all(calls)]
每个工具调用完成一个步骤,为模型提供新信息,并反馈到下一个决策中。一个简单的问题可能在一个迭代内完成,而修复一个复杂的 bug 或重构一个大型代码库可能需要数十次迭代,模型才能获得足够的信息来生成最终答案。
一旦你创建了 Agent,CrewAI 就会自动提供这个执行循环。你不需要自己实现 while 循环,只需定义 Agent 并为其分配任务。
构建第一个 Agent
让我们创建一个简单的 Bug 修复 Agent。
1from crewai import LLM, Agent, Crew, Task23bug_fixer = Agent(4 role="Bug Fixer",5 goal="Find and describe the fix for the reported bug in the codebase.",6 backstory="You read directories and files to build an accurate picture of the code.",7 llm="claude-sonnet-4-6",8)910task = Task(11 description="Find the fix for {objective}.",12 expected_output="A short description of the fix and which file it belongs in.",13)1415result = Crew(agents=[bug_fixer], tasks=[task]).kickoff(16 inputs={"objective": "the overdraft bug in account.py"}17)
这里需要理解三个概念:
- Agent 定义了谁来做工作,通过其角色、目标、LLM 和工具。
- Task 描述了任务分配。
- Crew 将 Agent 和任务结合在一起。调用 kickoff() 会运行上述相同的执行循环,无论底层模型是 Anthropic、OpenAI、Google 还是其他。
为 Agent 提供工具
工具让一个只能生成文本的模型能够真正作用于代码库。它们可以读取文件、写入文件、运行 Shell 命令以及调用外部 API。
CrewAI 原生提供了文件系统工具:
- FileReadTool 读取文件。
- DirectoryReadTool 列出目录。
- FileWriterTool 写入文件。
1from crewai_tools import DirectoryReadTool, FileReadTool, FileWriterTool23read_file = FileReadTool()4write_file = FileWriterTool()5list_dir = DirectoryReadTool()67filesystem_tools = [read_file, write_file, list_dir]
这些工具也可以充当外部记忆。Agent 不是将大型搜索结果保留在模型的上下文窗口中,而是可以将其写入文件,只保留文件名,并在需要时再读回来。
这保持了上下文窗口更小,模型更专注,Anthropic 称之为上下文工程。

内置工具只覆盖常见的工作流程。对于更具体的情况,你可以使用 @tool 装饰器将 Python 函数暴露为工具。
文档字符串充当了使用说明书,告诉模型该工具的作用、何时使用以及期望的输入是什么。
1from crewai.tools import tool2import subprocess34@tool("run_tests")5def run_tests(path: str = "tests/") -> str:6 """Run the pytest suite at the given path and return the result."""7 result = subprocess.run(8 ["pytest", path, "-q"], capture_output=True, text=True, timeout=1209 )10 output = result.stdout + result.stderr11 return output[-4000:] if len(output) > 4000 else output
规划长时间运行的任务
随着任务变得越来越复杂,一个简单的执行循环开始丢失原始目标。在足够多的工具调用、文件读取和中间结果之后,上下文被填满,目标被后续的一切所淹没。
这种缓慢的退化被称为上下文腐烂。
规划直接解决了这个问题。Agent 在执行任何工作之前会构建一个逐步计划,并在整个执行过程中将该计划保留在上下文中。
计划本身并不执行工作,它是一张路线图,使模型与原始目标保持连接,这与 Claude Code 的待办事项清单功能相同。

CrewAI 通过在 Crew 级别设置 planning=True 来添加此功能。它在执行前生成一个计划,并在任务进行过程中保持其可用性。
1from crewai import Crew, LLM23crew = Crew(4 agents=self.agents,5 tasks=self.tasks,6 planning=True,7 planning_llm=LLM(model="gpt-4o-mini"),8)
注意:默认情况下,CrewAI 使用 gpt-4o-mini 进行规划,你可以为此步骤替换任何你喜欢的 LLM。
单个 Agent 也可以使用 reasoning=True 来推理自己的工作:
1from crewai import Agent23bug_fixer = Agent(4 role="Bug Fixer",5 goal="Find and describe the fix for the reported bug in the codebase.",6 backstory="You read directories and files to build an accurate picture of the code.",7 tools=[FileReadTool()],8 reasoning=True,9 max_reasoning_attempts=3 # 可选:设置最大推理尝试次数10)
规划和推理解决不同的问题。规划为整个任务构建一个高层路线图,而推理则让一个 Agent 在行动前有时间思考自己的方法。
当启用推理时,Agent 会:
- 反思任务并起草一个执行计划。
- 评估计划是否就绪。
- 如果需要,完善计划,直到满意或达到 max_reasoning_attempts。
- 在执行前将最终确定的推理计划注入到任务中。

它们一起使 Agent 在长时间运行的任务中保持锚定,并减少偏离原始目标的漂移。
使用子 Agent 进行委派
规划让 Agent 保持专注,但并不能减少模型必须处理的信息量。在一个大型代码库上,即使是规划良好的任务也可能超出单个上下文窗口。
找到一个 bug 可能需要读取数十个文件,而主 Agent 不需要记住所有这些文件。
子 Agent 通过委派解决了这个问题。主 Agent 将特定任务交给一个辅助 Agent,该辅助 Agent 在自己的上下文中工作,并返回一个简短摘要。主 Agent 看到的是结论,而不是中间步骤。

CrewAI 通过层级工作流支持这一点,其中管理 Agent 将任务委派给专门的 Agent,并组合它们的结果。
在我们之前的设置中,一个 Bug 修复 Agent 完成了所有繁重的工作。让我们将工作拆分给一个管理者和三个专家:
- Codebase Explorer 探索代码并映射仓库。
- Software Engineer 实施请求的更改。
- Test Runner 在沙盒中运行测试并报告通过或失败。
- Engineering Lead 监督这三个专家。

1from crewai import Crew, Agent, Task, Process23explorer = Agent(4 role="Codebase Explorer",5 goal="Map the repository and surface the files relevant to the task.",6 backstory="You read directories and files to build a picture of the code.",7 tools=[read_file, list_dir],8 llm=llm,9) # 其他两个专家 Agent 类似1011manager = Agent(12 role="Engineering Lead",13 goal="Break the request into steps and delegate each to the right specialist.",14 backstory="You decide who does what, review tests, finish once change is done.",15 llm=llm,16 allow_delegation=True,17)1819crew = Crew(20 agents=[explorer, coder, tester],21 tasks=[task],22 manager_agent=manager,23 process=Process.hierarchical,24)
需要注意的一点是,allow_delegation 默认是禁用的,因此必须在管理者上显式启用。
沙盒化:保护 Agent 执行
一个具有 Shell 访问权限的 Agent 可以运行破坏性命令,而告诉模型不要做某事并不是一种安全措施。
真正的保护来自两个层面:
- 权限系统,要求对敏感操作进行审批。
- 沙盒,隔离执行环境,这样即使已批准的命令也无法触及宿主机。
Anthropic 使用了相同的方法。将代码执行移到沙盒中,可以减少用户需要审批操作的频率,同时仍然保护宿主系统。

CrewAI 中的沙盒化
在沙盒内而不是在宿主机上执行代码,应用了第二个层面。在这种设置中,代码在 E2B 内部运行,它会为每个会话启动一个全新的虚拟机,并在会话结束后销毁它。
Shell 命令和 Python 完全在这个隔离的环境中运行。

1from crewai_tools import E2BExecTool, E2BPythonTool2sandbox_tools = [E2BExecTool(), E2BPythonTool()] # 运行测试 / 运行代码
人机协同审批
在 Task 上设置 human_input=True 会在 Crew 生成答案后暂停。你审查输出,然后批准它或将其发回进行另一次迭代。
当执行到该任务时,CrewAI 会通过标准输入等待你的反馈。
1from crewai import Task23task = Task(4 description=(5 "In the working directory ./workspace, {objective}. "6 "Explore the code first, make the change, then run the tests and report."7 ),8 expected_output="A summary of the files changed and the final test output.",9 human_input=True,10)
如果你的 Crew 在 Web 应用或聊天界面(而不是终端)后面运行,CrewAI 基于 Webhook 的人机协同系统会处理相同的审查步骤。
记忆和检查点
默认情况下,Agent 在运行结束后会忘记一切。如果你第二天回来修复同一个项目中的另一个 bug,它会从零开始。
两种机制允许 Agent 跨运行携带信息,每种机制服务于不同的目的:
- 检查点 在运行期间保存 Agent 的状态,这样它可以在中断后恢复,或者从同一点沿不同路径继续。
- 持久记忆 跨独立对话存储事实,包括项目偏好,例如“在完成前始终格式化最终代码”。

CrewAI 中的记忆
CrewAI 提供了一个统一的 Memory 接口,而不是单独的短期记忆、长期记忆、实体记忆和外部记忆类型。保存时,它使用 LLM 来识别重要细节、组织它们,并使它们以后可检索。
在 Crew 上设置 memory=True 会为其提供跨运行记忆。在每个任务之后,CrewAI 会从输出中提取有用的事实并存储它们,在未来的运行中,它会检索相关记忆并将它们添加到任务提示中。

1from crewai import Crew23crew = Crew(4 agents=[explorer, coder, tester],5 tasks=[task],6 memory=True,7)
Crew 中的所有 Agent 共享其记忆,除非某个 Agent 被赋予了自己的记忆。
CrewAI 中的检查点
检查点是 Agent 进度的快照,包括其配置、任务状态、记忆、中间结果、输入和执行历史。
默认情况下,CrewAI 在每个任务完成时创建一个检查点,允许工作流在中断时从该点恢复。
检查点可以存在于两个内置存储之一:
- JsonProvider 将每个检查点保存为单独的 JSON 文件,便于手动读取和检查。
- SqliteProvider 将所有检查点存储在单个 SQLite 数据库中,在频繁检查点和更大工作负载下表现更好。

1from crewai import Crew23crew = Crew(4 agents=[explorer, coder, tester],5 tasks=[task],6 checkpoint=True,7)
Crew、Flow 和 Agent 都接受一个 checkpoint 参数,子元素继承父元素的值,除非它们自行设置。
整合在一起
以下是完整的框架在一个任务上的应用,包含了执行循环、工具、规划、子 Agent、沙盒化和记忆:
1from crewai import Agent, Crew, LLM, Process, Task2from crewai.tools import tool3from crewai_tools import (DirectoryReadTool, FileReadTool, FileWriterTool,4E2BExecTool, E2BPythonTool)56llm = LLM(model="anthropic/claude-sonnet-4.6")78list_dir = DirectoryReadTool(directory="./workspace")9filesystem_tools = [FileReadTool(), FileWriterTool(), list_dir]10sandbox_tools = [exec_tool, E2BPythonTool()]1112@tool("run_tests")13def run_tests(path: str = "tests/") -> str:14 """Sync ./workspace into the sandbox, then run pytest there."""15 return E2BExecTool().run(command=sync_and_test_command(path))1617explorer = Agent(role="Codebase Explorer", goal="Map repo, surface relevant files.",18 tools=[read_file, list_dir], llm=llm)19coder = Agent(role="Software Engineer", goal="Implement requested change.",20 tools=filesystem_tools, reasoning=True, llm=llm)21tester = Agent(role="Test Runner", goal="Run tests in sandbox, report pass/fail.",22 tools=sandbox_tools + [read_file] + [run_tests], llm=llm)23manager = Agent(role="Engineering Lead", goal="Delegate steps, finish once tests pass.",24 allow_delegation=True, llm=llm)2526task = Task(27 description="In ./workspace, {objective}. Explore, edit, test, report.",28 expected_output="Summary of changes and test output.", human_input=True,29)30crew = Crew(31 agents=[explorer, coder, tester], tasks=[task],32 manager_agent=manager, process=Process.hierarchical,33 planning=True, memory=True, checkpoint=True,34)35result = crew.kickoff(inputs={"objective": "fix failing tests in account.py"})
Agent 框架在成功可以自动检查时最容易评估。测试套件为 Agent 提供了一个具体的目标,因此它可以规划、编辑、测试并重复,直到所有测试通过。
因此,这是针对一个小型代码库进行测试的,一个 BankAccount 类,包含两个真实的 bug 和五个测试,其中三个测试失败。规则是只修复实现,不修改测试。
这反映了 Anthropic 内部评估编码 Agent 的方式。一个已发布的例子是,Claude 针对一个大型失败测试套件重建了 claude.ai 界面的克隆。
在这里,框架将项目从 3 个失败、2 个通过,变成了全部 5 个通过,并且只修改实现的规则关闭了编辑或删除失败测试这一捷径。

仍然需要你来做的工作
系统的某些部分不是框架为你构建的:
- 提示词。 每个 Agent 的行为来自其角色、目标和背景故事。让它们正确工作需要测试和迭代,没有配置标志可以替代。
- 执行环境。 沙盒,无论是 E2B 还是自管理的虚拟机,都需要设置并连接起来。
- 工具选择。 每个 Agent 获得哪些工具,以及哪个 Agent 应该拥有什么访问权限,是框架不会替你做出的设计决策。
框架本身也有成本。规划、子 Agent 和循环都会增加 API 调用,因此一个复杂的 Agent 设置最终可能比一个单次模型调用就能直接解决的任务更昂贵。
还有一个值得注意的长期限制。随着模型改进,一些脚手架变得不再必要,因为今天构建到框架中的某些内容,是对今天模型限制的变通办法,而不是永久需求。
Anthropic 最初使用上下文重置来防止 Claude Sonnet 4.5 过早结束任务,而随着能力更强的 Claude Opus 4.5 的出现,这些就不再需要了。

总结
这就是全部发现。编码 Agent 的能力主要存在于框架中,而编排框架为你提供的框架组件比你预想的要多。
循环、规划、委派、沙盒化和记忆都以配置项的形式出现,而提示词、执行环境和工具选择则仍然由你负责。
如果你想在自己的代码库上运行这个,CrewAI 的文档涵盖了这里使用的所有特性,并且该框架是完全开源的。
感谢阅读!
干杯! :)





