Anthropic 工程博客 · 中文学习笔记Anthropic 工程笔记

    为智能体编写高效工具——借助智能体本身

    Writing effective tools for agents — with agents

    #3 · 模块 B 工具与 MCP 原文发布:2025-09-11 阅读约 11 分钟 原文链接 ↗
    本页目录(14)
    1. 一句话总结
    2. 为什么重要
    3. 核心概念(中英对照)
    4. 方法 / 步骤
    5. 1. 先理解:工具为什么要“为智能体设计”
    6. 2. 开发循环
    7. 3. 五条写工具的原则
    8. 图解
    9. 图 1:评测驱动的工具开发闭环
    10. 图 2:从“包装 API”到“为智能体设计”的工具合并
    11. 图 3:一次工具调用的“高信号返回”设计
    12. 关键原话
    13. 实践建议
    14. 延伸阅读

    一句话总结#

    别把 API 端点原样包成工具丢给智能体:要按智能体的“感知方式”来设计工具,并用一套“原型 → 评测 → 让智能体自己帮你改”的循环持续优化。

    为什么重要#

    • 系统展开了《Building effective agents》附录里的“智能体-计算机接口(ACI)”,从理念变成了可执行的流程。
    • 给出了评测驱动的工具开发闭环,而且让 Claude Code 参与分析评测记录、批量重构工具。原文说文中大部分建议本身就是这样得出的。
    • 原则都很具体(工具合并、命名空间、response_format、截断与错误提示),可以直接拿来审查自家 MCP 服务器。

    核心概念(中英对照)#

    中文English简要解释(笔者概括)
    工具tool一种新型软件:确定性系统与非确定性智能体之间的契约。
    非确定性non-deterministic同样输入,智能体可能选择不同路径(调用工具、凭常识回答、先反问)。
    好用性 / 人体工学ergonomic对智能体而言是否顺手;原文发现对智能体顺手的工具对人也直观。
    可供性affordance使用者感知到“能用它做什么”;智能体与传统程序不同。
    评测任务evaluation task基于真实场景、通常需要多次工具调用的提示,配可验证的结果。
    验证器verifier判定回答是否正确,可以是字符串比对,也可以让 Claude 评判。
    留出测试集held-out test set不参与优化的测试集,防止对评测过拟合。
    交错思考interleaved thinking工具调用之间的思考,便于了解模型为何调用或不调用某工具。
    命名空间namespacing用统一前缀(按服务、按资源)给工具分组,划清边界。
    响应格式参数response_format让智能体选择返回“简洁”还是“详细”内容的枚举参数。
    分页 / 范围选择 / 过滤 / 截断pagination / range selection / filtering / truncation控制工具返回量的手段。
    工具注解tool annotationsMCP 中标注工具是否需要开放网络访问、是否有破坏性操作。

    方法 / 步骤#

    1. 先理解:工具为什么要“为智能体设计”#

    传统函数如 getWeather("NYC") 每次行为一致;但用户问“今天要不要带伞”,智能体可能调天气工具、直接凭常识答、或先问在哪个城市,也可能误用工具。所以写工具不能照着“给其他开发者写 API”的习惯来。

    2. 开发循环#

    ① 做原型

    • 用 Claude Code 写工具时,把依赖的库 / API / SDK 文档(如官方站点的 llms.txt)喂给它。
    • 包成本地 MCP 服务器或桌面扩展,在 Claude Code(claude mcp add ...)或 Claude Desktop 里试用;也可以直接在 API 调用中传入工具做程序化测试。
    • 自己先用,收集用户反馈。

    ② 生成评测任务

    • 让 Claude Code 探索工具,生成几十个提示-答案对;任务基于真实数据源和服务,避免过于简单的“沙盒”。好任务可能需要数十次工具调用。
    • 强任务 vs 弱任务(笔者按原文思路概括):强任务像真实请求,需要综合多步信息(例如“和某人约下周会议、附上上次会议纪要、订会议室”);弱任务只是直接给出参数让工具执行一步(例如“查日志里某个字段等于某值”)。
    • 每个提示配一个可验证的结果;验证器不要太严,别因为格式、标点或合理的同义表述就判错。
    • 可以注明“预期调用哪些工具”,但不要过度规定策略,正确路径往往不止一条。

    ③ 运行评测

    • 直接调用 LLM API,每个任务一个简单的 while 循环(模型调用与工具调用交替)。
    • 让评测智能体除结构化答案外,在调用工具和作答之前先输出推理和反馈,可能触发思维链、提升效果;用 Claude 时也可以直接开交错思考。
    • 除准确率外还要收集:单次工具调用与任务的总耗时、工具调用次数、token 总消耗、工具错误数。

    ④ 分析结果

    • 让智能体帮你发现问题(描述矛盾、实现低效、schema 混乱),但要注意它没说出来的可能更重要。
    • 读推理和反馈,也要读原始记录(包括工具调用和返回)。
    • 看指标:冗余调用多 → 调整分页或 token 上限参数;参数错误多 → 描述或示例要更清楚。原文例子:上线网页搜索工具时发现 Claude 总在查询里无谓地加上年份“2025”,影响结果,后来通过改进工具描述解决。

    ⑤ 让智能体来改

    • 把评测记录拼起来交给 Claude Code,让它分析并一次性重构多个工具,保证实现和描述前后一致。
    • 用留出测试集防过拟合;原文称这样还能在“专家手写”或 Claude 生成的工具基础上进一步提升。

    3. 五条写工具的原则#

    原则要点(概括)原文式例子
    选对要做的工具工具不是越多越好;不要机械包装 API 端点。智能体上下文有限,“返回全部再逐条读”很浪费。先围绕高影响工作流做少量精心设计的工具,可以在内部合并多步操作。用 search_contacts 代替 list_contacts;用 schedule_event 合并查空闲与建日程;用 search_logs 代替 read_logs;用 get_customer_context 一次汇总客户信息
    命名空间智能体可能同时接入几十个 MCP 服务器、上百个工具;按服务、按资源加前缀能减少混淆。前缀式和后缀式的效果有差别,且因模型而异,要用评测来选。asana_search、jira_search、asana_projects_search
    返回有意义的上下文只返回高信号信息;避免 uuid、mime_type 之类底层标识,优先 name、file_type 等。把随机 ID 解析成有语义的名字(甚至 0 起编号)能减少幻觉、提升检索精度。需要时提供 response_format(concise / detailed)。返回结构(XML / JSON / Markdown)也会影响效果,没有统一答案。原文 Slack 示例中,“简洁”返回约为“详细”的三分之一 token
    优化 token 效率可能返回大量内容的工具要有分页、范围、过滤、截断,并设合理默认值;Claude Code 默认把工具返回限制在 25,000 token。截断时提示更省 token 的做法;错误返回要写清可操作的修改建议,而不是只给错误码或堆栈。截断提示里建议“多次小范围搜索”而非一次大搜索
    把描述当提示来写像给新同事解释一样,把隐含知识(查询格式、术语、资源关系)写明;输入输出描述清楚并用严格数据模型约束;参数名不要有歧义(user_id 优于 user)。小改描述可能带来大提升:原文提到 Claude 3.5 Sonnet 在 SWE-bench Verified 上的成绩就得益于对工具描述的精确打磨。—

    图解#

    图 1:评测驱动的工具开发闭环#

    flowchart LR
        P[① 快速原型<br/>本地 MCP / 桌面扩展] --> G[② 生成真实、多步的评测任务<br/>+ 可验证结果]
        G --> R[③ 程序化运行评测<br/>简单 while 循环 + 收集指标]
        R --> A[④ 分析<br/>推理/反馈 + 原始记录 + 调用指标]
        A --> C[⑤ 交给 Claude Code<br/>批量重构工具与描述]
        C --> R
        C -. 定期 .-> H[留出测试集<br/>防过拟合]

    图 2:从“包装 API”到“为智能体设计”的工具合并#

    flowchart TB
        subgraph Before["机械包装 API(智能体要自己串联,中间结果都进上下文)"]
            direction LR
            a1[list_users] --> a2[list_events] --> a3[create_event]
        end
        subgraph After["为工作流设计(中间步骤在工具内部完成)"]
            direction LR
            b1["schedule_event<br/>查空闲 + 建日程"]
        end
        Before == 合并 ==> After

    图解:机械包装 API 时,智能体要自己依次调用 list_users、list_events、create_event;按工作流设计时合成一个 schedule_event。

    图 3:一次工具调用的“高信号返回”设计#

    flowchart TD
        Call["智能体调用 search_xxx(query, response_format)"] --> V{参数校验}
        V -- 不通过 --> E["可操作的错误提示<br/>(哪里错、正确格式示例)"]
        V -- 通过 --> Q[执行查询]
        Q --> S{结果是否过大?}
        S -- 是 --> T["分页 / 截断<br/>+ 提示如何缩小范围"]
        S -- 否 --> F{response_format}
        F -- concise --> C1["只返回内容与可读名称"]
        F -- detailed --> C2["附带后续调用需要的 ID"]

    图解:调用先过参数校验,不通过就返回可操作的错误提示;结果过大就分页或截断并提示如何缩小范围;response_format 决定只返回内容还是附带后续调用需要的 ID。

    关键原话#

    “Tools are a new kind of software which reflects a contract between deterministic systems and non-deterministic agents.” —— 工具是一种新型软件,体现的是确定性系统与非确定性智能体之间的契约。

    “More tools don’t always lead to better outcomes.” —— 工具多不一定效果好。

    实践建议#

    • 盘点现有工具:哪些只是对 API 端点的一比一包装?能否按工作流合并?
    • 每个工具都能用一句话说清用途,并与其他工具区分开;接入多个服务时统一命名空间。
    • 返回字段逐个审查:去掉智能体用不上的底层 ID;必须保留 ID 时提供 response_format。
    • 所有“可能很大”的返回都设分页 / 截断,并在截断说明里告诉智能体下一步怎么做。
    • 把错误信息改写成“告诉智能体怎么改”的提示。
    • 建 20 个以上真实多步任务作评测,跟踪准确率、调用次数、token、错误数;保留一份留出测试集。
    • MCP 服务器使用 tool annotations 标注破坏性操作和开放网络访问。
    • 笔者补充:改工具描述也要像改代码一样走评审,并在评测上做 A/B 对比。

    延伸阅读#

    站内笔记

    原文引用的资源


    本笔记依据 2026-10-17 抓取的在线原文撰写。原文:Anthropic,《Writing effective tools for agents — with agents》。

    进度只保存在本机浏览器,在学习路线中查看
    本页目录