AI、开发工具、智能体·

是什么让 Claude Code 如此出色(以及如何在你的智能体中重现这种魔力)!?[译]

深入解析 Claude Code 的设计哲学和实现细节,探索构建令人愉悦的 LLM 智能体的核心原则,从控制循环到工具设计的全方位指南

Claude Code 是迄今为止我使用过的最令人愉悦的 AI 智能体/工作流。它不仅让目标编辑或临时编码工具变得不那么恼人,使用 Claude Code 还让我感到快乐。它有足够的自主性来做有趣的事情,同时不会像其他一些工具那样引起令人不安的失控感。当然,大部分繁重的工作都是由新的 Claude 4 模型完成的(尤其是交错思维)。但我发现 Claude Code 客观上比 Cursor 或 Github Copilot 智能体使用起来更不恼人,即使使用相同的底层模型!是什么让它如此出色?如果你正在阅读这篇文章并点头赞同,我将尝试提供一些答案。

注意:这不是一篇关于 Claude Code 架构转储的博客文章(有一些很好的文章)。这篇博客文章旨在成为构建令人愉悦的 LLM 智能体的指南,基于我在过去几个月中使用和调试 Claude Code 的经验(以及我们拦截和分析的所有日志)。你可以在附录部分找到提示词工具。这篇文章大约 2000 字,所以系好安全带!如果你正在寻找一些快速要点,TL;DR 部分是一个很好的起点。

提示词统计

你可以清楚地看到不同的 Claude Code 更新。

Claude Code(CC)使用起来感觉很棒,因为它_就是简单地工作_。CC 是在对 LLM 擅长什么和糟糕什么的根本理解基础上精心制作的。它的提示词和工具弥补了模型的愚蠢,并帮助它在其擅长的领域发光发热。控制循环极其简单易懂且易于调试。

我们在 MinusX 一推出就开始使用 CC。为了深入了解其内部机制,Sreejith 编写了一个记录器,拦截并记录每个网络请求。以下分析来自我在过去几个月的广泛使用。这篇文章试图回答这个问题——"是什么让 Claude Code 如此出色,你如何在自己的基于聊天的 LLM 智能体中提供类似 CC 的体验?" 我们已经将其中的大部分内容整合到 MinusX 中,我很兴奋看到你也这样做!

工具使用统计

Edit 是最频繁的工具,其次是 Read 和 ToDoWrite

如何构建类似 Claude Code 的智能体:TL;DR

如果只能从中获得一件事,那就是——保持简单,笨蛋。LLM 本身就足够难以调试和评估。你引入的任何额外复杂性(多智能体、智能体交接或复杂的 RAG 搜索算法)只会让调试变得 10 倍困难。如果这样一个脆弱的系统能够工作,你以后会害怕对其进行大幅更改。所以,将所有内容保存在一个文件中,避免过度的样板脚手架,并至少重构几次 :)

以下是从 Claude Code 中得出的在你自己系统中实施的主要要点。

1. 控制循环

2. 提示词

3. 工具

4. 可操控性

Claude Code 在每个关键点都选择架构简单性——一个主循环、简单搜索、简单待办事项列表等。抵制过度工程的冲动,为模型构建良好的工具,让它发挥作用!这是端到端自动驾驶的重演吗?苦涩的教训?


1. 控制循环设计

1.1 保持一个主循环

可调试性 >>> 复杂的手工调整多智能体 lang-chain-graph-node 混合体。

尽管多智能体系统风靡一时,Claude Code 只有一个主线程。它定期使用几种不同类型的提示词来总结 git 历史、将消息历史整理成一条消息或创建一些有趣的 UX 元素。但除此之外,它维护着一个扁平的消息列表。它处理分层任务的一个有趣方式是将自己作为子智能体生成,但没有生成更多子智能体的能力。最多只有一个分支,其结果作为"工具响应"添加到主消息历史中。

如果问题足够简单,主循环就通过迭代工具调用来处理它。但如果有一个或多个复杂的任务,主智能体会创建自己的克隆。最多 1 个分支和待办事项列表的组合确保智能体有能力将问题分解为子问题,但也要关注最终期望的结果。

我非常怀疑你的应用需要多智能体系统。每增加一层抽象,你的系统就更难调试,更重要的是,你偏离了通用模型改进轨迹。

控制循环图

1.2 为所有事情使用更小的模型

CC 发出的所有重要 LLM 调用中超过 50% 是给 claude-3-5-haiku 的。它用于读取大文件、解析网页、处理 git 历史和总结长对话。它还用于提出一个词的处理标签——字面上为每一次按键!较小的模型比标准模型(Sonnet 4、GPT-4.1)便宜 70-80%。大量使用它们!

2. 提示词

