给 Spring Boot 3.4.5 Agent 服务接入搜索 Skill:从 Tavily...
给 Spring Boot 3.4.5 Agent 服务接入搜索 Skill从 Tavily 到自建 Search Skill 的迁移实录上周有个需求砸过来业务方要求把现有的 RAG 问答服务从「纯向量召回」升级成「向量 实时搜索」混合模式让 Agent 在回答市场资讯类问题时能实时拉取外部数据。老方案用的是 Tavily API跑了三个月问题越积越多——响应体里混着大量无关字段结构化程度差Agent 做二次解析时经常因为字段缺失抛空指针。更麻烦的是Tavily 的免费额度只够开发环境用生产环境按调用量计费上个月光搜索这块就烧了两千多块。项目背景当前服务基于 Spring Boot 3.4.5 JDK 21.0.5底层用 LangChain4j 1.0.1 做 LLM 编排向量检索走 Milvus 2.5Agent 框架自研核心调度层用 Spring AI 1.0.0-M6 的 Tool Calling 机制。原有搜索能力通过 REST 调用 Tavily 实现封装在SearchTool类里每次调用直接把查询词扔过去返回的 JSON 再硬解析成SearchResult对象。这个链路在 POC 阶段没问题但上了生产之后Tavily 返回结果的字段稳定性成了最大的隐患——同一个查询词今天返回results[0].content有值明天可能就变成results[0].snippet。需求分析核心需求有三条。第一搜索结果必须结构化输出字段名和类型在接口层就固定下来不允许上游随意变动。第二搜索覆盖范围要从通用网页扩展到金融、法律、代码等垂直领域业务方明确提了「问财报数据要能搜到 Wind 级别的内容」。第三接入方式要兼容现有 Tool Calling 体系不能推翻 Agent 调度层重写。非功能需求方面单次搜索 P99 延迟控制在 800ms 以内可用性 99.9%搜索调用成本需要降到原来的三分之一以下。方案对比当时评估了四个方向| 方案 | 接入复杂度 | 结构化程度 | 垂直领域覆盖 | 成本 | 兼容性 ||------|-----------|-----------|-------------|------|--------|| 继续用 Tavily API | 低 | 差字段不稳定 | 仅通用搜索 | 按量计费高 | 已有封装零改动 || Serper.dev API | 中 | 中字段基本固定 | 通用 部分垂直 | 按量计费中等 | 需重写 Tool 封装 || 自建 Search Skill 服务 | 高 | 完全可控 | 可配置扩展 | 固定基础设施成本 | 需适配 Skill 协议 || Brave Search API | 中 | 中 | 通用为主 | 按量计费中等 | 需重写 Tool 封装 |这个方案对比里Serper.dev 和 Brave Search 看起来是折中选择但实际跑了几组压测后发现它们在中文金融领域的召回质量明显不如预期——搜「宁德时代 2026 Q3 财报」返回的大多是新闻摘要而非原始公告。自建 Search Skill 虽然前期投入大但长期来看是唯一能同时满足结构化、垂直覆盖和成本控制三个硬指标的路线。核心实现整体架构分三层Agent 调度层Spring AI 1.0.0-M6→ Skill 网关层自研 Search Skill Gateway→ 搜索聚合层多源搜索 结构化转换。Skill 网关层是这次迁移的核心。它对外暴露一个标准的 Skill 接口Agent 侧通过 Tool Calling 调用内部根据查询意图路由到不同的搜索源。关键代码在 Skill 定义和路由逻辑javaTool(description 实时搜索外部信息支持通用网页和金融/法律/代码垂直领域)public SearchSkillResponse search(ToolParam(description 搜索查询词) String query,ToolParam(description 领域类型: general/finance/legal/code, required false) String domain) {SearchRequest request SearchRequest.builder().query(query).domain(domain ! null ? DomainEnum.valueOf(domain.toUpperCase()) : DomainEnum.GENERAL).maxResults(10).timeout(Duration.ofMillis(500)).build();return searchGateway.execute(request);}搜索聚合层做了两件事一是多源并发请求用CompletableFuture并行调 Brave Search、Google Custom Search 和内部垂直数据源二是统一结构化转换把所有源的返回结果归一化成固定的SearchSkillResponsejavapublic class SearchSkillResponse {private String query;private String domain;private List results;private long elapsedMs;private int totalFound;Datapublic static class StructuredResult {private String title;private String url;private String snippet;private String publishedDate;private String source;private double relevanceScore;}}这里有个设计决策值得展开说。官方 Skill 协议推荐用 MCPModel Context Protocol做 Tool 注册但在我们的场景下直接走 Spring AI 的Tool注解反而更合适。原因是 MCP 的 stdio 通道在 Windows 环境下有已知的环境变量传递问题参考近期社区讨论而我们的 CI/CD 流水线主力跑在 Windows Agent 上。绕开 MCP 直接用 Spring AI 原生注解省掉了协议适配层开发效率反而更高。这个选择跟社区主流推荐不同但在我们的部署环境里确实更稳。路由层用策略模式按 domain 分派到不同的SearchProvider实现。金融领域走自建的数据聚合对接了 Wind API 和部分公开财报源通用搜索走 Brave Search 加 Google Custom Search 双源融合代码领域走 GitHub Search API。每个 Provider 的超时独立控制任何一个源超时不影响整体返回——超时的那个源返回空结果集聚合层按相关性分数排序后取 Top 10。效果复盘迁移上线两周后的数据单次搜索 P99 延迟从原来的 1.4s 降到 620ms主要来自聚合层并发请求和超时熔断的效果。月度搜索调用成本从 2300 元降到 780 元降幅约 66%主要得益于自建聚合层可以复用内部已有的搜索 API 额度。Agent 回答质量方面业务方做了 200 条标注样本的盲测金融类问题的准确率从 61% 提升到 83%通用问答类基本持平78% vs 77%。上线过程中踩了两个坑。第一个是 Brave Search 的速率限制——并发请求一开就触发 429后来在 Provider 层加了令牌桶限流才稳住。第二个是结构化转换时的字段映射问题Google Custom Search 返回的snippet和 Brave 返回的description含义不完全一致前者经常截断、后者有时包含 HTML 标签统一处理时漏掉了 HTML 清洗导致 Agent 输出里偶尔混入标签碎片。这两个问题都是上线后第三天发现的修完之后才真正稳定。#后端 #Java #SpringBoot #SpringAI #Agent你在实际项目中有遇到类似问题吗欢迎在评论区分享你的经验和解决方案。

