Spring AI 多模型接入实战:OpenAI、Ollama、通义千问切换只需改配置

Spring AI 多模型接入实战:OpenAI、Ollama、通义千问切换只需改配置
本文是《Spring AI 实战》系列第 3 章。真实项目中你可能今天用 OpenAI明天就要换成 Ollama 降成本后天又要接入通义千问满足合规要求。Spring AI 的模型抽象层让这一切变得简单——切换模型只需改配置文件Java 代码一行不动。一、真实场景老板要换模型降成本假设你的 AI 客服系统已经上线使用的是 OpenAI GPT-4o每月 API 费用 5000 美元。某天老板看了账单要求把成本降下来。如果你用的是直接调用 OpenAI API 的方式// 硬编码了 OpenAI 的 API 地址、请求格式、认证方式// 换模型 重写所有 HTTP 调用代码RequestrequestnewRequest.Builder().url(https://api.openai.com/v1/chat/completions)// 硬编码.addHeader(Authorization,Bearer openaiApiKey)// 硬编码.post(RequestBody.create(openaiFormatJson,...))// 硬编码.build();换成本地 Ollama 或通义千问对不起上面的代码全部作废推倒重来。API 地址不同、认证方式不同、请求格式不同、响应格式不同。但如果你用的是 Spring AI只需要两步换 Starter 依赖pom.xml换配置application.ymlJava 代码一行不动。这不是魔法这是 Spring AI 模型抽象层的威力。二、Spring AI 的模型抽象层原理2.1 ChatModel 接口设计Spring AI 定义了一个核心接口ChatModel所有模型厂商的实现都遵循这个接口// Spring AI 的核心接口简化版publicinterfaceChatModel{/** * 调用大模型传入 Prompt返回 ChatResponse * 不管底层是 OpenAI、Ollama 还是通义千问调用方式完全一样 */ChatResponsecall(Promptprompt);}各厂商提供的实现类ChatModel接口 ├── OpenAiChatModel → 调用 OpenAI GPT 系列 ├── OllamaChatModel → 调用本地 Ollama 模型 ├── AnthropicChatModel → 调用 Anthropic Claude ├── GeminiChatModel → 调用 Google Gemini ├── MistralAiChatModel → 调用 Mistral AI └── ...更多厂商实现2.2 为什么切换模型只需改配置Spring Boot 的自动配置机制根据你引入的 Starter自动创建对应的ChatModelBean// 引入 spring-ai-starter-model-openai 后// Spring AI 自动创建 OpenAiChatModel Bean// 引入 spring-ai-starter-model-ollama 后// Spring AI 自动创建 OllamaChatModel Bean// 你的代码只依赖 ChatModel 接口不依赖具体实现// 所以切换 Starter 切换底层实现上层代码无感知这就是经典的面向接口编程——和 Spring Data 切换数据库驱动MySQL → PostgreSQL → Oracle是同一个道理。三、OpenAI 接入详解3.1 Starter 依赖dependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-starter-model-openai/artifactId/dependency3.2 application.yml 配置spring:ai:openai:# API Key必填从环境变量读取api-key:${OPENAI_API_KEY}# 自定义 API 地址可选# 如果你使用代理或兼容 OpenAI 协议的第三方服务需要设置这个# 默认值https://api.openai.com# base-url: https://your-proxy.com/v1chat:options:# 模型名称model:gpt-4o-mini# 温度参数0-2越高越有创造性temperature:0.7# 单次回复最大 token 数max-tokens:2048# 核采样参数0-1top-p:1.03.3 完整的 Service 调用代码ServicepublicclassOpenAiChatService{privatefinalChatClientchatClient;publicOpenAiChatService(ChatClient.Builderbuilder){this.chatClientbuilder.defaultSystem(你是一个专业的 AI 助手回答简洁清晰).build();}/** * 简单对话 */publicStringchat(Stringmessage){returnchatClient.prompt().user(message).call().content();}/** * 对话并获取 token 用量用于成本监控 */publicChatResultchatWithUsage(Stringmessage){ChatResponseresponsechatClient.prompt().user(message).call().chatResponse();varusageresponse.getMetadata().getUsage();returnnewChatResult(response.getResult().getOutput().getText(),usage.getPromptTokens(),usage.getGenerationTokens(),usage.getTotalTokens());}// 使用 Java Record 作为返回值publicrecordChatResult(Stringcontent,longpromptTokens,longgenerationTokens,longtotalTokens){}}3.4 OpenAI 计费详解模型输入价格每 1M tokens输出价格每 1M tokens上下文窗口推荐场景GPT-4o$2.50$10.00128K复杂推理、长文档分析、高质量生成GPT-4o-mini$0.15$0.60128K日常对话、分类、摘要性价比之王GPT-3.5-turbo$0.50$1.5016K简单任务已被 4o-mini 取代o1-mini$3.00$12.00128K复杂数学、编程推理o1-preview$15.00$60.00128K最强推理但价格极高实战建议大多数场景先用 GPT-4o-mini。它的成本只有 GPT-4o 的 1/16但质量已经非常好了。只有当 4o-mini 的输出质量不满足要求时再升级到 GPT-4o。3.5 踩坑提醒API Key 管理OpenAI 的 API Key 泄露 你的信用卡被盗刷。务必使用环境变量不要提交到 Git。建议在 OpenAI 后台设置 Monthly Limit月度消费上限。速率限制OpenAI 有 RPM每分钟请求数和 TPM每分钟 Token 数限制。免费账号限制更严格。生产环境需要实现重试和降级策略。网络问题中国大陆直连 OpenAI API 不稳定需要配置代理。可以在base-url中设置代理地址。四、Ollama 本地模型接入4.1 安装方式# WindowswingetinstallOllama.Ollama# Macbrewinstallollama# Linuxcurl-fsSLhttps://ollama.com/install.sh|sh安装后 Ollama 作为后台服务运行默认监听http://localhost:11434。4.2 常用模型推荐模型名参数量中文能力显存需求适用场景qwen2.57B优秀8GB推荐 16GB中文对话、问答、翻译中文场景首选llama3.18B一般8GB推荐 16GB英文对话、代码生成英文能力最强deepseek-r1:8b8B良好8GB推荐 16GB复杂推理、数学、逻辑分析gemma2:9b9B良好8GB推荐 16GB通用对话、指令跟随phi3.5:3.8b3.8B一般4GB轻量级任务、资源受限环境# 拉取推荐的中文模型ollama pull qwen2.5:7b# 验证模型可用ollama run qwen2.5:7b你好请介绍一下自己4.3 切换依赖pom.xml!-- 注释掉 OpenAI Starter --!-- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-openai/artifactId /dependency --!-- 换成 Ollama Starter --dependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-starter-model-ollama/artifactId/dependency4.4 切换配置application.ymlspring:ai:ollama:base-url:http://localhost:11434chat:options:model:qwen2.5:7b# Ollama 也支持 temperature 等参数temperature:0.74.5 Java 代码完全不变// 这个 Controller 在 OpenAI 和 Ollama 两种配置下都能正常工作// 因为 ChatClient 依赖的是 ChatModel 接口不是具体实现RestControllerpublicclassChatController{privatefinalChatClientchatClient;publicChatController(ChatClient.Builderbuilder){this.chatClientbuilder.build();}GetMapping(/chat)publicStringchat(RequestParamStringmsg){returnchatClient.prompt().user(msg).call().content();}}这就是 Spring AI 的核心价值代码与模型解耦。4.6 踩坑提醒模型拉取慢7B 模型约 4.5GB国内下载可能很慢。解决方案设置 Ollama 镜像环境变量OLLAMA_HOST或使用国内镜像站。端口冲突Ollama 默认使用 11434 端口。如果该端口被占用可以通过环境变量OLLAMA_HOST0.0.0.0:11435修改。Mac M 芯片兼容Apple Silicon 原生支持使用 Metal 加速体验很好。但 14B 的模型可能需要 32GB 以上内存。模型质量差异本地 7B 模型的能力远不如 GPT-4o。对于简单的分类、提取任务够用复杂推理任务建议用更大的模型或云端 API。五、通义千问百炼平台接入5.1 为什么国内推荐通义千问对比项OpenAI海外通义千问百炼国内网络延迟200-500ms海外服务器50-100ms国内服务器数据合规数据出境需评估合规风险数据不出境天然合规中文能力优秀优秀专门优化中文价格GPT-4o-mini: $0.15/$0.6qwen-plus: 更便宜有免费额度支付方式需要国际信用卡支付宝即可结论如果你是面向国内用户的项目通义千问是生产环境的首选。5.2 注册百炼平台获取 API Key打开 阿里云百炼平台登录阿里云账号没有就注册一个进入API-KEY 管理创建一个 API Key复制 API Key设置环境变量# Windows PowerShell$env:DASHSCOPE_API_KEYsk-xxxxxxxxxxxxxxxx# Linux/MacexportDASHSCOPE_API_KEYsk-xxxxxxxxxxxxxxxx5.3 兼容 OpenAI 协议的配置方式通义千问兼容 OpenAI 的 API 协议所以可以直接使用 Spring AI 的 OpenAI Starter只需要修改base-url!-- 依赖不变还是用 OpenAI Starter --dependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-starter-model-openai/artifactId/dependencyspring:ai:openai:# 关键把 base-url 改成通义千问的兼容地址base-url:https://dashscope.aliyuncs.com/compatible-mode/v1# API Key 使用百炼平台的 Keyapi-key:${DASHSCOPE_API_KEY}chat:options:# 使用通义千问的模型model:qwen-plustemperature:0.7看到没有依赖和代码都没变只改了base-url和api-key。这就是 OpenAI 兼容协议的好处——通义千问、DeepSeek、智谱、Moonshot 等国内大模型都兼容 OpenAI 协议都可以用同样的方式接入。5.4 通义模型选择表格模型定位输入价格输出价格上下文窗口适合场景qwen-turbo快速响应0.8元/百万tokens2元/百万tokens128K高并发、实时对话qwen-plus均衡性价比4元/百万tokens8元/百万tokens128K日常对话、内容生成推荐qwen-max旗舰模型20元/百万tokens60元/百万tokens32K复杂推理、长文本分析qwen-long超长上下文0.5元/百万tokens2元/百万tokens1000K长文档处理100万字实战建议大多数场景用qwen-plus。它的性价比最高中文能力优秀。只有当qwen-plus的输出质量不满足要求时比如复杂的数学推理再升级到qwen-max。六、模型参数调优指南不管你用哪个模型这三个参数都是核心调优点6.1 temperature 详解值效果类比0完全确定性每次返回相同结果查字典——同一个词永远查到同一个释义0.3基本确定微小变化教科书——严谨准确0.7适中有一定创造性有经验的同事——专业但不死板1.0有创造性每次可能不同脑暴会议——想法多样1.5高创造性可能胡说八道喝醉了的创意总监——天马行空但不可靠6.2 top_p 详解top_p是核采样参数也叫 nucleus sampling它和temperature一起控制输出的随机性。top_p 1.0不限制考虑所有可能的 tokentop_p 0.9只考虑概率累计前 90% 的 token排除 10% 的低概率 tokentop_p 0.5只考虑概率累计前 50% 的 token非常保守实战建议一般情况下用top_p 1.0默认值通过temperature来控制随机性即可。两者同时调整的效果不是简单的叠加一般不需要同时大幅调整。6.3 max_tokens 详解控制 AI 单次回复的最大 token 数量。1 token 大约 0.75 个英文单词或 0.5 个中文字max_tokens 100大约 50-75 个中文字max_tokens 2048大约 1000-1500 个中文字max_tokens 4096大约 2000-3000 个中文字注意max_tokens设置过小会导致回复被截断设置过大会浪费 token计费和增加延迟。6.4 五种场景的参数推荐场景temperaturetop_pmax_tokens原因代码生成0.1-0.21.02048需要确定性输出代码不能乱编问答/知识查询0.3-0.51.01024需要准确但允许适当变化翻译0.1-0.31.02048翻译需要精确不应该创造性发挥创意写作0.7-1.00.94096需要创造力和多样性数据分析0.2-0.41.02048需要准确的数据分析不能编造数据# 场景化配置示例spring:ai:openai:chat:options:# 代码生成场景model:gpt-4o-minitemperature:0.2max-tokens:20486.5 踩坑提醒temperature 过高导致胡说八道这是最常见的坑。如果你的应用需要准确输出代码、数据、事实务必把 temperature 设在 0.3 以下。很多 AI 幻觉问题就是 temperature 设置过高导致的。不同模型对参数的敏感度不同GPT-4o 对参数变化不太敏感在 0.1-1.0 范围内都比较稳定但较小的本地模型可能对 temperature 非常敏感。测试时注意对比。max_tokens 和成本的关系max_tokens 设置得越大单次调用的最大成本就越高。建议根据实际需求设置合理上限。七、多模型路由7.1 场景你的系统有不同类型的请求简单的问候、常见问题用便宜快速的模型复杂的技术问题用好模型代码生成用专门的代码模型。如何根据请求类型自动路由到不同的模型7.2 Qualifier 多 Bean 配置如果你的应用同时引入了多个 Starter比如同时引入 OpenAI 和 OllamaSpring Boot 会自动创建多个ChatModelBean。你需要用Qualifier区分它们ConfigurationpublicclassMultiModelConfig{/** * 主力模型用于日常对话和一般任务 * 使用 OpenAI GPT-4o-mini */BeanPrimary// 默认的 ChatModelpublicChatClientprimaryChatClient(ChatClient.Builderbuilder){returnbuilder.build();}/** * 高级模型用于复杂推理和分析任务 * 需要单独注入 OpenAiChatModel 并构建 */Bean(advancedChatClient)publicChatClientadvancedChatClient(Qualifier(openAiChatModel)ChatModeladvancedModel,ChatClient.Builderbuilder){// 用更高级的模型构建需要在 yml 中配置第二个模型returnbuilder.defaultModel(advancedModel).defaultSystem(你是一个资深的技术专家).build();}}7.3 路由 Service 代码ServicepublicclassSmartChatService{privatefinalChatClientsimpleClient;// 便宜快速的模型privatefinalChatClientadvancedClient;// 贵但强大的模型publicSmartChatService(PrimaryChatClientsimpleClient,Qualifier(advancedChatClient)ChatClientadvancedClient){this.simpleClientsimpleClient;this.advancedClientadvancedClient;}/** * 智能路由根据问题复杂度选择不同的模型 * * 简单问题问候、闲聊、常见问题→ 便宜模型 * 复杂问题技术分析、代码生成、推理→ 好模型 */publicStringsmartChat(Stringmessage){if(isSimpleQuestion(message)){// 简单问题用便宜模型省钱省时间returnsimpleClient.prompt().user(message).call().content();}else{// 复杂问题用好模型保证质量returnadvancedClient.prompt().user(message).call().content();}}/** * 判断问题是否简单简化版 * 实际项目中可以用轻量级分类器或规则引擎 */privatebooleanisSimpleQuestion(Stringmessage){Stringmsgmessage.toLowerCase();// 简单问候returnmsg.matches(.*(你好|hi|hello|谢谢|再见|拜拜).*)// 短问题通常比较简单||message.length()10;}}7.4 另一种方案单模型 不同参数如果你的应用只用一个模型厂商比如只用 OpenAI但需要根据场景调整参数ServicepublicclassParameterRouterService{privatefinalChatModelchatModel;publicParameterRouterService(ChatModelchatModel){this.chatModelchatModel;}/** * 根据场景动态调整参数 */publicStringchatWithParams(Stringmessage,Stringscenario){// 根据场景构建不同的参数varoptionsswitch(scenario){casecode-ChatOptions.builder().temperature(0.2)// 代码生成低温.maxTokens(4096)// 允许较长的代码输出.build();casecreative-ChatOptions.builder().temperature(1.0)// 创意写作高温.maxTokens(2048).build();default-ChatOptions.builder().temperature(0.7)// 默认.maxTokens(1024).build();};PromptpromptnewPrompt(List.of(newUserMessage(message)),options);returnchatModel.call(prompt).getResult().getOutput().getText();}}八、小结本章我们学习了 Spring AI 的多模型接入能力模型抽象层原理ChatModel接口 各厂商实现面向接口编程OpenAI 接入Starter 配置 计费详解生产环境首选 GPT-4o-miniOllama 本地模型零成本、数据不出本地推荐 qwen2.5:7b通义千问百炼国内首选兼容 OpenAI 协议改 base-url 即可模型参数调优temperature、top_p、max_tokens 的原理和场景推荐值多模型路由根据请求复杂度自动选择模型省钱又保质下一章我们将学习 Prompt Engineering 和 Advisor 机制——同样的模型好的 Prompt 能让输出质量翻倍。Spring AI 实战 — 第3章完整内容与源码