ARTICLE DETAIL

资讯详情

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

Spring Boot 3.x + MCP + Ollama 本地大模型实战:从零搭建支持工具调用的 AI 应用(TaoToken 统一 Key 接入版)

Spring Boot 3.x + MCP + Ollama 本地大模型实战:从零搭建支持工具调用的 AI 应用(TaoToken 统一 Key 接入版) 1. 为什么要在 Spring Boot 3.x 里同时用上 MCP 和 Ollama如果你是一个 Java 后端最近大概率被两件事反复刷屏一个是本地大模型 Ollama一个是让模型能真正“动手干活”的 MCP 协议。前者解决“模型跑在自己机器上、数据不出内网”的问题后者解决“模型只会聊天、不会调用你系统里的接口”的问题。把这两个东西塞进 Spring Boot 3.x就能得到一个既能本地推理、又能调用工具的企业级 AI 应用骨架。先说清楚这三个词分别是什么。Ollama 是一个本地大模型运行时一条ollama run llama3.2:3b就能把模型拉下来跑起来对外暴露兼容 HTTP 的 API默认监听11434端口。MCPModel Context Protocol是一套让模型和外部工具、数据源对话的协议你可以把它理解成“给模型用的 USB 接口”——工具方按协议暴露能力模型方按协议发现并调用。Spring Boot 3.x 则是承载这一切的容器用 Spring AI 把 Ollama 的对话能力和 MCP 的工具能力粘在一起。那为什么还要引入 TaoToken 统一 Key 接入因为本地小模型在工具调用时有个绕不开的坑参数字段容易“幻觉”。我实测 llama3.2:3b 在解析中文人名、订单号这类实体时经常把参数值拼错导致 MCP 服务端收到脏数据。生产环境里更稳的做法是双通道——日常对话走本地 Ollama 省钱省延迟关键的工具调用决策走 TaoToken 统一 API 通道https://taotoken.net/api用更强的模型保证 function calling 的参数准确率。TaoToken 在这里的角色是统一 Key 和统一入口你不用为每个模型厂商单独维护一套鉴权和 Base URL。这套组合适合谁适合已经会用 Spring Boot 写 REST 接口、想快速把 AI 能力接进现有系统的 Java 开发者适合对数据合规有要求、希望推理尽量本地化的团队也适合想研究 MCP 工具调用链路、但不想一上来就啃 Python 生态的同学。整条链路不需要 GPU一台 8G 内存的开发机就能跑通 llama3.2:3b工具调用部分用 TaoToken 兜底。下面我会按“先跑通本地模型 → 再接入 MCP 工具 → 最后用统一 Key 验证完整调用链”的顺序把每一步的配置和命令都给全。你照着敲遇到报错可以直接跳到第 5 节对照排查。2. 前置准备Ollama 部署与 TaoToken 统一 Key 获取2.1 用 Docker 把 Ollama 跑起来最省事的方式是 Docker。先拉镜像再挂载一个本地目录存模型这样容器删了模型还在docker pull ollama/ollama:latest docker run -d --name ollama \ -p 11434:11434 \ -v $PWD/ollama:/root/.ollama \ ollama/ollama:latest容器起来后进容器拉模型。这里选llama3.2:3b体积约 2GB支持 tools 调用适合本地先跑通链路docker exec -it ollama ollama pull llama3.2:3b docker exec -it ollama ollama list如果你不想用 DockerLinux 下也可以脚本安装curl -fsSL https://ollama.com/install.sh | sh ollama serve ollama pull llama3.2:3b验证 Ollama 是否正常直接打它的 tags 接口curl http://127.0.0.1:11434/api/tags返回 JSON 里能看到llama3.2:3b就说明模型就绪。这里提醒一句deepseek-r1:1.5b这类小模型不支持 tools 调用别拿它测工具链路会一直返回纯文本。2.2 拿 TaoToken 统一 Key本地小模型负责省钱但工具调用的参数准确性得靠更强的模型兜底。去 TaoToken 控制台创建一个 API Key这个 Key 同时能访问多个模型省得你为每家单独配鉴权。创建入口在控制台的 API Keys 页面https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite。创建后复制那串sk-开头的 Key先存到环境变量里别硬编码进代码export TAOTOKEN_API_KEYsk-你的keyTaoToken 的 API 基地址是https://taotoken.net/api注意这个地址不带任何查询参数直接作为 OpenAI 兼容协议的 base_url 使用。模型 ID 可以在模型对话页面确认比如gpt-4o-mini、claude-3-5-sonnet这类具体以控制台展示为准。2.3 Spring Boot 3.x 项目骨架用 start.spring.io 生成项目依赖勾选 Spring Web 和 Spring AI 的 Ollama starter。生成后build.gradle里补上 MCP client 依赖dependencies { implementation org.springframework.boot:spring-boot-starter-web implementation org.springframework.ai:spring-ai-starter-model-ollama implementation org.springframework.ai:spring-ai-starter-mcp-client testImplementation org.springframework.boot:spring-boot-starter-test }Spring AI 的版本管理建议用 BOM 统一避免 starter 之间版本错位。到这里前置就齐了Ollama 在 11434 跑着TaoToken Key 在环境变量里项目骨架能编译。3. 可复制配置application.yml 与 MCP 工具注册3.1 application.yml 完整配置把配置从 properties 换成 yml结构更清晰。下面这份可以直接抄注意base-url和模型名按你实际情况改spring: application: name: springboot-mcp-ollama-demo ai: ollama: base-url: http://localhost:11434 chat: model: llama3.2:3b options: temperature: 0.3 mcp: client: name: spring-ai-mcp-client version: 1.0.0 type: sync toolcallback: enabled: true sse: connections: server1: url: http://localhost:9800 openai: base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} chat: model: gpt-4o-mini这里有两个模型通道spring.ai.ollama是本地对话通道spring.ai.openai指向 TaoToken 的统一入口用于工具调用兜底。temperature调到 0.3 是为了让工具调用的参数更稳定别用默认的 0.7。3.2 MCP 工具注册与 ChatClient 装配MCP 客户端的核心是把远端 MCP 服务暴露的工具转成 Spring AI 能识别的ToolCallback再挂到ChatClient上。下面这个ChatService把两件事都做了Service public class ChatService { private final ChatClient localChatClient; private final ChatClient toolChatClient; public ChatService(OllamaChatModel ollamaChatModel, OpenAiChatModel openAiChatModel, ListMcpSyncClient mcpSyncClientList) { ToolCallbackProvider toolCallbackProvider new SyncMcpToolCallbackProvider(mcpSyncClientList); for (ToolCallback cb : toolCallbackProvider.getToolCallbacks()) { System.out.println(registered tool: cb.getToolDefinition().name()); } this.localChatClient ChatClient.builder(ollamaChatModel).build(); this.toolChatClient ChatClient.builder(openAiChatModel) .defaultToolCallbacks(toolCallbackProvider) .build(); } public String chat(String question) { return localChatClient.prompt().user(question).call().content(); } public String chatWithTools(String question) { return toolChatClient.prompt() .system(你是一个工具调用助手需要查询数据时必须调用工具不要编造。) .user(question) .call() .content(); } }关键点在于SyncMcpToolCallbackProvider会把所有已连接的 MCP 服务端工具聚合起来defaultToolCallbacks一挂模型在对话时就能自动决定要不要调工具。启动时打印registered tool是为了确认工具真的注册进来了如果这里没输出说明 MCP 连接没建立。3.3 一个最小 MCP 服务端工具调用要有服务端配合。下面是一个基于 SSE 传输的最小 MCP 服务端示例暴露一个“按姓名查用户”的工具SpringBootApplication public class McpServerApplication { public static void main(String[] args) { SpringApplication.run(McpServerApplication.class, args); } Bean public ToolCallback userQueryTool() { return FunctionToolCallback.builder(queryUserByName, (String name) - { MapString, Object user new HashMap(); user.put(name, name); user.put(level, VIP); user.put(balance, 1280); return user.toString(); }) .description(根据用户姓名查询用户信息参数为姓名) .inputType(String.class) .build(); } }服务端跑在 9800 端口客户端 yml 里的server1.url就指向它。工具名queryUserByName要和模型调用时生成的 name 对得上否则会报“tool not found”。4. 验证请求curl 打通工具调用链路4.1 先验证本地 Ollama 对话在写 Java 之前先用 curl 确认 Ollama 本身能对话curl http://127.0.0.1:11434/api/chat -d { model: llama3.2:3b, messages: [{role: user, content: 用一句话介绍 Spring Boot}], stream: false }返回 JSON 的message.content里有正常回答说明本地通道没问题。4.2 验证 TaoToken 统一通道再用同一个 Key 打 TaoToken 的 OpenAI 兼容接口确认统一通道可用curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: gpt-4o-mini, messages: [{role: user, content: 只回复两个字收到}] }如果返回choices[0].message.content是“收到”说明 Key 和 Base URL 都对。这一步很关键因为工具调用最终走的是这条通道通道不通后面全白搭。4.3 验证完整工具调用链启动 MCP 服务端9800和 Spring Boot 主应用后写一个 CommandLineRunner 触发带工具的对话Bean public CommandLineRunner runner(ChatService chatService) { return args - { String r1 chatService.chat(介绍一下你自己); System.out.println(local chat: r1); String r2 chatService.chatWithTools(查询姓名为林俊杰的用户信息); System.out.println(tool chat: r2); }; }启动日志里应该先看到registered tool: queryUserByName然后tool chat的输出里包含 VIP、1280 这些只有工具才能返回的数据。如果模型直接编了个答案而没调工具说明工具没挂上或者模型不支持 function calling。你也可以用 curl 直接打 Spring Boot 暴露的接口来验证前提是你加了一个 Controllercurl http://localhost:8080/chat/tools?q查询姓名为林俊杰的用户信息返回内容里出现工具返回的字段就证明“模型决策 → 工具调用 → 结果回填 → 模型总结”这条链路完整跑通了。5. 本篇常见报错排查5.1 401 Unauthorized打 TaoToken 接口返回 401九成是 Key 没读到。检查环境变量是否真的导出到当前 shellecho $TAOTOKEN_API_KEY如果为空说明export只在另一个终端生效。另外注意 yml 里写的是${TAOTOKEN_API_KEY}Spring 启动时如果读不到会直接报占位符解析失败而不是 401所以看到 401 基本是 Key 值本身错了或者带了多余空格。5.2 local proxy failed / connection refused这个报错通常出现在 Ollama 通道。先确认容器在跑docker ps | grep ollama curl http://127.0.0.1:11434/api/tags如果 curl 不通检查端口映射是不是-p 11434:11434。如果你把 Ollama 放在另一台机器base-url要改成那台机器的 IP别写 localhost。5.3 reading choices 相关解析异常日志里出现reading choices或 JSON 解析失败多半是模型返回了非标准结构。本地小模型在工具调用时偶尔会返回半截 JSON导致 Spring AI 反序列化失败。解决办法是把工具调用通道切到 TaoToken 的稳定模型本地通道只做纯对话。另外确认spring.ai.openai.chat.model填的是支持 function calling 的模型 ID。5.4 OAuth / 鉴权头缺失如果 MCP 服务端要求鉴权客户端连接时会报 OAuth 或 401。SSE 连接可以在 yml 里补 headerspring: ai: mcp: client: sse: connections: server1: url: http://localhost:9800 headers: Authorization: Bearer ${MCP_SERVER_TOKEN}没有鉴权需求就删掉这段别留空 header否则某些版本会报解析错误。5.5 工具注册了但模型不调用启动日志有registered tool但模型还是自己编答案。两个原因一是模型不支持 tools换llama3.2:3b或走 TaoToken二是 system prompt 没强调“必须调用工具”。把 system 消息写死成“需要查询数据时必须调用工具禁止编造”命中率会明显提升。我试过在 llama3.2:3b 上不加这句十次有六次直接编。6. 把统一 Key 接入长期编码与 Agent 工作流跑通上面这条链路后你会发现真正费时间的不是写代码而是反复调模型、换模型、对参数。TaoToken 的价值在于一个 Key 覆盖多个模型工具调用用强模型、日常对话用本地模型成本和质量都能兼顾。如果你打算把这套东西做成长期跑的编码助手或 Agent建议直接上 Coding Plan它按订阅方式提供稳定的模型调用额度适合持续性的开发场景https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite。模型对话调试入口在https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite接入文档在https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewriteAPI Key 管理还是那个https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite。最后给一个实用技巧把 Ollama 的base-url和 TaoToken 的base-url都做成配置项用 Spring Profile 区分 dev 和 prod。dev 环境全走本地prod 环境工具调用走 TaoToken这样本地开发不烧额度上线又能保证参数准确率。MCP 服务端的工具描述一定要写清楚参数类型和含义模型能不能正确调用一半取决于你的 description 写得够不够具体。
返回列表