AI Agent 的工具箱:深入理解 Tool Use 与 Spring AI Function Calling 实战

AI Agent 的工具箱:深入理解 Tool Use 与 Spring AI Function Calling 实战
Pei前言
我们之前聊过 AI Agent 的 ReAct 模式(”想一步做一步”)和 AI Agent 的记忆系统(”短期记忆 + 长期记忆”)。今天补齐 Agent 核心能力的最后一块拼图——Tool Use(工具使用)。
你可以把 AI Agent 想象成一个刚入职的新员工:
- ReAct 是他的思维方式——遇到问题先想(Reasoning),再动手(Acting)
- Memory 是他的笔记本——记着之前干过什么、客户说了什么
- Tool Use 是他桌上的各种工具——计算器、搜索引擎、数据库客户端
没有工具的 Agent,就像一个脑子很好但手被绑住的人,只能”纸上谈兵”。有了 Tool Use,Agent 才能真正和外部世界交互,完成实际任务。
什么是 Tool Use?
一句话解释:Tool Use 就是让大语言模型(LLM)决定”什么时候该调用哪个外部函数”,并把正确的参数传给它。
传统调用方式:
1 | 用户输入 → 程序硬编码逻辑 → 调用函数 → 返回结果 |
Tool Use 调用方式:
1 | 用户输入 → LLM 分析意图 → 决定调用哪个工具 + 传什么参数 → 程序执行函数 → 结果回传给 LLM → 生成最终回答 |
关键区别:传统方式是程序员提前写死所有分支,Tool Use 是让 LLM 在运行时动态决策。
一个生活化的例子
你问 Agent:”帮我查一下北京明天的天气,如果会下雨,就在我的待办里加一条’带伞’。”
没有 Tool Use 的 LLM 会回答:”抱歉,我无法访问天气数据……”
有了 Tool Use,Agent 的思考过程是这样的:
- 想(Reasoning):用户需要查天气,我应该调用
getWeather工具 - 做(Acting):调用
getWeather(city="北京"),获得结果 - 想:明天会下雨,用户要加待办,调用
addTodo - 做:调用
addTodo(content="带伞") - 回复:北京明天有雨,已经帮你加了待办”带伞”
注意这个过程中,是 LLM 自己决定调什么工具、传什么参数,而不是你写 if-else 去判断。
Tool Use 的核心机制
1. 工具定义(Tool Definition)
首先,你需要告诉 LLM 有哪些工具可用。每个工具需要定义:
- 名称(name):工具叫什么
- 描述(description):工具是干什么的
- 参数(parameters):需要传什么参数、类型是什么
1 | { |
重点:描述写得好不好,直接影响 LLM 能不能正确选择工具。这就像给新员工写操作手册,越清晰越好。
2. 工具选择(Tool Selection)
LLM 收到用户消息后,结合工具描述,决定是否需要调用工具。这里有三种情况:
- 不需要工具:用户问”1+1等于几”,LLM 直接回答
- 需要一个工具:用户问”北京天气怎样”,调用
getWeather - 需要多个工具:用户问”北京和上海明天天气分别怎样”,调用两次
getWeather
3. 工具执行与结果回传
LLM 只负责”决定调用”,实际执行是你的代码在做。执行完后,结果会回传给 LLM,由 LLM 生成最终的自然语言回答。
这个设计很关键——LLM 永远不会直接执行代码,它只是一个”调度员”。
Spring AI 实战:用 Java 实现 Function Calling
Spring AI 是 Spring 生态对 AI 的拥抱,它让 Java 开发者可以用最熟悉的方式接入 LLM。下面用一个完整例子演示如何实现 Tool Use。
环境准备
使用 Spring Boot 3.x + Spring AI:
1 | <dependencies> |
配置文件 application.yml:
1 | spring: |
第一步:定义工具
在 Spring AI 中,定义工具非常简单——写一个普通的 Java 方法,加上 @Tool 注解:
1 | import org.springframework.ai.tool.annotation.Tool; |
注意 @Tool 注解的 description 非常重要——它就是告诉 LLM “这个工具是干嘛的”。写得越准确,LLM 调用得越精准。
第二步:注册工具并调用
1 | import org.springframework.ai.chat.client.ChatClient; |
就这么多代码。Spring AI 会自动:
- 把
@Tool方法转成 OpenAI 的 Function Calling 格式 - 发送给 LLM 时带上工具描述
- 收到 LLM 的工具调用请求后,反射调用对应方法
- 把结果回传给 LLM,拿到最终回答
第三步:测试运行
1 |
|
调用 GET /chat?message=帮我查北京明天天气,如果下雨就加个带伞的待办,你会看到 Agent 自动完成多步调用:
1 | 用户:帮我查北京明天天气,如果下雨就加个带伞的待办 |
进阶:用 ToolCallback 实现更灵活的工具注册
除了 @Tool 注解,Spring AI 还支持用 ToolCallback 方式动态注册工具,适合工具列表需要从配置或数据库加载的场景:
1 | import org.springframework.ai.tool.ToolCallback; |
这种方式适合需要在运行时动态加载工具的场景,比如插件系统。
Tool Use 的几个关键设计原则
1. 工具描述要像写 API 文档
LLM 靠描述来理解工具。糟糕的描述会导致调用错误。
反面教材:
1 |
正面教材:
1 |
2. 参数名要有语义
反面教材:参数名 c、d——LLM 和人都看不懂
正面教材:参数名 city、date——一目了然
3. 工具数量要适度
理论上你可以注册几十个工具,但实际使用中,工具越多,LLM 选错的概率越大。建议单次对话不超过 10 个工具。如果工具很多,考虑用”路由”模式——先让 LLM 选类别,再选具体工具。
4. 工具执行要处理异常
工具执行可能失败(网络超时、参数错误等),记得 catch 异常并返回有意义的错误信息,而不是让整个调用链崩溃:
1 |
|
工具编排:从单工具到多步调用
现实中,一个复杂任务往往需要调用多个工具,甚至需要根据前一个工具的结果决定下一步调用什么。这就是 工具编排(Tool Orchestration)。
Spring AI 默认支持多轮工具调用(multi-turn),你不需要手动编排——LLM 会根据上下文自动决定下一步该调什么。
但你需要注意两个问题:
1. 循环调用:LLM 有时会陷入循环,反复调用同一个工具。Spring AI 默认限制了最大调用轮数(默认 10 轮),你可以调整:
1 | spring: |
2. Token 消耗:每次工具调用的结果都会占用上下文窗口。工具返回的数据要尽量精简,别把整个数据库表都丢给 LLM。
与之前知识的联系
现在把三篇 Agent 核心文章串起来看:
| 核心能力 | 解决的问题 | 对应文章 |
|---|---|---|
| ReAct | Agent 如何思考和行动 | ReAct 模式 |
| Memory | Agent 如何记住上下文 | 记忆系统 |
| Tool Use | Agent 如何使用外部工具 | 本文 |
三者缺一不可:
- 没有 ReAct,Agent 不知道该先做什么后做什么
- 没有 Memory,Agent 每次都像失忆一样从头开始
- 没有 Tool Use,Agent 只能”嘴上说说”,不能真正行动
小结
Tool Use 是让 AI Agent 从”聊天机器人”进化为”智能助手”的关键一步。Spring AI 让 Java 开发者可以用最低的成本实现这个能力——写个 @Tool 注解的方法,注册到 ChatClient,剩下的交给框架。
记住三个要点:
- 工具描述是灵魂——写清楚,LLM 才能用对
- LLM 是调度员——它只决定”调什么”,你的代码负责”怎么做”
- 异常处理不能忘——工具调用会失败,优雅地处理它
下一篇我们会聊聊 Agent 的另一个重要话题——Planning(规划),看看 Agent 如何把复杂任务拆解成可执行的步骤。敬请期待!







