Spring AI Alibaba 工具(Function Calling)使用
一、工具(Function Calling)简介
Spring AI Alibaba工具(Function Calling):https://java2ai.com/docs/1.0.0-M6.1/tutorials/function-calling/
1、工具(Function Calling)
“工具(Tool)”或“功能调用(Function Calling)”允许大型语言模型(LLM)在必要时调用一个或多个可用的工具,这些工具通常由开发者定义。工具可以是任何东西:网页搜索、对外部 API 的调用,或特定代码的执行等。
LLM 本身不能实际调用工具;相反,它们会在响应中表达调用特定工具的意图(而不是以纯文本回应)。然后,我们应用程序应该执行这个工具,并报告工具执行的结果给模型。
通过在请求中声明一个或多个工具,当 LLM 可以访问工具时,它可以在合适的情况下决定调用其中一个工具,这是一个非常强大的功能。
比如说,googleSearch 和 sendEmail 工具,并且有一个查询像是“我的朋友想了解 AI 领域的最新新闻。将简短的总结发送到 email.com”,那么它可以使用 googleSearch 工具查找最新新闻,然后总结这些信息并通过 sendEmail 工具将总结发送到指定的邮箱。
2、API 概览
通常,自定义函数需要提供一个 name、description 和 function call signature,以便模型知道函数能做什么、期望的输入参数。
Spring AI 使这一过程变得简单,只需定义一个返回 java.util.Function 的 @Bean 定义,并在调用 ChatModel 时将 bean 名称作为选项进行注册。
在底层,Spring 会用适当的适配器代码包装你的 POJO(即函数),以便与 AI 模型进行交互,免去了编写繁琐的样板代码。FunctionCallback.java 接口和配套的 FunctionCallbackWrapper.java 工具类包含了底层实现代码,它们是简化 Java 回调函数的实现和注册的关键。

