ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Spring AI 深度实战:Tool Calling 演进、MCP 协议与 SAA 智能体生态中的 TaoToken 统一接入配置

Spring AI 深度实战:Tool Calling 演进、MCP 协议与 SAA 智能体生态中的 TaoToken 统一接入配置 1. 为什么 Spring AI 项目一到 Tool Calling 就卡在模型接入层如果你正在用 Spring AI 写智能体大概率经历过这个阶段Tool注解写好了ChatClient也注入了本地跑一个天气查询 Demo 顺风顺水。可一旦把 Tool Calling 接到真实业务里问题就从模型会不会调工具变成了模型 Key 怎么管、多模型怎么切、MCP 服务端和客户端怎么共用一套通道。Spring AI 的 Tool Calling 本质是让大模型表达我要调用某个工具的意图真正执行工具的是你的 Java 应用。到了 Spring AI 2.0工具执行循环被提升到 Advisor 链里ToolCallingAdvisor变成可组合、可观测的一等公民。这意味着一次请求可能触发多轮模型决策 → 工具执行 → 结果回填每一轮都要打一次模型接口。如果模型接入层散落在各个ChatModelBean 里Key 硬编码在application.yml换模型就得改代码重新打包多智能体场景下更是灾难。MCP 协议把这个问题放大了。MCP 像 AI 应用的 USB-C 接口一次编写服务端所有兼容协议的模型都能调用。但 MCP Server 和 MCP Client 往往跑在不同进程、不同环境它们各自需要访问模型。SAASpring AI Alibaba的 Graph 多智能体框架里Supervisor Agent 协调多个子 Agent每个子 Agent 可能用不同模型Key 管理如果还是各管各的运维成本直接翻倍。我试过把模型接入层从业务代码里彻底抽出来用一个统一的 OpenAI 兼容通道承接所有模型请求。这样 Tool Calling 的每一轮决策、MCP 的工具发现、SAA 的多 Agent 调度都走同一个出口换模型只改配置不改代码。下面把application.yml和config.toml两套骨架都给出来再演示一次 Tool Calling 请求怎么验证。2. TaoToken 作为 Spring AI 统一模型接入层的前置准备TaoToken 提供的是 OpenAI 兼容的 API 通道对 Spring AI 来说它就是一个标准的base-urlapi-key组合。Spring AI 的OpenAiChatModel支持自定义baseUrl所以不需要为 TaoToken 写任何适配器直接复用官方 starter 即可。先明确几个地址后面配置里会反复用到官网入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentAPI 根地址https://taotoken.net/api模型对话体验https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewriteCoding Plan长期编码/Agent 场景https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite控制台https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewriteAPI Keys 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite你需要先拿到一个 Key。登录控制台后进 API Keys 页面创建一个复制出来形如sk-xxxx。这个 Key 就是 Spring AI 里spring.ai.openai.api-key的值。注意TaoToken 的 API 根地址是https://taotoken.net/apiSpring AI 的 OpenAI starter 会在后面自动拼/v1/chat/completions这类路径所以base-url填到/api即可不要自己再加/v1否则会变成/api/v1/v1/...导致 404。依赖方面Spring Boot 3.x Spring AI 1.x 或 2.x 都行。Maven 里加dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-openai-spring-boot-starter/artifactId version1.0.0/version /dependency如果你用 SAA再叠加spring-ai-alibaba-starter-dashscope或对应的 Graph starter。SAA 的ChatClient复用 Spring AI 的抽象所以底层ChatModel换成走 TaoToken 的OpenAiChatModel后上层 Graph 编排代码不用动。3. application.yml 与 config.toml 可复制配置骨架3.1 application.ymlSpring AI 主配置这是 Spring Boot 项目里最核心的一段。把base-url指向 TaoTokenapi-key用环境变量注入避免硬编码进 Git。spring: ai: openai: # TaoToken 统一通道所有模型请求从这里出去 base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} chat: options: # 默认模型Tool Calling 场景建议选支持 function calling 的 model: gpt-4o-mini temperature: 0.3 # 开启工具调用相关能力 embedding: options: model: text-embedding-3-small # 自定义多模型路由配置供业务层按场景选择 taotoken: models: default: gpt-4o-mini reasoning: gpt-4o cheap: gpt-4o-mini timeout: connect: 5000 read: 60000环境变量在启动时注入export TAOTOKEN_API_KEYsk-你的Key如果你要在同一个应用里挂多个模型比如 Supervisor Agent 用强模型、子 Agent 用便宜模型不要建多个OpenAiChatModelBean 各配各的 Key。正确做法是只保留一个走 TaoToken 的ChatModel通过ChatOptions在调用时覆盖model参数ChatOptions options ChatOptions.builder() .model(gpt-4o) .temperature(0.2) .build(); String answer chatClient.prompt() .user(帮我查一下北京天气并预订明天去上海的航班) .options(options) .tools(new WeatherTools(), new FlightTools()) .call() .content();这样模型接入层只有一个出口Tool Calling 的每一轮决策都走同一个base-urlKey 也只有一份。3.2 config.tomlMCP Server 侧配置MCP Server 经常是独立进程用 STDIO 或 Streamable HTTP 传输。如果你用 Spring AI 的 MCP Boot StarterServer 端配置可以放在application.yml但很多 MCP 工具比如社区里的通用 MCP 网关习惯用config.toml。下面这份骨架把模型通道和 MCP 服务注册分开管理。# config.toml - MCP Server 侧统一配置 [model] # 与 Spring AI 主应用共用同一个 TaoToken 通道 base_url https://taotoken.net/api api_key_env TAOTOKEN_API_KEY default_model gpt-4o-mini [mcp.server] name spring-ai-tools-server version 1.0.0 transport streamable-http port 8081 [mcp.server.tools.weather] enabled true description 根据城市获取实时天气 [mcp.server.tools.flight] enabled true description 查询和预订航班 [mcp.client] # MCP Client 连接远程 Server 时的超时 connect_timeout_ms 5000 read_timeout_ms 30000MCP Server 暴露工具用McpTool注解和 Tool Calling 的Tool写法几乎一致Component public class WeatherMcpTools { McpTool(description 根据城市获取天气预报) public String getWeather(String city) { // 实际业务逻辑 return weatherService.fetch(city); } }MCP Client 端通过 starter 自动配置连接底层模型调用依然走 TaoToken。这样 MCP 的一次编写、到处调用和 TaoToken 的一次配置、多模型切换就叠在一起了工具定义标准化模型通道也标准化。3.3 SAA Graph 场景的配置衔接SAA 的 Graph 多智能体框架里每个节点可能是一个 Agent。如果你用spring-ai-alibaba-graph底层ChatModel换成走 TaoToken 的实例后Graph 的StateGraph定义不用改。关键是把ChatClient的构建集中到一个Configuration里Configuration public class ModelConfig { Bean public ChatClient chatClient(OpenAiChatModel chatModel) { return ChatClient.builder(chatModel) .defaultSystem(你是一个可以调用工具的智能体) .build(); } }Supervisor Agent 和子 Agent 都注入这个ChatClient需要换模型时通过ChatOptions覆盖而不是新建 Bean。这样 SAA 的多智能体编排和 Tool Calling 的工具循环共享同一条模型通道观测和限流都能在一个点上做。4. 验证一次 Tool Calling 请求是否打通配置写完别急着上多智能体。先用一个最小 Tool Calling 请求验证通道是否打通。定义一个工具类Component public class WeatherTools { Tool(description 获取指定城市的实时天气) public String getWeather( ToolParam(description 城市名称例如北京) String city) { // 模拟返回实际接天气服务 return city 今天晴气温 22 度; } }然后写一个 CommandLineRunner 或测试方法发起请求SpringBootTest class ToolCallingVerifyTest { Autowired private ChatClient chatClient; Test void verifyToolCalling() { String result chatClient.prompt() .user(北京今天天气怎么样) .tools(new WeatherTools()) .call() .content(); System.out.println(模型返回: result); assertThat(result).contains(北京); } }跑起来后观察日志。一次成功的 Tool Calling 会看到这样的过程模型先返回一个工具调用意图getWeather参数city北京Spring AI 执行你的WeatherTools.getWeather把结果回填给模型模型再生成自然语言回答。最终控制台输出类似模型返回: 北京今天晴气温 22 度。如果日志里出现ToolCallingAdvisor或DefaultToolCallingManager的执行记录说明工具循环正常。Spring AI 2.0 里这个循环在 Advisor 链上你可以加一个自定义 Advisor 观察每一轮的工具调用方便排查。验证通过后把同样的ChatClient注入到 MCP Client 或 SAA Graph 节点里模型通道不用再配第二遍。这就是把接入层从业务代码解耦的直接收益Tool Calling、MCP、SAA 三条线共用一份base-url和api-key。5. 本篇常见错误排查5.1 404 或路径重复最常见的是base-url填成了https://taotoken.net/api/v1。Spring AI 的 OpenAI starter 会自动拼/v1/chat/completions结果变成/api/v1/v1/chat/completions。改成https://taotoken.net/api即可。如果你用的是其他框架先确认它是否自带/v1前缀。5.2 401 未授权检查TAOTOKEN_API_KEY环境变量是否真的注入到运行进程。IDEA 里跑测试时环境变量要在 Run Configuration 里配光在终端export对 IDE 启动的进程不一定生效。另外确认 Key 没有多余空格复制时容易带上换行。5.3 工具不被调用模型返回了自然语言但没触发工具通常是工具描述太模糊。Tool(description ...)要写清楚什么时候用这个工具而不是只写获取天气。Spring AI 从方法签名生成 JSON Schema参数描述用ToolParam补全。如果工具超过 30 个考虑用 Spring AI 2.0 的动态工具发现ToolSearchToolCallingAdvisor按需展开工具定义能省 34-64% 的 Token。5.4 MCP 连接超时MCP Server 用 Streamable HTTP 时确认端口没被占用config.toml里的port和实际监听一致。STDIO 传输则检查启动命令路径是否正确。MCP Client 的read_timeout_ms如果太短工具执行慢时会断连调到 30000 以上。5.5 SAA Graph 节点拿不到 ChatClientSAA 的 Graph 节点如果手动new了ChatClient就不会走 Spring 容器里的配置。确保通过构造器注入或者用ApplicationContext获取。多 Agent 场景下所有 Agent 共享同一个ChatClientBean模型切换靠ChatOptions不要每个 Agent 建一个。5.6 流式响应下工具调用异常Tool Calling 和流式输出一起用时部分模型在流式模式下工具调用事件的分片处理有差异。如果遇到工具参数解析失败先切非流式验证通道是否正常再排查流式适配。Spring AI 2.0 的ToolCallingAdvisor对递归调用做了处理升级后这类问题会少很多。6. 把模型接入层固定下来再往上叠智能体Tool Calling、MCP、SAA 这三层越往上越复杂但底层的模型接入需求反而越简单一个稳定的base-url一份可轮换的 Key一个能按场景切模型的出口。把这三样固定住上面的工具循环、协议适配、多 Agent 编排才不会因为换模型而推倒重来。如果你还在逐个服务配 Key建议先去 API Keys 页面把 Key 统一管起来https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite接入细节和参数说明看文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite想先验证模型在 Tool Calling 场景下的表现可以直接在模型对话里试https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite如果你的 Spring AI 项目要长期跑编码类 Agent 或高频工具调用Coding Plan 的通道更适合https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite配置骨架已经给全下一步就是把application.yml里的base-url换成https://taotoken.net/api跑一遍第 4 节的验证测试。工具循环日志出来那一刻接入层就算真正解耦了。
返回列表