目录

  • 前言
  • 一、Spring AI 中的工具调用(Tool Calling)
    • 1.1、概念
    • 1.2、工作原理
    • 1.3、技术选型
    • 1.4、原理解析
      • 1.4.1、实现接口
      • 1.4.2、工具调用
  • 二、工具调用(Tool Calling)开发
    • 2.1、文件操作
      • 2.1.1、概念描述
      • 2.1.2、概念描述
    • 2.2、联网搜索
      • 2.2.1、概念描述
      • 2.2.2、开发步骤
    • 2.3、网页抓取
      • 2.3.1、概念描述
      • 2.3.2、开发步骤
    • 2.4、资源下载
      • 2.4.1、概念描述
      • 2.4.2、开发步骤
    • 2.5、PDF生成
      • 2.5.1、概念描述
      • 2.5.2、开发步骤
    • 2.6、工具集中注册
      • 2.6.1、概念描述
      • 2.6.2、开发步骤

前言

若对您有帮助的话,请点赞收藏加关注哦,您的关注是我持续创作的动力!有问题请私信或联系邮箱:funian.gm@gmail.com

一、Spring AI 中的工具调用(Tool Calling)

1.1、概念

  • Spring AI 中的工具调用(Tool Calling)是指让 AI 大模型借助外部工具来完成自身无法直接处理的任务。这些外部工具可以是网页搜索、外部 API 调用、访问外部数据或执行特定代码等多种形式。例如,当用户询问成都最新天气时,AI 本身没有该实时数据,就可以调用 “查询天气工具” 来获取并返回结果。

1.2、工作原理

  • **工具调用的流程并非 AI 服务器直接调用工具或执行工具代码,而是由应用程序进行控制,这种设计的关键在于安全性,AI 模型无法直接接触 API 或系统资源,所有操作都必须通过应用程序执行,这样可以完全控制 AI 的行为。**具体流程如下:
    • 用户提出问题。
    • 程序将问题传递给大模型。
    • 大模型分析问题,判断是否需要使用工具以及使用何种工具,并确定所需参数。
    • 大模型输出工具名称和参数。
    • 程序接收工具调用请求,执行相应的工具操作。
    • 工具执行操作并返回结果数据。
    • 程序将抓取结果传回给大模型。
    • 大模型分析工具返回的内容,生成最终回答。
    • 程序将大模型的回答返回给用户。
      在这里插入图片描述

1.3、技术选型

  • Spring AI 实现工具调用的流程包括工具定义、工具选择、返回意图、工具执行、结果返回和继续对话。为了简化开发,推荐使用 Spring AI、LangChain 等开发框架,部分 AI 大模型服务商提供的 SDK 也能起到简化代码的作用。需要注意的是,并非所有大模型都支持工具调用,可在 Spring AI 官方文档中查看各模型的支持情况。

  • 工具定义模式。在 Spring AI 中,定义工具主要有基于 Methods 方法和 Functions 函数式编程两种模式:

    • 基于 Methods 方法:使用 @Tool 和 @ToolParam 注解标记类方法,语法简单直观,支持大多数 Java 类型作为参数和返回类型,包括基本类型、POJO、集合等,几乎支持所有可序列化类型作为返回类型,包括 void,适合大多数新项目开发,支持按需注册和全局注册,自动处理类型转换,通过注解提供描述文档。
    • Functions 函数式编程:使用函数式接口并通过 Spring Bean 定义,语法较复杂,需要定义请求 / 响应对象,不支持基本类型、Optional、集合类型作为参数和返回类型,适合与现有函数式 API 集成,通常在配置类中预先定义,需要更多手动配置进行类型转换,通过 Bean 描述和 JSON 属性注解提供文档支持。
  • 一般推荐学习基于 Methods 方法来定义工具,因为其更容易编写和理解,支持的参数和返回类型更多。

1.4、原理解析

1.4.1、实现接口

  • 工具底层数据结构:Spring AI 工具调用的核心在于ToolCallback接口,它是所有工具实现的基础。该接口中:
    • getToolDefinition()提供工具的基本定义,包括名称、描述和调用参数,这些信息传递给 AI 模型,帮助模型了解何时调用工具及如何构造参数。
    • getToolMetadata()提供处理工具的附加信息,如是否直接返回结果等控制选项。
    • 两个call()方法是工具的执行入口,分别支持有上下文和无上下文的调用场景。
    • 工具定义类ToolDefinition包含名称、描述和调用工具的参数。
