从构建 Claude 代码中得到的教训:像代理一样观察 | Thariq


作者:Thariq | 日期:2026年2月28日

构建代理框架最困难的部分之一是构建其动作空间。

Claude 通过工具调用进行操作,但在 Claude API 中,可以使用 bash、技能等基本元素以及最近引入的代码执行方式来构建工具(想了解更多关于 Claude API 的程序化工具调用,请阅读@RLanceMartin 的新文章)。

在所有这些选项中,你如何设计你的代理工具?你需要像代码执行或 bash 这样的单个工具吗?如果你有 50 个工具,每个工具对应代理可能遇到的使用场景,会怎样?

为了让自己站在模型的角度思考,我喜欢想象被给定一个困难的数学问题。为了解决它,你会想要哪些工具?这取决于你自己的技能!

纸质会是最低要求,但你会受限于手动计算。计算器会更好,但你需要知道如何操作更高级的选项。最快、最强大的选项是计算机,但你必须知道如何使用它来编写和执行代码。

这是一个设计你代理的有用框架。你想给它提供与其自身能力相匹配的工具。但你怎么知道那些能力是什么?你要关注,阅读它的输出,进行实验。你要学会像代理一样思考。

以下是我们在构建 Claude Code 时关注 Claude 所学到的教训。

改进启发与 AskUserQuestion 工具

在构建 AskUserQuestion 工具时,我们的目标是提升 Claude 提问的能力(通常称为启发)。

虽然 Claude 可以直接用纯文本提问,但我们发现回答这些问题似乎花费了不必要的时长。我们如何才能降低这种摩擦,增加用户与 Claude 之间的沟通带宽?

尝试 #1 - 编辑 ExitPlanTool

我们首先尝试的是给 ExitPlanTool 添加一个参数,让计划旁边有一个问题数组。这是最容易实现的事情,但它让 Claude 感到困惑,因为我们同时要求一个计划和一个关于计划的问题集。如果用户的答案与计划内容冲突怎么办?Claude 需要调用 ExitPlanTool 两次吗?我们需要另一种方法。

(你可以在我们的提示缓存文章中了解更多关于我们为什么制作了 ExitPlanTool 的原因)

尝试 #2 - 更改输出格式

接下来我们尝试修改 Claude 的输出指令,使其能够使用稍微修改过的 markdown 格式来提问。例如,我们可以要求它输出带有括号中备选答案的要点问题列表。然后我们可以解析并格式化那个问题作为用户的界面。

虽然这是我们能做的最普遍的修改,Claude 甚至似乎对此表示可以输出,但它并不保证。Claude 会附加额外的句子,省略选项,或者完全使用不同的格式。

尝试#3 - AskUserQuestion 工具

最后,我们决定创建一个 Claude 可以随时调用的工具,但在计划模式下尤其会提示它这样做。当工具被触发时,我们会显示一个模态窗口来展示问题,并阻止代理的循环直到用户回答。

这个工具允许我们提示 Claude 生成结构化输出,并帮助我们确保 Claude 为用户提供多个选项。它还给了用户组合这种功能的方法,例如在 Agent SDK 中调用它或在技能中引用它。

最重要的是,Claude 似乎很喜欢调用这个工具,我们发现它的输出效果很好。即使设计得再好的工具,如果 Claude 不明白如何调用它,也无法发挥作用。

这是 Claude Code 中引导的最终形式吗?我们不确定。正如你将在下一个示例中看到的那样,对某个模型有效的方法可能对另一个模型并非最佳。

更新功能 - 任务与待办事项

当我们首次推出 Claude Code 时,我们意识到该模型需要一个待办事项列表来保持其专注。待办事项可以在开始时编写,并在模型完成工作时进行勾选。为此,我们给了 Claude 待办事项编写工具,该工具可以编写或更新待办事项,并向用户显示它们。

但即便如此,我们经常看到 Claude 忘记自己该做什么。为了适应这种情况,我们每隔 5 轮就插入系统提醒,提醒 Claude 其目标。

但随着模型的改进,它们不仅不再需要被提醒 Todo List,反而觉得它限制了发挥。收到 Todo List 的提醒让 Claude 认为自己必须遵守列表,而不是修改它。我们还看到 Opus 4.5 在使用子代理方面也变得非常出色,但子代理如何在共享的 Todo List 上进行协调呢?

针对这种情况,我们将 TodoWrite 替换为任务工具(更多关于任务的信息请在这里阅读)。而待办事项主要是让模型保持专注,任务则更侧重于帮助代理之间相互沟通。任务可以包含依赖关系,在子代理之间共享更新,模型还可以修改和删除它们。

