课程大纲 › 领域 2:工具设计与 MCP

2.3 在多个 Agent 间合理分配工具并配置工具选择

タスクステートメント2.3:エージェント間でツールを適切に配分し、ツール選択を設定する

官方大纲原文(日文):知识 4 条 · 技能 5 条

需要掌握的知识

  • エージェントに多すぎるツール(例:4-5個ではなく18個)へのアクセスを与えると、判断の複雑さが増し、ツール選択の信頼性が低下するという原則
  • 専門外のツールを持つエージェントが、それらを誤用しがちである理由(例:統合エージェントがウェブ検索を試みる)
  • スコープを限定したツールアクセス:エージェントにはその役割に必要なツールのみを与え、頻度の高い特定のニーズに対しては役割横断のツールを限定的に与える
  • tool_choiceの設定オプション:"auto"、"any"、強制的なツール選択({"type": "tool", "name": "..."})

需要能做到的事

  • 各サブエージェントのツールセットをその役割に関連するものに制限し、専門外のツールの誤用を防ぐ
  • 汎用的なツールを制約付きの代替ツールに置き換える(例:fetch_urlを、ドキュメントURLを検証するload_documentに置き換える)
  • 複雑なケースはコーディネーター経由でルーティングしつつ、頻度の高いニーズに対してはスコープを限定した役割横断のツールを提供する(例:統合エージェント向けのverify_factツール)
  • tool_choiceの強制選択を使用して特定のツールが最初に呼び出されるようにし(例:エンリッチメントツールの前にextract_metadataを強制する)、後続のステップはフォローアップのターンで処理する
  • モデルが会話テキストを返すのではなく確実にツールを呼び出すように、tool_choice: "any"を設定する

课程讲解 · AI 草稿,未经人工审核 以官方文档为准

这一条考什么

考你在多 Agent 系统中如何分配工具,以及如何用 tool_choice 控制模型调用工具的方式。你需要理解:工具给得太多会降低选择可靠性;拿到专业之外工具的 Agent 容易越界误用;正确做法是按角色限定工具集,只为高频需求提供少量受限的跨角色工具;并能根据场景选用 "auto"、"any" 或强制指定某个工具。

核心概念

工具越多,选择越不可靠

每多一个工具,模型每一步都要多比较一个选项。给一个 Agent 18 个工具,而它的职责其实只需要 4–5 个,会带来两类问题:决策复杂度上升导致选错工具;工具定义占用上下文。更隐蔽的问题是角色与工具权限的矛盾:系统提示说"你是综合分析员",工具列表却提供了网页搜索,模型就会把"去搜一下"当成合法的补救手段。

为什么专业外工具会被误用

当综合 Agent 发现证据不足时,最"顺手"的做法是自己调用 web_search 补一点——它并不知道这会绕过协调者的研究计划、产出未经文档分析的来源,并与搜索 Agent 的工作重复。报告生成 Agent 拿到文档分析工具,也会在写报告时临时"再分析一下"。根因不是模型"不听话",而是配置把越界动作呈现为可用能力。解决方式是让工具集与角色一致:

  • 搜索 Agent:web_search、fetch_page。
  • 文档分析 Agent:load_document、extract_data_points。
  • 综合 Agent:只处理已提供的材料,外加一个受限的 verify_fact。
  • 报告 Agent:格式化与引用工具。

在 Agent SDK 中,这通过每个 AgentDefinition 的 tools 白名单实现。

限定范围的工具访问与跨角色工具

原则是"最小必要":每个 Agent 只拿到完成本职所需的工具。但如果某个跨角色需求非常频繁,每次都绕回协调者代价太高,可以提供一个范围受限的跨角色工具。例如综合 Agent 常需要核实一个具体数字,给它 verify_fact(claim, source_id)——只能针对已有来源核实单条论断,不能做开放式搜索。复杂情况(需要新的研究方向、大量新来源)仍然通过协调者路由。

用受限工具替代通用工具

通用工具权限太宽,容易被滥用。例如 fetch_url 可以抓取任意网址,文档分析 Agent 可能借此去访问无关网站。替换为 load_document(document_url),在实现中校验 URL 是否属于允许的文档库域名、类型是否为支持的文档格式,不符合就返回校验错误。工具的能力边界即是 Agent 的行为边界。

tool_choice 的选项

Messages API 的 tool_choice 控制模型是否、以及如何调用工具:

  • {"type": "auto"}(默认):模型自行决定是否调用工具、调用哪个,也可以直接用文本回答。
  • {"type": "any"}:必须调用某个工具,但由模型选择哪一个。适合"必须输出结构化结果、不能只回聊天文本"的场景。
  • {"type": "tool", "name": "extract_metadata"}:强制调用指定工具。适合确保某一步必须先执行。
  • {"type": "none"}:禁止调用工具。

注意:any 和强制 tool 时,API 会直接让模型输出 tool_use,不会先输出解释文本;使用扩展思考时只支持 auto 和 none。

强制首步,后续步骤在后续轮次处理

需求:必须先抽取元数据,再用它调用若干丰富化(enrichment)工具。做法:

  1. 第一轮设置 tool_choice={"type": "tool", "name": "extract_metadata"},保证第一步一定是它。
  2. 执行后把 tool_result 追加回对话。
  3. 后续轮次改回 auto(或 any),让模型根据元数据决定调用哪些丰富化工具。