public interface ToolCallback {/*** Definition used by the AI model to determine when and how to call the tool.*/ToolDefinition getToolDefinition();/*** Metadata providing additional information on how to handle the tool.*/ToolMetadata getToolMetadata();/*** Execute tool with the given input and return the result to send back to the AI model.*/String call(String toolInput);/*** Execute tool with the given input and context, and return the result to send back to the AI model.*/String call(String toolInput, ToolContext tooContext);
}

在这里插入图片描述

  • 注解定义工具的原理:当使用注解定义工具时,Spring AI 会在幕后做大量工作,包括:

    • JsonSchemaGenerator解析方法签名和注解,自动生成符合 JSON Schema 规范的参数定义,作为ToolDefinition的一部分提供给 AI 大模型。
    • ToolCallResultConverter负责将各种类型的方法返回值统一转换为字符串,便于传递给 AI 大模型处理。
    • MethodToolCallback实现对注解方法的封装,使其符合ToolCallback接口规范。这种设计让开发者可以专注于业务逻辑实现,无需关心底层通信和参数转换的复杂细节。如果需要更精细的控制,可以自定义ToolCallResultConverter来实现特定的转换逻辑,例如对某些特殊对象的自定义序列化。
  • 工具上下文:在实际应用中,工具执行可能需要额外的上下文信息,如登录用户信息、会话 ID 或者其他环境参数,Spring AI 通过ToolContext提供了这一能力。

在这里插入图片描述

1.4.2、工具调用