相关新闻

斑马线人行横道检测:用192张VOC+YOLO双格式数据集跑通小样本目标检测全流程

斑马线人行横道检测:用192张VOC+YOLO双格式数据集跑通小样本目标检测全流程

简介:面向目标检测学习者的斑马线人行横道检测数据集,含192张jpg图片及对应Pascal VOC、YOLO格式标注,类别为单一zebra_crossing,总标注框数542个,适合行人过街、交通元素检测等场景的模型训练与验证。需注意&#xff…

2026/10/10 10:59:30 阅读更多 →
多平台直播统一中控方案:一套系统管4个后台,人力成本降75%

多平台直播统一中控方案:一套系统管4个后台,人力成本降75%

直播做了两三年,最头疼的事就是平台太多。今天在抖音播,明天要去视频号,过两天还要快手、小红书一起上。品是一样的品,但后台不是一个后台,上链接要点四遍,改价格要改四回,发货更是四个仓库各发…

2026/10/10 10:58:29 阅读更多 →
HTML5语义化、CSS3动画与Flex布局:移动Web适配从入门到实战

HTML5语义化、CSS3动画与Flex布局:移动Web适配从入门到实战

如果你正在把前端基础教程从头往后刷,大概会有一个很明显的体感:前面 10 讲还是“认识 HTML 标签、写写 CSS 样式”的舒适区,到第 11—20 讲这个区间,难度会突然上一个台阶。这个阶段通常会把 HTML5 新增的语义化标签、CSS3 的选择…

2026/10/10 10:58:29 阅读更多 →

最新新闻

VFP报表预览与导出利器:FoxyPreview安装配置与PDF/Excel/CSV实战

VFP报表预览与导出利器:FoxyPreview安装配置与PDF/Excel/CSV实战

简介:这是面向Visual FoxPro开发者的FoxyPreviewer报表导出工具最新版本,能够将VFP报表灵活输出为PDF、HTML、XLS、CSV、图片及RTF等格式,便于分享、归档与二次分析,适合需要增强VFP报表功能的开发人员使用。压缩包内含245个文件&…

2026/10/10 13:25:25 阅读更多 →
房屋租赁微信小程序开发实战:表结构、接口与避坑指南

房屋租赁微信小程序开发实战:表结构、接口与避坑指南

简介:这是一份基于微信小程序的房屋租赁管理毕业设计资源,面向计算机专业学生及需要掌握SSM框架与小程序整合开发的开发者,适合毕业设计、课程设计或项目实训场景。系统包含管理员、中介、用户三类角色,覆盖房源管理、租房订单、账…

2026/10/10 13:25:25 阅读更多 →
三款降AI率工具实测:从原理到场景,选对方法让AI写作更像人

三款降AI率工具实测:从原理到场景,选对方法让AI写作更像人

“AI率”这两个字,最近几乎成了内容运营圈里的一个暗号。我一开始没太当回事,直到某个同事拿着稿子来找我:文档明明写完了,在检测服务里一过,AI率显示74%,系统直接提示“疑似AI辅助创作”,于是稿…

2026/10/10 13:25:24 阅读更多 →
C++实现A*算法:原理、代码与调优实践

C++实现A*算法:原理、代码与调优实践

做路径规划也好,做游戏寻路也好,只要涉及"从地图上的A点走到B点"这件事,A* 这个名字迟早会摆到你面前。我在模拟项目X里第一次独立实现C版A算法时,以为这只是一个"广度优先加上贪心"的小改进,结果…

2026/10/10 13:25:24 阅读更多 →
Linux chmod权限本质:从rwx到位操作与内核访问控制

Linux chmod权限本质:从rwx到位操作与内核访问控制

1. 为什么一个看似简单的权限命令,会让无数人反复踩坑?刚入行那会儿,我帮某高校实验室调试一套图像处理流水线,整个系统跑在CentOS服务器上。某天凌晨两点,一位A同学急匆匆发来消息:“脚本突然不执行了&…

2026/10/10 13:25:24 阅读更多 →
MacBook连接HP P1108打印机无反应?CUPS直连方案详解

MacBook连接HP P1108打印机无反应?CUPS直连方案详解

1. 为什么MacBook连HP P1108会“失联”——从驱动缺失到系统兼容性的真实断层你把HP LaserJet P1108打印机稳稳放在书桌右下角,USB线一插,MacBook屏幕右上角却迟迟不弹出“已检测到新打印机”的提示;打开“系统设置→打印机与扫描仪”&#x…

2026/10/10 13:24:23 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:25 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →