【SpringAI】第五弹:基于 Spring AI ToolCallback Function 实现文件操作、联网搜索、网页抓取、终端操作、资源下载、PDF生成等工具的开发与调用、核心特性解析

【SpringAI】第五弹:基于 Spring AI ToolCallback Function 实现文件操作、联网搜索、网页抓取、终端操作、资源下载、PDF生成等工具的开发与调用、核心特性解析


在这里插入图片描述
在这里插入图片描述

本节重点


以 Sprin‏g AI 框架为例,学习 A‏I 应用开发的核心特性 ——‏ 工具调用,大幅增强 AI ‏的能力,并实战主流工具的开发‌,熟悉工具的原理和高级特性。

具体内容包括:

  • 工具调用介绍
  • Spring AI 工具开发
  • 主流工具开发
  • 文件操作
  • 联网搜索
  • 网页抓取
  • 终端操作
  • 资源下载
  • PDF 生成
  • 工具进阶知识(原理和高级特性)

重点理解


  1. 使用 @Tool@ToolParam注解标记类方法

Spring AI 实现工具调用的流程;

img

Tool Calling 的工作原理

null

一、需求分析


之前我们通过 RAG 技术让 AI 应用具备了根据外部知识库来获取信息并回答的能力,但是直到目前为止,AI 应用还只是个 “知识问答助手”。本节我们可以利用 工具调用 特性,实现更多需求。

1. 联网搜索

比如智能推荐约会地点,示例用户提问:

  • 周末想带女朋友去上海约会,推荐几个适合情侣的小众打卡地?
  • 女朋友生气了,有哪些温柔的哄人技巧?

2. 网页抓取

比如分析恋爱案例,示例用户提问:

  • 最近和对象吵架了,看看恋爱帖子上的其他情侣是怎么解决矛盾的?

3. 资源下载

比如恋爱相关的图片 / 音视频下载,示例用户提问:

  • 下载一张适合做手机壁纸的星空情侣图片
  • 推荐并下载几首适合约会时播放的钢琴曲

4. 终端操作

比如执行代码来生成恋爱报告,示例用户提问:

  • 执行 Python 脚本来生成数据分析报告

5. 文件操作

比如保存用户恋爱档案,示例用户提问:

  • 帮我保存我的恋爱档案为文件

6. PDF 生成

比如恋爱计划、情感分析报告 PDF 生成,示例用户提问:

  • 生成一份《七夕约会计划》PDF,包含餐厅预订、活动流程和礼物清单
  • 分析我和对象近一个月的聊天记录,生成情感报告
img

而且这些需求还‏可以进行组合,比如用户先让 ‏AI 联网搜索约会地点、再下‏载约会地点的图片、最后将获取‏到的内容组合生成 PDF、并‌保存到本地,一条龙服务。

如果 AI‏ 能够完成上述需求,‏就不再只是一个有知识‏的 “大脑”,而是有‏手有脚,会利用工具完‌成任务的 “智能体” 了。

下面我们就来学习下实现上述需求的关键 —— 工具调用 技术。


二、工具调‏用介绍


什么是工具调用?


工具调用(Tool Calling)可以理解为让 AI 大模型 借用外部工具 来完成它自己做不到的事情。

跟人类一样‏,如果只凭手脚完成‏不了工作,那么就可‏以利用工具箱来完成‏。

工具可以是‏任何东西,比如网页‏搜索、对外部 AP‏I 的调用、访问外‏部数据、或执行特定‌的代码等。

比如用户提‏问 “帮我查询上海最‏新的天气”,AI 本‏身并没有这些知识,它‏就可以调用 “查询天‌气工具”,来完成任务。

目前工具调‏用技术发展的已经比较‏成熟了,几乎所有主流‏的、新出的 AI 大‏模型和 AI 应用开‌发平台都支持工具调用。


工具调用的工作原理


其实,工具调用的工作原理非常简单,并不是 AI 服务器自己调用这些工具、也不是把工具的代码发送给 AI 服务器让它执行,它只能提出要求,表示 “我需要执行 XX 工具完成任务”。而真正执行工具的是我们自己的应用程序,执行后再把结果告诉 AI,让它继续工作。

