Anthropic Agent 工程实战笔记(二)工具设计

本模块主要参考(官方)

  • 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)。


逻辑线索(本模块阅读顺序)

  1. 合约:工具面向 Agent,不是传统调用方;设计目标是「多策略可成功」。
  2. 选型:选对工具比多更重要(search 而非 list、合并多步、职责清晰)。
  3. 实现:namespacing、返回高信号、token 效率、可操作错误信息。
  4. 迭代 :用 eval (评测任务,evaluation)+ transcript 分析 + 改描述/实现,held-out(留出不做改描述用的测试集)防过拟合。
  5. 进阶:并行/嵌套调用、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]:优先高信号、可解释 (如 namefile_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. 延伸

相关推荐
梅羽落2 小时前
XPath笔记
笔记
桂花很香,旭很美2 小时前
Anthropic Agent 工程实战笔记(六)安全与生产
笔记·架构·agent
sponge'3 小时前
opencv学习笔记14:transformer
笔记·学习·transformer
xhyu614 小时前
【学习笔记】推荐系统 (4.召回:Deep Retrieval、其他召回通道、曝光过滤)
笔记·学习
两万五千个小时4 小时前
构建mini Claude Code:08 - Fire and Forget:用后台线程解锁 Multi-Agent 并行执行
人工智能·python·架构
桂花很香,旭很美5 小时前
Anthropic Agent 工程实战笔记(一)架构与选型
笔记·架构·language model
Aliex_git5 小时前
Sentry 私有部署和配置笔记
笔记·学习·sentry
qq_24218863325 小时前
金融AI反欺诈系统构建指南
人工智能·笔记·金融·课程设计
四谎真好看6 小时前
SSM学习笔记(SpringBoot篇)
spring boot·笔记·学习·学习笔记·ssm