在这里插入图片描述

  • 执行模式与核心组件:Spring AI 提供了框架控制的工具执行和用户控制的工具执行两种工具执行模式,这两种模式都依赖核心组件ToolCallingManager。
    • ToolCallingManager接口是管理 AI 工具调用全过程的核心组件,负责根据 AI 模型的响应执行对应的工具并返回执行结果给大模型,还支持异常处理,可统一处理工具执行过程中的错误情况。
	/*** Execute the tool call and return the response message. To ensure backward* compatibility, both {@link ToolCallback} and {@link FunctionCallback} are* supported.*/private InternalToolExecutionResult executeToolCall(Prompt prompt, AssistantMessage assistantMessage,ToolContext toolContext) {List<FunctionCallback> toolCallbacks = List.of();if (prompt.getOptions() instanceof ToolCallingChatOptions toolCallingChatOptions) {toolCallbacks = toolCallingChatOptions.getToolCallbacks();}else if (prompt.getOptions() instanceof FunctionCallingOptions functionOptions) {toolCallbacks = functionOptions.getFunctionCallbacks();}List<ToolResponseMessage.ToolResponse> toolResponses = new ArrayList<>();Boolean returnDirect = null;for (AssistantMessage.ToolCall toolCall : assistantMessage.getToolCalls()) {logger.debug("Executing tool call: {}", toolCall.name());String toolName = toolCall.name();String toolInputArguments = toolCall.arguments();FunctionCallback toolCallback = toolCallbacks.stream().filter(tool -> toolName.equals(tool.getName())).findFirst().orElseGet(() -> toolCallbackResolver.resolve(toolName));if (toolCallback == null) {throw new IllegalStateException("No ToolCallback found for tool name: " + toolName);}if (returnDirect == null && toolCallback instanceof ToolCallback callback) {returnDirect = callback.getToolMetadata().returnDirect();}else if (toolCallback instanceof ToolCallback callback) {returnDirect = returnDirect && callback.getToolMetadata().returnDirect();}else if (returnDirect == null) {// This is a temporary solution to ensure backward compatibility with// FunctionCallback.// TODO: remove this block when FunctionCallback is removed.returnDirect = false;}String toolResult;try {toolResult = toolCallback.call(toolInputArguments, toolContext);}catch (ToolExecutionException ex) {toolResult = toolExecutionExceptionProcessor.process(ex);}toolResponses.add(new ToolResponseMessage.ToolResponse(toolCall.id(), toolName, toolResult));}return new InternalToolExecutionResult(new ToolResponseMessage(toolResponses, Map.of()), returnDirect);}
  • 其有两个核心方法,resolveToolDefinitions从模型的工具调用选项中解析工具定义,executeToolCalls执行模型请求对应的工具调用。如果使用任何 Spring AI 相关的 Spring Boot Starter,都会默认初始化一个DefaultToolCallingManager,其中包含工具观察器、工具解析器、工具执行异常处理器的定义。

  • 工具调用判断:ToolCallingManager通过从 AI 返回的toolCalls参数中获取要调用的工具来判断是否要调用工具,由于实现可能会更新,建议通过查看源码来分析。

  • 框架控制的工具执行:这是默认且最简单的模式,由 Spring AI 框架自动管理整个工具调用流程。在这种模式下,框架会自动检测模型是否请求调用工具,自动执行工具调用并获取结果,自动将结果发送回模型,管理整个对话流程直到得到最终答案。

在这里插入图片描述

二、工具调用(Tool Calling)开发

  • 自主开发前提:当在社区中找不到合适的工具时,就需要进行自主开发。同时要注意,对于 AI 自身能够实现的功能,通常没必要将其定义为额外的工具,因为这会增加一次额外的交互,工具应被用于解决 AI 无法直接完成的任务。
  • 在开发过程中,要格外注意工具描述的定义,因为它会影响 AI 决定是否使用该工具。

2.1、文件操作

2.1.1、概念描述

  • 功能:文件操作工具主要有保存文件和读取文件两大功能。
  • 存储目录:由于文件操作会影响系统资源,所以需要将文件统一存放到一个隔离的目录。在constant包下新建文件常量类,约定文件保存目录为项目根目录下的/tmp目录,相关代码通过public interface FileConstant定义,其中String FILE_SAVE_DIR = System.getProperty(“user.dir”) + “/tmp”;指定了具体的保存路径。
  • 注意事项:建议将这个/tmp目录添加到.gitignore文件中,以避免提交隐私信息。
  • 后续任务:接下来需要编写文件操作工具类,并通过注解式定义工具。

2.1.2、概念描述

  • 1、定义文件保存目录
package com.funian.agent.constant;/*** @Auther FuNian* @Major Computer Software*/
public interface FileConstant {/*** 文件保存目录*/String FILE_SAVE_DIR = System.getProperty("user.dir") + "/tmp";
}
  • 2、文件读取和保存。
package com.funian.agent.tools;import cn.hutool.core.io.FileUtil;
import com.funian.agent.constant.FileConstant;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;/*** @Auther FuNian* @Major Computer Software*//*** 文件操作工具类(提供文件读写功能)*/
public class FileOperationTool {private final String FILE_DIR = FileConstant.FILE_SAVE_DIR + "/file";@Tool(description = "Read content from a file")public String readFile(@ToolParam(description = "Name of a file to read") String fileName) {String filePath = FILE_DIR + "/" + fileName;try {return FileUtil.readUtf8String(filePath);} catch (Exception e) {return "Error reading file: " + e.getMessage();}}@Tool(description = "Write content to a file")public String writeFile(@ToolParam(description = "Name of the file to write") String fileName,@ToolParam(description = "Content to write to the file") String content) {String filePath = FILE_DIR + "/" + fileName;try {// 创建目录FileUtil.mkdir(FILE_DIR);FileUtil.writeUtf8String(content, filePath);return "File written successfully to: " + filePath;} catch (Exception e) {return "Error writing to file: " + e.getMessage();}}
}
  • 3、单元测试类。
package com.funian.agent.tools;import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;import static org.junit.jupiter.api.Assertions.*;/*** @Auther FuNian* @Major Computer Software*/
class FileOperationToolTest {@Testvoid readFile() {FileOperationTool fileOperationTool = new FileOperationTool();String fileName = "Spring AI.txt";String result = fileOperationTool.readFile(fileName);Assertions.assertNotNull(result);}@Testvoid writeFile() {FileOperationTool fileOperationTool = new FileOperationTool();String fileName = "Spring AI.txt";String content = "Spring AI交流社区";String result = fileOperationTool.writeFile(fileName, content);Assertions.assertNotNull(result);}
}
  • 4、测试验证。

在这里插入图片描述

2.2、联网搜索

2.2.1、概念描述

  • 作用:联网搜索工具的作用是依据关键词来搜索网页列表。
  • 实现方式:可以使用专业的网页搜索 API,像 Search API,它能够实现从多个网站搜索内容,不过这类服务一般是按量计费的。另外,也能够直接使用 Google 或者 Bing 的搜索 API,甚至还可以通过爬虫和网页解析从某个搜索引擎获取内容。
  • 任务要求:需要阅读 Search API 的官方文档,重点关注 API 的请求参数和返回结果,并且从 API 返回的结果里,只提取关键部分。

在这里插入图片描述

{"organic_results": [...{"position": 2,"title": "【动物星球】动物星球商城_Animal Planet是什么牌子","link": "https://pinpai.smzdm.com/59685/","displayed_link": "什么值得买","snippet": "实时推荐动物星球(Animal Planet)商城正品特价。结合动物星球评测与动物星球最新资讯,全方位介绍Animal Planet是什么牌子?什么值得买综合各类动物星球优惠信息,计算最优购买方案,帮您轻松搞定正品...","snippet_highlighted_words": ["Animal", "Planet"],"thumbnail": "https://t8.baidu.com/it/u=1026803159,4238637210&fm=217&app=126&size=f242,150&n=0&f=JPEG&fmt=auto?s=01F65C9344640CAA12FCF17B0300D030&sec=1714842000&t=c3db150577185f3a818a8bbe73ddd2c4"},...]
}

2.2.2、开发步骤

  • 1、申请API_KEY:申请或者登录网站,申请Key。key千万别暴露。

在这里插入图片描述

  • 2、配置文件添加。
# searchApi
search-api:api-key: 自己的 API Key
  • 3、撰写工具类。
package com.funian.agent.tools;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;/*** @Auther FuNian* @Major Computer Software*//*** 网页搜索工具类*/
public class WebSearchTool {// SearchAPI 的搜索接口地址private static final String SEARCH_API_URL = "https://www.searchapi.io/api/v1/search";private final String apiKey;public WebSearchTool(String apiKey) {this.apiKey = apiKey;}@Tool(description = "Search for information from Baidu Search Engine")public String searchWeb(@ToolParam(description = "Search query keyword") String query) {Map<String, Object> paramMap = new HashMap<>();paramMap.put("q", query);paramMap.put("api_key", apiKey);paramMap.put("engine", "baidu");try {String response = HttpUtil.get(SEARCH_API_URL, paramMap);// 取出返回结果的前 10条JSONObject jsonObject = JSONUtil.parseObj(response);// 提取 organic_results 部分JSONArray organicResults = jsonObject.getJSONArray("organic_results");List<Object> objects = organicResults.subList(0, 10);// 拼接搜索结果为字符串String result = objects.stream().map(obj -> {JSONObject tmpJSONObject = (JSONObject) obj;return tmpJSONObject.toString();}).collect(Collectors.joining(","));return result;} catch (Exception e) {return "Error searching Baidu: " + e.getMessage();}}
}
  • 4、单元测试类。
package com.funian.agent.tools;import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;import static org.junit.jupiter.api.Assertions.*;/*** @Auther FuNian* @ClassName:WebSearchToolTest*/@SpringBootTest
public class WebSearchToolTest {@Testpublic void testSearchWeb() {WebSearchTool tool = new WebSearchTool("oJQtz4cpK4QgbfjyGV7Vsw6g");String query = "Spring AI官网";String result = tool.searchWeb(query);assertNotNull(result);}
}
  • 5、测试验证。

在这里插入图片描述

2.3、网页抓取

2.3.1、概念描述

  • 作用:网页抓取工具的作用是依据网址解析网页的内容。
  • 实现方式:使用 jsoup 库来实现网页内容抓取和解析。

2.3.2、开发步骤

  • 1、引入jsoup库。
<dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.19.1</version>
</dependency>
  • 2、编写网页抓取工具类。
package com.funian.agent.tools;/*** @Auther FuNian* @Major Computer Software*/import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;/*** 网页抓取工具*/
public class WebScrapingTool {@Tool(description = "Scrape the content of a web page")public String scrapeWebPage(@ToolParam(description = "URL of the web page to scrape") String url) {try {Document document = Jsoup.connect(url).get();return document.html();} catch (Exception e) {return "Error scraping web page: " + e.getMessage();}}
}
  • 3、单元测试。
package com.funian.agent.tools;import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;import static org.junit.jupiter.api.Assertions.*;/*** @Auther FuNian* @Major Computer Software*/
@SpringBootTest
class WebScrapingToolTest {@Testvoid scrapeWebPage() {WebScrapingTool webScrapingTool = new WebScrapingTool();String url = "https://www.aliyun.com/resources?spm=5176.29677750.J_4VYgf18xNlTAyFFbOuOQe.d_menu_3.275b154aRdMaua";String result = webScrapingTool.scrapeWebPage(url);Assertions.assertNotNull(result);}
}
  • 4、验证。

在这里插入图片描述

2.4、资源下载

2.4.1、概念描述

  • 作用:资源下载工具的作用是通过链接将文件下载到本地。
  • 实现方式:使用 Hutool 的HttpUtil.downloadFile方法来实现资源下载,后续需要编写资源下载工具类的代码。

2.4.2、开发步骤

  • 1、引入Hutool包。
  <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.37</version></dependency>
  • 2、编写下载类。
package com.funian.agent.tools;import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HttpUtil;import com.funian.agent.constant.FileConstant;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;import java.io.File;/*** @Auther FuNian* @Major Computer Software*//*** 资源下载工具类*/
public class ResourceDownloadTool {@Tool(description = "Download a resource from a given URL")public String downloadResource(@ToolParam(description = "URL of the resource to download") String url, @ToolParam(description = "Name of the file to save the downloaded resource") String fileName) {String fileDir = FileConstant.FILE_SAVE_DIR + "/download";String filePath = fileDir + "/" + fileName;try {// 创建目录FileUtil.mkdir(fileDir);// 使用 Hutool 的 downloadFile 方法下载资源HttpUtil.downloadFile(url, new File(filePath));return "Resource downloaded successfully to: " + filePath;} catch (Exception e) {return "Error downloading resource: " + e.getMessage();}}
}
  • 3、 编写单元测试类。
@SpringBootTest
public class ResourceDownloadToolTest {@Testpublic void testDownloadResource() {ResourceDownloadTool tool = new ResourceDownloadTool();String url = "https://home.console.aliyun.com/home/dashboard/Cost/logo.png";String fileName = "logo.png";String result = tool.downloadResource(url, fileName);assertNotNull(result);}
}
  • 4、测试验证。

在这里插入图片描述

2.5、PDF生成

2.5.1、概念描述

  • 作用:PDF 生成工具的作用是根据文件名和内容生成 PDF 文档并保存。
  • 实现方式:可以使用 iText 库来实现 PDF 生成。需要注意的是,iText 对中文字体的支持需要额外配置,不同操作系统提供的字体也有所不同,如果要做生产级应用,建议自行下载所需字体。不过对于学习来说,不建议在此处浪费太多时间,可以使用内置中文字体(不引入 font-asian 字体依赖也可以使用)。
  • 拓展操作:上述代码为了实现方便,直接将 PDF 保存到本地文件系统。此外,还可以将生成的文件上传到对象存储服务,然后返回可访问的 URL 给 AI 去输出;或者将本地文件临时返回给前端,让用户直接访问。

2.5.2、开发步骤

  • 1、引入依赖itext。
<!-- https://mvnrepository.com/artifact/com.itextpdf/itext-core -->
<dependency><groupId>com.itextpdf</groupId><artifactId>itext-core</artifactId><version>9.1.0</version><type>pom</type>
</dependency>
<!-- https://mvnrepository.com/artifact/com.itextpdf/font-asian -->
<dependency><groupId>com.itextpdf</groupId><artifactId>font-asian</artifactId><version>9.1.0</version><scope>test</scope>
</dependency>
  • 2、编写工具实现类。
package com.funian.agent.tools;import cn.hutool.core.io.FileUtil;
import com.funian.agent.constant.FileConstant;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;import java.io.IOException;/*** @Auther FuNian* @Major Computer Software*//*** PDF 生成工具*/
public class PDFGenerationTool {@Tool(description = "Generate a PDF file with given content", returnDirect = false)public String generatePDF(@ToolParam(description = "Name of the file to save the generated PDF") String fileName,@ToolParam(description = "Content to be included in the PDF") String content) {String fileDir = FileConstant.FILE_SAVE_DIR + "/pdf";String filePath = fileDir + "/" + fileName;try {// 创建目录FileUtil.mkdir(fileDir);// 创建 PdfWriter 和 PdfDocument 对象try (PdfWriter writer = new PdfWriter(filePath);PdfDocument pdf = new PdfDocument(writer);Document document = new Document(pdf)) {// 自定义字体(需要人工下载字体文件到特定目录)
//                String fontPath = Paths.get("src/main/resources/static/fonts/simsun.ttf")
//                        .toAbsolutePath().toString();
//                PdfFont font = PdfFontFactory.createFont(fontPath,
//                        PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED);// 使用内置中文字体PdfFont font = PdfFontFactory.createFont("STSongStd-Light", "UniGB-UCS2-H");document.setFont(font);// 创建段落Paragraph paragraph = new Paragraph(content);// 添加段落并关闭文档document.add(paragraph);}return "PDF generated successfully to: " + filePath;} catch (IOException e) {return "Error generating PDF: " + e.getMessage();}}
}
  • 3、编写单元测试。
package com.funian.agent.tools;import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;import static org.junit.jupiter.api.Assertions.*;/*** @Auther FuNian* @ClassName:PDFGenerationToolTest*/
@SpringBootTest
class PDFGenerationToolTest {@Testpublic void testGeneratePDF() {PDFGenerationTool tool = new PDFGenerationTool();String fileName = "Spring  AI.pdf";String content = "Spring  AI项目 https://docs.spring.io/spring-ai/reference/api/chat/comparison.html";String result = tool.generatePDF(fileName, content);assertNotNull(result);}
}
  • 4、测试验证。

在这里插入图片描述

2.6、工具集中注册

2.6.1、概念描述

  • 集中注册:在开发好众多工具类后,结合自身需求,可以创建工具注册类,一次性给 AI 提供所有工具,让 AI 自行决定何时调用,这样方便统一管理和绑定所有工具。
  • 设计模式:相关代码暗含多种设计模式。有了这个注册类,添加或移除工具只需修改这一个类,更利于维护。
    • 工厂模式(allTools () 方法作为工厂方法创建和配置多个工具实例并包装成统一数组返回)。
    • 依赖注入模式(通过 @Value 注解注入配置值,将工具通过 Spring 容器注入到需要的组件中)。
    • 注册模式(该类作为中央注册点集中管理和注册所有可用工具)。
    • 适配器模式(ToolCallbacks.from 方法将不同工具类转换为统一的 ToolCallback 数组)。

2.6.2、开发步骤

  • 1、实现集中注册类。
package com.funian.agent.tools;import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.ToolCallbacks;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @Auther FuNian* @Major Computer Software*//*** 集中的工具注册类*/
@Configuration
public class ToolRegistration {@Value("${search-api.api-key}")private String searchApiKey;@Beanpublic ToolCallback[] allTools() {FileOperationTool fileOperationTool = new FileOperationTool();WebSearchTool webSearchTool = new WebSearchTool(searchApiKey);WebScrapingTool webScrapingTool = new WebScrapingTool();ResourceDownloadTool resourceDownloadTool = new ResourceDownloadTool();TerminalOperationTool terminalOperationTool = new TerminalOperationTool();PDFGenerationTool pdfGenerationTool = new PDFGenerationTool();TerminateTool terminateTool = new TerminateTool();return ToolCallbacks.from(fileOperationTool,webSearchTool,webScrapingTool,resourceDownloadTool,terminalOperationTool,pdfGenerationTool,terminateTool);}
}
  • 2、使用集中工具。
  // AI 调用工具能力@Resourceprivate ToolCallback[] allTools;/*** AI 旅游报告功能(支持调用工具)** @param message* @param chatId* @return*/public String doChatWithTools(String message, String chatId) {ChatResponse chatResponse = chatClient.prompt().user(message).advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId).param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 20))// 开启日志,便于观察效果.advisors(new LoggerAdvisor()).tools(allTools).call().chatResponse();String content = chatResponse.getResult().getOutput().getText();log.info("content: {}", content);return content;}
  • 3、单元测试。
 @Testvoid doChatWithTools() {// 测试联网搜索问题的答案testMessage("周末想去成都,推荐几个适合的小众打卡地?");// 测试网页抓取:旅游案例分析testMessage("如何制定旅游攻略");// 测试资源下载:图片下载testMessage("下载一张成都SKP的照片");// 测试文件操作:保存用户档案testMessage("保存我的旅游攻略为文件");// 测试 PDF 生成testMessage("生成一份‘成都旅游计划’PDF,包括具体路线、消费");}private void testMessage(String message) {String chatId = UUID.randomUUID().toString();String answer = TravelApp.doChatWithTools(message, chatId);Assertions.assertNotNull(answer);}
  • 4、测试验证。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/914516.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/914516.shtml
英文地址,请注明出处:http://en.pswp.cn/news/914516.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis客户端使用(Client、Java、SpringBoot)

上篇文章&#xff1a; Redis数据类型之zsethttps://blog.csdn.net/sniper_fandc/article/details/149139955?fromshareblogdetail&sharetypeblogdetail&sharerId149139955&sharereferPC&sharesourcesniper_fandc&sharefromfrom_link 目录 1 Redis客户端…

Modbus 开发工具实战:ModScan32 与 Wireshark 抓包分析(一

引言 ** 在工业自动化领域&#xff0c;Modbus 协议犹如一座桥梁&#xff0c;连接着各种电子设备&#xff0c;实现它们之间高效的数据交互。从可编程逻辑控制器&#xff08;PLC&#xff09;到人机界面&#xff08;HMI&#xff09;&#xff0c;再到各类智能传感器&#xff0c;M…

Oracle SQL - 使用行转列PIVOT减少表重复扫描(实例)

[13/JUL/2025, Yusuf Leo, Oracle SQL Performance Tuning Series]我们经常会遇到从同一表中按不同维度取出不同区间的数据&#xff0c;再以相同的属性将这些数据分别汇总到一起的需求。这类需求往往迫使我们对同一个表反复去扫描&#xff0c;当原始数据量太大的时候&#xff0…

HTTP 请求方法详解:GET、POST、PUT、DELETE 等

在 HTTP 协议中&#xff0c;请求方法&#xff08;也称为 HTTP 动词&#xff09;定义了客户端希望对指定资源执行的操作类型。这些方法是 HTTP 报文的核心组成部分&#xff0c;决定了请求的目的和行为。 主要 HTTP 请求方法 1. GET 用途&#xff1a;获取资源 特点&#xff1a…

Android 代码热度统计(概述)

1. 前言 代码热度统计&#xff0c;在测试中一般也叫做代码覆盖率。一般得到代码覆盖率后就能了解整体样本在线上的代码使用情况&#xff0c;为无用代码下线提供依据。 做了一下调研&#xff0c;在Android中一般比较常用的是&#xff1a;JaCoCO覆盖率统计工具&#xff0c;它采…

RAG优化

RAG搭建本地AI知识库&#xff0c;在使用过程中遇到的三大痛点&#xff0c;以及相应的进阶方案。1. RAG知识库的三大痛点-- 内容理解不足&#xff1a;AI难以全面理解导入资料的内容&#xff0c;比如在向量编码时候&#xff0c;生硬的截断等导致分析结果不理想。eg: 知识库分割器…

Ubuntu 24.04 启用 root 图形登录

关键词&#xff1a;Ubuntu 24.04、root 登录、GDM、SSH、nano、配置文件一、前言 Ubuntu 默认禁用 root 账户 的图形与 SSH 登录&#xff0c;这是为了安全。但在某些场景&#xff08;如测试、救援、自动化脚本&#xff09;你可能需要 直接用 root 登录 GNOME 桌面。本文以 Ubun…

Jekyll + Chirpy + GitHub Pages 搭建博客

Chirpy 是适用于技术写作的简约、响应迅速且功能丰富的 Jekyll 主题&#xff0c;文档地址&#xff1a;https://chirpy.cotes.page/ &#xff0c;Github 地址&#xff1a;jekyll-theme-chirpy 。 1.开始 打开 chirpy-starter 仓库&#xff0c;点击按钮 Use this template -->…

学习 Flutter (一)

学习 Flutter (一) 1. 引言 什么是 Flutter&#xff1f; Flutter 是 Google 开发的一套开源 UI 框架&#xff0c;主要用于构建高性能、高保真、跨平台的应用程序。使用一套 Dart 编写的代码&#xff0c;开发者可以同时构建适用于&#xff1a; Android iOS Web Windows、mac…

Spring Boot 实现图片防盗链:Referer 校验与 Token 签名校验完整指南

Spring Boot 实现图片防盗链教程&#xff08;Referer 校验 Token 签名校验&#xff09;本文将详细讲解两种防盗链实现方案&#xff0c;并提供完整代码示例。方案一&#xff1a;Referer 校验通过检查 HTTP 请求头中的 Referer 字段判断来源是否合法。实现步骤创建 Referer 拦截…

从 JSON 到 Python 对象:一次通透的序列化与反序列化之旅

目录 一、为什么要谈 JSON 二、最快速上手&#xff1a;两把钥匙 dumps 与 loads 三、深入 dumps&#xff1a;参数是魔法棒 四、深入 loads&#xff1a;把风险挡在门外 五、文件级序列化&#xff1a;dump 与 load 六、处理中文与编码陷阱 七、异常场景与调试技巧 八、实…

Leetcode 3315. 构造最小位运算数组 II

1.题目基本信息 1.1.题目描述 给你一个长度为 n 的质数数组 nums 。你的任务是返回一个长度为 n 的数组 ans &#xff0c;对于每个下标 i &#xff0c;以下 条件 均成立&#xff1a; ans[i] OR (ans[i] 1) nums[i] 除此以外&#xff0c;你需要 最小化 结果数组里每一个 a…

黑搜小知识 | DNS域名解析过程是什么样的?

什么是DNS&#xff1f;DNS( Domain Name System)是“域名系统”的英文缩写&#xff0c;是一种组织成域层次结构的计算机和网络服务命名系统&#xff0c;它用于TCP/IP网络&#xff0c;它所提供的服务是用来将主机名和域名转换为IP地址的工作。举例来说&#xff0c;如果你要访问域…

MyBatis 使用教程及插件开发

作者&#xff1a;小凯 沉淀、分享、成长&#xff0c;让自己和他人都能有所收获&#xff01; 本文的宗旨在于通过简单干净实践的方式教会读者&#xff0c;使用 SpringBoot 配置 MyBatis 并完成对插入、批量插入、修改、查询以及注解事务和编程事务的使用&#xff0c;通过扩展插件…

Maui劝退:用windows直接真机调试iOS,无须和Mac配对

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

【极客日常】后端任务动态注入执行策略的一种技术实现

近期做项目时遇到一个场景&#xff0c;是需要在后端任务执行时动态注入策略。具体而言&#xff0c;笔者负责的后端服务&#xff0c;可以理解是会在线上服务发布时&#xff0c;对服务风险做实时扫描&#xff0c;那么这个扫描就需要根据当前线上服务发布上下文&#xff0c;匹配对…

8. JVM类装载的执行过程

1. JVM介绍和运行流程-CSDN博客 2. 什么是程序计数器-CSDN博客 3. java 堆和 JVM 内存结构-CSDN博客 4. 虚拟机栈-CSDN博客 5. JVM 的方法区-CSDN博客 6. JVM直接内存-CSDN博客 7. JVM类加载器与双亲委派模型-CSDN博客 8. JVM类装载的执行过程-CSDN博客 9. JVM垃圾回收…

Linux操作系统之信号:信号的产生

前言&#xff1a;上篇文章我们大致讲解了信号的有关概念&#xff0c;为大家引入了信号的知识点。但光知道那些是远远不够的。本篇文章&#xff0c;我将会为大家自己的讲解一下信号的产生的五种方式&#xff0c;希望对大家有所帮助。一、键盘&#xff08;硬件&#xff09;产生信…

pdf拆分

文章目录 背景目标实现下载 背景 好不容易下载的1000页行业报告&#xff0c;领导非要按章节拆分成20份&#xff01;学术论文合集需要按作者拆分投稿&#xff0c;手动分页到怀疑人生…客户发来加密合同&#xff0c;要求每5页生成独立文档&#xff0c;格式还不能乱&#xff01; …

vue3使用mermaid生成图表,并可编辑

效果图实际代码<template><div class"mermaid-container" style"z-index: 99999" ref"wrapperRef"><!-- 控制栏 --><div class"control-bar"><div class"control-bar-flex control-bar-tab-wrap"…