举个例子,‏假如用户提问 “编‏程导航网站有哪些热‏门文章?”,就需要‏经历下列流程:

  1. 用户提出问题:“编程导航网站有哪些热门文章?”
  2. 程序将问题传递给大模型
  3. 大模型分析问题,判断需要使用工具(网页抓取工具)来获取信息
  4. 大模型输出工具名称和参数(网页抓取工具,URL参数为 codefather.cn)
  5. 程序接收工具调用请求,执行网页抓取操作
  6. 工具执行抓取并返回文章数据
  7. 程序将抓取结果传回给大模型
  8. 大模型分析网页内容,生成关于编程导航热门文章的回答
  9. 程序将大模型的回答返回给用户

虽然看起来是 AI 在调用工具,但实际上整个过程是 由我们的应用程序控制的。AI 只负责决定什么时候需要用工具,以及需要传递什么参数,真正执行工具的是我们的程序。

你可能会好‏奇,为啥要这么设计‏呢?这样不是要让程‏序请求 AI 多次‏么?为啥不让 AI‌ 服务器直接调用工具程序

有这个想法很正常,但如果让你自己设计一个 AI 大模型服务,你就能理解了。很关键的一点是 安全性AI 模型永远无法直接接触你的 API 或系统资源,所有操作都必须通过你的程序来执行,这样你可以完全控制 AI 能做什么、不能做什么

举个例子,你有一个爆破工具‏,用户像 AI 提了需求 ”我要拆这栋房子“,虽然‏ AI 表示可以用爆破工具,但是需要经过你的同意,‏才能执行爆破。反之,如果把爆破工具植入给 AI,A‏I 觉得自己能炸了,就炸了,不需要再问你的意见。而‌且这样也给 AI 服务器本身增加了压力。


工具调用和功能调用


大家可能看到过 Function Calling(功‏能调用)这个概念,别担心,其实它和‏ Tool Calling(工具调‏用)完全是同一概念!只是不同平台或‌每个人习惯的叫法不同而已。

Spring AI 工具调用文档 的开头就说明了这一点:

null

煮波更喜‏欢 “工具调用” 这个‏说法,因为 Function 这个词更像是计‏算机行业的术语,不如工‌具更形象易懂、更具普适性。


工具调用的技术选型


我们先来梳理一下工具调用的流程:

  1. 工具定义:程序告诉 AI “你可以使用这些工具”,并描述每个工具的功能和所需参数
  2. 工具选择:AI 在对话中判断需要使用某个工具,并准备好相应的参数
  3. 返回意图:AI 返回 “我想用 XX 工具,参数是 XXX” 的信息
  4. 工具执行:我们的程序接收请求,执行相应的工具操作
  5. 结果返回:程序将工具执行的结果发回给 AI
  6. 继续对话:AI 根据工具返回的结果,生成最终回答给用户

通过上述流程,我们会发现,‏程序需要和 AI 多次进行交互、还要能够执行对应的‏工具,怎么实现这些呢?我们当然可以自主开发,不过还‏是更推荐使用 Spring AI、LangChai‏n 等开发框架。此外,有些 AI 大模型服务商也提‌供了对应的 SDK,都能够简化代码编写。

本教程后续‏部分将以 Spri‏ng AI 为例,‏带大家实战工具调‏用开发。


💡 需要注意的是,不是所有大模型都支持工具调用。有些基础模型或早期版本可能不支持这个能力。可以在 Spring AI 官方文档 中查看各模型支持情况。

null

三、Spring AI 工具开发


首先我们通过 Spring AI 官方 提供的图片来理解 Spring AI 在实现工具调用时都帮我们做了哪些事情?

img
  1. 工具定义与注册:Spring AI 可以通过简洁的注解自动生成工具定义和 JSON Schema让 Java 方法轻松转变为 AI 可调用的工具
  2. 工具调用请求:Spring AI 自动处理与 AI 模型的通信解析工具调用请求,并且支持多个工具链式调用
  3. 工具执行:Spring AI 提供统一的工具管理接口,自动根据 AI 返回的工具调用请求,找到对应的工具并解析参数进行调用,让开发者专注于业务逻辑实现。
  4. 处理工具结果:Spring AI 内置结果转换和异常处理机制,支持各种复杂 Java 对象作为返回值并优雅处理错误情况。
  5. 返回结果给模型:Spring AI 封装响应结果并管理上下文,确保工具执行结果正确传递给模型或直接返回给用户。
  6. 生成最终响应:Spring AI 自动整合工具调用结果到对话上下文,支持多轮复杂交互,确保 AI 回复的连贯性和准确性。