如果每一轮都强制 extract_metadata,模型就永远无法调用其他工具;如果只是把它排在工具数组第一位并用 auto,顺序并不能得到保证——数组顺序不是优先级。

正确做法与反模式

  • 正确:每个子 Agent 只获得与角色相关的 4–5 个工具。反模式:为方便起见给所有 Agent 全部 18 个工具。
  • 正确:用 load_document 这种校验输入的受限工具替代 fetch_url。反模式:保留通用抓取工具,再在提示里要求"只抓文档"。
  • 正确:为高频跨角色需求提供 verify_fact 之类的窄工具,复杂情况经协调者路由。反模式:干脆把 web_search 也给综合 Agent。
  • 正确:第一轮强制 extract_metadata,后续轮次放开选择。反模式:每轮都强制同一工具,或依赖工具在数组中的顺序。
  • 正确:必须产生工具调用而非聊天文本时用 tool_choice: "any"。反模式:用 auto 并在提示中恳求"请务必调用工具"。

常见陷阱

  • 现象是"综合 Agent 去做网页搜索",选项归因于"工具定义占用太多上下文"——不是主因;根因是角色与工具权限不匹配、工具过多,修复是按角色限定工具集。
  • "协调者无法追踪每个子 Agent 的能力导致误派"——问题出在子 Agent 自身调用越界工具,与协调者路由无关。
  • "把 extract_metadata 放在 tools 数组最前面,Claude 会优先调用"——数组顺序不保证调用顺序。
  • "每个请求都强制 tool_choice 为 extract_metadata"——后续丰富化步骤永远无法执行。
  • "把 tool_choice 从 auto 改为 any 来防止模型编造参数"——any 只保证会调用某个工具,不保证选对工具或参数可信。
  • "把所有跨角色需求都绕回协调者"——对高频的简单核实需求,增加不必要的延迟;合理折中是窄范围的跨角色工具。

实操练习

目标:用 anthropic SDK 验证"首轮强制工具、后续放开"的两阶段调用,并对比 auto 与 any。

  1. 保存下面的 tool_choice_lab.py 并运行。
  2. 观察第一轮是否一定调用 extract_metadata,第二轮模型调用了哪个丰富化工具。
  3. 把最后一段的 tool_choice 在 auto 与 any 间切换,观察是否出现纯文本回答。
import json
import anthropic

client = anthropic.Anthropic()
MODEL = "claude-sonnet-4-5"

TOOLS = [
    {"name": "extract_metadata",
     "description": "从文档文本中抽取标题、作者、发表年份、DOI。必须在任何丰富化操作之前执行。",
     "input_schema": {"type": "object",
                      "properties": {"title": {"type": "string"}, "authors": {"type": "array", "items": {"type": "string"}},
                                     "year": {"type": "integer"}, "doi": {"type": "string"}},
                      "required": ["title"]}},
    {"name": "lookup_citations",
     "description": "根据 DOI 查询被引次数。需要 extract_metadata 得到的 doi。",
     "input_schema": {"type": "object", "properties": {"doi": {"type": "string"}}, "required": ["doi"]}},
    {"name": "lookup_author_profile",
     "description": "根据作者姓名查询机构与研究方向。",
     "input_schema": {"type": "object", "properties": {"name": {"type": "string"}}, "required": ["name"]}},
]

doc = "Attention Is All You Need. Vaswani et al., 2017. DOI: 10.48550/arXiv.1706.03762"
messages = [{"role": "user", "content": f"整理这篇文献的元数据并补充被引信息:\n{doc}"}]

# 第一轮:强制 extract_metadata
r1 = client.messages.create(model=MODEL, max_tokens=800, tools=TOOLS, messages=messages,
                            tool_choice={"type": "tool", "name": "extract_metadata"})
tu = next(b for b in r1.content if b.type == "tool_use")
print("第一轮:", tu.name, tu.input)

messages += [{"role": "assistant", "content": r1.content},
             {"role": "user", "content": [{"type": "tool_result", "tool_use_id": tu.id,
                                            "content": json.dumps({"saved": True})}]}]

# 后续轮:放开选择(试试 auto 与 any)
r2 = client.messages.create(model=MODEL, max_tokens=800, tools=TOOLS, messages=messages,
                            tool_choice={"type": "any"})
print("第二轮 stop_reason:", r2.stop_reason,
      [(b.name, b.input) for b in r2.content if b.type == "tool_use"])

检查结果:第一轮的 stop_reason 为 tool_use 且工具必然是 extract_metadata,响应中没有前置文本;第二轮在 any 下一定会调用某个丰富化工具(通常是 lookup_citations),在 auto 下模型可能直接用文本总结。

自测清单

  • 为什么给一个 Agent 18 个工具比给 4–5 个更容易出错?除了上下文占用,还有什么根本原因?
  • 综合 Agent 去调用网页搜索,说明了配置上的什么问题?该如何修复?
  • 什么是"范围受限的跨角色工具"?举一个例子并说明何时仍应经协调者路由。
  • 为什么用 load_document 替代 fetch_url 更安全?
  • auto、any、强制 tool、none 分别适合什么场景?
  • 如何保证某个工具一定第一个被调用,同时不阻碍后续步骤?

对应题目(3)

题目归类由 AI 判断,仅供参考。

练习这 3 道题