1、文件操作
文件操作工具主要提供 2 大功能:保存文件、读取文件。
特性 | Methods 方式 |
---|---|
定义方式 | 使用 @Tool和 @ToolParam注解标记类方法 |
语法复杂度 | 简单,直观 |
支持的参数类型 | 大多数 Java 类型,包括基本类型、POJO、集合等 |
编写文件操作工具类,通过注解式定义工具,代码如下:
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 the 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();
}
}
}
注意:在 AI 调用工具时,一定要思考 健壮性问题 ,如果调用工具失败,要try catch 操作,否则对话就会崩溃。
2、网页抓取
网页抓取工具的作用是根据网址解析到网页的内容。
编写网页抓取工具类
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 doc = Jsoup.connect(url).get();
return doc.html();
} catch (IOException e) {
return "Error scraping web page: " + e.getMessage();
}
}
}
编写单元测试代码:
@SpringBootTest
public class WebScrapingToolTest {
@Test
public void testScrapeWebPage() {
WebScrapingTool tool = new WebScrapingTool();
String url = "https://blog.csdn.net/cui_hao_nan?spm=1000.2115.3001.5343";
String result = tool.scrapeWebPage(url);
assertNotNull(result);
}
}
debug 结果显示
3、终端操作
终端操作工具的作用是在终端执行命令。
1)可以通过 Java 的 Process API 实现终端命令执行,注意 Windows 和其他操作系统下的实现略有区别)。工具类代码如下:
public class TerminalOperationTool {
@Tool(description = "Execute a command in the terminal")
public String executeTerminalCommand(@ToolParam(description = "Command to execute in the terminal") String command) {
StringBuilder output = new StringBuilder();
try {
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", command);
// Process process = Runtime.getRuntime().exec(command);
Process process = builder.start();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
}
}
int exitCode = process.waitFor();
if (exitCode != 0) {
output.append("Command execution failed with exit code: ").append(exitCode);
}
} catch (IOException | InterruptedException e) {
output.append("Error executing command: ").append(e.getMessage());
}
return output.toString();
}
}
debug 结果展示
4、资源下载
资源下载工具的作用是通过链接下载文件到本地。
1)使用 Hutool 的 HttpUtil.downloadFile 方法实现资源下载。资源下载工具类的代码如下:
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();
}
}
}
5、PDF 生成
PDF 生成工具的作用是根据文件名和内容生成 PDF 文档并保存。
可以使用 itext 库 实现 PDF 生成。需要注意的是,itext 对中文字体的支持需要额外配置,不同操作系统提供的字体也不同,如果真要做生产级应用,建议自行下载所需字体。
1)给项目添加依赖:
<!-- 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)编写工具类实现代码:
public class PDFGenerationTool {
@Tool(description = "Generate a PDF file with given content")
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();
}
}
}
上述代码中,为了实现方便,我们是直接保存 PDF 到本地文件系统。此外,你还可以将生成的文件上传到对象存储服务,然后返回可访问的 URL 给 AI 去输出;或者将本地文件临时返回给前端,让用户直接访问。
6、集中注册
开发好了很多工具类后,可以结合我们自己的需求,可以给 AI 一次性提供所有工具,让它自己决定何时调用。所以我们可以创建 工具注册类,方便统一管理和绑定所有工具。
@Configuration
public class ToolRegistration {
@Bean
public ToolCallback[] allTools() {
FileOperationTool fileOperationTool = new FileOperationTool();
WebScrapingTool webScrapingTool = new WebScrapingTool();
ResourceDownloadTool resourceDownloadTool = new ResourceDownloadTool();
TerminalOperationTool terminalOperationTool = new TerminalOperationTool();
PDFGenerationTool pdfGenerationTool = new PDFGenerationTool();
return ToolCallbacks.from(
fileOperationTool,
webScrapingTool,
resourceDownloadTool,
terminalOperationTool,
pdfGenerationTool
);
}
}
- 工厂模式:allTools()方法作为一个工厂方法,负责创建和配置多个工具实例,然后将它们包装成统一的数组返回。这符合工厂模式的核心思想 -集中创建对象并隐藏创建细节
- 注册模式:该类作为一个中央注册点,集中管理和注册所有可用的工具,使它们能够被系统其他部分统一访问。
- 适配器模式的应用:ToolCallbacks.from 方法可以看作是一种适配器,通过自动识别 @Tool注解,将各种不同的工具类转换为统一的ToolCallback 数组,使系统能够以一致的方式处理它们。
7、使用工具
在 LoveApp 类中添加工具调用的代码,通过 tools 方法绑定所有已注册的工具:
@Resource
private ToolCallback[] allTools;
public String doChatWithTools(String message, String chatId) {
ChatResponse response = chatClient
.prompt()
.user(message)
.advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
// 开启日志,便于观察效果
.advisors(new MyLoggerAdvisor())
.tools(allTools)
.call()
.chatResponse();
String content = response.getResult().getOutput().getText();
log.info("content: {}", content);
return content;
}