二、工具(Function Calling)使用
示例需求: 我们将创建一个聊天机器人,通过调用我们自己的函数来回答问题。
为了支持聊天机器人的响应,我们将注册一个自己的函数,该函数接受位置信息并返回该位置的天气。
当模型需要回答诸如 “What’s the weather like in Boston?” 这样的问题时,AI 模型将调用客户端,将位置值作为参数传递给函数。这种类似 RPC 的数据将以 JSON 格式传递。
我们的函数调用某个基于 SaaS 的天气服务 API,并将天气响应返回给模型以完成对话。
1、自定义函数
使用 ToolCallback接口。
这里定义一个 RealTimeWeatherFunction函数来获取实时天气信息。
/*** 获取实时天气信息*/
@Slf4j
@Component
public class RealTimeWeatherFunction implements ToolCallback {@Overridepublic ToolDefinition getToolDefinition() {ToolDefinition toolDefinition = DefaultToolDefinition.builder()//.name(getName()).name("realTimeWeatherFunction").description("获取实时天气信息")// inputSchema值为:JSON字符串.inputSchema("""{"city": {"type": "string","description": "城市名"},"days": {"type": "integer","description": "天数"},"hours": {"type": "integer","description": "小时数"}}""").build();log.info("RealTimeWeatherFunction --> getToolDefinition方法,toolDefinition = {}", toolDefinition);return toolDefinition;}/*** @param toolInput JSON字符串为 getToolDefinition方法中定义的 inputSchema* model.* @return*/@NotNull@Overridepublic String call(String toolInput) {log.info("RealTimeWeatherFunction --> call方法,toolInput = {}", toolInput);if (StringUtils.isBlank(toolInput)) {return null;}// TODO 模拟西安未来5天天气状况的数据String weatherData = getWeatherData();return weatherData;}public String getWeatherData(){return """嗯,用户问的是西安未来24小时和15天的天气情况,我得先看看搜索结果里的各个网页内容。首先,今天是2025年3月25日,所以得找最新的信息。网页1提到从3月26日开始陕西会有寒潮,大风沙尘天气,最高气温降幅可达20℃。不过用户关心的是未来24小时,也就是到3月26日的天气。网页1里的西安三日天气显示,今天(25日)晴,14℃~29℃;明天(26日)多云,14℃~25℃。不过这个网页的发布时间是3月25日8点21分,应该是最新的。网页2是天气网的7天预报,显示25日(今天)晴,27/13℃,也就是最高27℃,最低13℃?不过网页1里的今天温度是14℃~29℃,这可能存在矛盾。需要确认哪个更准确。网页3发布于3月25日0点,提到今天(25日)晴天间多云,16时气温21.2℃~32℃,可能用户所在时间不同,但今天白天的最高气温在网页3里提到是29℃。而网页7提到3月25日西安最高气温可达29℃,所以可能网页1的今天温度是14℃~29℃,但实际可能更高,比如网页7提到24日最高气温32℃,25日可达29℃。但用户问的是未来24小时,也就是从今天3月25日到3月26日的天气。网页2的天气预报显示26日多云,26/11℃,也就是最高26℃,最低11℃,但网页1里的明天(26日)是14℃~25℃,这里也有不一致。可能网页1的数据更准确,但需要结合其他网页。网页3提到26日夜间至28日有寒潮,26日夜间开始降温,风力加大到4-5级,阵风6级以上,并伴有沙尘。所以未来24小时可能包括26日白天,而26日白天可能多云,温度在25℃左右,但到夜间开始降温。网页3的具体预报显示26日晴转多云,夜间有5级阵风,浮尘,12℃~27℃。所以未来24小时到26日晚上,温度可能在12℃到27℃之间,但夜间开始降温,并有大风和沙尘。关于15天的天气,网页2提供了7天的预报,但用户需要15天。不过搜索结果里没有直接的15天数据,可能需要根据现有的7天预报和趋势来推断。网页2的7天预报显示到31日都是多云或阴天,气温逐渐回升,但可能之后会有更多变化,但具体无法确定。网页6提到寒潮影响持续到3月30日左右,最低气温出现在29日夜间到30日凌晨。网页3的预报显示到31日气温回升到4℃~18℃,但可能之后继续回升。不过只能根据现有数据尽量总结。此外,沙尘和霜冻的情况需要注意。网页1、3、5、6都提到沙尘天气,尤其是26日至27日。霜冻出现在27日至31日,尤其是山区。森林火险红色预警在网页4提到,需要注意防火。综合以上信息,未来24小时应该是今天(25日)晴,高温29℃,夜间转多云,26日白天多云,可能有浮尘,温度在14℃到25℃之间,但夜间开始剧烈降温,风力加大。而15天的天气可能前7天有详细数据,后续只能根据趋势推测,但需要说明可能的不确定性。""";}
}
函数调用某个天气服务 API逻辑替换为 同样的用户问题返回 deepseek的推理信息。
deepseek的推理信息如下:

2、编写 Controller接口
在 Prompt 请求中指定函数有几种方式:
- 全局设置默认函数集合
- ChatModel请求中指定函数集合
在普通 Controller Bean 中注入 ChatModel 实例,并为 Prompt 指定函数,实现下面几个功能:
- 简单调用
- 流式调用
/*** “工具(Tool)”或“功能调用(Function Calling)”允许大型语言模型(LLM)在必要时调用一个或多个可用的工具,这些工具通常由开发者定义。**/
@Slf4j
@RestController
@RequestMapping("/dashscope/function-calling")
public class DashScopeFunctionCallingController {private final ChatModel dashScopeChatModel;/*** 使用如下的方式自动注入 ChatModel** @param chatModel*/public DashScopeFunctionCallingController(ChatModel chatModel) {this.dashScopeChatModel = chatModel;}/*** 编程方式自行创建一个 ChatClient.Builder 实例.* 使用自动注入 ChatModel** @param chatModel*///public DashScopeFunctionCallingController(ChatModel chatModel) {//// this.dashScopeChatModel = chatModel;//// // 构造时,可以设置 ChatClient 的参数// // {@link org.springframework.ai.chat.client.ChatClient};// this.dashScopeChatClient = ChatClient.builder(chatModel)// // 实现 Chat Memory 的 Advisor// // 在使用 Chat Memory 时,需要指定对话 ID,以便 Spring AI 处理上下文。// .defaultAdvisors(// new MessageChatMemoryAdvisor(new InMemoryChatMemory())// )// // 实现 Logger 的 Advisor// .defaultAdvisors(// new SimpleLoggerAdvisor()// )// // 设置 ChatClient 中 ChatModel 的 Options 参数// .defaultOptions(// DashScopeChatOptions.builder()// .withTopP(0.7)// .build()// )// // 设置默认 System Message// //.defaultSystem("你是一个AI搞笑段子手,以搞笑,幽默,风趣的风格回答所有的问题。")// // 设置默认函数集合// //.defaultFunctions("")// .build();//}/*** 简单调用方式*/@GetMapping("/simple/chat")public String simpleChat(@RequestParam(defaultValue = "西安未来5天天气状况") String userInputPrompt) {// 指定参数DashScopeChatOptions chatOptions = DashScopeChatOptions.builder()// 指定使用的模型.withModel(DashScopeApi.ChatModel.QWEN_PLUS.getModel())// 指定函数调用.withFunction("realTimeWeatherFunction").build();ChatResponse chatResponse = dashScopeChatModel.call(new Prompt(userInputPrompt, chatOptions));String aiOutput = chatResponse.getResult().getOutput().getText();log.info("simpleChat --> userInputPrompt = {}, aiOutput = {}", userInputPrompt, aiOutput);return aiOutput;}/*** Stream 流式调用。* 可以使大模型的输出信息实现打字机效果。*/@GetMapping("/stream/chat")public Flux<String> streamChat(HttpServletResponse response, @RequestParam(defaultValue = "西安未来5天天气状况") String userInputPrompt) {// 避免接口返回乱码response.setCharacterEncoding("UTF-8");// 指定参数DashScopeChatOptions chatOptions = DashScopeChatOptions.builder()// 指定使用的模型.withModel(DashScopeApi.ChatModel.QWEN_PLUS.getModel())// 指定函数调用.withFunction("realTimeWeatherFunction").build();log.info("streamChat --> userInputPrompt = {},", userInputPrompt);Flux<ChatResponse> stream = dashScopeChatModel.stream(new Prompt(userInputPrompt, chatOptions));Flux<String> flux = stream.map(chatResponse -> chatResponse.getResult().getOutput().getText());return flux;}}
deepseek的回答如下:

启动项目,访问接口与 AI 大模型智能对话。

自定义函数的调用信息:
- getToolDefinition方法:项目启动会调用一次,接口访问一次会调用多次。
- call方法:项目启动没有调用,接口访问一次会调用一次,并接收到 String toolInput参数(inputSchema的Json数据)。

– 求知若饥,虚心若愚。
相关文章:
Spring AI Alibaba 工具(Function Calling)使用
一、工具(Function Calling)简介 Spring AI Alibaba工具(Function Calling):https://java2ai.com/docs/1.0.0-M6.1/tutorials/function-calling/ 1、工具(Function Calling) “工具(Tool)”或“功能调用(Function Calling…...
Touch Diver:Weart为XR和机器人遥操作专属设计的触觉反馈动捕手套
在虚拟现实(VR)和扩展现实(XR)领域,触觉反馈技术正逐渐成为提升沉浸感和交互体验的重要因素。Weart作为这一领域的创新者,凭借其TouchDIVER Pro和TouchDIVER G1触觉手套,为用户带来了高度逼真的…...
[深度学习]图片分类任务
图片分类任务 文章目录 图片分类任务分类任务回归和分类如何做分类的输出 图片分类卷积神经网络保持特征图大小不变更大的卷积核和更多的卷积核层数特征图怎么变小卷积神经网络中特征图改变卷积到全连接分类任务的LOSS一个基本的分类神经网络 经典神经网络AlexNetVggNetResNet …...
关系图:赋能数据可视化的动态扩展
关系图 关系图是一种用于展示节点之间关系和连接的图表类型。具有高度的可定制性、丰富的交互功能和动画效果,能够展示节点之间的和连接,以及随着数据的变化而呈现的动态效果。 【组件概述】 1.节点和边的可定制性: 关系图提供了丰富的配置…...
k8s存储介绍(三)valume概述与emptydir
目录 一、Kubernetes 中的 Volume 详解 基本概念 Volume 的主要类型(这里简单介绍,后续章节会详细介绍) 1. 本地存储类型 2. 网络存储类型 3. 云提供商存储 4. 特殊用途类型 PersistentVolume (PV) 和 PersistentVolumeClaim (PVC) S…...
Nodejs 项目打包部署方式
方式一:PM2 一、准备工作 确保服务器上已安装 Node.js 环境建议使用 PM2 进行进程管理(需要额外安装) 二、部署步骤 1.首先在服务器上安装 PM2(推荐): npm install -g pm22.将项目代码上传到服务器&…...
uv - Getting Started 开始使用 [官方文档翻译]
文章目录 uv亮点安装项目脚本工具Python 版本pip 接口了解更多 入门安装 uv安装方法独立安装程序PyPICargoHomebrewWinGetScoopDockerGitHub 发布 升级 uvShell 自动补全卸载 第一次使用 uv特性Python 版本脚本项目工具pip 接口实用工具 获取帮助帮助菜单查看版本故障排除问题在…...
C++类与对象的的第三个简单的实战练习-3.25笔记
哔哩哔哩C面向对象高级语言程序设计教程(118集全) 简单实战三 创建项目 打开VS,点击创建一个新项目 创建一个空项目 点击下一步 点击工程名称,选择添加 选择新建项 选择C类 取名 点击确定,这时候还需要一个main.cpp …...
CentOS安装sshpass工具-自动化SSH密码认证
sshpass是一个在Linux环境下用于自动化SSH密码认证的工具。 一、功能特点 自动化SSH登录:sshpass允许用户在命令行中直接传递密码,从而无需在SSH连接时手动输入密码。这对于自动化脚本和批处理任务非常有用,因为它可以在非交互式环境下完成…...
k8s中service概述(一)ClusterIP
ClusterIP 是 Kubernetes 中最基础且常用的 Service 类型,主要用于在集群内部提供稳定的网络访问端点。以下是关于 ClusterIP Service 的详细说明: 1. ClusterIP 的核心功能 集群内部访问:ClusterIP 提供一个集群内部的虚拟 IP(VI…...
详解接口的常见请求方式
详解接口的常见请求方式 一、 常见接口请求方式1. GET2. POST3. PUT4. DELETE5. PATCH6. HEAD7. OPTIONS 二、 实现方法1. 前端实现2. 后端实现 三、 作用与主要区别四、 举例讲解1. 创建 Spring Boot 工程2. 添加依赖3. 编写 Controller 实现接口关键点说明 4. 启动与测试5. 总…...
HarmonyOS-ArkUI Grip组件
我们在学习List的时候,已经捎带引入了Grid。讲解如下图所示: 也就是,如果一个表,长宽基本都是一致的,那么此时可以完全不用Grid也可以实现,并且,优先考虑的就是List。 如果List实现不了的情况下…...
2025清华大学:DeepSeek教程全集(PDF+视频精讲,共10份).zip
一、资料列表 第一课:Deepseek基础入门 第二课:DeepSeek赋能职场 第三课:普通人如何抓住DeepSeek红利 第四课:让科研像聊天一样简单 第五课:DeepSeek与AI幻觉 第六课:基于DeepSeek的AI音乐词曲的创造法 第…...
jupyter使用过程中遇到的问题
1、No module named ‘notebook.extensions’ 报错内容为: No module named notebook.extensions解决办法 出现这个错误代表你尝试给 Jupyter notebook 安装自动补全的插件,但是 notebook 没安装成功; 解决办法:不用 pip 安装 n…...
mac vim命令快捷键
目录 移动光标插入模式复制/粘贴删除搜索/替换退出 移动光标 快捷键说明0 / ^跳到行首,移动到光标所在行的"行首"$跳到行末,移动到光标所在行的"行尾"gg跳到文件第一行G移动到文章的最后[n]G跳到第n行w光标跳到下个字的开头e光标跳…...
【Golang】defer与recover的组合使用
在Go语言中,defer和recover是两个关键特性,通常结合使用以处理资源管理和异常恢复。以下是它们的核心应用场景及使用示例: 1. defer 的应用场景 defer用于延迟执行函数调用,确保在函数退出前执行特定操作。主要用途包括ÿ…...
低代码配置式Web组态解析
低代码配置式Web组态技术通过可视化操作和预置组件库,大幅降低开发门槛,适用于工业控制、物联网监控、数据可视化等场景。以下是综合行业实践和产品特性的分析: 一、核心功能与优势 可视化编辑与拖拽布局 提供图形化编辑器࿰…...
KiLog2MaximumIncrement的由来和KiMaximumIncrementReciprocal的由来
第一部分:KiLog2MaximumIncrement的由来 i 1; j KeMaximumIncrement; while ((1UI64<<i) < KeMaximumIncrement) { i; } KiLog2MaximumIncrement i; 2^17131072 2^18262144 i18KiLog2MaximumIncrement 中…...
基于web的家政服务网站
内容摘要 由于互联网的使用,人们在管理、应用、服务等领域使用数据更加简洁、方便,大大提高了工作效率。互联网正逐渐融入我们的生活,影响和改变我们的生活。 家政服务管理系统是典型的信息管理系统(MIS)。其开发主要…...
mac命令行快捷键
光标移动 Ctrl A: 将光标移动到行首。Ctrl E: 将光标移动到行尾。Option 左箭头: 向左移动一个单词。Option 右箭头: 向右移动一个单词。 删除和修改 Ctrl K: 删除从光标到行尾的所有内容。Ctrl U: 删除从光标到行首的所有内容。Ctrl W: 删除光标前的一个单词。Ctrl …...
聚水潭数据集成到MySQL的最佳实践分享
聚水潭数据集成到MySQL的技术案例分享 在本次技术案例中,我们将探讨如何通过轻易云数据集成平台,将聚水潭的数据高效、可靠地集成到MySQL数据库中。具体的集成方案为“聚水潭-商品信息查询-->BI初本-商品信息表_copy”。该方案旨在实现从聚水潭获取商…...
线性代数核心概念与NumPy科学计算实战全解析
前言 学习方法: 思维导图,梳理 多记忆,函数名和功能,参数 学会应用,不要钻牛角尖 一、浅解线性代数 1.1标量 标量是一个只有大小没有方向的量。在数学上,标量通常表示为一个普通的数字,如质量…...
Spring Boot中接口数据字段为 Long 类型时,前端number精度丢失问题解决方案
Spring Boot中接口数据字段为 Long 类型时,前端number精度丢失问题解决方案 在Spring Boot中,当接口数据字段为 Long 类型时,返回页面的JSON中该字段通常会被序列化为数字类型。 例如,一个Java对象中有一个 Long 类型的属性 id …...
C#自定义曲线便器功能实现(简化版)
目录 一、曲线编辑器实现功能 二、实现方法说明 三、关键代码说明 1、绘制背景板和曲线 2、绘制坐标系面板 3、绘制曲线 四、工程下载连接 一、曲线编辑器实现功能 添加或者删除控制点,通过移动控制点来修改曲线形状 二、实现方法说明 1、坐标系系统&#x…...
Unity Shader编程】之复杂光照
在Unity Shader的LightMode标签中,除了前向渲染和延迟渲染外,还支持多种渲染模式设置。以下是主要分类及用途: 一、核心渲染路径模式 前向渲染相关 ForwardBase 用于基础光照计算,处理环境光、主平行光、逐顶点/SH光源及光照贴图。…...
解锁U盘属性0字节困境,重获数据生机
在数字化浪潮中,U盘宛如一位忠诚的“数据信使”,频繁穿梭于各种设备之间,为我们存储和传输着重要信息。然而,当U盘突然显示属性为0字节时,就如同这位信使突然“失声”,让我们陷入了数据丢失的恐慌之中。U盘…...
⭐算法OJ⭐二叉树的直径【树】(C++实现)Binary Tree Paths
543. Binary Tree Paths(二叉树的直径) Given the root of a binary tree, return the length of the diameter of the tree. The diameter of a binary tree is the length of the longest path between any two nodes in a tree. This path may or m…...
docker使用命令笔记
docker使用命令笔记 1. 安装docker2. 拉取镜像3. 镜像与容器4. 基于镜像创建容器4. 操作创建好的容器5. docker文件传输6. ubuntu的docker的一些基本环境搭建 记录docker的一些使用命令 1. 安装docker 遵循官方安装说明即可,windows需要下载docker desktop后在doc…...
字典树与01trie
字典树简介 当我们通过字典查一个字或单词的时候,我们会通过前缀或关键字的来快速定位一个字的位置,进行快速查找。 字典树就是类似字典中索引表的一种数据结构,能够帮助我们快速定位一个字符串的位置。 字典树是一种存储字符串的数据结构…...
vue - [Vue warn]: Duplicate keys detected: ‘0‘. This may cause an update error.
问题描述: vue项目中,对表单数组赋值时,控制台抛出警告: 问题代码: 问题分析: 1、Vue 要求每个虚拟 DOM 节点必须有唯一的 key。该警告信息通常出现在使用v-for循环的场景中,多个同级节点使用…...
