asp做的网站,道滘网站仿做,济南网站建设代码,做自媒体一般都注册几个网站目录前言一、Spring AI 中的工具调用#xff08;Tool Calling#xff09;1.1、概念1.2、工作原理1.3、技术选型1.4、原理解析1.4.1、实现接口1.4.2、工具调用二、工具调用#xff08;Tool Calling#xff09;开发2.1、文件操作2.1.1、概念描述2.1.2、概念描述2.2、联网搜索…
目录前言一、Spring AI 中的工具调用Tool Calling1.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.gmgmail.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) {ListFunctionCallback toolCallbacks List.of();if (prompt.getOptions() instanceof ToolCallingChatOptions toolCallingChatOptions) {toolCallbacks toolCallingChatOptions.getToolCallbacks();}else if (prompt.getOptions() instanceof FunctionCallingOptions functionOptions) {toolCallbacks functionOptions.getFunctionCallbacks();}ListToolResponseMessage.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/u1026803159,4238637210fm217app126sizef242,150n0fJPEGfmtauto?s01F65C9344640CAA12FCF17B0300D030sec1714842000tc3db150577185f3a818a8bbe73ddd2c4},...]
}2.2.2、开发步骤
1、申请API_KEY申请或者登录网站申请Key。key千万别暴露。 2、配置文件添加。
# searchApi
search-api:api-key: 自己的 API Key3、撰写工具类。
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) {MapString, 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);ListObject 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库。
dependencygroupIdorg.jsoup/groupIdartifactIdjsoup/artifactIdversion1.19.1/version
/dependency2、编写网页抓取工具类。
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?spm5176.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包。 dependencygroupIdcn.hutool/groupIdartifactIdhutool-all/artifactIdversion5.8.37/version/dependency2、编写下载类。
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 --
dependencygroupIdcom.itextpdf/groupIdartifactIditext-core/artifactIdversion9.1.0/versiontypepom/type
/dependency
!-- https://mvnrepository.com/artifact/com.itextpdf/font-asian --
dependencygroupIdcom.itextpdf/groupIdartifactIdfont-asian/artifactIdversion9.1.0/versionscopetest/scope
/dependency2、编写工具实现类。
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、测试验证。