下面是一个较早版本的流程图,也能帮助我们理解这个过程:

img

定义工具


工具定义模式

在 Spr‏ing AI 中,定‏义工具主要有两种模式‏:基于 Method‏s 方法或者 Fun‌ctions 函数式编程。

记结论就行了,我们只用学习 基于 Methods 方法 来定义工具,另外一种了解即可。原因是 Methods 方式更容易编写、更容易理解、支持的参数和返回类型更多。

二者的详细对比:

特性Methods 方式Functions 方式
定义方式使用 @Tool@ToolParam注解标记类方法使用函数式接口并通过 Spring Bean 定义
语法复杂度简单,直观较复杂,需要定义请求/‏响应对象
支持的参数类型大多数 Java 类型,包括基本类型、POJO、集合等不支持基本类型、O‏ptional、集合类型
支持的返回类型几乎所有可序列化类型,包括 void不支持基本类型、Op‏tional、集合类型等
使用场景适合大多数新项目开发适合与现有函数式API集成
注册方式‏支持按需注册和全局注册通常在配置类中预先定义
类型转换自动处理需要更多手动配置
文档支持 ‌通过注解提供描述通过Bean描述和JSON属性注解

举个例子来对比这两种定义模式:

1. Methods 模式:通过 @Tool 注解定义工具,通过 tools 方法绑定工具

classWeatherTools{ @Tool(description ="Get current weather for a location")publicStringgetWeather(@ToolParam(description ="The city name")String city){ return"Current weather in "+ city +": Sunny, 25°C";}}// 使用方式ChatClient.create(chatModel).prompt("What's the weather in Beijing?").tools(newWeatherTools()).call();

2. Functions 模式:通过 @Bean 注解定义工具,通过 functions 方法绑定工具

@ConfigurationpublicclassToolConfig{ @Bean@Description("Get current weather for a location")publicFunction<WeatherRequest,WeatherResponse>weatherFunction(){ return request ->newWeatherResponse("Weather in "+ request.getCity()+": Sunny, 25°C");}}// 使用方式ChatClient.create(chatModel).prompt("What's the weather in Beijing?").functions("weatherFunction").call();

显然 Methods 模式的开发量更‏少(我估计很多同学都没写‏过 Function 函‏数式编程),更推荐这种方‌式,所以下面重点讲解这种方式。


定义工具

Spring AI 提供了两种定义工具的方法 —— 注解式编程式


1. 注解式

只需使用 @Tool 注解标记普通 Java 方法,就可以定义工具了,简单直观。

每个工具最好都添加详细清晰的描述,帮助 AI 理解何时应该调用这个工具。对于工具方法的参数,可以使用 @ToolParam 注解提供额外的描述信息和是否必填。

示例代码:

