搭 Agent harness 最难的部分之一,是构造它的工具。

Claude 完全通过 工具调用 行动,但 Claude API 里可以用多种原语来构造工具,例如 bash、skills 和 代码执行。(关于 Claude API 上的 programmatic tool calling,可参见 @RLanceMartin 的新文章。)

那么该怎么设计 Agent 的工具?给一个通用工具(如 bash 或代码执行)?还是五十个专用工具,每个场景一个?

要站在模型的立场想:给你一道很难的数学题,你希望有什么工具?这取决于你自己的能力。

纸笔是最低配置,但只能手算。计算器更好,但你得会用更高级的功能。最快最强的是电脑,前提是你会写代码并执行。

这对设计 Agent 很有用:工具要贴合模型自身的能力。可怎么知道那些能力是什么?得观察、读它的输出、做实验——学会像 Agent 一样看。

如果你在搭 Agent,会碰到和我们一样的问题:何时加工具、何时删、怎么区分。下面是我们做 Claude Code 时的答案,包括一开始做错的地方。

用 AskUserQuestion 工具改进 elicitation

Diagram titled “Finding the sweet spot”: a spectrum from “no structure” to “too rigid”. Modified markdown output sits near “no structure” (free but messy, hard to format). An ExitPlanTool parameter sits near “too rigid” (the plan is already formed, so the questions come too late). The AskUserQuestion tool is highlighted in the middle (structured, composable, with a clear UI surface).

做 AskUserQuestion 工具时,目标是提升 Claude 提问的能力(常称作 elicitation)。

Claude 本来可以用纯文本提问,但我们发现回答那些问题感觉多花了不必要的时间。怎么降低摩擦、提高用户与 Claude 之间的沟通带宽?

尝试 1:改 ExitPlanTool

第一种做法是给 ExitPlanTool 加一个参数,让它在计划旁边带一组问题。实现最省事,但 Claude 会困惑:我们同时在要一份计划和关于计划的一组问题。若用户答案与计划冲突怎么办?Claude 要不要调两次 ExitPlanTool?我们知道这条路不通,于是推倒重来。(为何做 ExitPlanTool,见 提示词缓存那篇。)

尝试 2:改输出格式

接下来,我们改 Claude 的输出说明,让它用稍作修改的 markdown 格式提问。例如,输出带括号备选的项目符号问题列表,再解析并做成给用户的 UI。

Claude 大多能产出这种格式,但不稳定:会多加句子、丢掉选项,或干脆放弃结构。换下一种。

尝试 3:AskUserQuestion 工具

The AskUserQuestion tool in the Claude Code terminal: tabs for Paradigm, Theme, Snacks, Indentation and Submit, the question “Which programming paradigm do you prefer for this project?”, and numbered options: Functional, Object-Oriented, Procedural, Mixed, Type something, and Chat about this.

最终我们做成一个 Claude 随时可调的工具,并在 Plan Mode 下特别提示它调用。工具触发时弹出模态框展示问题,并阻塞 Agent 循环直到用户作答。

这让我们可以提示 Claude 给出结构化输出,并确保给用户多个选项。用户也能组合使用,例如在 Agent SDK 里调用,或在 Skill 里引用。

最重要的是,Claude 似乎愿意调用这个工具,输出也好用。毕竟,再精巧的工具,Claude 不会调也没用。

这是 Claude Code 里 elicitation 的最终形态吗?大概不是。Claude 更强了,服务它的工具也要跟着变。下一节是一个曾经有用、后来开始碍事的工具。

随能力更新:tasks 与 todos

Diagram titled “From todos to tasks”: on the left, a single agent with a checklist (set up project, write tests, implement feature, deploy). An arrow labeled “models improve” points to the right, where Agent A and Agent B share tasks with dependencies: Tasks 1 and 2 are done and feed Task 3, which is in progress, followed by Task 4.

Claude Code 刚上线时,我们发现模型需要一份 todo 列表 才能不跑偏。Todos 可在开头写好,做完再勾掉。于是我们给了 Claude TodoWrite 工具,用来写入或更新 Todos 并展示给用户。

即便如此,Claude 还是常忘掉要做什么。我们每隔 5 轮插入系统提醒,把目标再告诉它。

模型变强后,To-do 列表显得束缚。一直被提醒 todo 列表,Claude 会觉得必须死守列表,而不是发现需要改道时修改它。我们也看到 Opus 4.5 用 subagent 好得多了,但 subagent 怎么在一份共享 todo 上协调?

于是我们用 Task 工具 替换了 TodoWrite。Todos 侧重让模型不跑偏;tasks 则帮助 Agent 彼此沟通。Tasks 可带依赖、跨 subagent 同步更新,模型也能改、能删。

模型能力上去后,曾经需要的工具可能变成约束。要 不断回头检查 哪些工具还需要。这也是为什么最好只支持一小批能力画像相近的模型。

设计搜索接口

我们做过最重要的工具,是让 Claude 自己找上下文的那些。

Claude Code 内部刚发布时用的是 RAG:向量库预索引代码库,harness 在每次回复前检索相关片段交给 Claude。RAG 又快又强,但要索引和配置,跨环境也脆弱。更关键的是:上下文是给 Claude 的,不是它自己找的。

既然 Claude 能搜网页,为什么不能搜你的代码库?给它 Grep 工具,就能让它自己搜文件、自己攒上下文。

Claude 越聪明,在合适工具下就越会自己构建上下文。

引入 Agent Skills 时,我们把渐进披露(progressive disclosure)形式化了:Agent 可通过探索增量发现相关上下文。

Claude 可以读 Skill 文件,那些文件再引用其他文件,模型可递归读取。实际上,Skill 的常见用法就是给 Claude 加更多搜索能力,比如教它怎么用某个 API 或查数据库。

一年下来,Claude 从几乎不会自己攒上下文,变成能跨多层文件嵌套搜索,找到刚好需要的那一段。

渐进披露现在是我们在不加新工具的前提下加功能的常用手法。下一节说明原因。

渐进披露:Claude Code Guide Agent

Claude Code 目前大约有 20 个工具,团队经常回头问:要不要这么多才最有效。加新工具门槛很高,因为又多给模型一个要权衡的选项。

例如,我们发现 Claude 对自己怎么用 Claude Code 不够了解。问它怎么加 MCP、某个 slash 命令做什么,它答不上来。

本可以把这些信息全塞进系统提示词,但用户很少问这些,只会加重上下文腐化(context rot),干扰 Claude Code 的主业:写代码。

于是我们试渐进披露:给 Claude 一个文档链接,需要时再加载和搜索。这能用,但 Claude 会把大块文档拉进上下文,才能找到用户一句话就能得到的答案。

于是我们做了 Claude Code Guide——用户一问 Claude Code 本身,Claude 就调用的 subagent。Subagent 在自己的上下文里搜文档,按详细说明搜索和抽取,只交回答案。主 Agent 的上下文保持干净。

这不是完美方案(问它怎么配置自己时仍可能糊涂),但我们在不加新工具的前提下扩大了 Claude 的行动空间。

像 Agent 一样看是艺术,不是科学

给模型设计工具既是艺术也是科学。高度依赖你用的模型、Agent 的目标,以及它运行的环境。

最好的建议?常做实验,读输出,试新东西。最重要的是,试着像 Agent 一样看。

开始使用 Claude Code。

本文作者 Thariq Shihipar,Anthropic Member of Technical Staff,负责 Claude Code。