首页/新闻资讯/正文详情

程序员实战:SpringAI 整合 MCP 与 Tavily 实现智能联网搜索的配置骨架

发布时间:2026/9/26 10:57:37 来源:云帆数科 栏目:资讯中心
程序员实战:SpringAI 整合 MCP 与 Tavily 实现智能联网搜索的配置骨架
1. 为什么 SpringAI 接 MCP 调 Tavily 总在配置这一步卡住大模型的知识截止日期是绕不过去的坎。你问它今天有什么新的 Java 版本发布、某个库最近有没有爆出 CVE它要么答不上来要么一本正经地编。SpringAI 把大模型调用封装得很舒服但一旦要让它“联网”很多人就卡在 MCP 协议和 Tavily 的对接上——不是依赖拉不下来就是工具注册了但模型根本不调用或者调用了却拿不到结构化结果。这篇面向 Java 后端目标很明确在本地搭一个能跑起来的 Demo让 SpringAI 通过 MCP 协议挂载 Tavily 联网搜索工具用户问实时问题时模型能自动触发搜索并基于结果回答。我会给出 application.yml 的完整配置骨架、MCP 客户端与工具注册的代码结构、Tavily API Key 的注入方式以及一次联网检索请求的验证步骤和返回结果检查点。适合已经写过 Spring Boot、想给 AI 应用加“实时信息”能力但被 MCP 配置劝退的同学。核心检索词先摆清楚SpringAI 是 Spring 生态的大模型开发框架MCP 是它用来做多工具协作的协议层Tavily 是专为 AI 设计的联网搜索工具返回结构化 JSON 而不是一堆 HTML。三者串起来模型就能在需要时自己去搜。2. 前置准备TaoToken 侧要拿到什么在写代码之前先把模型调用这一端的凭证准备好。我这边习惯用 TaoToken 来统一管理模型接入它的 API 地址是 https://taotoken.net/api 兼容 OpenAI 风格的调用方式SpringAI 的 OpenAI starter 可以直接指过去。你需要做两件事第一拿到一个可用的 API Key。登录后进控制台在 API Keys 页面创建一个新 Key复制出来。这个 Key 后面会写进 application.yml作为模型调用的凭证。创建入口在这里https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentspringai_mcp_tavily第二确认你要用的模型名。如果你只是跑通联网搜索的链路选一个支持工具调用function calling的模型就行因为 MCP 的工具注册最终依赖模型的工具调用能力。模型对话页面可以先手动试一下https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentspringai_mcp_tavilyTavily 那边也需要一个 Key。去 Tavily 官网注册后在 Dashboard 里能看到以tvly-开头的 API Key免费额度足够本地 Demo 跑很多次。这个 Key 和模型 Key 是两回事别混。注意模型 Key 和 Tavily Key 都要通过环境变量或配置文件注入不要硬编码在代码里提交到仓库。下面配置里我会用占位符你替换成自己的。3. 可复制配置application.yml 与 MCP 客户端骨架3.1 Maven 依赖SpringAI 的版本迭代比较快这里用 1.0.0-M1 这个里程碑版本MCP 和 Tavily 的适配包都在。JDK 用 17Spring Boot 3.2.x。parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.2.5/version relativePath/ /parent dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-core/artifactId version1.0.0-M1/version /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-mcp/artifactId version1.0.0-M1/version /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-tavily-search/artifactId version1.0.0-M1/version /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-openai/artifactId version1.0.0-M1/version /dependency /dependencies repositories repository idspring-milestones/id urlhttps://repo.spring.io/milestone/url snapshotsenabledfalse/enabled/snapshots /repository /repositories3.2 application.yml 配置骨架这里把模型、Tavily、MCP 三块配置分开写方便你定位问题。模型这块把 base-url 指向 TaoToken 的 API 地址Key 用环境变量注入。spring: ai: openai: api-key: ${TAOTOKEN_API_KEY} base-url: https://taotoken.net/api chat: options: model: gpt-4o-mini temperature: 0.3 tavily: api-key: ${TAVILY_API_KEY} search: max-results: 5 include-answer: true response-format: json mcp: enabled: true default-timeout: 30000几个参数说明一下。temperature调到 0.3 是为了让模型在决定是否调用工具时更稳定太高容易乱答。max-results: 5控制 Tavily 返回的搜索结果条数太多会撑爆上下文。include-answer: true让 Tavily 自己先给一个初步总结模型再基于这个总结和原始结果生成最终回答。default-timeout给 30 秒联网搜索偶尔会慢。3.3 MCP 协作器配置类MCP 的核心是ToolCallingMcpCoordinator它负责协调模型和工具。你把 Tavily 搜索工具注册进去模型在需要时就会调用。package com.example.ai.config; import org.springframework.ai.mcp.ToolCallingMcpCoordinator; import org.springframework.ai.tavily.search.TavilySearchTool; import org.springframework.ai.openai.OpenAiChatClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class McpConfig { Bean public ToolCallingMcpCoordinator toolCallingMcpCoordinator( OpenAiChatClient openAiChatClient, TavilySearchTool tavilySearchTool) { ToolCallingMcpCoordinator coordinator new ToolCallingMcpCoordinator(openAiChatClient); coordinator.registerTool(tavilySearchTool); coordinator.setToolCallingMode(ToolCallingMcpCoordinator.ToolCallingMode.AUTO); return coordinator; } }ToolCallingMode.AUTO是关键它让模型自己判断当前问题需不需要联网。如果你设成ALWAYS那每次请求都会触发搜索浪费额度也拖慢响应。3.4 服务类与控制器服务类封装调用逻辑系统提示词里明确告诉模型“需要实时信息时必须先搜索”。package com.example.ai.service; import lombok.RequiredArgsConstructor; import org.springframework.ai.mcp.ToolCallingMcpCoordinator; import org.springframework.ai.mcp.model.McpRequest; import org.springframework.ai.mcp.model.McpResponse; import org.springframework.stereotype.Service; Service RequiredArgsConstructor public class SearchService { private final ToolCallingMcpCoordinator mcpCoordinator; public String intelligentSearch(String userQuery) { String systemPrompt 你是一个基于实时数据的智能助手。当问题涉及最新信息、实时数据或你不确定的内容时必须先调用 Tavily 搜索工具获取数据再基于搜索结果生成回答。回答需注明信息来源。; McpRequest request McpRequest.builder() .systemMessage(systemPrompt) .userMessage(userQuery) .build(); McpResponse response mcpCoordinator.coordinate(request); if (response.isSuccess()) { return response.getFinalAnswer(); } throw new RuntimeException(智能搜索失败 response.getErrorMsg()); } }控制器暴露一个 GET 接口方便用浏览器或 curl 直接测。package com.example.ai.controller; import com.example.ai.service.SearchService; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; RestController RequiredArgsConstructor public class SearchController { private final SearchService searchService; GetMapping(/search) public String search(RequestParam String q) { return searchService.intelligentSearch(q); } }4. 验证请求一次联网检索的完整过程与结果检查点配置写完后启动应用。启动日志里要确认两件事Tavily 的TavilySearchToolBean 被创建了MCP 协作器初始化成功。如果启动报NoSuchBeanDefinitionException多半是依赖没拉全或者包名写错。用 curl 发一个需要实时信息的请求curl http://localhost:8080/search?q2024年Java生态有哪些值得关注的新变化观察返回结果检查点有三个第一回答里有没有出现具体的时间、版本号、项目名这类实时信息。如果模型只是泛泛而谈“Java 一直在发展”说明它没触发搜索直接用自己的知识答了。这时候去日志里看有没有 Tavily 的调用记录。第二回答末尾有没有标注信息来源。Tavily 返回的结果里带 URL模型整合后应该会引用。如果完全没有来源可能是include-answer没生效或者模型忽略了搜索结果。第三响应时间。正常联网搜索加模型生成大概 3 到 8 秒。如果秒回基本可以断定没走搜索链路。你也可以在 Tavily 的 Dashboard 里看 API 调用次数每发一次搜索请求那边计数会加一。这是最直接的验证方式。5. 本篇常见错排查5.1 模型不调用 Tavily直接自己回答这是最常见的问题。原因通常是系统提示词不够强硬或者模型本身不支持工具调用。先确认你用的模型在 TaoToken 的模型列表里标注了支持 function calling。然后在系统提示词里把“必须先调用搜索工具”写得更明确甚至可以加一句“如果你不确定答案的时效性必须搜索”。另一个可能是ToolCallingMode设成了NONE或者没设。检查配置类里是不是AUTO。5.2 启动报 Tavily 相关 Bean 找不到检查spring-ai-tavily-search依赖有没有加版本号是否和 core 一致。另外application.yml里spring.ai.tavily.api-key必须配没配的话 Tavily 的自动配置不会生效Bean 就不会创建。Key 用环境变量注入时确认环境变量在启动前已经 export 了。5.3 搜索返回了结果但模型回答是空的看McpResponse的isSuccess()和getErrorMsg()。如果 Tavily 返回了结果但模型生成失败可能是上下文太长超了模型限制。把max-results从 5 降到 3 试试。也可能是response-format设成了非 json导致解析异常。5.4 请求超时default-timeout默认 30 秒如果网络波动或者 Tavily 响应慢会抛超时。可以调到 60000。但更根本的是检查 base-url 和网络连通性TaoToken 的 API 地址是 https://taotoken.net/api 确认没有拼错。5.5 返回结果里出现乱码或格式错乱Tavily 返回的 JSON 里如果有特殊字符模型整合时可能处理不好。在系统提示词里加一句“搜索结果中的特殊字符请原样保留不要转义”。另外确认response-format: json配置生效如果 Tavily 返回的是纯文本模型解析会出问题。6. 把链路跑通之后可以做什么这套骨架跑通后你手里就有了一个能联网的 SpringAI 应用。接下来可以做的扩展不少把 Tavily 换成或叠加其他 MCP 工具比如数据库查询、内部 API 调用MCP 的注册机制是一样的把ToolCallingMode从AUTO改成根据问题类型动态切换省额度或者把搜索结果缓存起来相同查询短时间内不重复调 Tavily。如果你打算长期做编码类或 Agent 类的项目模型调用量会上去可以看看 Coding Plan 的额度方案https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentspringai_mcp_tavily接入过程中如果遇到 Key 或权限相关的报错先去 API Keys 页面确认 Key 状态和额度https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentspringai_mcp_tavilyMCP 和 Tavily 的对接细节官方文档里有更完整的参数说明https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentspringai_mcp_tavily我自己的习惯是先把/search接口用 curl 跑通确认 Tavily 被调用了、结果被整合了再去接前端。这样出问题时排查范围小不用在浏览器和日志之间来回切。

