Claude-Code-智能体编程-二-
Claude Code 智能体编程(二)
原文:Agentic Coding with Claude Code
译者:飞龙
图 4.24 – 通用 MCP 配置在启动时加载所有工具
大多数设置遵循此模式。单一的通用 MCP 配置用于加载所有 MCP 服务器和工具。初衷是为智能体配备它可能需要的一切。
结果是每个会话都加载所有 MCP 服务器和所有 MCP 工具,即使它们不相关。这在编写任何提示词之前就可能消耗数万个 Token。
在本节中,我们介绍此问题并演示如何使用上下文工程技术来修复它。
示例仓库和 MCP 服务器
本节使用的代码可在本书 GitHub 仓库的context‑engineering‑mcp分支中找到。要访问仓库链接,请遵循前言中下载示例代码文件部分的步骤。我们从第一次提交开始,以便完全复现设置。
该仓库包含一个在verbose_mcp_server.py中实现的简单 MCP 服务器。该服务器使用 FastMCP 编写,并暴露了大量 MCP 工具,包括以下内容:
-
add_two_numbers -
subtract_two_numbers -
multiply_two_numbers
该服务器有意包含许多不需要的 MCP 工具。每个工具还包含详细描述。示例如下:
图 4.25 – 冗长的 MCP 工具定义增加上下文大小
这些描述有助于 MCP 客户端决定是否应调用工具,但它们也直接增加了上下文大小。
运行 MCP 服务器
MCP 服务器使用 UV 包管理器运行。仓库包含一个定义 FastMCP 依赖项(github.com/PrefectHQ/fastmcp)的uv.lock文件。请遵循以下步骤:
-
运行
uv sync并使用以下命令激活虚拟环境:source .venv/bin/activate -
环境激活后,FastMCP CLI(
github.com/jlowin/fastmcp)即可使用。我们使用fastmcp run verbose_mcp_server.py ‑‑transport http启动 MCP 服务器。
繁冗数学运算 MCP 服务器
繁冗数学运算 MCP 服务器现已使用可流式 HTTP 传输运行,并暴露在 http://127.0.0.1:8000/mcp。
将运行中的 MCP 服务器添加到 Claude Code
我们需要检查 MCP 服务器及其工具在加载到会话后如何影响上下文。在 MCP 服务器本地运行的情况下,我们打开 Claude Code 并添加此 MCP 服务器。
为此,我们创建一个项目级 MCP 配置文件,名为 .mcp.json。
如果我们返回仓库并检查分支,有一个标题为添加基于项目的 MCP 配置的提交。此配置可直接复制,按需添加 API 密钥。示例中显示的 API 密钥已进行混淆处理。
项目级 MCP 配置
项目级 MCP 配置定义了四个 MCP 服务器:
-
一个本地运行的繁冗 MCP 服务器
-
Context7,此前已介绍过 (https://context7.com/)
-
Tavily (https://tavily.com/),用于搜索互联网、爬取网站和提取网页
-
Playwright MCP,用于浏览器自动化
图 4.26 – 定义在 mcp.json 中的包含多个服务器的项目级 MCP 配置
这是一个项目级配置,意味着当从项目目录启动 Claude Code 时,所有四个 MCP 服务器都会自动加载。
配置中的 API 密钥已进行混淆处理。
要验证配置是否正确应用,请执行以下步骤:
-
打开终端。
-
切换目录到项目文件夹。
-
确认你位于
context-engineering-mcp分支。 -
运行 Claude Code。
-
运行
/mcp确认所有四个 MCP 服务器均已连接。
图 4.27 – Claude Code 中连接的多个 MCP 服务器。
检查上下文使用情况
接下来,我们运行 /context 以检查当前会话的上下文使用情况。
此时,尽管尚未编写任何提示词,我们已经接近上下文窗口的一半。/context 的输出揭示了可用 Token 的分布情况。
图 4.28 – MCP 工具消耗了上下文窗口的大部分
细分情况如下:
-
约 2,000 个 Token 用于 Claude Code 的系统提示词
-
Claude Code 的系统工具消耗了约 12,000 个 Token
-
MCP 工具描述消耗了接近 20% 的上下文窗口
没有消息。没有记忆文件。未配置子代理。
如果存在子代理,它们也会出现在上下文中,包括描述如何以及何时使用它们的说明。
在此阶段,上下文窗口已消耗近 50%。
视任务而定,许多 MCP 服务器,尤其是繁冗数学 MCP 工具,都是不必要的。
通过限定 MCP 配置范围来减少上下文
为减少上下文使用,必须更严格地限定 MCP 配置范围。
执行以下步骤:
-
删除项目级
.mcp.json文件。 -
创建一个名为
.mcp.json.tavily的新文件。 -
从仓库复制 Tavily MCP 配置。
-
将其粘贴到
.mcp.json.tavily中。
图 4.29 – 使用 mcp.json.tavily 的限定范围 MCP 配置。
此配置现在仅包含 Tavily MCP 服务器。
接下来,使用限定范围的配置启动 Claude Code:
返回终端并运行以下命令:
claude --mcp-config .mcp.json.tavily
--mcp-config 标志接受以空格分隔的 MCP 配置文件路径。
Claude 启动时,我们再次使用 /mcp 检查 MCP 服务器。
图 4.30 – 使用限定范围配置的活动 MCP 服务器。
此时,我们看到了预期的 Tavily MCP。然而,我们也看到了繁冗 MCP 服务器和 Context7。Playwright MCP 服务器不再存在。
发生这种情况是因为 Claude Code 仍在从用户级 MCP 配置加载 MCP 服务器,其中包含 Context7、Tavily 和繁冗 MCP 服务器。
强制执行严格的 MCP 配置
为确保仅加载预期的 MCP 配置,必须强制执行严格配置。
运行以下命令:
claude --mcp-config .mcp.json.tavily --strict-mcp-config
--strict-mcp-config 标志指示 Claude Code 忽略默认的 MCP 层级结构,仅加载指定配置文件中定义的 MCP 服务器。
让我们验证结果:
-
运行
/mcp并确认仅加载了 Tavily MCP 服务器。 -
运行
/context并验证 MCP 工具的上下文使用量显著减少,因为仅 Tavily MCP 服务器处于活动状态。
图 4.31 – 启用严格 MCP 配置后的上下文使用情况
MCP 相关上下文使用量从近 20% 下降至约 2.4%。
这使代理能够保持专注,并避免为当前任务(本例中为研究)携带不必要的工具上下文。
在会话中动态管理 MCP
除了基于配置的限定范围外,MCP 服务器还可以在会话中动态管理。
为此,请执行以下步骤:
-
恢复通用的项目级
.mcp.json配置。 -
重启 Claude Code。
-
禁用繁冗 MCP 服务器。
-
禁用 Playwright MCP 服务器。
-
运行
/mcp确认两个服务器均已禁用。 -
运行
/context。
图 4.32 – 禁用选定服务器后的 MCP 上下文使用情况
MCP 相关上下文使用量现在约为 3.2%。
此方法允许使用 CLI 在会话中直接启用或禁用 MCP 服务器,而无需修改 MCP 配置文件。
MCP 的当前局限性
MCP 旨在标准化代理连接数据的方式。然而,其当前实现引入了若干缺点。这些局限性主要源于 LLM 上下文的管理方式以及代理任务的执行方式。
图 4.33 – LLM 与外部 API 之间的 MCP 抽象层
因此,代理可能比预期更慢、更昂贵且效果更差。没有完美的协议,MCP 也不例外。
上下文污染
MCP 最大的问题是上下文污染。MCP 要求工具定义预先加载到模型的上下文中。这些定义(包括所需参数和预期输出)被放入系统提示词中。
图 4.34 – 预加载 MCP 工具定义导致的上下文污染
由于必须预加载所有工具定义,这产生了巨大的 Token 开销。要使用 MCP 服务器,代理必须接收每个可用工具的定义。
在包含 GitHub MCP、Slack MCP 和 Central MCP 等服务器、共 58 个工具的配置中,工具定义 allein 可在对话开始前消耗 55,000 个 Token。在某些情况下,工具定义可消耗数十万 Token。
在 LLM 应用和代理系统中,上下文是必须优化的主要资源。当上下文被工具定义饱和时,代理会携带大量无关信息。
过多的 MCP 工具导致上下文膨胀
例如,一个负责修改前端页面的智能体,仍会携带数千行与无关工具(如数据库工具或 PDF 阅读器)相关的上下文。这些无关数据会在对话的每一步和每一次迭代中持续存在。
图 4.35 – 过多 MCP 工具导致的“大海捞针”问题
随着无关定义填满上下文,模型性能下降。模型必须在海量信息中搜索,导致产生幻觉、指令跟随失败或工具选择错误的可能性增加。上下文污染越严重,模型定位相关信息就越困难。
低效的智能体执行
除了上下文管理,MCP 还给智能体执行带来了低效问题。
图 4.36 – 重复 MCP 工具调用导致的低效智能体执行
传统的 MCP 用法依赖“乒乓式”交互模式。每个动作都需要一个完整的往返过程:
-
模型请求工具。
-
工具执行。
-
结果被追加到对话历史中。
-
整个更新后的历史被发回模型以确定下一步。
当需要多次工具调用时,这个过程会迅速膨胀。即使中间结果对于生成最终答案并非必要,它们仍会累积在上下文窗口中。虽然其中一些结果在后续阶段本可移除,但当前的 MCP 实现会保留它们,进一步污染上下文。
图 4.37 – 模型、客户端与服务器之间的 MCP 工具调用往返
每次往返都需要一次额外的 LLM 推理。多次推理增加了延迟和成本。随着工具调用规模扩大,模型调用次数也随之增加,导致执行变慢、开支变大。
“母语”问题——JSON 与代码
MCP 还强迫 LLM 以一种不符合其训练方式的模式运行。
图 4.38 – LLM 训练与工具调用格式的对比
该协议严重依赖结构化的工具调用令牌和 JSON Schema。然而,LLM 主要是在自然语言文本和代码上训练的,而非专门的工具调用语法令牌上。
尽管模型厂商已提升了工具调用的可靠性,但这种格式并非模型的原生运行模式。文本和代码是 LLM 更自然的表达形式。特别是代码,比基于 JSON 的工具调用机制更贴近训练数据和模型能力。
这种错位在模型的训练分布与 MCP 要求的结构化交互风格之间制造了摩擦。
工具定义与 Schema 的局限性
MCP 工具定义和 JSON Schema 描述了工具的样子:其参数、输入和输出。然而,这些 Schema 无法捕捉使用模式。
图 4.39 – JSON Schema 在工具用法上的局限
使用模式包括何时应使用工具、如何在上下文中使用工具,以及何时不应使用工具。这比单纯的结构定义是一个更深层的概念。
即使提供了指导工具使用的指令,Schema 本身也无法编码这些行为约束。因此,该协议定义了结构,却未定义意图或正确的应用模式。
Cloudflare 的 CodeMode
Cloudflare 首先在一篇博客文章(https://blog.cloudflare.com/code-mode/)中推出了 CodeMode,这是一种旨在改变智能体与 MCP 工具交互方式的执行模型。
这一思路旨在解决前述关于 MCP 的缺点,特别是由多次 LLM 调用导致的上下文膨胀和延迟增加。
Cloudflare 建议不按常规方式使用 MCP,而是将 MCP 中的所有工具定义、工具接口和工具实现转换为 TypeScript API。LLM 不再通过工具调用来选择调用哪个工具,而是被要求生成使用该 TypeScript API 的代码。
图 4.40 – Cloudflare CodeMode 以代码执行取代工具调用
在此模型中,LLM 生成需执行的完整代码。生成的代码包含多个以函数调用形式实现的工具调用。随后,该代码在沙箱中一次性执行。
这种方法减少了工具调用中的往返次数。LLM 编写代码在内部执行调用序列,而非反复进行“调用工具、接收结果、再调用工具”的循环。主要优势在于 LLM 擅长编写代码。编写代码是 LLM 的常规任务,且其拥有海量代码训练数据。因为代码只需编写一次、执行一次,工具定义无需重复发送,从而减少了 Token 消耗。
关键观察
Cloudflare 指出,MCP 常被用于直接向 LLM 暴露工具。在 CodeMode 中,MCP 工具被转换为 TypeScript API,LLM 编写代码来调用该 API。
据报告,智能体因此能处理更多工具和更复杂的工具。MCP 的一个问题是工具过多会增加上下文大小,进而增加成本和延迟并降低性能。当工具以 TypeScript API 而非直接工具定义的形式呈现时,性能会提升。解释在于 LLM 训练中见过大量真实的 TypeScript 代码,但仅见过极少量人为构造的工具调用示例。
当必须将多个调用串联在一起时,该方法被描述为特别有效。在传统 MCP 用法中,每次工具输出必须传回 LLM 后才能进行下一次调用。这种重复消耗时间、精力和 Token。当 LLM 编写代码时,它在内部完成所有调用,仅返回最终结果。
得出的结论是:LLM 编写代码来调用 MCP,比直接调用 MCP 表现更好。
工具调用及其约束
在传统 MCP 用法中,LLM 生成代表工具调用的特殊令牌。这些令牌被解析以提取函数名和参数。系统随后执行函数并返回结果。
这些特殊的工具调用令牌在真实世界数据中并不常见。它们是在训练期间引入的句法构造。尽管模型厂商显著提升了工具调用性能,但该机制本质上仍是合成的。
当暴露过多工具或过于复杂的工具时,LLM 可能难以选择正确的工具,或错误地使用它们。因此,建议 MCP 服务器设计者简化 API,使其更适合 LLM 消费。
相比之下,LLM 处理完整编程 API 更有效。它们无需简化即可分析复杂 API 并生成代码。区别在于 LLM 见过大量真实代码,却极少见到真实的工具调用。
文中提供了一个类比:让 LLM 用工具调用执行任务,相当于让莎士比亚速成中文后要求他用中文写剧本。暗示是工具调用并非模型的强项。
MCP 的角色
MCP 依然有用,因为它提供了一种连接智能体与工具的统一方法。MCP 工具代表带有文档的 RPC 接口。大多数 MCP 服务器封装了现有的传统 API。
与其将 MCP 工具直接暴露为可调用工具,CodeMode 会将它们转换为编程语言 API。尽管传统 API 已经存在,但 MCP 提供了一种统一的方式来连接并了解这些 API,这在基于代理的系统中依然很有价值。
集成 CodeMode
Cloudflare 扩展了其 Agent SDK 以支持 CodeMode。在典型的 AI SDK 设置中,模型配置包含系统提示词、用户消息和工具。在 CodeMode 中,工具和提示词会使用 CodeMode 辅助函数进行封装。
例如,考虑一个使用 Cloudflare AI SDK 构建的应用程序,其代码如下:
const stream = streamText({
model: openai("gpt-5.3"),
system: "You are a helpful research assistant.
Your job is to help the user...",
messages: [
{ role: "user", content: "Research on deep agents" }
],
tools: {
research agent's tool definition
}
})
使用 CodeMode 时,系统提示词和工具定义会在传递给应用程序之前,通过 codemode 辅助函数进行封装。
import { codemode } from "agents/codemode/ai";
const { system, tools } = codemode({
system: " You are a helpful research assistant.
Your job is to help the user...",
tools: [
research agent's tool definition
],
})
完成此更改后,应用程序会生成并执行调用所定义工具(包括 MCP 服务器)的 TypeScript 代码。
将 MCP 转换为 TypeScript
当在 CodeMode 中连接到 MCP 服务器时,Agent SDK 会获取 MCP 服务器的 Schema 并将其转换为 TypeScript API。生成的 API 包含源自 Schema 的 TypeScript 定义和文档注释。
这些 TypeScript 定义会被加载到代理的上下文中。目前整个 API 会一次性加载,尽管未来的改进可能允许动态搜索或浏览 API。
尽管一次性加载整个 API 仍会增加上下文大小,但这仅在初始化时发生一次。随后 LLM 读取 API 并生成代码。由于 LLM 擅长处理代码,这种方法利用了这一优势。
在沙箱中执行
在 CodeMode 中,代理获得的是一个用于执行 TypeScript 代码的单一工具,而不是直接呈现所有 MCP 工具。
生成的代码运行在一个与互联网隔离的安全沙箱中。沙箱只能通过代表已连接 MCP 服务器的 TypeScript API 来访问外部系统。
当沙箱代码调用 API 函数时,调用会通过 RPC 经由代理循环路由回 MCP 服务器。沙箱使用 console.log() 返回结果。执行完成后,日志会返回给代理。
在传统 MCP 流程中:
-
代理从 MCP 服务器接收工具 Schema。
-
LLM 调用包含与 MCP 工具匹配的工具定义。
-
LLM 输出用于函数调用的特殊 Token。
-
代理解析并执行工具调用。
-
过程重复。
而在 CodeMode 中:
-
代理从 MCP 服务器检索工具 Schema。
-
LLM 调用包含源自这些 Schema 的 TypeScript API。
-
LLM 针对该 API 编写 TypeScript 代码。
-
代码在沙箱中执行。
-
沙箱通过 RPC 绑定与 MCP 服务器交互。
-
最终日志返回给代理。
下图展示了传统 MCP 执行与 CodeMode 之间的架构对比。
Figure 4.41 – Traditional MCP vs Code Mode execution flow
CodeMode 作为一种替代执行模型呈现,它依赖于 LLM 生成代码的能力,同时保留 MCP 作为统一的集成层。
使用 Claude Code 插件管理配置
请查阅官方文档参考:code.claude.com/docs/en/plugins。
插件将斜杠命令(技能)、子代理、MCP 服务器和钩子捆绑成一个可共享的原语。这些插件可以在团队内部共享,或发布到开源社区,从而在各环境中实现复用和一致性。
在引入插件之前,复用配置需要大量的手动工作。例如,要使用开源仓库中的一个斜杠命令,我们必须导航到该仓库,复制斜杠命令,并将其粘贴到本地 .claude 目录中。子代理和钩子也适用相同流程。MCP 服务器遵循不同的设置流程,但整体工作流仍然是手动且碎片化的。
Claude Code 插件通过将所有这些组件捆绑到一个可无缝安装和集成的插件中来解决此问题。插件可以来自开源仓库或内部仓库,并跨团队共享。
Claude Code 提供了一个直观且易用的基于 CLI 的插件系统。
插件系统的优势
插件的主要优势之一是能够跨团队共享统一的 Claude Code 设置。例如,新员工入职时,我们可能希望他们拥有与团队其他成员相同的工具、相同的代理和子代理,以及相同的 MCP 服务器。插件提供了一种标准化 Claude Code 开发环境的机制。
插件还支持细粒度安装。我们可以不安装整个插件,而仅安装特定组件,例如单个 MCP 服务器。
此外,Claude Code 引入了一个称为 marketplace(市场)的新原语。Marketplace 由一个描述可安装插件的 JSON 文件表示。
值得注意的是,Google 的 Gemini CLI 引入了一个类似的概念,称为 Gemini Extensions。Gemini Extensions 于 2025 年 10 月 8 日发布,而 Claude Code 插件于 2025 年 10 月 9 日发布。这仅差一天的时间差表明,要么是 Claude Code 团队进行了极快的迭代,要么是两个团队在同时实现同一个想法。
探索官方插件市场
为了了解插件如何工作,我们从 Claude Code 课程仓库开始。
在 Claude Code 开源仓库中,有一个 .claude‑plugin 目录。该目录内包含一个 marketplace.json 文件。
该文件定义了官方插件市场。它列出了可用插件,并为每个插件提供元数据和源路径。
市场中列出的插件示例包括:
-
pr‑review‑toolkit -
commit‑commands -
agent‑sdk‑dev -
feature‑dev -
Security guidelines
Marketplace 作为一个注册表,Claude Code 可以加载它以发现可用插件。
向 Claude Code 添加市场
在安装插件之前,必须向 Claude Code 添加一个市场。
要添加市场,请按以下步骤操作:
-
打开 Claude Code 并运行以下命令:
/plugin -
选择 Browse 并安装插件。
-
由于最初未配置市场,请选择 Add Marketplace。
-
提供以下任一项:
-
GitHub 仓库 URL
-
指向
marketplace.json文件的直接链接
-
在本例中,提供了官方 Claude Code 仓库的基础 URL。Claude Code 会自动检测市场文件并加载可用插件。
市场文件加载后,插件列表及其描述将变为可见。
Figure 4.42 – Claude Code plugin marketplace showing available plugins
审查插件来源与安全考量
在此阶段,仅可见插件描述。要了解插件实际安装的内容,必须检查插件源代码。
marketplace.json 中的每个插件条目都包含一个 source 字段。该字段指向插件实现的位置。
安装插件之前
在安装插件之前,审查其来源非常重要。从安全角度来看,这类似于安装 MCP 服务器或使用他人编写的系统提示词和 Agent。在不审查实现的情况下安装插件会引入风险。
审查插件来源
请遵循以下步骤审查插件来源:
-
打开
marketplace.json文件。 -
定位插件条目。
-
识别
source字段。 -
在仓库中导航到该源路径。
例如,agent‑sdk‑dev 插件指向仓库内的一个目录。要检查它,请遵循以下步骤:
-
导航到仓库。
-
打开
plugins/目录。 -
打开
agent‑sdk‑dev/目录。 -
打开
.claude‑plugin/目录。 -
检查
plugin.json文件。
plugin.json 文件包含插件元数据,并定义了该插件安装的 Agent 和斜杠命令(技能)。
另一个例子是 feature-dev 插件。该插件包含多个 Agent,例如:
-
Code reviewer(代码审查员)
-
Code explorer(代码探索员)
-
Code architect(代码架构师)
它还包含一个在 feature‑dev.md 中定义的斜杠命令。该斜杠命令用于描述要实现的功能并指导工作流。
安装和管理插件
添加市场后,即可安装和管理插件。
安装插件
要安装插件,请遵循以下步骤:
-
使用
/plugin打开插件界面。 -
选择 Browse and install plugins(浏览并安装插件)。
-
定位
commit‑commands插件。 -
打开插件详情。
-
选择 Install(安装)。
-
等待安装完成。
安装后,该插件会出现在已安装插件列表中。
验证安装
要验证插件已安装并启用,请遵循以下步骤:
-
打开已安装插件列表。
-
定位
commit-commands插件。 -
确认其标记为已安装。
-
确认其已启用。
更新插件
插件由仓库支持,可随时间更新。要更新插件,请遵循以下步骤:
-
选择已安装的插件。
-
找到 Update(更新)选项。
-
应用更新。
更新插件在概念上类似于针对仓库的最新版本进行变基。
尝试卸载插件
插件界面包含卸载选项。要尝试卸载插件,请遵循以下步骤:
-
选择已安装的插件。
-
找到 Uninstall(卸载)选项。
-
尝试卸载插件。
在此阶段,卸载无法按预期工作。卸载操作不会移除插件。这似乎是当前的限制或 Bug。
Figure 4.43 – 尝试卸载 Claude Code 插件
使用 feature-dev 插件
接下来,使用 feature‑dev 插件演示完整的工作流。
继续之前,请确保该插件已安装并启用。
Figure 4.44 – Claude Code 中的 Feature-dev 插件详情
启动工作流
要启动工作流,请遵循以下步骤:
-
打开 Claude Code 并运行以下命令:
/feature-dev -
等待插件初始化。
命令执行后,Claude 进入发现阶段。此时,Claude 开始提问以了解需要实现的功能。
在 feature-dev 工作流期间处理 Git 状态
在切换分支之前,Claude Code 会检查仓库的当前 Git 状态。
此时,仓库可能包含未提交的本地更改。在不处理这些更改的情况下切换分支可能导致冲突或工作丢失。
检查 Git 状态
作为工作流的一部分:
-
Claude 检查当前工作树状态。
-
Claude 检测到存在本地未提交更改。
-
Claude 判断直接切换分支不安全。
这些检查作为 feature-dev 工作流的一部分自动发生。
暂存本地更改
为安全地继续,Claude 使用 git stash 保存当前工作状态。
在此步骤中,Claude 执行以下操作:
-
暂存当前工作目录的更改
-
确认工作树现已干净
-
继续切换分支
这确保了本地更改不会丢失。
切换分支并恢复状态
检查功能分支后,Claude 返回原始分支并恢复之前的 Git 状态:
-
Claude 切回主分支。
-
Claude 重新应用暂存的更改。
-
Claude 确认工作目录已恢复。
此时,仓库回到原始状态,本地更改保持完好。
提供功能详情
本示例中的任务是更新仓库的 README 文件。
README 文件包含一个列出课程章节的表格。一个新章节存在于名为 context‑engineering‑mcp 的 GitHub 分支中,该分支必须添加到表格中。要访问仓库链接,请遵循 Preface(前言)中 Download the example code files(下载示例代码文件)部分的步骤。
出现提示时,请执行以下操作:
-
描述所需的更改。
-
提供
context‑engineering‑mcp分支的 URL。
检查功能分支中的 README 文件
Claude 检查功能分支中的 README 文件。在此步骤中,Claude 执行以下操作:
-
切换到
context‑engineering‑mcp分支。 -
检查
README文件。 -
识别表格结构。
Figure 4.45 – 在功能分支中检查 README
切回主分支
检查功能分支后,Claude 执行以下操作:
-
切回主分支。
-
准备应用更改。
-
提出新的表格条目。
审查和优化建议的更改
Claude 为新表格条目生成初步描述。继续之前,请执行以下操作:
-
审查描述。
-
识别不准确之处。
-
优化措辞。
Figure 4.46 – 审查和优化建议的 README 更改
该描述基本正确,继续之前只需微调。
提交、推送和验证更改
变更获批后,将发生以下情况:
-
Claude 创建提交。
-
Claude 将提交推送到远程仓库。
-
刷新仓库。
-
打开
README文件。 -
验证新章节条目是否出现在表格中。
Figure 4.47 – 提交后验证 README 更新
这确认工作流成功完成。
插件市场与企业用例
Claude Code 支持第三方插件市场。
例如,DevOps 自动化市场可提供包含与基础设施工作流相关的斜杠命令、Agent 和 MCP 服务器的插件。组织还可创建供内部使用的私有市场。这些市场可包含特定于内部工具或团队的插件并保持私有。
平台公司(如 Supabase)很可能会发布自己的市场和插件,以改善与 Claude Code 的集成。
插件还支持细粒度安装。单个斜杠命令或 MCP 服务器等独立组件可单独安装,无需安装整个插件。该插件生态系统预计将不断发展,并在企业级 Claude Code 采用中发挥重要作用。
总结
在本章中,你学习了 MCP 创建的原因以及它如何解决 AI 系统中的集成问题。你探索了其核心架构:主机、客户端和服务器,并了解了 MCP 如何实现可复用的跨平台工具集成。通过实践示例,你配置并使用了 Context7 MCP,将服务器连接到 Claude,并使用 CLI 管理 MCP 设置。你还了解了糟糕的 MCP 配置如何污染上下文窗口并降低性能,以及如何通过上下文工程和作用域配置来优化使用。最后,你探索了 Claude Code 插件,考察了 MCP 的局限性,并回顾了 CodeMode 作为一种替代执行模型。
理解 MCP 非常重要,因为它正逐渐成为基于智能体 AI 开发中的基础集成层。知道如何高效地使用它以及何时对其提出质疑,将帮助你构建更具扩展性和有效性的 AI 系统。
在下一章中,我们将介绍 GitHub 仓库配置、拉取请求和议题自动化,以及 GitHub Actions 在工作流执行中的使用。
获取本书的 PDF 副本、代码包等
扫描二维码(或访问 packtpub.com/unlock)。按名称搜索本书,确认版本,然后按照页面上的步骤操作。
注意:请准备好发票。直接从 Packt 网站购买的不需要发票。
5 使用 Claude Code 和 GitHub 自动化你的开发工作流
在本章中,我们将深入探讨 Claude Code 与 GitHub 之间的集成。该集成涉及一系列配置步骤,包括安装 GitHub CLI、将其配置为与 Claude Code 协同工作,以及选择 Claude Code 将在其上运行的仓库。
配置完成后,Claude Code 可以直接在仓库中使用。它可以在拉取请求和议题中被 @提及,此时它会审查代码、提出修复建议并帮助解决报告的问题。Claude Code 还可以参与拉取请求工作流,在创建拉取请求时审查变更。
当打开拉取请求时,将使用 GitHub Actions 来运行自动化。GitHub Actions 是 GitHub 的无服务器工作流平台,通常用于 CI/CD 任务。在此设置中,GitHub Actions 执行依赖于 Claude Code CLI 和 Claude Code SDK 的工作流。
对于不熟悉 GitHub Actions 的读者,它是一个响应事件运行的自动化系统。这些事件可以包括在议题中 @提及 Claude 或打开新的拉取请求等操作。每个事件都可以根据项目需求配置为触发特定的工作流。
工作流本身使用 YAML 文件定义,通常称为 GitHub 工作流文件。这些文件描述了哪些事件应触发操作,以及响应时应执行哪些命令或脚本。
该集成已用于实际生产系统。例如,Anthropic 在其开源仓库中将 Claude Code 与 GitHub Actions 结合使用,以自动化议题处理和相关工作流。要查看公开示例,请参阅 Anthropic 的 GitHub Actions 工作流:github.com/anthropics/skills/actions。
本章将涵盖以下主题:
-
安装和配置 Claude Code GitHub 集成
-
@提及 Claude Code 以解决 GitHub 议题
-
利用项目记忆重新运行议题解决流程
安装和配置 Claude Code GitHub 集成
在本节中,我们将使用一个名为 IceBreaker (github.com/emarco177/IceBreaker) 的不同仓库来演示集成,这是一个托管在 GitHub 上的开源项目。我们仅将此仓库用于演示目的。你可以使用任何你拥有的 GitHub 仓库跟随操作。如果你选择使用自己的仓库,请确保你拥有管理员权限,因为安装 Claude GitHub 应用和配置工作流需要管理员权限。
在开始安装之前,请确保你是在一个已经初始化并连接到 GitHub 的 Git 仓库目录中运行 Claude Code。在本章中,我们使用已经配置好的 IceBreaker 仓库。集成仅在有效的 GitHub 仓库内才能工作。
要开始 GitHub 集成,从桌面打开 Claude Code 并输入 /git。这将显示 /install-github-app 命令。选择此命令将启动设置过程。
在 Claude Code 可以与 GitHub 账户集成之前,必须满足两个先决条件:
-
首先,必须在本地安装 GitHub CLI(也称为
ghCLI)。此时 CLI 尚未安装,接下来我们将安装它。 -
其次,GitHub CLI 必须经过 GitHub 账户的身份验证。Claude Code 依赖此经过验证的会话与仓库进行交互。
安装先决条件
安装命令因操作系统而异。下面的示例展示了使用 Homebrew 的 macOS。如果你使用的是 Linux 或 Windows,请参阅官方 GitHub CLI 安装文档,获取适合你平台的相应命令:cli.github.com/
要安装并验证 GitHub CLI,请完成以下步骤:
-
打开一个新的终端实例,并使用以下命令安装 GitHub CLI:
brew install gh -
安装完成后,通过运行以下命令验证 CLI 是否可用:
gh --help -
接下来,通过运行以下命令使用 GitHub 对 CLI 进行身份验证:
gh auth login
在身份验证过程中,选择 HTTPS 作为连接方式,然后通过网页浏览器登录。系统会提供一个一次性代码,必须在浏览器中输入该代码以完成身份验证。如果启用了双因素认证,则使用配置的第二因素完成批准。
完成此步骤后,GitHub CLI 已成功通过身份验证,Claude Code 集成的所有先决条件均已就绪。
安装 Claude GitHub 应用
完成先决条件后,我们返回 Claude 继续安装。我们关闭不再需要的终端窗口,并按提示在 Claude 中按 Enter 键。此时,我们将被重定向到一个 GitHub 页面。
Figure 5.1 – 安装 Claude GitHub 应用
开始将 Claude Code 集成到 GitHub 账户中。此集成允许 Claude 发表评论、创建拉取请求并解决议题。我们将在本书后面演示这些功能。
点击 Install 后,我们被重定向回 Claude Web 应用程序。返回终端,我们再次按 Enter 键继续。
安装 GitHub 工作流
安装集成需要向仓库添加一个 GitHub 工作流。该工作流运行处理 Claude 评论和操作的管道。
将向你提供两个安装选项:
-
Tag Claude,允许我们在议题和拉取请求评论中 @提及 Claude,然后通过 GitHub 工作流运行。
-
Claude Code Review,自动审查新的拉取请求。
我们选择第一个选项。
接下来,我们选择一种身份验证方法。由于 Claude 的使用会消耗 Token,因此需要有人为这些 Token 付费。我们可以配置一个与 Claude 订阅关联的长期 Token,或者提供一个 Anthropic API 密钥。长期 Token 适用于订阅范围内的中小规模使用,而 API 密钥通常用于运行大规模或高频工作流、可能超出订阅限制的情况。在本例中,我们选择与 Claude 订阅关联的长期 Token。
确认此选择后,我们授权该集成。此授权还会跟踪 Token 消耗并将其与 Claude 订阅关联。
如果出现错误,是因为 GitHub 集成是从未连接到 GitHub 仓库的目录发起的。
要修复此问题,请在已初始化并连接到您账户的 GitHub 仓库的项目目录中打开一个新终端。在本例中,我们使用前文介绍且已配置好 GitHub 的 IceBreaker 目录。
重新打开 Claude,再次导航至 GitHub 安装页面,Claude 应能正确检测当前仓库。打开配置弹窗,选择相应账户,并授予仓库访问权限。确认后,返回 CLI 并使用长效 Token 再次配置 Claude Code。
创建 Pull Request
认证完成后,Claude 通过获取仓库信息初始化集成,并自动创建 Pull Request。
Figure 5.2 – Automatically Creating a Pull Request for Claude GitHub workflow
此 Pull Request 包含 .github 目录下的多个更新文件。这些是配置 GitHub 工作流的 YAML 文件。我们打开 Pull Request 进行审查。
该工作流使 Claude 能在评论和 Issue 中被 @提及,并允许其通过 GitHub Actions 运行。GitHub Actions 提供了 Claude 运行的计算环境,且工作流配置为使用与我们账户关联的 Token。
从安全角度看,API 密钥或访问 Token 作为 GitHub Actions Secret 存储。这在配置期间自动完成。只有拥有相应仓库访问权限的用户才能触发工作流。当 Claude 被 @提及 时,它可以创建分支、提交和评论。
合并 Pull Request 前,新添加的 GitHub 工作流应自动运行。在 GitHub Actions 选项卡中,我们将看到 Claude Code 工作流正在执行。成功完成后,继续合并。
工作流运行期间,它会更新 Pull Request。Claude 读取其添加的文件,具体为 .github/workflows 下的两个 YAML 文件:claude.YAML 和 claude‑code‑review.YAML。它针对安全问题和代码质量审查这些文件,并将反馈直接发布在 Pull Request 中。
审查结束时,Claude Code 批准该 Pull Request,表明它认为这些更改可接受,如下截图所示。
Figure 5.3 – Pull request approved with all checks passed
我们现在合并 Pull Request。合并后,仓库应包含一个之前不存在的新目录 .github/workflows。该目录下有集成添加的两个 YAML 文件:
-
claude.YAML -
claude‑code‑review.YAML
第一个 YAML 文件将展示 Claude 工作流配置。文件将包含一个名为 Run Claude Code 的步骤。认证 Token 从名为 CLAUDE_CODE_OAUTH_TOKEN 的 Secret 引用。没有敏感信息直接存储在工作流文件中,这保证了设置的安全性。
name: Claude Code
on:
issue_comment:
types: [created]
jobs:
claude:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@beta
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
下方展示了工作流文件的简化摘录。
Figure 5.4 – Claude GitHub Actions Workflow YAML File
至此,集成完成。配置可进一步自定义,包括选择模型、定义 Claude 可用的工具,以及调整其他设置以匹配特定需求。
使用 Claude Code 解决 GitHub Issue
本节演示如何在安装集成后,通过 @提及 Claude Code 来帮助解决 GitHub 仓库中的 Issue。
我们首先导航至仓库的 Issues 部分。我们关注的 Issue 是一个简单的 Issue,由用户 happyLolonly 创建。该用户提出的问题是:通过将变量从 linkedin_username 重命名为 linkedin_url 来提高可读性,因为该变量实际存放的是 LinkedIn URL。
首先在 Issue 上 @提及 Claude 并请求其解决问题:
@claude, can you fix this
Claude 被 @提及 后,新的 GitHub Action 会自动开始运行。在本例中,该 Action 称为 small rename。一旦提及 Claude,即触发此 Action。
打开 Action 查看详情,实时观察流式日志。日志主要由显示工具调用、工具输入和工具输出的 JSON 输出组成。虽然此信息利于深度调试,但人类难以阅读,且难以在宏观层面跟进。
对于大多数情况,不如返回 Issue 本身,而非检查原始日志。
Claude 的待办列表与上下文发现
回到 Issue 视图,Claude 创建一个随进度更新的待办列表。Claude 采取的第一步是尝试在仓库中定位 CLAUDE.md 文件。
Figure 5.5 – Claude To-Do List and Context Discovery in Issue View
CLAUDE.md 文件的目的是提供额外上下文。这些文件帮助 Claude 了解技术栈、项目结构、编码规范以及我们想传达的任何偏好。这属于上下文工程的一部分,即我们有意提供信息以帮助模型更有效地执行任务。
剧透预警!此仓库中没有 CLAUDE.md 文件。这是有意为之,旨在说明一个重要观点:在 Agentic AI 工作流中,事情并不总能正确运行,错误在所难免。
因此,仔细审查任何更改而非盲目接受至关重要。此原则贯穿所有 Agentic 工作流,不仅限于此例。
审查提议的更改
Claude 完成待办列表后,会更新名为 linkedin.py 的文件。我们随后通过创建 Pull Request 打开 diff 进行查看。
Figure 5.6 – Reviewing the pull request with proposed changes
乍看之下,Pull Request 描述似乎合理。然而,当你检查实际代码更改时,会发现 Claude 重命名了一个作为第三方服务 API 请求一部分的变量。
Figure 5.7 – Incorrect Variable Rename Breaking Third-Party API Contract
这是个问题。第三方 API 期望载荷遵循特定格式及特定变量名。更改此变量名会破坏与外部端点的契约,导致代码失败。
因此,该 Pull Request 不正确,不应被接受。
理解 Claude 的工作流
Claude 在其自动创建的新分支上执行更改。分支遵循类似 claude/issue/<issue‑number> 的命名约定。这是个重要细节,因为它意味着 Claude 从不直接在主分支上工作。
我们完全保留是否审查、修改或合并变更的控制权。这种分支策略也是扩展智能体工作流的基础。在实践中,我们可以并行运行多个 Claude 实例,每个实例在自己的分支上工作。
这一想法关联到更高级的工作流,例如使用 Git 工作树,我们将在本书后面介绍。
这个例子展示了使用 Claude Code 解决问题的威力和局限性。Claude 可以快速自动化变更,但如果缺乏足够的上下文,它可能会引入破坏性变更。代码审查依然至关重要,而理解 Claude 如何在分支中操作则是随着我们扩展智能体工作流而变得关键的。
使用 CLAUDE.md 添加仓库上下文
本节的目标是展示添加显式仓库上下文如何帮助 Claude Code 在解决问题时产生更准确、更可靠的变更。
如果 Claude 因为缺乏足够的仓库上下文,而未能解决之前涉及变量重命名的 GitHub 问题,会怎样?让我们看看如何验证这一假设。我们首先进入桌面,GitHub 项目目录就在那里。我们在 Cursor 中打开项目并运行一次快速获取以拉取最新变更。此时,我们已经拥有上一步中的 YAML 文件。接下来,我们打开 Claude。
初始化仓库上下文
我们在 Claude 中运行 /init 命令。如前所述,此命令会生成一个 CLAUDE.md 文件,捕获特定于仓库的上下文,包括技术栈、项目结构和其他相关细节。确认命令后,Claude 开始扫描仓库文件。这个过程只需很短的时间,Claude 就会收集所需信息。
初始化期间,Claude 会请求执行某些命令的权限,例如列出文件。我们明确允许这些操作。本地设置文件会更新以将批准的命令加入白名单,这些权限在本地会话期间持久有效。这种批准模型提供了对 Claude 允许执行操作的细粒度控制。
扫描完成后,Claude 写入 CLAUDE.md 文件。
审查并提交 CLAUDE.md
我们在源目录中找到新创建的 CLAUDE.md 文件并审查其内容。该文件包含仓库的结构化摘要,看起来是正确的。
然后我们指示 Claude 提交 CLAUDE.md 文件。Claude 准备一条提交信息,我们审查并接受。提交在本地创建,然后推送到远程仓库。提交此文件可确保仓库上下文被版本化、与团队共享,并在 Claude Code 在自动化工作流(如 GitHub Actions)中运行时可用。
在提交历史中,我们应该会看到一条新记录,表明已添加 CLAUDE.md。
Figure 5.8 – 将 CLAUDE.md 提交到仓库
有了可用的仓库上下文,我们回到 Claude 之前未能解决的问题。
我们再次在问题上提及 Claude,并请其解决该问题。这一次,我们提供了一个额外的提示,指明所需的变更位于特定函数内。我们提交评论:
@claude, can you please address this issue? Please notice that you need to edit the function `ice_break_with`
GitHub Actions 流水线立即启动,确认 Claude Code 已被触发。我们等待工作流完成。
检查 Claude 的变更
Claude 生成任务列表并开始执行。虽然由于额外的提示,该实验略有偏向性,但它仍然演示了提供适当上下文的效果。
工作流完成后,检查 Claude 创建的分支。变更显示变量名已从 linkedin_username 更新为 linkedin_url,且该更新已在函数定义和调用点处一致地应用。与上一次尝试不同,此变更保留了外部 API 契约,且未破坏集成。逻辑是正确的。
我们现在可以创建一个标题为 Renamed linkedin_username to linkedin_url 的拉取请求。这准确反映了变更的范围。
Figure 5.9 – 使用修正后的变量名创建拉取请求
拉取请求一打开,Claude Code 审查工作流就会自动运行。Claude 分析差异并执行代码审查,生成审查步骤和发现的清单。
该审查系统完全可配置。根据需要,可以添加额外的检查,如代码检查工具、测试执行或自定义验证规则。这种可配置性是 Claude Code 能在基于团队的工程工作流中有效运作的关键原因。
审查完成,总体评估为批准。未发现功能性问题。
审查批准后,拉取请求即可合并。
总结
在本章中,我们探讨了 Claude Code 如何与 GitHub 集成,以及如何将其作为真实开发工作流的一部分使用。我们演示了安装所需工具、配置 Claude GitHub 应用,以及设置允许 Claude 响应问题和拉取请求的 GitHub Actions 工作流。我们还了解了 Claude 如何通过创建分支、打开拉取请求和参与自动化审查来运作,以及为什么审查其变更至关重要。通过实际示例,我们观察到缺少仓库上下文如何导致错误变更,以及引入 CLAUDE.md 文件如何提高准确性。至此,您已清楚地了解如何安全地使用 Claude Code,它在何处增加价值,以及如何保留对代码库的完全控制权。
在下一章中,我们将专注于结构化智能体工作流,探讨规划模式、规格驱动开发以及并行智能体协调的实践。
获取本书的 PDF 副本、代码包等
扫描二维码(或访问 packtpub.com/unlock)。按名称搜索本书,确认版本,然后按照页面上的步骤操作。
注意:请准备好发票。直接从 Packt 网站购买的不需要发票。
# 6 Claude Code 规划与多智能体工作流智能体编码工作流受益于结构、规划和受控执行。随着系统变得更复杂并包含更多工具和自动化,依赖临时提示会增加意外变更和不可预测行为的风险。
本章探讨 Claude Code 如何通过规划和多智能体执行支持结构化智能体工作流。它展示了从探索性提示转向规格驱动开发如何提高安全性和可预测性,以及如何协调多个智能体高效地在同一代码库上工作。虽然示例使用的是 Claude Code,但讨论的原则广泛适用于智能体系统。
Claude Code 规划模式在官方文档中有介绍。有关规划模式如何工作及何时使用的简要概述,请参阅以下内容:
code.claude.com/docs/en/common-workflows#how-to-use-plan-mode
在本章中,我们涵盖以下主题:
-
Claude Code 规划模式
-
并行使用多个 Claude Code 智能体
Claude Code 规划模式
6 Claude Code 规划模式与并行开发
Claude Code 提供了一个规划模式,支持从探索式编码向规格驱动开发转变。该模式是智能体编码工作流中的基础原则。在规划模式下,Claude Code 仅限于只读操作,负责在进行任何代码更改之前生成规格说明或实施计划。
规划模式允许 Claude Code 对问题空间进行研究、分析和推理,随后生成详细的实施计划。在计划被明确审查并批准之前,不允许进行代码更改。
规划模式的特征
规划模式是一个只读阶段。Claude Code 可以读取文件、分析代码库、进行 MCP 调用、搜索文档并设计解决方案。它无法编辑、创建或删除文件,无法进行 Git 提交、安装软件包,或执行任何执行层面的操作。
该模式映射了资深软件工程师的工作流程。流程始于收集上下文、理解需求和业务约束。接下来进行规划,仅在审查和批准后才进入执行阶段。
规划工作流
规划工作流遵循结构化的序列:
-
Claude Code 对现有代码库或提供的需求进行研究和分析。
-
制定一份全面的实施计划或规格说明。
-
提交计划供审查。
-
批准后,Claude Code 退出规划模式并开始实施。
这种策略与执行的分离提供了一致性和安全性,特别是在处理大型或复杂代码库时。
通过建立只读规划阶段,该工作流为安全且审慎地做出实施决策创建了结构化基础。这一基础使得我们能够理解为何规划产物(如规格说明)在更可靠的开发工作流中扮演核心角色,我们将在接下来探讨这一点。
规格驱动开发的优势
在设计复杂系统或理解大型项目时,规划模式尤为有用。主要优势在于规划与执行的清晰分离,这能降低风险并提高可靠性。
常见的做法是将生成的计划或规格导出为 Markdown 文件。该文件可被共享、协作审查,并在项目生命周期中复用。这种方法通过使规划产物显性化和持久化,提升了 Claude Code 的整体价值。
该工作流是规格驱动开发的一个示例。与其立即实施功能,不如花时间定义业务问题、明确要解决的内容以及确定解决方案。这种方法能带来更好的结果,并能缩短整体实施时间,特别是结合子智能体时。
一份定义良好的规格能为语言模型界定问题空间、建立清晰边界并减少幻觉。它能防止意外副作用,例如不必要的文件更改或无关功能的回归。
以下示例演练了如何通过端到端的规划与细化工作流在实践中应用这些原则。
示例:迭代优化 Hook 市场规格
在本练习中,我们将使用 Claude Code 的规划模式为一个名为 HookHub 的新 Next.js 项目起草规格说明。我们不直接编写实现代码,而是首先将项目的结构和需求定义为规划产物。这种方法允许我们在生成代码前迭代优化设计。
### 实操:使用规划模式
在项目目录中打开 Claude Code:
claude
进入规划模式:
/plan
以下示例展示了输入 /plan 命令后 Claude Code 在规划模式下的运行状态。
图 6.1 – 执行 /plan 命令后在规划模式下运行的 Claude Code
在规划模式下,输入了以下提示词:
-
为名为 HookHub 的 Web 应用程序创建详细规格说明
-
该应用程序应:
-
显示可用的
Claude Codehooks -
以卡片形式渲染
-
将每张卡片链接到其 GitHub 仓库
-
支持按 Hook 事件类型筛选
-
Claude Code 接收指令,为可用 Claude Code hooks 的市场生成一款 Web 应用程序的规格说明。该应用以卡片集合的形式展示 hooks,每张卡片链接到一个包含 Claude Code hook 的 GitHub 仓库,旨在支持开发者工作流。
在规划模式下,Claude Code 生成初始任务列表、收集相关信息并产出规格文档。此阶段不编写任何代码。Claude Code 执行研究、定义概念,并输出供后续实施使用的结构化规格说明。
图 6.2 – 规划模式下生成的初始 HookHub 应用程序规格
初始规格包含需要细化的设计和功能决策。特别是在此用例中,hooks 采用轮播布局展示,且仅包含部分可用的 hook 事件类型。
规格通过反馈进行细化。移除了基于轮播的展示方式,改为在主页显示所有 hook 卡片。向规格中添加了更多 hook 事件类型,包括代码生成后触发的事件。
持久化 Hook 市场规格
细化完成后,Hook 市场应用的最终规格被导出为 Markdown 文件。
图 6.3 – 导出并保存 HookHub 规格为 Markdown 文件
.md 文件可提交至代码仓库,或存储在指定位置(如 .claude 目录)。该规格作为持久化的项目记忆被保留,并作为后续 Claude Code 请求的上下文被复用。
这种持久化的规范约束了 Claude Code 在实施过程中的行为,并在使用子智能体时确保一致的指导。
本示例展示了如何使用规划模式和深度思考生成、细化并持久化具体的应用程序规格。通过对真实设计决策进行迭代,并将生成的规格作为项目记忆保留,该工作流为执行建立了稳定的上下文。有了规格作为基础,便可有效应用更高级的执行模式,包括并行开发。
并行使用多个 Claude Code 智能体
Claude Code 支持同时运行多个 AI 智能体以加速开发工作流。核心理念是并行化独立任务,从而在更短时间内完成更多工作。此方法涉及在同一项目中运行多个 Claude Code 实例。
该工作流可理解为多智能体编码系统的一个入门示例。虽然存在涉及子智能体的更复杂智能体工作流,但此设置演示了两个独立的 Claude Code 实例并行运行。
图 6.4 – 在同一共享代码库上并行工作的 Claude Code 智能体
多个智能体可以比作多个开发者在同一个项目、同一个 GitHub 分支上工作。每个智能体都拥有对整个代码库的读写权限。这种共享访问使得协作成为可能,但也需要仔细考虑任务分配以避免冲突。这种方法的有效性取决于分配给每个智能体的任务性质。
识别适合并行执行的任务
当任务相互独立时,并行执行才有效。合适任务的示例包括修复不相关的 Bug、构建独立的 UI 页面,或在组件库中创建独立的组件。这些任务可以并发执行,互不干扰。
相互依赖的任务不应并行执行。一个常见的例子是全栈功能:先实现后端 API 端点,再由前端消费。如果单独的智能体同时在前端和后端工作,前端智能体可能会尝试消费一个尚不存在的 API。这通常会导致模拟实现或做出与最终 API 不符的假设,从而引发接口差异。
多智能体工作流中的一项关键技能是识别哪些任务真正独立,哪些是顺序执行的。独立任务可以并行执行,而顺序任务必须按顺序完成。在这种工作流中,工程师的角色从直接实现转变为对 AI 智能体工作的协调与监督。
示例:HookHub 项目中的并行开发
本示例展示了如何利用本章前面创建的 HookHub 规范,让多个 Claude Code 智能体并行工作。该规范定义了应用程序的结构,并为实现提供了共享参考。
该项目基于 project/hookhub 分支,从某个特定提交开始,该提交包含之前构建的应用程序状态。此提交代表智能体操作的基线,并定义了要实现的更改范围。
### 确立起始点
此演示始于 `project/hookhub` 分支的以下提交:
<在此处插入提交哈希值>
要复现起始状态:
git checkout project/hookhub
git reset --hard <commit-hash>
npm install
npm run dev
此时,应用程序显示:
-
一个基础的 Hero 区域
-
以简单布局渲染的 Hook 卡片
-
无视觉优化
应用程序显示 Hook 卡片,并作为向多个智能体分配并行任务的上下文。
图 6.5 – 用于识别并行智能体执行的独立任务的 HookHub 界面
要有效使用多个智能体,我们首先需要识别真正独立的任务。独立任务可以并行执行,从而加快开发速度。
将独立任务分配给智能体
在当前的 HookHub 界面中,页面的两个部分可以分别改进,使它们成为并行工作的良好候选者。识别出两个独立任务:
-
更新 Hook 卡片组件以改进其视觉设计
-
更新主页的 Hero 区域
图 6.6 – 两个并行运行的 Claude Code 实例,分别更新 HookHub 界面的不同部分
每个任务分配给一个单独的 Claude Code 实例。一个智能体被指示修改 Hook 卡片组件文件,而另一个智能体被指示修改 Hero 区域。
### 运行多个 Claude Code 实例
打开两个独立的终端窗口。
终端 1 – 更新 Hook 卡片组件
claude
提示词:
改进 HookCard 组件的视觉设计。
仅修改:
src/components/HookCard.tsx
请勿修改其他文件。
终端 2 – 更新 Hero 区域
claude
提示词:
重新设计 Hero 区域。
仅修改:
src/components/Hero.tsx
请勿修改 HookCard.tsx。
现在两个智能体独立并行运行。
这种设置之所以有效,是因为 Hook 卡片组件和 Hero 区域是在单独的文件中实现的。如果两个组件定义在同一个文件中,并发修改将会引入冲突。
将组件分离到单独的文件中可以提高可维护性、可读性和可测试性。这是软件开发中的通用最佳实践,在使用智能体工作流时尤为重要。
并发执行任务
两个 Claude Code 实例独立运行,并行执行其分配的任务。每个智能体仅修改与其任务相关的文件。由于组件是隔离的,执行过程中不会发生文件冲突。
执行完成后,更新后的 Hook 卡片组件和更新后的 Hero 区域反映了各自分配的更改。
图 6.7 – 对 Hook 卡片和 Hero 区域进行并发更新后的 HookHub 界面
审查并提交更改
一旦两个智能体完成工作,将审查更改并提交到仓库。该提交记录了因多智能体工作流而对 Hook 卡片组件和 Hero 区域所做的改进。
两个智能体完成工作后,审查更改:
git status
git diff
如果更改看起来正确:
git add .
git commit -m "使用并行 Claude Code 智能体优化 HookCard 和 Hero"
本示例演示了当任务独立且范围界定得当时,如何利用多个 Claude Code 实例并发工作以加速开发。
本章中的示例有意演示了多智能体执行的最简单形式:多个 Claude Code 实例在同一分支上操作,拥有共享文件访问权限,通过修改不同文件来避免冲突。
这种设置有助于理解并行执行的核心思想。然而,在同一分支上运行多个智能体本质上是脆弱的。如果智能体修改重叠的文件或引入不兼容的更改,就会发生冲突。
在专业开发环境中,并行工作的行业标准方法是使用 Git 分支或 Git 工作树来隔离更改。使用 Git 工作树时,每个智能体在其自己的分支上、在其自己的工作目录中操作,拥有代码库的独立副本。之后以受控方式审查并合并更改。
本章侧重于概念清晰度和最简单的可复现设置。更稳健的并行化策略,包括分支隔离和结构化合并工作流,将在本书后面介绍。
概要
在本章中,我们探讨了 Claude Code 如何通过规划模式和多智能体执行来支持智能体开发工作流。我们研究了规划模式如何通过将分析与实现分离来实现规范驱动开发,以及如何利用深度思考来优化规范并将其持久化为项目记忆。我们还演示了多个 Claude Code 智能体如何在共享代码库中并行处理独立任务。
在下一章中,我们将探索 Claude Code 子智能体,以及它们如何在复杂开发任务中实现结构化、隔离且并发的工作流。
获取本书的 PDF 副本、代码包等
扫描二维码(或访问 packtpub.com/unlock),按名称搜索本书,确认版本,然后按照页面上的步骤操作。
注:请准备好发票。直接从 Packt 网站购买 不需要发票。
7 使用 Claude Code 子代理
在本章中,我们将探索 Claude Code 子代理,以及它们如何实现结构化、可扩展的工作流。我们首先了解什么是子代理,它们与主 Claude Code 代理有何不同,以及为什么上下文隔离是其设计的核心。这些基础知识在依赖子代理进行更高级的工程场景之前至关重要。
随后我们将进入实战实现环节。我们将配置自定义子代理,检查提示词和工具访问权限如何影响执行,并详细分析上下文流向。最后,我们将通过无限代理循环模式使用并发子代理来扩展执行规模,演示如何利用并行代理编排来探索多种实现方案并选择最佳结果。
本章将涵盖以下主题:
-
Claude Code 子代理简介
-
配置第一个子代理
-
测试子代理
-
使用子代理时维护内容流
-
使用并发子代理进行扩展
-
无限提示词
Claude Code 子代理简介
在本节中,我们将了解 Claude Code 子代理 的概念。本节偏向理论且宏观,但在动手实践前理解这些内容非常重要。我们将深入探讨该主题,包括底层实现方面的内容。
我们无需编写数十个单独的提示词,只需执行一条命令(如 /cook),即可编排一个专业化 AI 代理团队。每个代理专为执行单一任务而设计,但能将该任务完成得极其出色。
根据官方文档(https://code.claude.com/docs/en/sub-agents),子代理是预先配置好的 AI 人设,Claude Code 可以将任务委派给它们。每个子代理都有其特定的用途和专长领域。从实际角度来看,这意味着每个子代理由一个特定的提示词定义。子代理的部分特性如下:
-
每个子代理拥有自己的系统提示词。我们完全控制该提示词,并可指定代理应如何运作、能做什么以及如何去做。这赋予了我们对代理行为的完全灵活性和控制力。
-
子代理在独立于主对话的上下文窗口中运行。这种上下文隔离是一项重要功能,因为它能防止上下文污染。主对话不会将偏见引入子代理的任务中。每个子代理始终专注于其高层目标。这一特性至关重要,将在本章后续内容中进一步讨论。
-
每个子代理可配置特定的工具集,规定其被允许使用的工具。从安全角度来看,这非常重要,因为它允许我们遵循最小权限原则。我们应仅授予子代理达成目标所需的工具。例如,代码审查代理可能需要读取文件或在线获取信息的工具。然而,因其职责仅限于代码审查,不应赋予其执行 Shell 命令或写入文件的工具。这种选择性的工具访问是子代理的关键属性。工具访问包含原生
Claude Code工具,以及通过 MCP 服务器暴露的集成。技能(我们将在稍后章节中探讨)位于不同层面,定义的是结构化能力而非直接的工具权限。 -
子代理可复用。我们只需创建一次,即可在不同项目中使用,并作为各类工作流的一部分与团队共享。触发子代理的方式多种多样。它们可使用 Markdown 文件描述,并遵循
Claude Code使用的相同层级结构。示例如下:
name: code-reviewer
description: Senior code review agent. Automatically analyzes code changes for bugs, security flaws, and convention violations. Invoke after any code modification.
tools: Read, Grep, Glob, Bash
model: inherit
---
You are a meticulous code reviewer embedded in the he110.me project (Next.js 16, React 19, TypeScript, Firebase, Tailwind v4).
## Workflow
1. **Collect diffs**: Execute `git diff --staged` and `git diff` to capture all pending changes. If both are empty, fall back to `git diff HEAD~1` for the most recent commit.
2. **Examine full files**: For each touched file, read it entirely — not just the changed lines. Understand the surrounding logic, imports, and how the modification integrates with existing code.
3. **Trace dependencies**: Use Grep/Glob to locate every consumer of modified functions, types, or exports. Flag any call sites that need updating.
4. **Validate project rules** (per CLAUDE.md):
- Firestore Timestamps converted via `.toMillis()` before reaching client components
- AI utilities imported exclusively from `lib/ai/langsmith.ts`, never from `ai` directly
- All profile writes routed through API endpoints, never via client-side Firestore SDK
- Authenticated requests use `authFetch()`
- `VoiceWaves` shares the recorder's MediaStream rather than opening its own
- Styles follow mobile-first approach (bare classes = mobile, progressively enhanced with `sm:`, `md:`, `lg:`)
## Severity Levels
### Critical — block merge
- **Security holes**: injection vectors, XSS, leaked credentials, absent `verifyAuth()` checks, SSRF, open redirects
- **Data corruption risk**: unguarded write operations, race conditions, malformed Firestore batches
- **Auth gaps**: missing ownership verification (`currentUser.uid === profile.uid`), exposed protected endpoints
- **Downstream breakage**: altered signatures or deleted exports without updating all dependents
### Warnings — resolve before shipping
- API handlers lacking input sanitization
- Swallowed promises or absent try/catch around async work
- Performance pitfalls: gratuitous re-renders, missing memoization on costly computations, repeated Firestore round-trips
- Inconsistent API response shapes across routes
- Loose typing (`any`, implicit `any`)
### Suggestions — worth considering
- Clearer naming for variables or functions
- Logic that could be expressed more simply
- Existing helpers in `lib/` that already solve the same problem
# Response Format
Group findings by severity. For every finding include:
- **Location**: file path and line number
- **Issue**: single-sentence summary
- **Impact**: what goes wrong if ignored
- **Recommended fix**: a concrete code snippet demonstrating the correction
项目级子代理(特定于单个仓库)在 .claude/agents/ 目录下创建。与项目相关的所有代理均存放于此。
用户级子代理(跨所有项目共享)存储在 home 目录下的 ~/.claude/agents/ 中。
子代理文件结构
子代理使用以下结构通过 Markdown 定义:
图 7.1 – 子代理文件结构
每个子代理定义以 YAML 前置元数据块开头。仅 name 和 description 为必填字段,但可定义其他配置选项,包括 tools、skills、mcp、model、hooks、memory 等。完整架构请参阅官方文档(https://code.claude.com/docs/en/sub-agents)。description 字段帮助主代理决定何时调用该子代理。
相同的概念也适用于子代理。子代理作为工具供主 Claude Code 代理使用。name 和 description 字段是必需的,不能省略,因为它们有助于 Claude Code 决定是否调用特定的子代理。
子代理定义还包括子代理被允许使用的工具。这些工具按名称列在 Markdown 文件中。如果此部分留空,则子代理将被授予访问所有可用工具的权限。工具定义也可以包含 MCP,这将在后面介绍。
子代理定义的最后一部分是系统提示词。此提示词包含子代理的所有指令。它可以以任何方式格式化,可以包含静态或动态上下文,并提供显著的灵活性。这是一个系统提示词,而不是用户提示词,这一区别很重要。系统提示词和用户提示词的区别将在本章后面详细讨论。
与 React 代理的关系
如果您以前构建过 LLM 应用程序,此结构可能看起来很熟悉。它非常类似于 React 代理模式,其中模型被赋予一组工具,每个工具都有名称和描述,以及定义通用指令并界定代理专业领域的提示词:
from langgraph.prebuilt import create_react_agent
agent = create_react_agent(
model="anthropic:claude-4-7-sonnet-latest",
tools=[get_weather],
# A static prompt that never changes
prompt="Never answer questions about the weather."
)
agent.invoke(
{"messages": [{"role": "user",
"content": "what is the weather in sf"}]}
)
Claude Code 代理、Claude Code 子代理和传统 React 代理之间有很强的相似性。然而,存在一个关键区别:Claude Code 的主编码代理及其子代理能够执行长时间运行的任务,并从头到尾实现功能。
理解这一点的一种方式是将 React 代理视为一个更广泛的类别,其中有一个深度代理的子集。Claude Code 的编码代理及其子代理属于这一子集。要被视为深度代理,它们必须满足某些特征,这将在课程后面介绍。
了解这些代理在底层如何工作,可以更好地洞察它们的行为,并能更有效地使用 Claude Code 的子代理。
配置第一个子代理
本节将重点介绍配置第一个子代理。创建一个新分支并打开 Claude,然后使用 /agents 命令查看可用代理列表:
图 7.2 - 使用 /agents 命令查看可用代理
此时,没有项目级代理,也没有安装用户级代理。唯一可用的代理是通用内置代理。还没有用户创建的代理。
如前所述,代理可以在两个不同的作用域中创建。在这种情况下,我们选择项目级代理,以便配置可以提交到存储库并作为项目的一部分共享。有两种可用的创建代理的方式。
-
使用 Claude 生成
-
手动配置
我们从第一种方法开始,这是最简单的方法,直接通过 Claude 生成。
定义代理描述
点击第一个选项后,我们将首先被要求定义代理描述。此描述指定代理的目标及其操作方式。Claude Code 的主代理使用此描述来决定是否应调用子代理。
Create new agent
Step 3: Describe what this agent should do and when it should be used (be comprehensive for best results)
A funny staff senior ultra software engineer that will review the code provided to him. Use this agent when you get an input like funny review.
在此示例中,我要求定义一个有趣的资深资深超级软件工程师来审查提供给他的代码。当输入包含诸如 "funny review" 之类的短语时,打算使用此代理。这确立了代理的特征及其主要目标,即审查代码。
包含一个关键词触发器来控制何时调用代理。当与 Claude 交互并显式调用代理时,此触发器变得很有用。代理也可以通过斜杠命令调用。
如果提示词感觉太模糊或太宽泛,可以使用单独的 Claude 实例来改进 Claude Code 子代理提示词,而不是手动优化。需要将原始提示词作为输入提供,并请求使其更清晰,从而生成更详细的系统提示词。然后可以直接复制并使用此改进的系统提示词。代理不是手动作为 Markdown 文件编写的,因为使用 CLI 在代理目录中创建代理。
应用系统提示词
输入提示词后,将向您显示诸如 "funny review" 和 "funny code review" 之类的激活触发器。这些触发器决定何时调用代理。
图 7.3 - 配置子代理系统提示词和激活触发器
按 Enter 键继续配置过程,将生成代理配置。
为代理选择工具
下一步是选择代理可以使用的工具:
图 7.4 - 设置期间子代理的工具列表
您可以选择所有工具,也可以根据您的自定义选择任何特定工具。
在我们的例子中,由于这是一个代码审查代理,它主要需要只读工具。如果需要,也可以启用编辑工具和执行工具。也可以添加 MCP 工具。
通过启用高级选项,我们可以查看 Claude Code 中可用的完整工具列表,包括 bash、glob、grep、ls、read 和 edit。之前配置的来自 Context7 的 MCP 工具也可用并已附加。完成选择后,隐藏高级选项并继续该过程。
选择模型和视觉设置
然后我们选择子代理使用的模型:
图 7.5 - 选择模型并查看子代理配置摘要
模型选择将在本书后面详细讨论,但在这种情况下,选择了 Sonnet 以平衡性能、价格和延迟。
您还将被要求选择一种颜色。在此配置中,选择了黄色。
保存前,将显示配置摘要。如果需要,也可以编辑配置。至此,代理创建完成。
查看生成的代理配置
我们打开生成的代理文件以查看其内容。该文件包含所有配置的信息。
文件顶部是代理名称,随后是代理描述。此描述有助于 Claude Code 的主代理确定何时应调用子代理。接下来列出可用工具。未启用写入工具。选定的模型是 Sonnet,颜色是黄色。
name: code-comedy-carl
description: >
当你想要一个既有趣又有娱乐性的代码审查,将真实的技术反馈与喜剧元素相结合时,请使用此 Agent。当用户请求搞笑审查、娱乐性审查、吐槽我的代码,或提及 Carl 或 CodeComedy Carl 时激活。该 Agent 以编程幽默、梗图和机智观察包装深刻的技术审查,同时保持专业性和教育价值。
tools: Glob, Grep, LS, Read, NotebookRead, WebFetch, TodoWrite, WebSearch, mcp__context7__resolve-library-id, mcp__context7__get-library-docs
model: sonnet
color: yellow
所有配置值均可根据需要修改。定义完 Agent 后,它即可投入使用。
测试我们的 Subagent
我们首先创建一个计算斐波那契函数的主 Python 文件:
> write a main python file that calculated fibonacci function
准备就绪后,即可使用该斐波那契实现。
Figure 7.6 – 创建斐波那契脚本以调用 Review Subagent
运行代码审查 Subagent
为演示 Subagent 如何被调用及其工作方式,我们在 @main.py 上运行一段幽默代码审查:
funny review @main.py
此操作会显示先前创建的 Review Agent 并生成一个实例。Agent 初始化、读取文件内容并开始处理。
若存在其他文件,可再次打开 Claude,创建同一 Review Agent 的额外实例。这说明了 Agent 的用处:可创建多个实例,每个实例在隔离环境中运行,互不影响。
通过展开 Agent 视图(Windows/Linux 为 Ctrl+R,macOS 为 Cmd+R),可查看 Agent 的所有内部活动。
生成多个 Review 实例
现在不止生成一次 Review,而是生成两次:
❯ create 2 funny code reviews of @main.py
此时会生成两个 Pull Request Agent 实例。可观察第一个与第二个实例处理任务的过程:
Figure 7.7 – 为同一文件生成多个 Review Subagent 实例
需注意:这两个 Review Agent 是顺序而非并发运行的。Claude Code 并不总假设任务相互独立;若对可能的依赖关系存在不确定性,它会选择串行执行而非并行。
实践中,可通过提示词措辞来影响此行为。若期望并行执行,提示词应明确说明。例如,与其要求“review this PR”,不如说“review these files in parallel”或“create separate review agents for each file”。让任务独立性显而易见,可增加并发执行的可能性。
尽管本例中 Agent 顺序运行,但 Claude Code 的真正优势在于有意并行执行多个 Subagent。本章后续将探讨这一点。
添加 额外 Agent
若需另一个 Agent,可在 agents 目录下新建定义文件来创建。
使用 Subagent 时的上下文流向
本节将借助下图剖析使用 Subagent 时的上下文流向,并理解 Subagent 为何在此场景下有用。我们从主 Agent 线程(即主对话)开始。该线程中的每条消息都会增加上下文的 Token 规模。
Figure 7.8 – 主 Agent 与 Subagent 之间的上下文流向
当主 Agent 决定使用 Subagent 时,会创建一个新提示词。该提示词传递给 Subagent,代表 Subagent 执行期间唯一接收的上下文。Subagent 不知晓之前发生的完整对话,仅能访问主 Agent 生成的提示词。
我们可以优化此提示词,使主 Agent 以更利于任务执行、产出更好结果的方式提示 Subagent。Subagent 的执行质量完全取决于此提示词,因为它是唯一提供的上下文。Subagent 独立工作、调用所需工具、可能执行集成,最后返回单一精简响应。每次生成新 Subagent,均从仅含生成提示词的全新上下文开始。
这种方法使主线程保持精简。通过将大量上下文委托给 Subagent,Subagent 在隔离环境中运行,仅将结果制品返回主 Agent。这样主对话可维持较小的上下文窗口。
因主 Agent 上下文越多性能越差,此法减少了使用 /compact 或 /clear 等命令的必要。保持主上下文精简有助于维持性能与稳定性。
总之,主 Agent 向 Subagent 发送单一输入,Subagent 完成工作并返回单一输出。这在持续推进任务的同时,实现了有效的上下文压缩。
实际中的上下文窗口
为直观演示,我们观察随 Claude Code 对话推进、上下文窗口如何增长。大语言模型有 Token 限制,我们受限于可发送的 Token 数量。
Figure 7.9 – 多轮对话中上下文窗口的增长
可选 200K、100 万 Token 的模型,未来甚至可能达 200 万或 1000 万。无论规模如何,上限均为有限。我们应避免触及上限——超限即请求失败;即便未超限,更大上下文也会增加成本(每 Token 均有价格)并因延迟升高而拖慢响应。
更重要的是,临近上限时易发生上下文污染。积累过多上下文会导致大量内容与当前任务无关,结果质量下降。这并非最佳工作方式,故我们要尽量保持上下文精简。
在与 Claude Code 交互中,每轮对话、每条消息都消耗 Token 并扩大上下文窗口。例如首轮增加 10K Token,次轮增至 30K,第五轮可能达 100K。
使用单个 Claude Code 实例时,最终会达到积累上下文过大、难以有效管理的临界点。此时需用 /compact 压缩上下文、用 /clear 完全清空,或另开新实例重头开始。这是在有限上下文窗口内工作的自然结果。
关键在于:上下文有限,单个 Claude Code 实例无法无限期处理所有事务。上下文上限直接制约了我们与 Claude Code 的交互方式。
子代理
子代理提供了一种优雅的方式来解决这一限制。每次使用子代理时,它都会在自己的上下文窗口中运行。子代理消耗的 Token 不计入主 Claude 代理的额度。
图 7.10 – 通过将工作卸载给子代理来保留主上下文
执行结束时,子代理返回单一的浓缩响应。此响应可能包含 15K 或 20K Token,并可能包含摘要或代码变更。关键在于,子代理的完整内部上下文不会累积在主对话中。
这种方法在保持主上下文精简的同时,仍允许完成大量工作。每个子代理作为一个独立的侧链运行,拥有自己的系统提示词,专门针对特定任务量身定制。得益于这种专业化,子代理通常比主代理单独工作时能更有效地解决其任务。
这种上下文与责任的分离是子代理的核心理念。这是一个简单的概念,但也非常强大。
到目前为止,我们一直关注子代理如何隔离上下文并向主代理返回浓缩结果。下一步是了解如何更有意识地塑造子代理的行为。
示例:创建 Mermaid 图表子代理
我们将仔细研究子代理的系统提示词和配置,并了解修改它们如何影响执行流程和输出。我们将通过一个示例来实现这一点。
创建子代理配置
在 Claude Code 中开始一个新会话。首先,调整输出样式并查看可用代理。该代理的目的是根据文本输入生成 Mermaid 图表。因此,需要创建一个新代理。使用 /agents 命令,选择项目级代理,并直接使用 Claude 生成它。
创建新代理
描述该代理应做什么以及何时使用(为了获得最佳效果,请全面描述)
帮我编写一个 mermaid 图表代理,它将接收我的输入并根据输入创建一个 mermaid 图表
Mermaid 是一个基于 JavaScript 的绘图和制图工具,允许我们使用简单、可读的语法定义图表(mermaid.live/)。这些图表可以在 GitHub 等平台以及其他文档系统上受控且清晰地渲染。支持多种图表类型,且语法刻意设计得轻量级。
Claude Code 生成新子代理的元数据。在此阶段,目标不是构建最完美的代理。相反,我们专注于观察 Claude Code 主代理与我们创建的子代理之间的交互。这包括理解它们如何通信、传递了什么输入以及返回了什么输出。最初的提示词故意保持基础,稍后将进行优化。
工具选择与上下文考量
生成子代理后,我们选择它可以使用的工具:
图 7.11 – 为 Mermaid 图表子代理选择工具
已启用只读工具、编辑工具和执行工具。此时,我们为此子代理选择的工具超出了其所需范围。
Mermaid 图表生成器的唯一职责是根据文本输入生成 Mermaid 语法。它不需要 bash 等执行工具,也不需要写入权限来修改文件。授予这些额外能力是不必要的。
这是工具污染的一个例子,即子代理被配备了其特定任务不需要的工具。每个工具定义都会增加子代理上下文窗口的 Token 消耗。因此,过度配置工具会增加上下文大小并引入可避免的开销。此外,通过赋予代理超出其预期范围的能力,还可能造成不必要的安全风险。
实践中,子代理应仅被授予它们实际需要的最小工具集。这遵循最小权限原则,即组件仅获得执行其任务所需的足够权限,别无其他。应避免过度配置工具,以降低上下文开销并限制不必要的能力。
完成工具选择后,我们可以选择 Sonnet 模型并分配颜色。子代理配置最终确定并保存,生成一个名为 mermaid‑diagram‑generator.md 的新文件。
图 7.12 – 最终确定并保存 Mermaid 图表子代理配置
理解子代理配置
现在我们检查生成的文件,其中包含完整的子代理定义。该子代理的名称为 mermaid‑diagram‑generator。您还会注意到,描述被追加到了 Claude Code 主代理的系统提示词中。
---
name: mermaid-diagram-generator
description: 当您需要将文本描述、需求、流程或概念转换为可视化的 Mermaid 图表时,请使用此代理。示例包括:<example>背景:用户想要可视化软件架构流程。 user: '我有一个 Web 应用,带有 React 前端,调用 Node.js API,后者查询 PostgreSQL 数据库并将结果缓存在 Redis 中' assistant: '我将使用 mermaid-diagram-generator 代理为此架构创建可视化图表' <commentary>由于用户正在描述系统架构,请使用 mermaid-diagram-generator 代理创建合适的 Mermaid 图表。</commentary></example> <example>背景:用户需要记录业务流程。 user: '你能帮我创建一个客户入职流程的流程图吗?它从注册开始,然后是邮箱验证、资料设置,最后是账户激活' assistant: '我将使用 mermaid-diagram-generator 代理为您的入职流程创建一个流程图' <commentary>用户正在描述一个顺序流程,因此请使用 mermaid-diagram-generator 代理创建流程图。</commentary></example> 主代理应始终将概念简化为核心要点。同时向子代理编写一些 ASCII 图来表示该概念。
tools: Glob, Grep, Read, WebFetch, TodoWrite, WebSearch, BashOutput, KillBash, Edit, MultiEdit, Write, NotebookEdit, Bash
model: sonnet
color: cyan
---
此描述决定了哪些子代理可供主代理使用,并强烈影响特定子代理的调用时机。通过此字段,我们可以指导主代理如何委派任务。
描述以代理功能的高层总结开头,随后列出应触发该代理的用户输入示例。在本例中,该代理旨在将文本描述、需求、流程和概念转换为可视化的 Mermaid 图表。总结和示例均有助于主代理决定何时将工作委派给此子代理。
除了决定何时调用子代理外,描述还指示主代理如何提示子代理。由于子代理在隔离的上下文中运行,它们接收到的唯一信息就是主代理生成的提示词。通过精心设计此描述,我们可以控制该提示词的结构、格式和内容。这种影响子代理提示方式的能力,是 Claude Code 最强大的特性之一。
在 YAML 前置元数据下方,我们定义了子代理的内部逻辑。此部分代表子代理的系统提示词,包含针对特定任务量身定制的指令。这些指令可以分步骤构建,也可以定义子代理如何格式化其响应。
当子代理完成执行后,其内部上下文会被清除,并向主代理返回单一响应。该响应是唯一保留的产物。我们可以塑造该响应的内容和格式,以便主代理能更有效地处理它。
调用子代理
配置就绪后,让我们通过请求检索增强生成流程的 Mermaid 图表来调用子代理。主代理将把此请求委托给 Mermaid 图表子代理,并生成以下内容:
图 7.13 - 调用 Mermaid 子代理
检查此次调用可让我们看到传递给子代理的确切提示词。该提示词请求生成一个全面的 Mermaid 图表,以说明典型的检索增强生成流程,包括向量数据库、嵌入模型、文档分块、检索、查询处理和 LLM 生成器等组件。它还指定了使用带有清晰标签和逻辑流向的适当 Mermaid 图表类型。
调用后,子代理在其独立的隔离上下文中执行。完成后,Claude Code 会自动将子代理的最终响应转发回主代理。此响应通常包含 Mermaid 图表语法及图表解释。
评估结果
我们复制子代理生成的 Mermaid 语法,并使用支持 Mermaid 输入的绘图工具进行渲染。本例中,我使用了 Excalidraw (excalidraw.com),它是免费使用的。在该工具中,我只是粘贴了 Mermaid 语法并按下了 Enter 键。
图 7.14 - 在 Excalidraw 中渲染生成的 Mermaid 图表
如你所见,图表生成成功,并可视化了检索增强生成架构。
然而,有时结果可能不尽如人意。生成的图表可能一眼难懂、缺乏清晰组织,甚至让人感到不知所措。即使我们熟悉检索增强生成,也不一定能立即看清各组件如何交互。
这一结果清楚地表明,子代理配置需要改进。接下来,我们将专注于调整子代理定义,通过自定义描述子代理的 Markdown 来生成更清晰、结构更合理的结果。
优化子代理描述
我们首先返回子代理配置,在描述中添加额外指令。由于目的是简化图表细节,我在描述中添加了以下内容:
主代理应始终将概念简化到核心要点(GIST)。同时向子代理编写一些代表该概念的 ASCII 绘图。
该指令指定主代理应始终将概念简化至其核心要点。此处的意图是影响主代理构建将传递给子代理的提示词的方式。
还添加了一句请求概念的可视化表示并明确降低代码优先级的指令。此阶段的重点完全在于塑造主代理为子代理生成的提示词。通过修改 description 字段,我们可以操控主代理提示子代理的方式。
我们还可以指示主代理执行如进行 API 调用等操作。这种能力引入了重要的安全考量。
由于描述会被追加到 Claude Code 主代理的系统提示词中,来自不可信来源的子代理定义可能包含恶意指令。具有有害描述的克隆子代理可能在本地机器上执行意外或危险的操作。这是描述级控制如此强大的一个重要隐含意义。
观察更新后的提示词流程
为查看更新是否生效,保存文件,重新打开 Claude Code,并编写类似请求以创建检索增强生成流程的 Mermaid 图表。
图 7.15 - 显示传递给子代理的要点级指令的更新后提示词流程
查看发送给子代理的提示词,我们可以看到其中包含了要点级简化。这证实主代理已成功受到更新后描述的影响。请求现在包含简化的概念表示,这是注入子代理的唯一上下文。
此提示词是子代理接收到的完整且完整的上下文。预期这种改进将提升子代理输出的性能和质量。
评估子代理输出
执行完成后,可检查生成的流程图。与之前的图表相比,结构应更有条理。索引和检索组件应更易识别,整体流程应一目了然:
图 7.16 - 更新后的子代理生成的优化 RAG 流程图
新图表更简单,步骤更少,因此更易于理解。
返回给主代理的最终响应不会直接包含 Mermaid 代码。代码仅在展开并手动复制子代理输出时可见。取而代之的是,它包含执行工作的摘要:
图 7.17 - 子代理返回摘要而非原始 Mermaid 代码
这显示了当前子代理配置的一个局限性。子代理返回的是摘要而非实际图表代码,意味着它未完全达到预期目标。子代理清除其内部上下文并仅返回单一响应,而在本例中,该响应不包含期望的产物。这种行为需要解决,将在“优化子代理输出”部分处理。
到目前为止,重点一直在于操控主代理发送给子代理的提示词。虽然这改进了结果,但单靠此法还不够。
下一步是超越提示词塑造,开始操控子代理本身的内部逻辑和执行流程。通过这样做,我们能更精细地控制子代理执行任务的方式,进一步提高其输出质量。
优化子代理输出
我们现在需要更新子代理配置,明确要求子代理仅返回实际图表,不包含任何额外废话。这成为代理的第七个也是最后一步。此处目标是影响子代理向主代理返回输出时的响应格式:
图 7.18 - 更新子代理以仅返回 Mermaid 图表而无任何额外文本
我还添加了第零步,指示子代理检查在线资源,看是否已存在可作灵感的预制图表。
图 7.19 - 添加第零步以在生成前检查现有图表
该指令笼统提及图表而非特指 Mermaid 图表。这行得通是因为子代理拥有网络搜索工具。
如果你希望保持输出简洁,则需要在描述中明确提及这一点,随后提醒保持解决方案最小化。
Figure 7.20 – Updating the subagent system prompt to enforce simple, minimal output
这部分 Markdown 定义了子代理的内部逻辑,仅适用于子代理本身,不影响主代理。
添加这些更改后,保存配置。
观察更新后的执行流程
再次发出相同的提示以生成 Mermaid 图表。任务按预期委托给 Mermaid 图表子代理。
通过检查调用详情,我们可以看到主代理传递给子代理的完整提示。该提示代表了子代理执行期间可用的全部上下文。
Figure 7.21 – Inspecting the full prompt passed from the main agent to the subagent
搜索将花费显著的时间,但最终应确认我们已成功影响了子代理的执行流程。子代理执行的第一个动作是按指令进行的网络搜索。
执行完成后,子代理再次返回汇总响应,而非原始图表代码。这是代理框架呈现子代理响应的当前限制。完整的 Mermaid 语法在内部生成,但不会直接显示在主线程中。要检查图表,必须手动展开并复制子代理输出。然后将 Mermaid 语法粘贴到绘图工具中进行渲染。
Figure 7.22 – Mermaid parsing error displayed in Excalidraw during diagram rendering
渲染期间,出现与流程框周围样式相关的解析错误。要继续,请移除该样式。之后,图表将成功渲染。
Figure 7.23 – Correctly rendered RAG architecture diagram after fixing Mermaid styling issues
渲染后的图表比之前的版本组织得更好。可以看到两条截然不同的流程:一条代表检索路径,另一条代表索引路径。
在检索侧,流程展示了用户查询被嵌入,随后对向量存储进行相似性搜索,检索前 K 个文档,并进行提示增强。检索到的上下文被追加到提示中,然后发送给语言模型。在索引侧,流程展示了文档被加载、预处理、分块、嵌入并存储在向量数据库中。
总体而言,结果明显更好。图表更简单、结构更清晰、一目了然。
配置更新就绪后,将更改提交到仓库。该提交包括编辑后的子代理定义和修改的文件。
推送提交后,更新后的配置可在仓库的 subagents 分支下获取。
至此,我们已经考察了子代理的核心机制:如何创建、主代理与子代理之间上下文如何流动,以及如何通过配置和系统提示塑造其行为。我们还探讨了修改影响主代理的描述或子代理的内部指令如何直接影响执行和输出。
所有先前的示例均聚焦于单个子代理。然而,这种方法的真正优势在生成并并行运行多个子代理时变得清晰。通过并发执行任务,我们可以一次探索多种实现,并更有效地扩展工程工作流。在下一节中,我们将从单代理委托转向协调并行执行。
通过并发子代理进行扩展
本节的实现基于 Infinite Agentic Loop 仓库(github.com/disler/infinite-agentic-loop),作者为 IndieDevDan。如果你对代理式编码模式和多代理工作流感兴趣,他的作品值得探索。他定期分享关于代理式开发的实用见解,更多作品可在 agenticengineer.com 找到。
本节中,我们将探索生成多个并发工作的子代理来实现一项功能。每个子代理产出自己的实现,随后我们评估不同输出并选择最强版本。这种方法代表了一种软件工程模型:并行生成多种实现,评估后再集成。
这种方法在令牌使用方面可能变得昂贵。当生成多个子代理时,每个独立运行,并根据其自身的上下文和执行步骤消耗令牌。由于每个代理都会生成代码、评估代码,并可能执行额外推理,总体令牌使用量可能显著增加。
我在此刻意不提供成本估算。定价频繁变动,且令牌消耗因代码库大小、代理数量和任务复杂度而异。使用此模式时,请仔细监控使用情况。
本节演示的实现基于仓库 Infinite Agentic Loop(github.com/disler/infinite-agentic-loop),由 IndieDevDan 创建。我们将其作为本示例中运行并发子代理的基础。IndieDevDan 是一位专注于代理式编码内容的 YouTuber,该仓库作为本节运行并发子代理的基础。该仓库和相关视频讨论随本章一并引用。
环境设置
我们将继续在 Project Hookhub 项目中工作。该仓库已在本地克隆,我们进入工作目录。
git clone https://github.com/PacktPublishing/Agentic-Coding-with-Claude-Code
随后我们进入 Claude Code 速成课程目录并切换到 project/hookhub 分支。从提交列表中,我们选择标题如下的提交:
Merge pull request #1 from emarco177/claude/add-anthropic-footer-01NXAnJSjYR7cx3t5Ag9HzAE
这是本节使用的提交。我们复制提交哈希并将其检出:
git checkout -b project/hookhub<commit-hash>
我们应获得以下输出:
Figure 7.24 – HookHub project opened on the correct branch in Cursor
我们可以确认处于正确分支,并导航进入 hookhub 目录。现有的 Next.js 项目随之打开。
安装依赖
打开 Next.js 项目后,我们安装依赖:
npm install
安装期间,若检测到任何漏洞,可通过运行以下命令修复:
npm audit fix --force
所有关键漏洞修补完成后,即可启动开发服务器:
npm run dev
至此,使用 Anthropic 主题的 HookHub 应用成功运行。环境现已就绪:
Figure 7.25 – HookHub application running successfully with the Anthropic theme
此时设置完成,我们可以继续编排多个代理并行工作。
无限斜杠命令
现在,我们将重点放在智能体解码上。在 Infinite Agentic Loop(无限智能体循环)代码库中,有一个名为 infinite 的斜杠命令。
该命令接受三个输入:
-
一个
spec文件 -
一个输出目录
-
一个数字
它读取描述我们要实现功能的 spec 文件。随后,它生成指定数量的智能体。这些智能体并发并行工作。每个智能体生成自己的产物,并将产物存储在输出目录中。
该命令可以作为精简版运行,用于小批量智能体。其架构也支持扩展到更大数量的智能体,甚至接近无限循环的并发执行。
在本节中,我们从精简版开始。
在本例中,我们要求子智能体实现 Hero 组件的不同变体。
重组 Hero 组件
我们首先创建一个名为 specs 的新目录。该目录用于保存所有的 spec 文件。
此时,应用程序有一个包含页脚和 Hook 卡片的 components 目录,但没有专门的 Hero 组件。Hero 的实现目前位于 page.ts 中。在创建 spec 之前,我们将 Hero 的实现从 page.ts 提取到 components 目录中,以清理并重组代码库。我使用的提示词如下:
Hi, can you please take the implementation from page.ts? There is a hero implementation there.
I want to create a new component from it under the components directory, just to organize the code a little bit.
Hero 的实现从 page.ts 中提取出来,并在 components 目录下创建了一个新的 hero.tsx 文件。page.tsx 内部的导入语句也被更新以引用这个新组件:
图 7.26 - 将 Hero 部分提取到单独的 hero.tsx 组件中
接着,在以下提示词的帮助下,我们将 hero.tsx 移动到 components 下的专用 hero 目录中:
Can you please also move the hero.tsx file into a hero directory under components?
在此操作过程中,请务必显式标记文件,以确保修改的是正确文件。
移动完成后,原始的 Hero 实现从 page.ts 中移除。项目结构现在体现了一个位于自己目录中的专用 Hero 组件。
我们现在创建了一个 heros 目录。该目录的目的是存储多个子智能体生成的输出产物。此时,项目结构整洁,已准备好进行规范编写。
从 Hero 文件生成 spec 文件
接下来,基于 hero.tsx 请求生成一个 spec 文件,使用以下提示词:
> Can you please review the hero.tsx file and create from it a spec file describing what this component should do, what its goals are, and specific guidelines, because I'm going to implement different variations of this component. @../src/components/heros/Hero.ts
该提示词包含以下内容:
-
对
hero.tsx的审查 -
一份描述组件用途、目标和指南的规范
-
将生成的
spec文件放置在specs目录中(显式标记)
Claude 将审查 Hero 的实现并生成规范文件。
图 7.27 - 生成的包含 Hero 组件规范的 hero.spec.md 文件
创建了一个包含 Hero 组件完整规范的新文件。Hero 组件作为 HookHub 的主要着陆区域,旨在立即传达产品的价值主张、目标及其背景层。
在本地创建一个 .claude 目录。因为这是一个新分支,且 Claude 尚未在此代码库副本中初始化,所以该目录不存在。
在此目录内,添加一个 commands 文件夹。从 Infinite Agentic Loop 代码库中,将 infinite.md 斜杠命令复制到此文件夹中。
该命令负责编排多个子智能体的并发执行。
在此阶段,我们不分析其内部实现。重点转移到实际使用上。
运行无限斜杠命令
退出 Claude 并重新启动,以便加载新的斜杠命令。Claude 初始化后,/infinite 命令即可用。
根据代码库说明,该命令需要三个输入:
-
一个
spec文件:在本例中为hero.spec -
一个输出目录:在本例中为
heros -
数量:在本例中,我们将使用六个智能体
按如下方式执行命令并提供这些输入:
>/infinite @../specs/hero.spec.md @../src/components/heros/
主智能体首先读取 spec 文件。成功读取后,主智能体即拥有了待实现内容的完整上下文。Claude Code 将启动六个并行子智能体来生成独特的 Hero 变体。我们将看到类似以下的任务:
图 7.28 - 并行子智能体任务生成多个 Hero 组件变体
待办事项列表更新,子智能体开始并发运行。
同样,这属于成本较高的操作。每个智能体独立运行,生成自己的代码,并可能自行测试。如果使用 Anthropic API 密钥而非 Max 模式,应监控 Token 使用量,因为此工作流会消耗大量 Token。
每个子智能体在本地机器上运行。如果将智能体数量增加到大得多的规模(例如 100 个),解决方案需要跨机器扩展。这可以通过 Claude 的云服务实现。随着智能体开始完成任务,它们开始将输出文件写入 heros 目录。
如果因本地环境问题导致文件创建遇到阻碍,Claude Code 会尝试恢复。
一旦允许文件创建,多个 hero 文件就会出现在 heros 目录中。最终,所有六个版本均创建完毕。
图 7.29 - heros 目录中创建的多个生成的 Hero 组件文件
此时,我们有了六个不同的 Hero 实现。
现在所有版本都已存在,我们发出一个新提示词:
Take all the hero implementations and show them on the main landing page one after another so we can compare them and choose the best one.
这是一个独立于斜杠命令的新提示词。务必记住,每个子智能体都在其自身隔离的上下文中运行。它们彼此不知情,且都从干净的初始状态开始。这有助于高效管理上下文。
主页面被更新以导入每个 Hero 变体并按顺序渲染。
page.tsx 中预期的变更如下。
-
从 heros 目录导入所有 Hero
-
在页面布局中按顺序渲染它们
审查差异可确认以下内容:
-
添加了新的导入语句
-
每个 Hero 按顺序渲染
应用程序现在显示以下 Hero 变体:
-
Minimal(极简风格)
-
Centered(居中风格)
-
Waveform(波形风格)
-
Particles(粒子风格)
-
Terminal(终端风格)
-
Gradient mesh(渐变网格风格)
每个版本在着陆页上均可见。
在此阶段,我们将使用终端风格的 Hero 作为首选实现。
细化前清理上下文
继续之前,我们检查上下文窗口。由于之前的操作,它可能已严重膨胀。
我们清理上下文,然后发出一个新提示词:
仅保留 page.tsx 中的终端 Hero 组件。从主着陆页移除所有其他 Hero 组件。保持 heroes 目录下的所有 Hero 文件不变。page.tsx 文件和 heroes 目录已显式标记。
由于上下文现已清理,执行速度将更快。
主页已更新为仅渲染终端 Hero 组件。其他 Hero 组件保留在 heroes 目录中。页面现已简化。
我们现在通过运行以下命令提交更改:
git add
git status
然后我们请求一条提交信息,描述以下内容:
-
主页上的
Hero组件变更 -
新增用于运行多个子代理的斜杠命令
我们使用的提示词如下:
Hi, can you please create a commit message about changing the hero in the main page? And please add that we also added a slash command for running multiple subagents.
Claude 检查差异并生成提交信息。提交被创建并推送。
刷新仓库后,提交将出现,其信息类似如下:Add hero component system and infinite agent slash command。
目前为止我们做了什么
我们使用了 /infinite 斜杠命令并行生成子代理。每个子代理独立实现一个变体。一旦生成所有变体,我们将它们并排渲染,进行视觉评估,并选择最佳实现。
这种方法让我们能够通过算力进行扩展。我们愿意花费的 Token 数量决定了我们能负担多少并行探索。
我们尚未深入探究其底层原理。这将在下一节解决。
IndieDevDan 的 Infinite Agentic Loop 仓库和配套的 YouTube 视频深入剖析了斜杠命令本身的实现。
Infinite prompt (无限提示词)
在本节中,我们将回顾 infinite.md 文件以及生成所有那些子代理的提示词。这是一个 高阶提示词。它接收一个提示词作为输入,并动态生成提示词。
这可以被视为 元提示词,类似于函数式编程中的高阶函数,后者接收函数作为参数并可返回函数作为返回值。这里我们对提示词做同样的事情。我们在 Infinite Agentic Loop 命令中看到了这一机制的实际运作。
提示词开始如下:
Think deeply about this infinite generation task. You are about to embark on a sophisticated iterative creation process.
Think deeply 指令旨在激活模型的深度推理能力。这是发送给我们主代理(主 Claude Code 代理)的提示词。
在 Variables(变量)部分,提示词定义了如下行:
spec_file: $ARGUMENTS output_dir: $ARGUMENTS count: $ARGUMENTS
该行声明了三个变量:spec_file、output_dir 和 count。每个变量暂时被赋值为 $ARGUMENTS 占位符。
当调用 /infinite 斜杠命令时,整个参数字符串作为 $ARGUMENTS 传入提示词。运行斜杠命令时提供的值被放置在同一行,导致重复值多次出现。这些重复值就是提供给斜杠命令的相同输入。
提示词包含负责解析的部分。当调用斜杠命令时,包含其参数的整个提示词被发送给 Claude Code 的主代理。提示词包含主代理如何解析输入的指令。
解析定义如下:
-
spec_file:Markdown 规范文件的路径 -
output_dir:迭代结果保存的目录 -
count:迭代次数,1到N或 "infinite"
所有解析均由主代理完成。没有负责解析的代码。每次调用命令时,解析都由 LLM 动态完成。
变量定义并解析后,执行进入几个阶段。
阶段 1:规范分析
阶段 1 是规范分析。主代理被指示阅读并深度理解位于 spec_file 的规范文件。这里使用了解析后的 spec 文件路径。
spec 文件定义以下内容:
-
生成何种类型的内容
-
格式和结构要求
-
任何特定参数或约束
-
迭代间预期的演进模式
提示词指示主代理仔细思考规范意图,以及每次迭代应如何在前序工作基础上构建。
在先前示例中,没有迭代或前序工作的演进,因为这未写入 spec 文件。如果我们想这样做,提示词支持该功能。
这是给主代理的第一条指令:读取 spec 文件并理解我们要做什么。
阶段 2:输出目录侦察
阶段 2 是输出目录侦察。主代理被指示彻底分析 output_dir 以了解当前状态。
此阶段包含:
-
列出所有现有文件及其命名模式
-
识别当前存在的最高迭代编号
-
分析现有迭代间的内容演进
-
理解前序生成的轨迹
-
确定新迭代存在的空白或机会
在先前示例中,没有迭代编号。我们使用了想要采用的风格名称。
此阶段指示主代理检查已完成的工作。
阶段 3:迭代策略
阶段 3 是迭代策略。基于规范分析和现有迭代,主代理被指示执行以下操作:
-
确定起始迭代编号或要创建的文件名
-
规划每次迭代如何保持独特性和演进性
-
考虑如何在保持新颖性的同时基于前序迭代构建
-
如果
count为无限,准备持续生成直到达到上下文限制
此阶段仍处于规划中。
阶段 4:并行代理协调
阶段 4 进入子代理的并行执行。主代理被指示部署多个子代理并行生成迭代,以实现最大效率和创意多样性。
分发策略定义如下:
-
计数 1–5 时,同时启动所有代理
-
计数 6–20 时,分批启动,每批 5 个代理以管理协调
-
计数为 "infinite" 时,以 3 到 5 个代理为一波启动,监控上下文并生成新波次
代理分配协议
主代理使用 Claude Code 的 task tool 生成子代理。提示词描述了主代理应如何创建传入这些子代理的提示词。
每个子代理的输入是一个提示词。子代理在上下文隔离中运行,并向主代理输出一条消息。
每个子代理接收以下内容:
-
规范上下文:完整的规范文件分析
-
目录快照:启动时
output_dir的当前状态 -
迭代分配:具体的迭代编号、起始编号及代理索引
-
唯一性指令:避免复制现有迭代概念的显式指令
-
质量标准:来自规范的详细要求
由于我们提供目录快照作为输入,子代理将知晓至今发生的事情。这有助于避免重复想法和重复实现。
在先前示例中,我们没有迭代编号,因此迭代分配映射到我们使用的文件名。
子代理任务结构
提示词包含传递给每个子代理的任务结构。
任务框架如下:
-
generate iteration [NUMBER] for [SPEC_FILE] in [OUTPUT_DIR] -
you are subagent [X] generating iteration [NUMBER]
每个子代理提示词都包含如下上下文:
-
规范(完整规范分析)
-
现有迭代(当前
output_dir内容的摘要) -
您的迭代编号
-
分配的创意方向
-
需求
提示词包含如下指令:
-
read and understand the specification completely(完整阅读并理解规范) -
analyze existing iterations to ensure the output is unique(分析现有迭代以确保输出唯一)
子代理提示词中还包含其他指令。
并行执行管理
随后提示词回到主代理的执行管理指令。
主代理被指示执行以下操作:
-
使用任务工具同时启动所有分配的子代理
-
监控代理进度和完成情况
-
通过重新分配迭代编号来处理代理失败
-
确保不生成重复的迭代编号
-
收集并验证所有已完成的迭代
这是高阶提示词的主要部分。它接收一个提示词作为输入并输出许多提示词,因为每个子代理接收不同的提示词。
一个提示词创建出许多提示词。该命令还包含无限运行的指令,以及上下文优化和执行原则。这为主代理提供了更多上下文。
这是一个高层级提示词。
思考那些以提示词为输入并生成提示词作为输出的提示词,这非常有创新性。对我来说,阅读此内容令人震撼。向 IndieDevJam 致敬,以及如何创建和界定自定义样式、使用 YAML 等结构化格式,以及在样式定义中自动化行为。
获取本书的 PDF 副本、代码包等
扫描二维码(或访问 packtpub.com/unlock)。按名称搜索本书,确认版本,然后按照页面上的步骤操作。
注意:请准备好发票。直接从 Packt 网站购买不需要发票。
8 创建和自定义输出样式
输出样式 是 Claude Code 中最强大且被低估的功能之一。它们定义了响应的结构和呈现方式,实际上塑造了用户与模型之间的通信协议。
在本章中,我们将探讨输出样式如何塑造 Claude Code 的沟通方式。您将学习如何创建自定义输出样式,在用户或项目层面对其进行界定,以及如何修改响应结构。我们还将探索输出样式如何与系统提示词交互,YAML 等结构化格式如何改变推理模式,以及如何直接在样式定义中自动化工作流。
读完本章后,您将理解如何设计 Claude Code 的交互模型,而不仅仅是消费其输出。您将能够设计专用配置、运行具有不同角色的并行会话、为您的设置进行版本控制,并使用自定义状态行扩展界面。
在本章中,我们将涵盖以下主题:
-
使用 Claude Code 创建自定义输出样式
-
创建高级项目级输出样式
-
在 Claude Code 中自定义状态行
-
高级状态行:显示最后的用户提示词
-
AI 编码的未来:专业化代理团队
Claude Code 中可用的内置输出样式可能会随时间演变。根据您安装的版本,您看到的样式可能不止本章所示的那些。
使用 Claude Code 创建自定义输出样式
使用 /output‑style 列出可用的输出样式时,Claude Code 会显示当前激活的样式以及任何内置样式。
默认情况下,系统包含以下样式:
-
Default(默认)
-
Explanatory(解释性)
-
Learning(学习型)
下图显示了 Claude Code CLI 中的输出样式选择界面。当前激活的样式会被高亮显示,内置样式列在其下方。
Figure 8.1 – Claude Code CLI 输出样式选择界面
如图所示,CLI 会展示可用样式并指示哪个处于激活状态。Explanatory 和 Learning 样式是由 Anthropic 团队预构建的。您可以创建自定义输出样式,而不必使用这些预定义样式。
创建和查看新的输出样式
要创建用户级输出样式,请在以下位置创建一个 Markdown 文件:
~/.claude/output-styles/
要创建项目级输出样式,请在以下位置创建:
.claude/output-styles/
该文件使用 YAML 前置元数据,后跟 Markdown 内容,这与子代理的定义方式类似。以下示例展示了位于 ~/.claude/output‑styles/minimal‑bullets.md 的文件:
---
description: Concise bullet-point responses with direct communication
---
# Communication Style
- Use bullet points for all responses
- Be direct and to the point
- No unnecessary language or filler
# Response Format
- Lead with the answer
- Use nested bullets for hierarchy
- Skip preamble and transitions
# Tone
- Professional and concise
- No hedging or qualifications
该文件包含以下内容:
-
一个描述,将其定义为具有直接沟通、无多余语言的简洁要点式响应
-
详述沟通风格的扩展章节
-
响应格式准则
-
语气准则
样式生成后,Claude Code 会将此定义写入磁盘。下图显示了写入磁盘的生成的 minimal-bullets 定义。选择 minimal‑bullets 样式后,它会成为当前激活的输出样式。查看可用输出样式列表时,会相应地指示所选样式。
Figure 8.2 – 已选择 Minimal-bullets 样式
一个示例输出样式生成的响应采用要点格式,结构直接、简洁,无废话。
Figure 8.3 – Claude 使用 minimal-bullets 输出样式进行响应
一旦选择了样式,Claude Code 会将其指令应用于后续请求。
输出样式如何工作
输出风格
选择输出风格会用特定于风格的自定义指令替换 Claude Code 系统提示的部分内容。Claude Code 移除其默认的软件工程指令,并用所选风格的指令替代。
无论选择哪种输出风格,Claude Code 的核心功能(包括用于跟踪的文件操作和脚本执行)均保持可用。
修改后的系统提示会随通过 Claude Code 发出的每个请求直接发送给 LLM。因此,这是同一个底层模型在不同的系统提示下运行。
使用 /command 切换输出风格时,Claude Code 会更新其内部系统提示模板,并将更新后的模板应用于后续的 LLM 调用。
项目级输出风格仅在特定项目内生效。
为何选择 YAML
将 YAML 作为输出风格,能将沟通从显式指令转变为隐式语义结构,由格式本身传达含义。
在 YAML 输出中,格式本身成为一种丰富的通信协议,其中缩进、键的选择、排序和结构决策均承载意义。因 YAML 支持层级,它自然映射到复杂的编码任务。
依赖关系表现为父子关系。优先级可从顺序推断。作用域通过嵌套层级表示。相比于列出顺序步骤,嵌套的 YAML 结构编码了问题空间的逻辑架构。为使此更具体,请看一个真实任务的结构示例。
以下示例是启用 YAML 输出风格时 Claude Code 返回的实际输出。
Task: "Fix authentication bug"
Priority: "Urgent high"
Complexity: "Medium"
approach:
investigate:
auth_flow: &flow
- login_endpoint
- token_validation
- session_middleware
debugging:
logs: "./auth.log"
reproduce: "invalid_token_scenario"
fix:
dependencies: [*flow]
files_to_modify:
auth.js:
scope: "token refresh logic"
risk: "low"
middleware.js:
scope: "validation checks"
risk: "urgent"
verify:
tests: ["auth_integration", "token_expiry"]
manual_check: "login flow end-to-end"
metadata:
estimated_time: "2 hours"
rollback_plan: "revert commits"
monitoring: "error_rate_dashboard"
让我们拆解此结构:
-
task定义建立上下文 -
approach部分捕获调查路径和调试工件

浙公网安备 33010602011771号