Claude Code 有极其详细的提示词,充满了启发式方法、示例和重要(啧啧)提醒。系统提示词约 2800 个令牌,工具占了惊人的 9400 个令牌。用户提示词总是包含 claude.md 文件,通常可能是另外 1000-2000 个令牌。系统提示词包含关于语调、风格、主动性、任务管理、工具使用策略和执行任务的部分。它还包含日期、当前工作目录、平台和操作系统信息以及最近的提交。

去阅读整个提示词

2.1 使用 claude.md 来协作用户上下文和偏好

大多数编码智能体创建者已经确定的一个主要模式是上下文文件(又称 Cursor Rules / claude.md / agent.md)。Claude Code 有无 claude.md 的性能差别简直是天壤之别。这是开发者传授无法从代码库推断的上下文和编码所有严格偏好的绝佳方式。例如,你可以强制 LLM 跳过某些文件夹或使用特定库。CC 在每个用户请求中发送 claude.md 的全部内容

我们最近在 MinusX 中引入了 minusx.md,它正在快速成为我们智能体编码用户和团队偏好的事实上的上下文文件。

2.2 特殊 XML 标签、Markdown 和大量示例

XML 标签和 Markdown 是结构化提示词的两种方式已经相当确定。CC 大量使用两者。以下是 Claude Code 中一些值得注意的 XML 标签:

  • <system-reminder>:这在许多提示词部分的末尾使用,提醒 LLM 它可能会遗忘的事情。示例:
<system-reminder>这是一个提醒,你的待办事项列表目前是空的。不要明确地向用户提及这一点,因为他们已经知道了。如果你正在处理可以从待办事项列表受益的任务,请使用 TodoWrite 工具创建一个。如果不是,请随意忽略。再次强调,不要向用户提及这条消息。</system-reminder>
  • <good-example><bad-example>:这些用于编码启发式方法。当有多个看似合理的路径/tool_calls 模型可以选择时,它们特别有用。示例可以用来对比情况并非常清楚地表明哪条路径更可取。示例:
尝试通过使用绝对路径并避免使用 `cd` 在整个会话中维护当前工作目录。如果用户明确请求,你可以使用 `cd`。
<good-example>
pytest /foo/bar/tests  
</good-example>
<bad-example>
cd /foo/bar && pytest tests
</bad-example>

CC 还使用 markdown 在系统提示词中划分清晰的部分。示例 markdown 标题包括:

  • 语调和风格
  • 主动性
  • 遵循约定
  • 代码风格
  • 任务管理
  • 工具使用策略
  • 执行任务
  • 工具

3. 工具

去阅读整个工具提示词 - 它有惊人的 9400 个令牌长!

3.1 LLM 搜索 >>> 基于 RAG 的搜索

CC 与其他流行编码智能体的一个显著不同之处在于它拒绝 RAG。Claude Code 搜索你的代码库就像你会做的那样,使用非常复杂的 ripgrepjqfind 命令。由于 LLM 非常了解代码,它可以使用复杂的正则表达式找到几乎任何它认为相关的代码块。有时它最终会用较小的模型读取整个文件。

RAG 在理论上听起来是个好主意,但它引入了新的(更重要的是,隐藏的)失败模式。使用什么相似性函数?什么重排序器?如何分块代码?对于大型 JSON 或日志文件怎么办?使用 LLM 搜索,它只是查看 json 文件的 10 行来理解其结构。如果需要,它会再查看 10 行——就像你会做的那样。最重要的是,这是可以进行强化学习的——BigLabs 已经在努力了。模型承担大部分繁重的工作——应该如此,大幅减少智能体中的活动部件数量。另外,以这种方式连接两个复杂、智能的系统只是难看。我最近和朋友开玩笑说这是 LLM 时代的相机与雷达,我只是半开玩笑。

3.2 如何设计好的工具?(低级与高级工具)

这个问题让任何构建 LLM 智能体的人夜不能寐。你应该给模型通用任务(如有意义的操作)还是应该是低级的(如打字、点击和 bash)?答案是看情况(你应该两者都用)。

Claude Code 有低级(Bash、Read、Write)、中级(Edit、Grep、Glob)和高级工具(Task、WebFetch、exit_plan_mode)。CC 可以使用 bash,那为什么要单独给一个 Grep 工具?这里的真正权衡是你期望智能体使用工具的频率 vs 智能体使用工具的准确性。CC 使用 grep 和 glob 如此频繁,以至于将它们制作成单独的工具是有意义的,但同时,它也可以为特殊场景编写通用的 bash 命令。

同样,还有更高级的工具,如 WebFetch 或 'mcp__ide__getDiagnostics',它们在功能上极其确定。这省去了 LLM 进行多次低级点击和打字的麻烦,并使其保持在轨道上。帮帮这个可怜的模型,好吗!?工具描述有详细的提示词,包含大量示例。系统提示词有关于"何时使用工具"或如何在两个可以执行相同任务的工具之间选择的信息。