相关推荐

怎么将Cursor设置成中文?TaoToken 统一 Key 接入下的 settings.json 配置骨架
怎么将Cursor设置成中文?TaoToken 统一 Key 接入下的 settings.json 配置骨架

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

OpenClaw 生态开源项目全景:ZeroClaw、IronClaw、MoltWorker 与 clawdbot-feishu 的 TaoToken 统一接入配置
OpenClaw 生态开源项目全景:ZeroClaw、IronClaw、MoltWorker 与 clawdbot-feishu 的 TaoToken 统一接入配置

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

使用OpenAI API为你的Agent注入“大脑”:TaoToken统一Key接入与settings.json配置实战
使用OpenAI API为你的Agent注入“大脑”:TaoToken统一Key接入与settings.json配置实战

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

Substrate不是框架:区块链运行时开发工具链深度解析
Substrate不是框架:区块链运行时开发工具链深度解析

1. 项目概述:Substrate不是“框架”,而是一套可组合的区块链构建工具链你搜“substrate”,十有八九会看到一堆“Substrate是Polkadot的底层”“Substrate是Rust写的区块链框架”这类说法。但实话讲,这种描述既不准确,也… · 2026/9/26 12:14:02

django智能宿舍门禁管理系统52309-计算机课程设计、毕业设计
django智能宿舍门禁管理系统52309-计算机课程设计、毕业设计

