本模块主要参考(官方)
-
1\] [Writing effective tools for agents](https://www.anthropic.com/engineering/writing-tools-for-agents)(Anthropic Engineering,Sep 2025)
-
3\] [The "think" tool](https://www.anthropic.com/engineering/claude-think-tool)(Anthropic Engineering)
本模块在整体中的位置
在模块一确定「要用工具」之后,工具设计 直接决定 Agent 能多稳、多省 context、多好调试。Anthropic 把工具定义为「确定性系统(你的实现)与非确定性系统(Agent)之间的合约」------和传统 API 不同,工具要允许 Agent 用多种合理策略都能成功,而不是只支持一种固定用法。本模块的线索是:先理解这份「合约」的特殊性(§1)→ 再学会选对工具、写好返回与错误(§2--§4)→ 再用评测驱动迭代(§5)→ 最后用到高级用法与 Think(§6)。
逻辑线索(本模块阅读顺序)
- 合约:工具面向 Agent,不是传统调用方;设计目标是「多策略可成功」。
- 选型:选对工具比多更重要(search 而非 list、合并多步、职责清晰)。
- 实现:namespacing、返回高信号、token 效率、可操作错误信息。
- 迭代 :用 eval (评测任务,evaluation)+ transcript 分析 + 改描述/实现,held-out(留出不做改描述用的测试集)防过拟合。
- 进阶:并行/嵌套调用、Think 工具用于复杂推理。
本模块总流程图:工具设计与迭代 [1]
原型工具
建 Eval 任务
跑 Eval 取 transcript
分析:选错工具? 参数错? 返回冗长?
改描述/实现
Held-out 通过则收口
1. 工具是「非确定性系统」的合约 [1]
- 据 [1],工具面向的是 Agent(非确定性),不是传统 API 调用方;设计目标应是让 Agent 在多种合理策略下都能成功,而不是只支持一种固定用法。
- 最「符合人体工学」的工具,往往对人类也更好理解;可先用原型 + 真实用例测试,再系统评测 [1]。
2. 选对工具比多更重要 [1]
- 不要简单把现有 API 包一层就给 Agent [1]:Agent 有上下文上限,返回「全部列表」再让模型逐条看会浪费 context。应提供「按需检索」类工具(如
search_contacts/search_logs),而不是list_*。 - 可把多步操作合并为一个工具,减少调用链与中间结果对 context 的占用:
| 不推荐 | 推荐 |
|---|---|
get_customer_by_id + list_transactions + list_notes |
get_customer_context 一次拉齐客户相关信息 |
read_logs 返回全量 |
search_logs 只返回相关行 + 少量上下文 |
list_users + list_events + create_event |
schedule_event 查档期并创建会议 |
- 工具之间职责清晰、不重叠;若人类都说不清「该用哪个」,模型更不行。原因:工具名与描述会一起进 context;重叠或模糊会浪费 token 并增加选错工具的概率。
2.1 分流程图:工具选型决策
是
否
是
否
需要给 Agent 的能力
返回是否可能很大?
提供 search/过滤/分页 工具
是否常多步连续调用?
合并为单工具 如 get_customer_context
单工具即可
职责清晰、namespacing
3. Namespacing 与返回内容 [1]
- Namespacing (命名空间)[1]:多 MCP (Model Context Protocol,模型上下文协议,见 01)/ 多工具时用前缀或后缀做命名空间(如
asana_search/asana_projects_search),便于模型选对工具;前缀/后缀对评测结果有影响,需在自己的 evals 里验证。 - 返回内容 [1]:优先高信号、可解释 (如
name、file_type),少用裸 UUID;将 UUID 解析为语义化名称或 0-based ID 可显著提高检索类任务准确率。 - 可选
response_format(如 concise / detailed)控制 token 量 [1]:detailed:含 ID 等,便于后续 tool 调用。concise:仅内容摘要,省 context。
原文以 Slack 线程为例:detailed 约 206 tokens,concise 约 72 tokens(约 1/3),且 concise 仍保留线程内容,仅去掉thread_ts等 ID,适合「只读不继续调用」的场景。
示例:用枚举控制返回详略 [1]
python
# 工具提供 response_format 参数,由 Agent 按需选择
from enum import Enum
class ResponseFormat(Enum):
DETAILED = "detailed" # 含 ID,便于后续 tool 调用
CONCISE = "concise" # 仅内容,省 context
3.2 可运行代码示例 [1]
以下为可直接运行 的 Anthropic API 工具定义与单轮调用示例:一个「查当前时间」工具 + 带可操作错误信息的「平方」工具。运行前需 pip install anthropic 并设置 ANTHROPIC_API_KEY。
python
import os
from anthropic import Anthropic
client = Anthropic()
# 工具定义:描述清晰、参数无歧义、错误可操作 [1]
tools = [
{
"name": "get_utc_time",
"description": "返回当前 UTC 时间(ISO 8601)。用于用户问「几点了」等需要当前时间的场景。",
"input_schema": {
"type": "object",
"properties": {},
"required": [],
},
},
{
"name": "square_number",
"description": "计算一个数的平方。参数 x 必须为数字(int 或 float),否则返回错误说明。",
"input_schema": {
"type": "object",
"properties": {
"x": {"type": "number", "description": "要平方的数"},
},
"required": ["x"],
},
},
]
def run_tool(name: str, params: dict) -> str:
"""执行工具并返回可被模型理解的字符串;错误时返回可操作说明 [1]。"""
from datetime import datetime, timezone
if name == "get_utc_time":
return datetime.now(timezone.utc).isoformat()
if name == "square_number":
x = params.get("x")
if x is None:
return "错误:缺少参数 x。请提供数字,例如 {\"x\": 5}。"
try:
return str(float(x) ** 2)
except (TypeError, ValueError):
return "错误:x 必须是数字。请使用例如 {\"x\": 5} 或 {\"x\": 3.14}。"
return "未知工具。"
# 单轮:让模型选工具并执行
msg = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=256,
messages=[{"role": "user", "content": "请用工具计算 7 的平方,并告诉我现在 UTC 时间。"}],
tools=tools,
)
for block in msg.content:
if block.type == "tool_use":
result = run_tool(block.name, block.input)
print(f"Tool {block.name}({block.input}) => {result}")
else:
print("Reply:", block.text[:200])
以上体现了:清晰描述 、input_schema 带 description 、错误返回可操作 。多轮 agent 循环见(一)架构与选型 §3.8。LangGraph 1.0 下用 @tool 定义工具并用 model.bind_tools(tools) 单轮/多轮调用的完整示例见 延伸阅读 的「五、LangGraph 1.0 对照代码」§5.2。
4. Token 效率与错误信息 [1]
- 对可能很大的返回做 [1]:分页、范围选择、过滤、截断,并设合理默认值;Claude Code 默认单次工具返回上限约 25k tokens。
- 截断时在说明里引导模型「多次小范围检索」而非一次大查询 [1]。
- 错误信息要可操作 [1]:明确说明哪里不对、如何改,避免只给错误码或堆栈。
- 反面 :只返回
400 Bad Request或一长串 traceback,模型难以自我修正。 - 正面:在错误里写清「哪个参数不合法、期望格式是什么、可参考示例:...」,模型更容易在下一轮改对。
- 反面 :只返回
- Claude Code 默认单次工具返回上限约 25k tokens [1];大返回务必做分页/过滤/截断,并在描述里引导「多次小范围请求」。
5. 用评测驱动工具迭代 [1]
- 流程 :原型 → 建 eval(真实场景任务,可让 Claude 帮忙生成大量 prompt--outcome (任务结束时的环境终态/结果)对)→ 跑 eval(简单 agent 循环即可)→ 看 transcript / 推理 / 反馈 → 用 Claude 分析并改工具描述与实现 → 重复。用 held-out 集(留出不做改描述用的测试集)防过拟合。
- 任务质量 [1](原文举例):
- 强任务 (多步、真实场景、可验证):
- 「客户 Sarah Chen 刚提交取消请求。准备挽留方案:① 离开原因 ② 最有吸引力的挽留方案 ③ 做方案前需注意的风险」。
- 「客户 9182 反馈单次购买被扣款三次。查所有相关日志并判断是否有其他客户受影响。」
- 「与 Jane 下周约会议讨论 Acme 项目,附上最近一次项目规划会议笔记并预订会议室。」
- 弱任务(单步、过窄):「用客户 ID 45892 查取消请求」「在支付日志里搜 purchase_complete 和 customer_id=9182」------不利于考察策略与多工具组合。
- 强任务 (多步、真实场景、可验证):
- 工具描述 :像给新同事写说明------写清专用查询格式、术语、资源关系;参数名无歧义(如
user_id而非user);可加示例与边界说明。 - 在 SWE-bench Verified 上,仅对工具描述的精细优化就带来明显错误率下降与通过率提升 [1]。
示例:大返回分页/截断 [1]
工具返回可能很大时,在实现里做分页或截断,并在描述里引导模型「多次小范围请求」:
python
def search_logs(query: str, limit: int = 50, offset: int = 0) -> str:
"""返回匹配的日志行;单次最多 limit 条,用 offset 分页。建议多次小范围查。"""
# db 为占位,实际需实现或接入真实数据源
rows = db.query_logs(query, limit=limit, offset=offset)
if len(rows) >= limit:
return "\n".join(rows) + f"\n[已截断,共 {limit} 条;可加大 offset 继续]"
return "\n".join(rows)
示例:跑 eval 收集 transcript [1]
迭代工具时「跑 eval → 看 transcript」的最小循环:多次 trial(单次尝试),收集通过与否与简要 outcome(真实场景可存完整 transcript 供分析)。
python
def run_eval_n_trials(tasks: list[tuple[str, str]], n_trials: int = 3) -> list[dict]:
"""对每个 task 跑 n_trials 次,记录每次 passed 与 outcome。"""
results = []
for task_id, task_input in tasks:
trials = []
for _ in range(n_trials):
reply, outcome = agent_harness(task_input) # 你的 agent 调用
passed = grader(outcome)
trials.append({"passed": passed, "outcome": outcome})
results.append({"task_id": task_id, "trials": trials})
return results
6. 高级工具用法与 Think [2][3]
- Advanced tool use:任务复杂时的并行调用、嵌套调用与错误处理;与「选对工具、一次做对」配合使用。
- Think tool :复杂推理前先「停下来想」的 CoT (Chain-of-Thought,思维链)工具化;对代码 debug、数学解题等场景有质的提升。
- 实现上可在 system 或工具侧提供「先输出推理再行动」的约定或专用工具。
7. 实战自检清单
- 是否有
list_*类工具可改为search_*/ 按需拉取?多步是否可合并为单工具? - 返回是否多用 name/file_type 等可解释字段,少用裸 UUID?是否提供 concise/detailed 选项?
- 大返回是否有分页/过滤/截断与默认值?错误信息是否可操作?
- 是否已建 eval(含 held-out)并迭代工具描述?描述是否无歧义、带示例?
- 多工具是否做了 namespacing?是否在 eval 里验证过命名对选工具的影响?
8. 本模块要点回顾(便于自检与分享)
- 定位:工具是 Agent 与环境的合约;要支持多种合理策略成功,而非单一用法。
- 选型:优先 search/按需拉取、合并多步、职责清晰;避免 list 全量、工具重叠。
- 实现:namespacing 便于选工具;返回高信号、可解释(少裸 UUID);可选 concise/detailed 控 token;错误信息要可操作。
- 迭代:原型 → eval(真实任务、可让 Claude 生成)→ 看 transcript → 改描述与实现 → held-out 防过拟合。
- 描述:像给新同事写说明;参数无歧义、带示例与边界;SWE-bench 上仅优化描述就带来明显提升。
参考文献(本模块)
| 编号 | 来源 | 链接 |
|---|---|---|
| [1] | Anthropic, Writing effective tools for agents | https://www.anthropic.com/engineering/writing-tools-for-agents |
| [2] | Anthropic, Introducing advanced tool use | https://www.anthropic.com/engineering/advanced-tool-use |
| [3] | Anthropic, The "think" tool | https://www.anthropic.com/engineering/claude-think-tool |
| [4] | Anthropic, Equipping agents with Agent Skills | https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills |
9. 延伸
- Tool evaluation cookbook : tool-evaluation 端到端示例。
- Developer Guide : Best practices for tool definitions;
- MCP tool annotations : tool annotations 标清需 open-world 或破坏性操作的工具。
- GitHub : anthropic-sdk-python 含 Messages API 与 tool use 示例;claude-agent-sdk-demos 有多工具示例。索引有「GitHub 与官方源码」汇总。
- 上一模块:(一)架构与选型 · 下一模块:(三)上下文与记忆。