Claude Code 中的工具

3.3 让智能体管理待办事项列表

这是个好主意的原因有很多。上下文衰减是长期运行的 LLM 智能体中的常见问题。它们热情地开始解决困难问题,但随着时间的推移迷失方向并退化为垃圾。当前智能体设计解决这个问题有几种方式。许多智能体已经实验了显式待办事项(一个模型生成待办事项,另一个模型实现它们)或多智能体交接+验证(PRD/PM 智能体 -> 实现者智能体 -> QA 智能体)

我们已经知道多智能体交接不是个好主意,原因很多很多。CC 使用显式待办事项列表,但是模型维护的。这使 LLM 保持在轨道上(它已经被大量提示频繁参考待办事项列表),同时给模型在实现过程中纠正路线的灵活性。这也有效地利用了模型的交错思维能力来即时拒绝或插入新的待办事项。

4. 可操控性

4.1 语调和风格

CC 明确尝试控制智能体的美学行为。系统提示词中有关于语调、风格和主动性的部分——充满指令和示例。这就是为什么 Claude Code「感觉」在其评论和急切性方面有品味。我建议将其中的大部分内容原样复制到你的应用中。

# 一些语调和风格的示例
- 重要:除非用户要求,否则你不应该用不必要的前言或后记(如解释你的代码或总结你的操作)回答。
除非用户要求,否则不要添加额外的代码解释摘要。

- 如果你不能或不会帮助用户做某事,请不要说为什么或可能导致什么,因为这听起来很说教和恼人。

- 除非用户明确要求,否则只使用表情符号。避免在所有通信中使用表情符号,除非被要求。

4.2「这很重要」仍然是最先进的

不幸的是,在要求模型不要做某事方面,CC 并没有更好。IMPORTANT、VERY IMPORTANT、NEVER 和 ALWAYS 似乎是引导模型远离雷区的最佳方式。我期望模型在未来变得更加可操控并避免这种丑陋。但现在,CC 大量使用这个,你也应该这样做。一些示例:

- 重要:除非被要求,否则不要添加***任何***注释

- 非常重要:你必须避免使用搜索命令如 `find` 和 `grep`。相反使用 Grep、Glob 或 Task 来搜索。你必须避免读取工具如 `cat`、`head`、`tail` 和 `ls`,使用 Read 和 LS 来读取文件。\n  - 如果你_仍然_需要运行 `grep`,停止。首先总是使用 ripgrep `rg`

- 重要:除非你确信 URL 是为了帮助用户编程,否则你绝不能为用户生成或猜测 URL。你可以使用用户在其消息或本地文件中提供的 URL。

4.3 编写算法(包含启发式和示例)

识别 LLM 需要执行的最重要任务并为其编写算法是极其重要的。尝试扮演 LLM 的角色并通过示例工作,识别所有决策点并明确编写它们。如果这是流程图的形式会有帮助。这有助于构建决策制定并帮助 LLM 遵循指令。一定要避免的一件事是大量的「应做」和「不应做」。它们更难跟踪,并保持互斥。如果你的提示词有几千个令牌长,你会无意中有冲突的「应做」和「不应做」。在这种情况下,LLM 变得极其脆弱,并且无法纳入新的用例。

Claude Code 系统提示词中的任务管理执行任务工具使用策略部分明确走过要遵循的算法。这也是添加大量启发式方法和 LLM 可能遇到的各种场景示例的部分。

加分:为什么要关注 BigLab 提示词?

在引导 LLM 方面的很多努力都是试图逆向工程它们的后训练/RLHF 数据分布。你应该使用 JSON 还是 XML?工具描述应该在系统提示词中还是只在工具中?你的应用当前状态怎么样?看看他们在自己的应用中做了什么并用它来指导你的应用是有帮助的。Claude Code 设计非常有主见,它有助于用来形成你自己的设计。

结论

再次,主要要点是保持简单。极端的脚手架框架弊大于利。Claude Code 真正让我相信「智能体」可以简单而又极其强大。我们已经将其中的许多经验整合到 MinusX 中,并继续整合更多。

如果你对将自己的 LLM 智能体 Claude Code 化感兴趣,我很乐意聊天——在 twitter 上联系我!如果你想要为你的 Metabase 训练类似 Claude Code 的数据智能体,查看 MinusX 或在这里与我安排演示。快乐(Claude)编码!


附录

这里原文包含了完整的工具和提示词定义,由于篇幅限制在翻译中省略

原文链接:https://minusx.ai/blog/decoding-claude-code/


© 2025 智人飞扬