随着模型能力的提升,曾经需要的工具现在可能反而限制了它们。重要的是要不断重新审视关于所需工具的先前假设。这也是为什么坚持使用一组能力特征相似的小模型是有用的原因。

设计一个搜索界面

对 Claude 来说,一套特别重要的工具是搜索工具,这些工具可用于构建它自己的上下文。

Claude Code 刚推出时,我们使用 RAG 向量数据库为 Claude 寻找上下文。虽然 RAG 功能强大且快速,但它需要索引和设置,并且在多种不同环境下可能不稳定。更重要的是,Claude 是被给予这个上下文,而不是自己去寻找。

但如果 Claude 可以在网上搜索,为什么不能搜索你的代码库呢?通过给 Claude 一个 Grep 工具,我们可以让它搜索文件并自行构建上下文。

随着 Claude 变得越来越智能,我们看到了这种模式:如果给它合适的工具,它就越来越擅长构建自己的上下文。

当我们引入代理技能时,我们正式化了渐进式披露的概念,这允许代理通过探索逐步发现相关上下文。

Claude 可以读取技能文件,这些文件可以引用其他模型可以递归读取的文件。事实上,技能的一个常见用途是为 Claude 添加更多搜索功能,比如给它使用 API 或查询数据库的指令。

在一年多的时间里,Claude 从几乎无法构建自己的上下文,发展到能够在多层文件中进行嵌套搜索,以找到它需要的精确上下文。

渐进式披露现在是我们常用的技术之一,用于在不添加工具的情况下增加新功能。

渐进式披露 - Claude 代码指南代理

Claude 代码目前拥有约 20 个工具,我们不断自问是否需要全部这些工具。添加新工具的门槛很高,因为这会给模型增加一个需要考虑的选项。

例如,我们注意到 Claude 对如何使用 Claude 代码了解不够。如果你问它如何添加 MCP 或斜杠命令的作用,它将无法回答。

我们可以将所有这些信息放在系统提示中,但由于用户很少询问这些内容,这会增加上下文混乱,并干扰 Claude Code 的主要工作:编写代码。

相反,我们尝试了一种渐进式披露的方式。我们给了 Claude 一个指向其文档的链接,它随后可以加载以搜索更多信息。这种方式有效,但我们发现 Claude 在寻找正确答案时,会加载大量结果到上下文中,而实际上只需要答案。

因此,我们创建了 Claude Code 指南子代理,当您询问关于它自身时,Claude 会被提示调用该子代理。该子代理包含大量关于如何有效搜索文档以及应返回内容的详细指令。

虽然这并不完美,但当你询问 Claude 如何设置自己时,它仍然可能会混淆,但它比以前好多了!我们能够在不添加工具的情况下,向 Claude 的动作空间中添加内容。

一门艺术,而非科学

如果你希望得到一套关于如何构建工具的严格规则,不幸的是,这并非本指南的内容。为你的模型设计工具,既是一门科学,也是一门艺术。它很大程度上取决于你使用的模型、代理的目标以及它所处的环境。

多进行实验,阅读你的输出,尝试新事物。像代理一样思考。

https://x.com/trq212/status/2027463795355095314

如果觉得内容不错,欢迎你点一下「在看」,或是将文章分享给其他有需要的人^^

相关好文推荐:

通过元学习Agent记忆设计学习如何持续学习 | Yiming Xiong

超越 RAG 以实现智能体记忆:通过解耦和聚合进行检索 | ICML

你的工作不会消失,它只是不断在你身边逐渐萎缩 | Jan Tegze

AI 时代的软件与软件公司应该长什么样?

意图即生产力:重新定义产品与开发的边界

Embedding Model 如何“学会”语义相似?

Embedding Model 是什么?

OpenClawd的运作原理 | Hesamation

一个使用 OpenRouter 的 1 万亿令牌实证研究 | OpenRouter AI

Moltbot(Clawdbot)做对了什么?

一个月内把编码主力交给 Agent 的真实体验 | karpathy

从 DeepSeek V3 到 Mistral 3 Large:现代大语言模型(LLM)架构设计概览(三)| Sebastian Raschka

从 DeepSeek V3 到 Mistral 3 Large:现代大语言模型(LLM)架构设计概览(二)| Sebastian Raschka

从 DeepSeek V3 到 Mistral 3 Large:现代大语言模型(LLM)架构设计概览(一)| Sebastian Raschka

Agent 设计模式 | Lance

递归语言模型(Recursive Language Models) | Alex Zhang

Manus 中的上下文工程 | Lance

引入嵌套学习(Nested Learning):一种用于持续学习的全新机器学习范式

如何构建多智能体研究系统

0条留言

留言