classWeatherTools{ @Tool(description ="获取指定城市的当前天气情况")StringgetWeather(@ToolParam(description ="城市名称")String city){ // 获取天气的实现逻辑return"北京今天晴朗,气温25°C";}}

2. 编程式

‏如果想在运行时动‏态创建工具,可以选‏择编程式来定义工具,‏更灵活。

先定义工具类:

classWeatherTools{ StringgetWeather(String city){ // 获取天气的实现逻辑return"北京今天晴朗,气温25°C";}}

然后将工具类转换为‏ ToolCallback 工具定义‏类,之后就可以把这个类绑定给 Cha‏tClient,从而让 AI 使用‏工具了。 ‌

Method method =ReflectionUtils.findMethod(WeatherTools.class,"getWeather",String.class);ToolCallback toolCallback =MethodToolCallback.builder().toolDefinition(ToolDefinition.builder(method).description("获取指定城市的当前天气情况").build()).toolMethod(method).toolObject(newWeatherTools()).build();

其实你会发‏现,编程式就是把注‏解式的那些参数,改‏成通过调用方法来设置‏了而已

在定义工具时,需要注‏意方法参数返回值类型的选择。Sprin‏g AI 支持大多数常见的 Java 类‏型作为参数和返回值,包括基本类型、复杂对象、‏集合等。而且返回值需要是可序列化的,‌因为它将被发送给 AI 大模型。

以下类型目前不支持作为工具方法的参数或返回类型:

  • Optional
  • 异步类型(如 CompletableFuture, Future)
  • 响应式类型(如 Flow, Mono, Flux)
  • 函数式类型(如 Function, Supplier, Consumer)

使用工具


定义好工具后‏,Spring AI ‏提供了多种灵活的方式将‏工具提供给 ChatC‏lient,让 AI ‌能够在需要时调用这些工具。

1. 按需使用:这是最简单的方式,直接在构建 ChatClient 请求时通过 tools() 方法附加工具。这种方式适合只在特定对话中使用某些工具的场景。

String response =ChatClient.create(chatModel).prompt("北京今天天气怎么样?").tools(newWeatherTools())// 在这次对话中提供天气工具.call().content();

2. 全局使用:如‏果某些工具需要在所有对话中都可用‏,可以在构建 ChatClien‏t 时注册默认工具。这样,这些工‏具将对从同一个 ChatClie‌nt 发起的所有对话可用。

ChatClient chatClient =ChatClient.builder(chatModel).defaultTools(newWeatherTools(),newTimeTools())// 注册默认工具.build();

3. 更底层的使用方‏式:除了给 ChatClient ‏绑定工具外,也可以给更底层的 Ch‏atModel 绑定工具(毕竟工具‏调用是 AI 大模型支持的能力),‌适合需要更精细控制的场景。

// 先得到工具对象ToolCallback[] weatherTools =ToolCallbacks.from(newWeatherTools());// 绑定工具到对话ChatOptions chatOptions =ToolCallingChatOptions.builder().toolCallbacks(weatherTools).build();// 构造 Prompt 时指定对话选项Prompt prompt =newPrompt("北京今天天气怎么样?", chatOptions); chatModel.call(prompt);

4. 动态解析:一般情况下,使用前面 3 种方式即可。对于更复杂的应用,Spring AI 还支持通过 ToolCallbackResolver 在运行时动态解析工具。这种方式特别适合工具需要根据上下文动态确定的场景,比如从数据库中根据工具名搜索要调用的工具。在本节的工具进阶知识中会讲到,先了解到有这种方式即可。


总结一下,在使用工具时,Spring AI 会自动处理工具调用的全过程:

  • 从 AI 模型决定调用工具 =>
  • 到执行工具方法 =>
  • 再到将结果返回给模型 =>
  • 最后模型基于工具结果生成最终回答。

这整个过程对开发者来说是透明的,我们只需专注于 实现工具 的业务逻辑即可。

那么,怎么实现工具呢?


工具生态


首先,工具的本质就是一种插件。能不自己写的插件,就尽量不要自己写。我们可以直接在网上找一些优秀的工具实现,比如 Spring AI Alibaba 官方文档 中提到了社区插件。

虽然文档里只提到了屈指可数的插件数,但我们可以顺藤摸瓜,在 GitHub 社区找到官方提供的更多 工具源码,包含大量有用的工具!比如翻译工具、网页搜索工具、爬虫工具、地图工具等:

img

💡 这种搜‏集资源的能力,希望大家也‏能够掌握,尤其是学新技术‏的时候,即使官方文档写的‏不够清晰完善,我们也可以‌从开源社区中获取到一手信息。


四、主流工具开发


如果社区中没找到合‏适的工具,我们就要自主开发。需要注‏意的是,AI 自身能够实现的功能通‏常没必要定义为额外的工具,因为这会‏增加一次额外的交互,我们应该将工具‌用于 AI 无法直接完成的任务

下面我们依次来实现需求分析中提到的 6 大工具,开发过程中我们要 格外注意工具描述的定义,因为它会影响 AI 决定是否使用工具。

先在项目根包下新建 tools 包,将所有工具类放在该包下;并且工具的返回值尽量使用 String 类型,让结果的含义更加明确。

image-20250910165749068

文件操作


文件操作工具主要提供 2 大功能:保存文件、读取文件。

由于会影响系统资源,所以我们需要将文件统一存放到一个隔离的目录进行存储

image-20250909100334038

constant 包下新建文件常量类,约定文件保存目录为项目根目录下的 /tmp 目录中。

/** * 文件常量 */publicinterfaceFileConstant{ /** * 文件保存目录 */String FILE_SAVE_DIR =System.getProperty("user.dir")+"/tmp";}

建议同时将这个目录添加到 .gitignore 文件中,避免提交隐私信息。

image-20250909100416621

编写文件操作工具类,通过注解式定义工具,代码如下:

  • 可以将文件读、写操作的具体实现直接交给 AI 生成:我们只需把 Spring AI 官方文档中的示例代码以及拟调用的 API 接口告诉 AI 即可。
  • 为了简化框架处理并提升性能,建议将这两个方法的返回值都声明为 String。因为一旦被 Spring AI 注册为“工具”,其执行结果会作为上下文回传给大模型;String 类型无需额外序列化转换,既减少了失败风险,也让我们能够精确控制回传给模型的内容。
image-20250909153204435
/** * 文件操作工具类 (提供文件读写功能) */public <

Read more

Python 入门必吃透:函数、列表与元组核心用法(附实战案例)

Python 入门必吃透:函数、列表与元组核心用法(附实战案例)

🔥草莓熊Lotso:个人主页 ❄️个人专栏: 《C++知识分享》《Linux 入门到实践:零基础也能懂》 ✨生活是默默的坚持,毅力是永久的享受! 🎬 博主简介: 文章目录 * 前言: * 一. 函数:告别重复代码的 “代码工厂” * 1.1 为什么需要函数? * 1.2 函数的核心语法(重点) * 1.3 函数的进阶用法(嵌套 + 递归) * 1.4 函数核心小结 * 二. 列表和元组:批量存储数据的 “容器” * 2.1 列表(list):最常用的可变容器 * 2.2 元组(tuple):不可变的序列容器 * 2.3 列表的元组小结 * 结尾:

By Ne0inhk

Python金融数据API终极指南:从入门到精通掌握Finnhub

Python金融数据API终极指南:从入门到精通掌握Finnhub 【免费下载链接】finnhub-pythonFinnhub Python API Client. Finnhub API provides institutional-grade financial data to investors, fintech startups and investment firms. We support real-time stock price, global fundamentals, global ETFs holdings and alternative data. https://finnhub.io/docs/api 项目地址: https://gitcode.com/gh_mirrors/fi/finnhub-python 在金融科技开发领域,获取实时股票数据和全球金融数据是构建投资分析系统的关键。Finnhub Python

By Ne0inhk
【2026 最新】Python 与 PyCharm 详细下载安装教程 带图展示(Windows 版)

【2026 最新】Python 与 PyCharm 详细下载安装教程 带图展示(Windows 版)

前言 Python 是当今最流行的编程语言之一,广泛应用于 Web 开发、数据分析、人工智能、自动化脚本等领域。而 PyCharm 作为 JetBrains 公司推出的 Python 专业集成开发环境(IDE),凭借智能代码补全、调试器、虚拟环境管理、版本控制集成等强大功能,成为众多开发者首选工具。 本教程专为 Windows 系统用户 编写,将手把手指导你完成 Python 解释器 和 PyCharm IDE 的下载、安装与基础配置,助你快速搭建本地 Python 开发环境。 一、Python 下载与安装 1.1 访问 Python 官网 打开浏览器,访问 Python 官方网站:Download

By Ne0inhk

Python 小白 Debug 全指南:从 “看报错就懵” 到 “1 分钟定位 bug”(万字版)

【个人主页:玄同765】   大语言模型(LLM)开发工程师|中国传媒大学·数字媒体技术(智能交互与游戏设计)   深耕领域:大语言模型开发 / RAG知识库 / AI Agent落地 / 模型微调   技术栈:Python / LangChain/RAG(Dify+Redis+Milvus)| SQL/NumPy | FastAPI+Docker ️   工程能力:专注模型工程化部署、知识库构建与优化,擅长全流程解决方案         专栏传送门:LLM大模型开发 项目实战指南、Python 从真零基础到纯文本 LLM 全栈实战、 从零学 SQL + 大模型应用落地、大模型开发小白专属:从 0 入门 Linux&Shell       「让AI交互更智能,让技术落地更高效」 欢迎技术探讨/项目合作!

By Ne0inhk