news 2026/7/21 18:30:52

AI Agent 工程实践(13):Tool Calling——Agent 为什么要学会用工具?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI Agent 工程实践(13):Tool Calling——Agent 为什么要学会用工具?

发布时间:2026-07-12
标签:AI Agent|LLM|Tool Calling|Function Call|工程实现


系列导航

上一篇:AI Agent 工程实践(12):为什么很多 Multi-Agent 项目最后都失败了?
下一篇:AI Agent 工程实践(14):MCP——为什么它正在成为 Agent 的 USB 接口?
本文是 [AI Agent 工程实践] 系列的第 13 篇(第二季 · 工程实现)。


Agent 最让人憋屈的时刻:它分析了一堆,然后告诉你"你应该改这个函数"——但你得自己去改。

它能认识问题,不能动手解决问题。像一个只出方案、不下工地的顾问。

让它能动起来的,只有一个东西:Tool。Tool 是 Agent 的手——没有它,再聪明的 Agent 也只是个聊天机器人。但很多人把 Tool Calling 要么想得太简单("在 prompt 里写个命令就行"),要么想得太复杂("需要一套完整的插件系统")。

这一篇讲清楚中间态:Tool Calling 到底怎么设计,从 Schema 到 Registry 到 Selection 到 Retry,让 Agent 不只是"说",而是"做"。


本文你将学到

✓ Agent 为什么必须会用工具——以及不用工具时能力的上限在哪
✓ Tool 的六层能力梯度:从 LLM 内嵌到 Shell/Database 外部系统
✓ Tool Calling 四大核心概念:Registry / Schema / Selection / Retry
✓ 一个可复用的 Tool Calling 设计模板——直接拿到项目里用

适合阅读

✓ 用 Function Call 做过 Agent、但觉得"调用不稳定"的人
✓ 在搭 Agent 的工具系统、不确定怎么组织和管理的人
✓ 被 Tool Calling "格式漂移"折磨过的开发者


问题背景

Agent 前几篇搭好了记忆(10)、工作流(11)、决策框架(12),但还缺一条腿:它怎么和外部世界交互。

没有 Tool 的 Agent,能力边界就是 LLM 的知识截止日期 + 上下文。它能写代码,但不能跑代码;能建议你查数据库,但不能自己查;能告诉你"你去搜一下",但不能自己搜。

这就是 Tool Calling 要解决的问题:让 LLM 从"说"变成"做"。但 Tool Calling 不是简单地在 prompt 里加一句"你可以调用以下函数"。它涉及四个实际的工程问题:

  • Tool 怎么声明——LLM 怎么知道"有这个工具、参数是什么"
  • Tool 怎么选择——有 50 个工具时,怎么选对的
  • Tool 怎么调用——调用格式不稳定怎么办
  • Tool 调用失败怎么办——重试?换工具?降级?

一句话:没有工具的 Agent 是顾问,有工具的 Agent 是工程师。而从顾问到工程师,差的不是一行 prompt,是一整套工具调用系统。


错误尝试

第一次:在 prompt 里手写工具调用

最早的"Tool Calling"就是一段 prompt:"当需要查数据库时,输出 SQL:SELECT * FROM ...,我会执行后把结果贴给你。"

结果:格式经常漂移——有时输出 SQL,有时直接输出解释,有时忘了加 ``。更致命的是,模型会"幻想"SQL 语法——它写了SELECT * FROM nonexistent_table`,我执行失败后它说"那你先建表"——没有约束的 Tool Calling 就是和模型玩文字游戏。

第二次:给每个工具硬编码调用逻辑

吸取教训,工具调用不和模型商量了——硬编码:if task == "db_query": run_sql()

结果:灵活度归零。加一个新工具要改 Router 代码(第 05 篇的问题重现),换一个工具要改调用逻辑。硬编码的工具系统,和硬编码的规则系统一样脆弱——不是 Tool Calling,是 if-else 地狱。

两次尝试指向同一个结论:Tool Calling 需要的是"声明式管理 + 结构化调用",不是 prompt 里的自由文本,也不是代码里的硬编码。它需要一套独立的治理机制。


关键观察

我把"工具调用成功"和"失败"的案例做了对比,发现失败集中在四个环节:

失败环节典型表现占比
Schema 不清晰参数类型填错、必填字段遗漏~30%
Selection 错误有更合适的工具但没选到~25%
调用格式漂移输出了工具描述而不是参数 JSON~25%
失败无重试一次调用失败就停了~20%

pie title Tool Calling 失败原因分布 "Schema 不清晰" : 30 "Selection 错误" : 25 "调用格式漂移" : 25 "失败无重试" : 20

没有工具的 Agent 是顾问,有工具的 Agent 是工程师。

但更准确地说:有工具的 Agent 可能是工程师,也可能是一个乱用扳手的学徒——Tool Calling 需要治理,不只是"有"就行。

问题不在"要不要 Tool",而在"怎么管 Tool"——Schema 让 LLM 知道怎么用、Registry 统一管理能力清单、Selection 在多个工具里找到对的、Retry 在失败时兜底。这四个就是 Tool Calling 的治理四件套。


最终方案:Tool Calling 四件套 + 六层能力梯度

Tool 的六层能力梯度

不是所有 Tool 都在同一层级。从模型内部到外部系统,能力是逐级梯度扩展的:

越往右,Tool 离 LLM 越远,风险越大:LLM 内嵌推理零风险,Shell 命令可能删库。Tool 设计的第一原则:危险性越高的 Tool,越需要 Schema 约束和人工审批。

四件套:Registry / Schema / Selection / Retry

1. Tool Registry —— 统一能力清单

Registry 是工具注册中心——所有可用工具在这里声明。它不是代码里的字典,是可被 LLM 读取的声明文件

# tool-registry.yaml browser_search: schema: search.yaml # 工具 Schema 引用 risk_level: low db_query: schema: query.yaml risk_level: medium retry: 3 # 最大重试次数 shell_exec: schema: shell.yaml risk_level: high requires_approval: true # 高危工具需审批

Registry 的作用:让加工具不需要改代码。新工具加一个 yaml 就上线,和第 05 篇 Rule Router 的"加 heavy 文件"同一种设计哲学。

2. Tool Schema —— 契约式声明

每个 Tool 必须有 JSON Schema,定义名称、描述、参数类型、约束条件。LLM 不认识"你的代码",但一定认识 Schema:

{ "name": "db_query", "description": "执行一个只读 SQL 查询。仅支持 SELECT。", "parameters": { "type": "object", "properties": { "sql": { "type": "string", "description": "要执行的 SELECT 语句", "pattern": "^SELECT.*$" // 只允许 SELECT }, "database": { "type": "string", "enum": ["users", "orders"] // 限定可查的库 } }, "required": ["sql"] } }

Schema 是 Tool Calling 的契约——LLM 按契约填参数,系统按契约校验。没有 Schema 的 Tool,等于没有接口文档的 API。

3. Tool Selection —— 在多个工具里找对的

50 个工具时,"该用哪个"不是 LLM 靠直觉判断的——需要 Selection 机制:

  • 按任务类型路由(和第 05 篇 Router 同构):task_type=db→ 只暴露 db 相关工具
  • 按危险等级过滤:普通任务只露出risk_level ≤ medium的工具
  • 按上下文裁剪:当前对话里用过的工具提权,没出现过的不建议

Selection 不是让 LLM 在海量工具里"猜",而是先缩小候选集,再让 LLM 精准选择——和第 10 篇 Memory 的"先过滤再检索"同一个模式。

4. Tool Retry —— 调用失败后的兜底

Tool Calling 的失败不是"要不要重试"的问题,是"怎么重试更聪明":

失败类型策略
参数格式错误重试 1 次,纠正参数
工具不存在不重试,找替代工具
超时重试 3 次,指数退避(1s/2s/4s)
高危工具失败不重试,转人工审批
def call_with_retry(tool, args, max_retries=3): for attempt in range(max_retries): try: return tool.run(args) except SchemaError: # 参数问题 → 纠正重试 args = correct_args(args) except ToolNotFound: # 工具不存在 → 找替代 tool = find_alternative(tool) except TimeoutError: # 超时 → 退避重试 sleep(2 ** attempt) return fallback() # 全失败 → 降级

Retry 不只是"再来一次",它是"根据失败原因换策略"——Schema 错就修参数,工具不存在就换工具,超时就等一等。这是一种带上下文的恢复机制


架构图 / 流程图

Tool Calling 完整链路

关键点:LLM 不直接访问工具——它通过 Schema 描述工具、通过 Selection 筛选工具、通过 Registry 获取工具、通过 Retry 恢复工具。每一层都是"让 LLM 和工具之间保持安全距离"的防火墙。


代码或配置示例

完整工具声明(Schema + Registry)

# tools/browser_search.yaml name: browser_search description: "使用 Tavily Search API 搜索互联网" parameters: query: type: string description: "搜索关键词" required: true max_results: type: integer default: 5 risk_level: low retry: max: 3 strategy: exponential_backoff
# tool-registry.yaml — 统一注册 tools: browser_search: schema: browser_search.yaml risk: low db_query: schema: db_query.yaml risk: medium retry: 3 shell_exec: schema: shell_exec.yaml risk: high requires_approval: true # 高危必审批

Tool Calling 入口逻辑

def tool_call(task, registry, llm): # 1. LLM 决策:需要哪个工具、什么参数 tool_name, args = llm.decide(task, tools=registry.list_schemas()) # 2. Selection:校验合法性(任务匹配 + 安全等级) if not registry.is_allowed(tool_name, task): return fallback("Tool not allowed for this task") # 3. 从 Registry 拿到工具实例 tool = registry.get(tool_name) # 4. 执行 + Retry return call_with_retry(tool, args)

代码不长,但四个概念全在里面:LLM 读 Schema 选工具 → Selection 做合法性校验 → Registry 管理能力 → Retry 兜底执行。


设计权衡

候选方案优点缺点为什么不选
Prompt 手写工具调用零工程格式漂移、无约束、不可靠Tool Calling 不是文字游戏
硬编码工具选择稳定不灵活、无法动态扩展每加工具改代码,不可持续
声明式四件套可扩展、有约束、可恢复需维护 Schema选择理由:唯一把 Tool Calling 从"碰运气"变成"可治理"的方案

Tool Calling 不是越复杂越好。如果你的 Agent 只用一个工具(比如只查数据库),一个直接调用就够了,不需要 Registry。四件套的价值在工具多、风险分层、需要动态扩展时体现。


总结

✅ Agent 没有 Tool 只是顾问——能做分析,不能做事。Tool 是 Agent 的手。
✅ 六层能力梯度:LLM 内嵌 → Function Call → Python → Browser → Shell → Database,越往右离 LLM 越远、风险越大。
✅ Tool Calling 四件套:Schema(契约声明)/ Registry(统一管理)/ Selection(安全裁剪)/ Retry(分类兜底)。
✅ 核心设计原则:LLM 不直接访问工具——通过 Schema 描述、Selection 过滤、Registry 获取、Retry 恢复。
✅ 工具少就别上四件套——一个直接调用就够。工具多、风险分层时才值得。


参考资料

  • OpenAI Function Calling 官方文档→ Tool Schema 的标准格式与参数约束规范
  • Anthropic — Tool Use 文档→ 声明式 Tool Calling 的设计哲学与安全模型
  • LangChain — Tool 抽象与 Callbacks→ Registry 与 Retry 的工程参考实现
  • 第 05 篇:Rule Router→ 任务路由思想,Tool Selection 的同构设计
  • 第 10 篇:Memory 架构→ "先过滤再检索"模式,Tool Calling"先 Selection 再执行"的同源设计

系列导航

上一篇:AI Agent 工程实践(12):为什么很多 Multi-Agent 项目最后都失败了?
下一篇:AI Agent 工程实践(14):MCP——为什么它正在成为 Agent 的 USB 接口?
本文是 [AI Agent 工程实践] 系列的第 13 篇(第二季 · 工程实现)。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/20 18:15:26

5分钟快速掌握Mermaid Live Editor:新手图表制作工具完整教程

5分钟快速掌握Mermaid Live Editor:新手图表制作工具完整教程 【免费下载链接】mermaid-live-editor Edit, preview and share mermaid charts/diagrams. New implementation of the live editor. 项目地址: https://gitcode.com/GitHub_Trending/me/mermaid-live…

作者头像 李华
网站建设 2026/7/20 18:11:44

DDR1平台运行Win11:复古硬件的极限挑战

1. 复古硬件的逆袭:DDR1平台运行Win11的可行性分析当DDR5内存成为市场主流,价格却居高不下时,一位名叫奥莫雷斯的硬件改装玩家却将目光投向了二十年前的DDR1内存。他成功在一套由酷睿2 Q6600处理器、DDR1内存和AGP接口的ATI HD 4650显卡组成的…

作者头像 李华
网站建设 2026/7/20 18:10:40

Ruby开发者必备:RuboCop Performance常见问题与解决方案终极指南

Ruby开发者必备:RuboCop Performance常见问题与解决方案终极指南 【免费下载链接】rubocop-performance An extension of RuboCop focused on code performance checks. 项目地址: https://gitcode.com/gh_mirrors/ru/rubocop-performance 想要提升Ruby代码性…

作者头像 李华
网站建设 2026/7/20 18:07:48

利用OpenCore Legacy Patcher为老旧Mac安装最新macOS的完整指南

利用OpenCore Legacy Patcher为老旧Mac安装最新macOS的完整指南 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher OpenCore Legacy Patcher是一款基于Python的开…

作者头像 李华
网站建设 2026/7/20 18:07:25

如何快速部署金融预测模型:开源股票预测工具的完整指南

如何快速部署金融预测模型:开源股票预测工具的完整指南 【免费下载链接】Kronos Kronos: A Foundation Model for the Language of Financial Markets 项目地址: https://gitcode.com/GitHub_Trending/kronos14/Kronos 在当今复杂的金融市场中,传…

作者头像 李华