前言 ✨ 博主介绍:一线全栈工程师,毕设实战引路人。技术栈覆盖Java、Python、C#、PHP、Node.js及UniApp跨端开发,擅长多语言项目落地与架构设计。持续分享毕设源码、开题报告、技术选型心得与职场踩坑经验。用工程化思维写代码,帮… · 2026/9/26 12:14:02

Substrate区块链开发框架入门:从Runtime、FRAME到自定义pallet实践
Substrate区块链开发框架入门:从Runtime、FRAME到自定义pallet实践

1. 先搞清楚:技术圈天天说的Substrate,到底是干什么的1.1 一个词的两副面孔你在搜索引擎里输入"substrate",大概率会看到两类完全不同的结果:一类来自生物化学领域,说的是酶反应中的"底物"&#x… · 2026/9/26 12:14:02

Canvas悬挂弹性文字特效:弹簧阻尼模型与鼠标交互实现
Canvas悬挂弹性文字特效:弹簧阻尼模型与鼠标交互实现

简介:一份基于HTML5 Canvas的悬挂弹性文字交互特效代码,面向有一定JavaScript基础、希望进阶动态网页开发的读者。资源通过Canvas绘制文字,并结合鼠标移动事件与弹性物理模型,实现文字被拖动后自然回弹的动态效果;代码… · 2026/9/26 12:14:02

【老计带你懂AI算法】07:聚类,没有标准答案时,让机器自己把数据分堆
【老计带你懂AI算法】07:聚类,没有标准答案时,让机器自己把数据分堆

【老计带你懂AI算法】07:聚类,没有标准答案时,让机器自己把数据分堆开头:从有答案到没答案 前面五篇讲的模型,有个共同的前提,你得先给数据打好标签。这是垃圾邮件那不是、这套房卖了多少钱、这个肿瘤是良性… · 2026/9/26 12:13:56

2048中文网页版HTML5实战:DOM语义化、双模交互与无障碍渲染
2048中文网页版HTML5实战:DOM语义化、双模交互与无障碍渲染

简介:这是一份基于HTML5技术实现的2048中文网页版游戏源码,面向前端初学者与HTML5/CSS3/JavaScript综合实践者,帮助理解互动游戏开发中的核心Web技术落地路径。资源共10个文件,含1个主入口HTML、3个JS脚本(含jQuery与游… · 2026/9/26 12:13:56

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21

OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置

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

向下兼容与向上兼容:接口设计中的兼容性策略与工程实践
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践

一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码