https://www.anthropic.com/engineering/writing-tools-for-agents


代理工具深度解析:Q&A

Q1:这篇文章的核心论点是什么?为什么为 AI 代理(Agent)编写工具,和我们平时为其他程序员写 API 有本质区别?

A: 这篇文章的核心论点是:为非确定性的 AI 代理设计工具,必须从根本上改变我们编写和思考软件的方式。

这与传统 API 设计的本质区别在于交互对象的不同:

  1. 传统 API (确定性世界):

    • 本质: 是一个确定性系统与另一个确定性系统之间的契约。
    • 类比: 就像两台精确咬合的齿轮。你调用 getWeather("NYC"),它就一定会、也只会用完全相同的方式去获取纽约市的天气。输入相同,过程和输出永远相同。
  2. 代理工具 (非确定性世界):

    • 本质: 是一个确定性系统 (工具) 与一个非确定性系统 (AI 代理) 之间的契约。
    • 类比: 更像是你给一个极富创造力但有时会分心、会误解的“人类实习生”(AI 代理)下达指令。当你问“我今天需要带伞吗?”,代理可能会:
      • 直接调用天气工具。
      • 先反问你在哪个城市。
      • 甚至可能“幻想”出一个天气信息。
    • 结论: 我们不能再假设调用者会 100% 精确、理性地使用工具。因此,工具的设计目标不再仅仅是实现功能,更是要引导、辅助代理,并对它的“不确定性”行为有鲁棒性
Q2:文章提出了一个怎样的开发流程来打造高效的代理工具?听起来像个可以动手实践的循环。

A: 是的,它提出了一个非常实用的、以评估为驱动的迭代开发循环。这很符合你动手实践的风格:

  1. 第一步:构建原型 (Build a Prototype)

    • 快速搭建工具的初始版本。你可以把相关的 SDK、API 文档喂给像 Claude Code 这样的编码助手,让它帮你生成工具代码的初稿。
  2. 第二步:运行评估 (Run an Evaluation)

    • 这是最关键的一步。你需要系统性地衡量代理使用这些工具的效果。你需要:
      • 创建真实的测试任务: 基于真实世界的使用场景,设计需要调用工具(甚至多次调用)才能完成的复杂任务。例如,“安排下周与张三的会议,讨论项目A,并附上上次的会议纪要”。
      • 建立验证机制: 定义一个标准来判断代理是否成功完成了任务。
  3. 第三步:与代理协作分析与改进 (Collaborate with Agents to Improve)

    • 让代理(比如 Claude)去分析评估过程中产生的日志、对话记录和失败案例。代理非常擅长从大量的文本中发现模式,比如:
      • “看起来代理总是把 user_iduser_name 搞混。”
      • “这个工具的描述似乎有歧义,导致代理用错了。”
    • 基于这些分析,你(或者让代理帮你)重构和优化工具代码、描述等。
  4. 第四步:重复循环

    • 将优化后的工具再次投入评估,如此循环往复,直到性能达到满意的水平。

这个过程的本质是将“工具开发”从一个纯粹的工程问题,转变为一个包含“实验、测量、优化”的科学问题

Q3:在选择实现哪些工具时,有什么“避坑”指南吗?为什么说“工具并非越多越好”?

A: 这是一个非常深刻的观点。这里的核心原则是:“面向工作流,而非面向功能”

  • 本质: AI 代理的“上下文窗口”(Context)是其最宝贵的资源,类似于人类的“注意力”或“短期记忆”。如果一个工具返回大量无关信息,就会严重消耗这个资源。

  • 要避免的坑:

    • 无脑封装: 不要简单地把现有的每一个 API 终端都封装成一个工具。
    • 返回“全量数据”: 避免创建像 list_all_users 这样会返回巨大列表的工具。代理需要“逐字逐句”地在上下文中阅读这个列表来找到目标,极其低效。
  • 推荐的做法:

    • 合并操作: 将人类处理任务时经常连续执行的多个步骤,合并成一个工具。
      • 例子: 不要提供 list_users, list_events, create_event 三个工具,而是提供一个 schedule_event 工具,它在内部完成查找参会者有空的时间并创建日历事件的所有操作。
    • 提供搜索/过滤能力: 将“遍历”的计算压力从代理的“大脑”(上下文)转移到工具本身。
      • 例子:search_logs(keyword="error") 代替 read_logs()
  • 类比: 你不会想通过从头到尾读完一本字典来查找一个词的意思(消耗巨大注意力),你会直接使用索引或按字母顺序查找(高效的工具)。

