根据调试经验,Agent工具选择错误占故障40%;OpenAPI schema远不够,需补充场景、互斥关系、参数边界等细节描述。
我来完整翻译这篇文章。
我调试过的大多数 agent 失败并不是推理失败。模型的推理是正确的。它只是选择了错误的工具,因为工具描述没有告诉它需要了解的内容。
这是一个讨论不足的问题,而且你添加的集成越多,问题就越严重。以下是我们学到的内容。
假设你的 agent 有四个日历相关的工具可用:
[
{ "name": "calendar_create_event", "description": "Creates a calendar event" },
{ "name": "calendar_quick_add", "description": "Adds an event from text" },
{ "name": "scheduling_book_slot", "description": "Books a scheduling slot" },
{ "name": "meeting_schedule", "description": "Schedules a meeting" }
]
现在用户说:"帮我在周四和 Sarah 预约 30 分钟。"
你会选哪一个?你也不知道,而且你拥有模型没有的上下文。模型会选一个,大约 60% 的时间它会成功,当它失败时,这个失败是静默的——在错误的系统中创建了一个事件,一个星期后才有人发现。
我们追踪的大约 40% 的 agent 失败都可以追溯到工具选择,而不是推理。这令人惊讶,改变了我们投入工程时间的地方。
一个 schema 告诉你一个工具接受什么。但它不会告诉你:
文档也没有这些,因为文档是为已经知道自己在集成哪个产品的人类编写的。而 agent 是在产品之间进行选择。
以下是我们汇聚的模板:
name: calendar_create_event
purpose: >
Create an event on the user's primary Google Calendar when you already
know the exact date, time, and duration.
use_when:
- The time is fully specified ("Thursday 2pm for 30 minutes")
- The user owns the calendar being written to
do_not_use_when:
- The time is approximate or needs negotiation → use scheduling_book_slot
- Inviting external participants who need to pick → use scheduling_book_slot
- The user said "find a time" rather than naming one
reversible: yes — event can be deleted via calendar_delete_event
side_effects: sends invitations to all attendees immediately
cost: low
requires: google_calendar connection active
do_not_use_when 块中带有显式重定向正在做大部分工作。它不是在描述这个工具——它在描述这个工具与相邻工具之间的边界,这正是模型不确定的地方。
手工编写这些超过几十个工具就不能扩展。我们的循环是:
从 schema 和任何存在的文档中使用模型生成初稿。发布它。它会很平庸。记录每个选择,以及 agent 被要求做什么和它选择了什么。当选择错误时,不要修补 prompt——修补应该被选择的工具和被选择的工具的描述。随着时间推移,描述成为系统犯过的每个错误的记录。
def record_misselection(task, chosen_tool, correct_tool):
# The fix goes in the tool metadata, not the system prompt.
# System prompt fixes don't generalize; description fixes do.
boundary_note = infer_distinguishing_feature(task, chosen_tool, correct_tool)
tools[correct_tool].use_when.append(boundary_note)
tools[chosen_tool].do_not_use_when.append(
f"{boundary_note} → use {correct_tool}"
)
第 5 步是重要的。每一个本能都说通过向系统 prompt 添加规则来修复选择错误。抵制它。Prompt 修复是全局的,它们相互冲突,它们不能在模型升级后存活。描述修复是涉及工具的本地化,它们能够组合。
相关的,而且可以节省真金白银:不要在循环的每一步都发送每个工具 schema。Schema 可能是你的 token 消耗的很大一部分,因为它们在每次迭代时重新发送,而不是每次运行发送一次。
def relevant_tools(context, all_tools, k=8):
# Cheap pre-filter — embedding similarity between the current
# goal and each tool's `purpose` field
scored = rank_by_similarity(context.goal, all_tools, key="purpose")
return scored[:k] + always_include(all_tools)
上下文中的工具越少,也意味着更好的选择准确性,所以这帮了两次。大多数框架鼓励预先将所有内容交给 agent;超过大约十几个工具,这是错误的默认设置。
行业在竞争模型质量和集成数。目前都不是 agent 可靠性的真正来源。
语义层——每个工具的含义、何时适用、它与相邻工具的区别——是不起眼的策展工作,没人将其作为功能发布。在我们的经验中,这也是 agent 演示效果很好和可以无人值守运行的 agent 之间的区别。
如果我从头开始,我会从第一天开始将其视为核心产品,而不是要度过的基础设施。
构建 DeskFerry 时——跨 1500+ 集成的 agent,这就是我们开始关心这个问题的方式。欢迎在下面提问。