1. Spring AI工具调用实战:从原理到旅游计划PDF生成
作为一名长期从事AI应用开发的工程师,我深刻体会到工具调用(Tool Calling)能力对于构建实用AI系统的关键作用。今天我将分享如何利用Spring AI框架,通过多工具集成实现一个智能旅游计划生成系统,最终输出结构化的PDF文档。
1.1 工具调用的核心价值
工具调用本质上是一种"能力扩展"机制。就像人类使用螺丝刀、计算器等工具来弥补自身局限一样,AI模型通过调用外部工具来完成它无法独立处理的任务。这种机制带来了三大核心优势:
- 突破知识时效性限制:大模型训练数据存在时间滞后,通过调用搜索引擎API获取最新信息
- 扩展功能边界:原生不支持的操作如文件读写、PDF生成等,通过专用工具实现
- 提升结果可靠性:数学计算、数据查询等精确操作交由专业工具执行,避免模型幻觉
在旅游计划场景中,用户可能提出这样的复合需求:"查找杭州三天两夜旅游攻略,包含景点介绍、交通方式和酒店推荐,整理成PDF"。这需要组合多种工具能力:
mermaid复制graph TD
A[用户请求] --> B[搜索引擎获取最新攻略]
B --> C[网页抓取补充详情]
C --> D[本地文件存储中间结果]
D --> E[PDF生成最终报告]
1.2 Spring AI的实现架构
Spring AI通过精巧的架构设计,将工具调用流程标准化。下图展示了关键组件交互:

核心处理流程分为六个阶段:
- 工具注册:通过
@Tool注解声明Java方法为可调用工具 - 请求解析:自动将用户query转换为工具调用请求
- 参数校验:基于JSON Schema验证参数合规性
- 工具执行:反射调用对应Java方法
- 结果封装:统一处理返回值和异常
- 响应生成:整合工具结果到模型回复
这种设计让开发者只需关注业务逻辑,无需处理繁琐的协议转换和流程控制。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 声明式工具开发实战
2.1 文件操作工具实现
文件读写是旅游计划系统的基石功能,用于保存中间结果和最终报告。以下是增强版的TextFileTool实现:
java复制@Slf4j
@Component
public class TextFileTool {
@Value("${travel.ai.files.root}")
private String rootDir;
@Tool(description = "Read text file with UTF-8 encoding")
public String readFile(
@ToolParam(description = "Filename with extension") String filename,
ToolContext context) {
Path filePath = buildPath(filename, context);
try {
String content = Files.readString(filePath);
log.debug("Read {} bytes from {}", content.length(), filePath);
return content;
} catch (IOException e) {
log.error("File read failed", e);
return "Error: " + e.getMessage();
}
}
private Path buildPath(String filename, ToolContext ctx) {
String sessionId = ctx.getOrDefault("sessionId", "default");
return Paths.get(rootDir, sessionId, filename);
}
}
关键实现细节:
- 路径隔离:不同会话的文件存储在不同子目录,避免冲突
- 异常处理:捕获IO异常并返回友好错误信息
- 日志记录:详细记录操作轨迹便于问题排查
经验提示:文件工具应做好权限控制,避免路径遍历攻击。实际项目中建议添加如下校验:
java复制if (!filename.matches("[a-zA-Z0-9_\\-]+\\.[a-z]+")) { throw new IllegalArgumentException("Invalid filename"); }
2.2 网页搜索工具集成
旅游信息需要实时性,我们集成SearchAPI实现联网搜索:
java复制@Component
public class WebSearchTool {
@Value("${api.search.key}")
private String apiKey;
@Tool(description = "Search web for travel information")
public String search(
@ToolParam(description = "Search keywords") String query) {
String url = "https://api.search.io/v1/search?q="
+ URLEncoder.encode(query) + "&api_key=" + apiKey;
String json = HttpUtil.get(url);
return extractSnippets(json);
}
private String extractSnippets(String json) {
// 解析JSON提取标题、链接和摘要
// 返回格式化字符串
}
}
实测搜索"杭州三日游"返回结果示例:
code复制1. 【携程攻略】杭州3天2夜自由行
链接: https://you.ctrip.com
摘要: 推荐路线:Day1西湖环湖游,Day2灵隐寺+龙井村...
2. 【马蜂窝】杭州经典行程规划
链接: https://www.mafengwo.cn
摘要: 包含交通建议、必吃美食和网红打卡点...
3. 旅游计划生成系统实现
3.1 核心业务流程设计
系统通过工具链实现旅游计划生成:
-
信息收集阶段:
- 调用搜索工具获取攻略框架
- 使用网页抓取补充景点详情
-
内容加工阶段:
- 文本工具保存中间结果
- 人工审核修正关键信息
-
报告生成阶段:
- PDF工具生成图文报告
- 邮件工具发送最终结果
java复制public TravelPlan generatePlan(String destination, int days) {
// 阶段1:信息收集
String searchResults = webSearchTool.search(destination + days + "日游");
String details = webScraper.scrape(top3Results(searchResults));
// 阶段2:内容加工
String refinedContent = aiModel.refine(searchResults + details);
textFileTool.save("draft.txt", refinedContent);
// 阶段3:报告生成
String pdfPath = pdfTool.generate("travel_plan.pdf", refinedContent);
return new TravelPlan(pdfPath);
}
3.2 PDF生成工具深度优化
旅游报告需要专业排版,我们对PDF工具进行增强:
java复制public class PdfTool {
@Tool(description = "Generate travel report PDF")
public String generateReport(
@ToolParam(description = "Markdown content") String content) {
// 1. 转换Markdown为HTML
String html = markdownToHtml(content);
// 2. 加载中文字体
Font chineseFont = loadFont("微软雅黑");
// 3. 设置PDF样式
ConverterProperties props = new ConverterProperties();
props.setFontProvider(new DefaultFontProvider(chineseFont));
// 4. 生成PDF
HtmlConverter.convertToPdf(html, outputStream, props);
return "report_" + System.currentTimeMillis() + ".pdf";
}
}
优化点包括:
- 中文支持:显式加载中文字体避免乱码
- 样式定制:通过CSS控制排版样式
- 图片处理:自动下载网络图片并调整尺寸
生成的PDF包含以下专业元素:
- 封面页与目录
- 分章节的行程安排
- 景点照片与地图
- 预算表格和注意事项
4. 生产环境经验总结
4.1 性能优化方案
在实际部署中,我们遇到并解决了以下性能问题:
-
工具调用延迟:
- 问题:搜索工具API响应慢(平均800ms)
- 方案:引入本地缓存(Caffeine)
java复制@Cacheable(value = "searchResults", key = "#query") public String cachedSearch(String query) { return originalSearch(query); } -
PDF生成内存溢出:
- 问题:大文档处理时内存消耗高
- 方案:启用分块处理和流式写入
java复制PdfWriter writer = new PdfWriter(out, new WriterProperties().setFullCompression(true));
4.2 监控与运维实践
完善的监控体系包括:
-
指标收集:
- 工具调用成功率/耗时
- 异常类型统计
- 资源使用情况
-
日志规范:
java复制MDC.put("sessionId", ctx.getSessionId()); log.info("Tool {} executed in {}ms", toolName, duration); -
告警规则:
- 连续5次工具调用失败
- PDF生成时间超过10秒
- 磁盘空间不足预警
5. 扩展应用场景
本方案的架构可复用于其他信息处理场景:
-
企业报告生成:
- 对接CRM获取客户数据
- 自动生成季度分析报告
-
学术研究助手:
- 文献检索与摘要
- 实验数据可视化报告
-
电商导购系统:
- 商品对比分析
- 个性化推荐清单
工具调用模式正在重塑AI应用开发范式。通过Spring AI的优雅实现,开发者可以快速构建具备专业能力的智能系统。随着工具生态的丰富,AI将能处理越来越复杂的现实任务。
