【保姆級圖文詳解】Spring AI 中的工具調用原理解析,工具開發:文件操作、聯網搜索、網頁抓取、資源下載、PDF生成、工具集中注冊

目錄

  • 前言
  • 一、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"…