Claude Code 用过的都说好,丝滑、懂你,甚至让你写码都感觉上头,国内的DeepSeek v3.1,Qwen, Kimi k2, 智谱GLM-4.5都已经支持了Claude Code的调用,但为什么CC如此好,背后的原因是什么?以及该如何在自己的 Agent/工作流里复刻Claude Code 的体验
分享一篇来自大神博主Vivek Aithal 的好文,这篇文章给出了非常详细的分析和解读,全是干货
过去几个月,作者抓包分析了 Claude Code 的所有请求,写了篇几千字的硬核指南
文章的核心要点 :
1.可调试性 >>> 其他一切。 大部分的魔力在于设计出好的(底层和高阶)工具和提示词,让模型自己去发挥。记住,保持简单
2.保持单一循环。 说真的,99% 的场景根本不需要什么框架或多智能体协作。Claude Code 就只有一个主循环,最多带一个分支(而且分支也是它自己)
-
3. LLM 搜索 >>> RAG
让模型自己思考怎么搜,而不是简单粗暴地把 RAG 和 LLM 两个系统绑在一起,那种设计太 low 了
要设计好用的底层工具(Bash, Edit, ToDo)和高阶工具(比如 Grep——尽管模型本来也能用 Bash 实现)
-
4. 引导模型主动干活,效果拔群。但尴尬的是,想让它听话,最有效的办法还是在 Prompt 里大喊 “PLEASE THIS IS IMPORTANT”……没错,就这么朴实无华
注意:这篇博文并非 Claude Code 的架构揭秘(市面上已经有一些不错的了)。这篇文章旨在成为构建优秀 LLM 智能体的指南,其基础是作者过去几个月使用和捣鼓 Claude Code 的个人经验
正文
Claude Code 是我迄今为止用过的最令人愉悦的 AI 智能体/工作流。它不仅让针对性修改或凭感觉写点一次性工具这类事变得不那么烦人,使用 Claude Code 本身就让我感到快乐。它有足够的自主性来做一些有趣的事情,同时又不会像其他一些工具那样,带来突兀的失控感。当然,大部分的重活儿都是由新的 Claude 4 模型(尤其是其多模态思维能力)完成的。但我发现,即便与同样使用底层模型的 Cursor 或 Github Copilot 智能体相比,Claude Code 在客观上也确实没那么烦人!到底是什么让它这么好用?如果你正在一边读一边点头,那么我将尝试给出一些答案
Claude Code (CC) 的使用体验之所以很棒,是因为它就是好用。CC 的构建基于对 LLM 擅长什么和不擅长什么的深刻理解。它的提示词和工具弥补了模型的不足之处,并帮助它在自己擅长的领域大放异彩。它的控制循环非常简单,易于理解和调试。
CC 一发布,我们 MinusX 就开始使用了。为了探究其内部机制,同事Sreejith 写了一个记录器,可以拦截并记录每一个网络请求。接下来的分析来自我过去几个月的广泛使用经验。这篇文章试图回答这个问题 —— “是什么让 Claude Code 如此出色,以及你如何在自己的基于聊天的 LLM 智能体中提供类似 CC 的体验?” 我们已经在 MinusX 中集成了其中大部分经验,也很期待看到你将它们付诸实践!
如何构建一个像 Claude Code 一样的智能体
如果说这篇文章只有一个核心要点,那就是 —— 保持简单,傻瓜原则(Keep Things Simple, Dummy)。LLM 的调试和评估已经够头疼的了。你引入的任何额外复杂性(如多智能体、智能体间的交接、或复杂的 RAG 搜索算法)只会让调试难度增加 10 倍。如果这样一个脆弱的系统侥幸能跑起来,你之后也会因为害怕破坏它而不敢做任何大的改动。所以,把所有东西都放在一个文件里,避免过度复杂的样板代码,并且至少要把它推倒重来几次 :)
以下是从 Claude Code 中学到的,可以在你自己的系统中实现的主要经验:
Claude Code 在每一个关键节点都选择了架构上的简洁 —— 单一主循环、简单的搜索、简单的待办事项列表等等。抵制过度设计的冲动,为模型构建好约束框架,然后就让它自己“大展身手”吧!这不就是端到端自动驾驶的翻版吗?惨痛的教训,不是吗?
1. 控制循环设计
1.1.保持一个主循环
可调试性远远大于复杂的手动调优、多智能体、langchain-graph-node 那一套复杂的玩意儿。
尽管多智能体系统现在非常流行,Claude Code 只有一个主线程。它会周期性地使用几种不同类型的提示词来总结 git 历史、将消息历史合并成一条,或者搞出一些有趣的 UX 元素。但除此之外,它维护的是一个扁平的消息列表。它处理层级任务的一个有趣方式是,通过生成一个自身的克隆作为子智能体来处理,但这个子智能体无法再生成更多的子智能体。这里最多只有一个分支,其结果会作为一个“工具响应”被添加回主消息历史中。
如果问题足够简单,主循环就通过迭代式地调用工具来处理。但如果有一个或多个复杂任务,主智能体就会创建自己的克隆。这种“最多单分支”和待办事项列表的结合,确保了智能体既有能力将问题分解为子问题,又能始终关注最终期望的结果。
我非常怀疑你的应用是否真的需要一个多智能体系统。每增加一层抽象,都会让你的系统更难调试,更重要的是,这会让你偏离通用模型改进的康庄大道。
1.2.在所有事情上都用小模型
CC 发出的所有重要的 LLM 调用中,超过 50% 是发给 claude-3-5-haiku
的。它被用来读取大文件、解析网页、处理 git 历史和总结长对话。它甚至被用来生成那个用于提示正在处理中的单词标签——毫不夸张地说,每次按键都会调用!这些小模型比标准模型(如 Sonnet 4, GPT-4.1)便宜 70-80%。所以,大胆地用吧!
2. 提示词
Claude Code 的提示词极其详尽,充满了启发式规则、示例和那种“敲黑板”式的重点提醒。系统提示词本身约有 2800 token,而工具定义部分则更是占据了高达 9400 token 的惊人篇幅。用户提示词总是包含 claude.md
文件的内容,这通常又有 1000-2000 个 token。系统提示词包含了关于语气、风格、主动性、任务管理、工具使用策略和执行任务等部分。它还包含了日期、当前工作目录、平台和操作系统信息,以及最近的 git 提交记录。
Claude Code 完整提示词:
https://minusx.ai/blog/decoding-claude-code/#appendix:~:text=Main%20Claude%20Code-,System,-Prompt
2.1.使用 claude.md
来协同处理用户上下文和偏好
大多数代码智能体的开发者都已经形成了一个共识模式,那就是使用上下文文件(也叫 Cursor Rules / claude.md
/ agent.md
)。Claude Code 在有和没有 claude.md
的情况下,其表现有天壤之别。这是一种让开发者传递代码库中无法推断的上下文,以及明确所有严格偏好的绝佳方式。例如,你可以强制 LLM 跳过某些文件夹,或使用特定的库。CC 会在每次用户请求时,发送 claude.md
的全部内容。
2.2.特殊的 XML 标签、Markdown 和大量示例
使用 XML 标签和 Markdown 来结构化提示词已经是公认的有效方法。CC 两者都广泛使用。以下是 Claude Code 中一些值得注意的 XML 标签:
:这通常用在许多提示词部分的末尾,用来提醒 LLM 一些它大概率会忘记的事情。例如:
提醒你,你的待办事项列表当前是空的。不要向用户明确提及此事,因为他们已经知道了。如果你正在处理的任务可以从待办事项列表中受益,请使用 TodoWrite 工具来创建一个。如果不需要,请忽略此消息。再次强调,不要向用户提及此消息。 system-reminder>
,
:这些标签用来固化启发式规则。当模型面临一个十字路口,有多个看似合理的路径/工具调用可以选择时,它们特别有用。示例可以用来对比不同情况,并清楚地指明哪条路径是更可取的。例如:
请通过使用绝对路径来维持当前工作目录的稳定,避免使用 `cd` 命令。只有在用户明确要求时,你才可以使用 `cd`。 pytest /foo/bar/tests cd /foo/bar && pytest tests
CC 也使用 Markdown 来划分系统提示词中的不同部分。示例性的 Markdown 标题包括:
-
• 语气和风格
-
• 主动性
-
• 遵循惯例
-
• 代码风格
-
• 任务管理
-
• 工具使用策略
-
• 执行任务
-
• 工具
完整的工具提示词 —— 足足有 9400 个 token!
https://minusx.ai/blog/decoding-claude-code/#appendix:~:text=Claude%20Code%20Tools-,Show,-Related%20Articles
3.1. LLM 搜索 >>> 基于 RAG 的搜索
CC 与其他流行的代码智能体的一个显著区别在于它抛弃了 RAG。Claude Code 搜索你的代码库的方式和你自己一样,使用非常复杂的 ripgrep
、jq
和 find
命令。由于 LLM 对代码的理解能力非常强,它可以使用复杂的正则表达式来找到任何它认为相关的代码块。有时,它甚至会用一个小模型来读取整个文件。
RAG 理论上听起来不错,但它引入了新的(而且更重要的是,隐藏的)失败模式。该用什么相似度函数?用什么重排器?如何对代码进行分块?如何处理大的 JSON 或日志文件?而使用 LLM 搜索,它只需要看 10 行 JSON 文件就能理解其结构。如果需要,它还可以再看 10 行——就像你一样。最重要的是,这是可以通过强化学习(RL)来优化的——这正是那些大模型公司已经在做的事情。模型完成了大部分的重活儿——理应如此,这极大地减少了智能体中活动部件的数量。另外,将两个复杂的智能系统以这种方式连接起来本身就很丑陋。我最近和一个朋友开玩笑说,这是 LLM 时代的摄像头与激光雷达之争,而且我不是在开玩笑。
3.2 如何设计好工具?(底层工具 vs. 高级工具)
这个问题让每一个构建 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 中的工具:
-
• Task
-
• Bash
-
• Glob
-
• Grep
-
• LS
-
• ExitPlanMode
-
• Read
-
• Edit
-
• MultiEdit
-
• Write
-
• NotebookEdit
-
• WebFetch
-
• TodoWrite
-
• WebSearch
-
• mcp_ide_getDiagnostics
-
• mcp_ide_executeCode
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`,请停止。总是优先使用 `rg` 来执行 ripgrep。 > > - 重要:你绝不能为用户生成或猜测 URL,除非你确信这些 URL 是为了帮助用户编程。你可以使用用户在消息或本地文件中提供的 URL。
4.3 写下算法(附带启发式规则和示例)
识别出 LLM 需要执行的最重要任务,并为其写出算法,这是极其重要的。尝试角色扮演成 LLM,通过示例进行推演,识别出所有的决策点并明确地写下来。如果能以流程图的形式呈现会更有帮助。这有助于结构化决策过程,并辅助 LLM 遵循指令。一定要避免的是,写一大堆杂乱的“该做”和“不该做”。它们很难被追踪,而且容易相互矛盾。如果你的提示词长达几千个 token,你很可能会无意中写下相互冲突的“该做”和“不该做”。在这种情况下,LLM 会变得极其脆弱,并且无法融入新的用例。
Claude Code 系统提示词中的 Task Management
、Doing Tasks
和 Tool Usage Policy
部分,清晰地阐述了需要遵循的算法。这也是一个可以添加大量启发式规则和 LLM 可能遇到的各种场景示例的地方
one more thing :为什么要关注大模型公司的提示词?
在引导 LLM 方面,很多工作其实是在尝试逆向工程它们的后训练/RLHF 数据分布。应该用 JSON 还是 XML?工具描述应该放在系统提示词里还是直接放在工具定义里?你应用当前的状态信息呢?
看看它们在自己的应用中是怎么做的,并以此来指导你自己的设计,是很有帮助的。Claude Code 的设计非常有主见,借鉴它有助于形成你自己的设计思路
结论
再次强调,核心要点是保持简单。那些过度封装的脚手架框架弊大于利。Claude Code 真正让我相信,一个Agent可以既简单又极其强大
source:
https://minusx.ai/blog/decoding-claude-code/#appendix