大模型的知识是训练出来的,训练完成之后就确定了。
你问它“帮我查一下明天北京的天气”,它答不上来——不是它笨,是因为他拿不到实时的天气数据。
Function Call 解决的就是这个问题:让大模型在对话过程中能调用外部工具,拿到训练数据里没有的信息。
这篇内容从工作原理讲起,拆解 Spring AI 的 @Tool 注解和编程式 API,再看求职派在生产环境里怎么用。

我们实现了一套自定义的 ReAct 循环,并通过 ToolContext 给每个工具传递用户身份。读完你会明白,从定义一个工具到它在多 Agent 系统里跑起来,中间到底经历了什么。
01、Function Call 的工作原理
一次工具调用的完整流程分四步。

第一步,应用把工具清单随请求一起发给大模型。清单里包含每个工具的名称、功能描述和参数格式,大模型通过这份清单来了解自己有哪些“外挂”可以用。
第二步,大模型判断当前的问题需不需要调用工具。如果需要,它会在响应里返回一条工具调用指令,包含工具名和对应的参数值。
第三步,应用程序根据这条指令找到对应的工具去执行,拿到执行结果。
第四步,把结果回传给大模型,大模型结合工具返回的信息,生成最终的回复交给用户。
注意:大模型自己不执行任何工具。它只负责两件事——决定该调哪个工具,以及生成调用参数。真正干活的始终是应用程序这一侧。
Spring AI 在这个流程之上做了一层封装,把“定义工具、注册工具、执行工具、回传结果”这几步全部自动化了。

上图中橙色的部分就是 Spring AI 的工具封装层。
它提供了两种方式把一个 Java 方法变成大模型可以调用的工具:声明式(通过 @Tool 注解)和编程式(通过底层的回调方法)。
先从最简单的声明式开始说起。
02、用 @Tool 注解定义工具
定义一个获取当前时间的工具,只需要在方法上加一个 @Tool 注解就够了。
class DateTimeTools {
@Tool(description = "Get the current date and time")
String getCurrentDateTime() {
return LocalDateTime.now()
.atZone(LocaleContextHolder.getTimeZone().toZoneId())
.toString();
}
}
description 这个属性是写给大模型看的说明书,告诉大模型什么场景下该用这个工具。
它不是代码注释,而是直接影响大模型调用决策的关键信息。描述得不清楚,大模型可能会在该调用的时候不调用,或者在不该调用的时候乱调用。

把工具注入到对话中也很简单,调用 ChatClient 时通过 `tools...
回复