Q4:文章中提到的“命名空间 (Namespacing)”和“优化返回内容”具体指什么骚操作?

A: 这两个都是为了让工具对代理更“友好”(Ergonomic)的关键操作。

  1. 命名空间 (Namespacing):

    • 作用: 分组和消歧。当代理有权访问来自不同服务(比如 Asana, Jira, Slack)的几百个工具时,它很容易混淆。
    • 操作: 给工具名称加上前缀,形成逻辑分组。例如,asana_search_tasksjira_search_issues
    • 本质: 这就像在代码中用 modulepackage 来组织函数一样,为代理提供了一个清晰的“工具地图”,帮助它在正确的“抽屉”里找到正确的工具。
  2. 优化返回内容 (Returning Meaningful Context):

    • 作用: 提升信噪比,降低代理的理解成本
    • 操作:
      • 返回自然语言而非ID: 尽量返回人类可读的名称(name: "Project Phoenix")而不是一串无意义的ID (uuid: "a1b2c3d4...")。这能显著减少代理的“幻觉”。
      • 提供不同详细度的格式: 可以给工具增加一个 response_format 参数(如 "concise""detailed")。默认用简洁模式节省Token,当代理需要ID去调用下一个工具时,再让它自己请求详细模式。
      • 优化错误和截断提示: 如果返回内容被截断,提示应该告诉代理如何获取更多信息(例如,“结果已截断,请使用 page 参数翻页”)。如果调用出错,错误信息应该清晰地告诉代理如何修正它的输入。
    • 本质: 这是在和代理进行“高效沟通”。你不会跟同事说“去处理工单 8f5b...”,你会说“去处理那个关于登录问题的工单”。
Q5:这篇文章最让我感兴趣的是“与代理协作”。它具体是如何让代理来优化自己的工具的?

A: 这确实是全文最“赛博朋克”也最具启发性的一点。其核心是利用 LLM 强大的代码分析和重构能力

具体流程如下:

  1. 收集“第一手资料”: 运行完一轮评估后,你会得到大量的“交互记录 (transcripts)”,里面包含了:

    • 用户的原始请求。
    • 代理的“思考链 (Chain-of-Thought)”。
    • 代理实际调用的工具和参数。
    • 工具返回的结果。
    • 代理的最终回答。
    • 任务成功或失败的标记。
  2. 让代理成为“代码审查员”:

    • 你把这些原始的、混杂的交互记录整个喂给一个编码能力强的代理(如 Claude Code)。
    • 然后给它一个指令,例如:“分析以上评估日志,找出导致任务失败或效率低下的原因,并重构相关的工具定义(包括函数实现、参数和描述),以提升整体性能。
  3. 代理能发现的问题:

    • 描述歧义:search 这个描述太模糊了,我应该把它改成 search_documents_by_keyword。”
    • 参数设计不佳: “代理总是忘记传 user_id,也许我应该把这个参数设为必填,并在描述里举个例子。”
    • 实现效率低下: “这个工具返回了太多无用字段,我来修改一下,只返回 namesummary。”
    • 命名不一致: “所有 Asana 相关的工具都应该以 asana_ 开头,我来统一一下。”

本质: 这是一种元编程 (Metaprogramming) 的思想在 AI 领域的应用。你不再是手动调试和优化每一行代码,而是创建一个评估环境,让 AI 在这个环境中“演化”和“迭代”自己的工具集,从而实现性能的自我提升。这极大地提升了优化的效率和规模。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