Spring AI + 千问3.5接入实战:Java服务一行代码调用大模型

发布时间:2026/10/21 14:41:52
Spring AI + 千问3.5接入实战:Java服务一行代码调用大模型 如果你是个写 Java 的后端最近刷到 AI 相关的东西肯定心痒过——别人五分钟接个 GPT写个 Python 脚本就满屏跑 Demo我们自己还在用 RestTemplate 跟各种模型平台拉扯 HTTP 响应。靠 Java 接入大模型真没想象中那么痛苦Spring AI 的出现把这条路基本铺平了配合千问 3.5 这类成熟的中文模型几行配置加一行调用就能给你原来的 Spring Boot 服务开一个“AI 接口”。这篇文章不写那些抄来抄去的官方文档就从一个实际接项目的角度把 Spring AI 千问 3.5 集成的完整思路、代码、参数和踩坑记录全摊开讲。适合已经会写 Spring Boot、想快速让业务拥有对话、文案生成、结构化抽取能力的人也适合纯 Java 项目想低成本试水 AI 的团队。1. 项目概述与核心思路拆解1.1 为什么说 Java 接入大模型是个“脏活累活”很多人觉得 Java 接大模型难难在哪先看两类现状。第一类是完全没有 AI 经验的团队。他们以为大模型接口无非就是“发个 HTTP 请求把返回的 JSON 拼出来”真上手才发现要处理的事情一大堆认证怎么带、错误码怎么识别、流式返回怎么解析、上下文怎么传、重试怎么做、并发会不会被限流。这些事每一项都不难但合在一起就得写小几百行工具代码还得反复跟对方的接口文档对。第二类是已经有 AI 经验、但一直用 Python 的团队。Python 生态里的大模型 SDK 实在太多了封装也成熟拿到 key 就能跑。Java 这边虽然也有个别模型厂商提供的 SDK但不同平台一套风格换一个模型就得重新学一套 API。等你写完接 A 厂的代码又听说 B 厂模型更便宜更好用想换改动范围不是几行配置能解决的。说白了Java 生态缺的不是“能不能接”缺的是一个统一抽象层。就像当年 JDBC 解决了数据库方言问题、Spring Data 解决了数据访问模板问题AI 领域也需要一个类似的规范把不同模型平台的差异挡住。Spring AI 做的就是这件事。它把当前主流的对话模型、向量模型、图片模型全部收拢到一套 Spring 风格 API 里你面向的是ChatClient这个接口背后接的是千问、通义、文心还是国外某个模型业务代码基本可以不改。1.2 Spring AI 到底帮你做了什么Spring AI 是 Spring 生态推出的 AI 应用开发框架思路和 Spring Data 一脉相承你只定义要“做什么”至于“怎么做”交给自动配置去完成。它的核心组件叫ChatClient。你可以理解成以前我们调数据库用JdbcTemplate调 Redis 用RedisTemplate现在调大模型用ChatClient。这个对象由框架自动装配你只要往上下文里注入ChatClient.Builder就能生成一个可用的客户端。具体来说它帮我们处理了几层事情统一的请求模型。不管底层是千问还是别的模型平台你只需要给ChatClient传user内容、system提示词、options参数其余按框架统一的模型对象执行。自动配置。引入对应模型的 starter 依赖后Spring Boot 会在启动时读取application.yml里的配置自动创建ChatClient不需要你自己 new。流式响应支持。大模型天然适合流式输出Spring AI 把响应封装成Flux前端可以直接走 SSE 协议。结构化输出。返回 JSON 可以自动映射到 Java 对象这是日常业务里最实用的能力。工具函数调用和 RAG 等高级能力。这些对老手扩展来说很舒服后面我会提到。它的价值不是让你少写一个工具类而是让整个 AI 集成的“硬编码链路”透明化。你甚至不需要关心 HTTP 请求细节模型平台的接口变了可能是框架顺手帮你适配而不是你熬夜改代码。1.3 为什么拿千问 3.5 来打样选千问 3.5 作为示例原因很现实。首先千问系列模型对中文任务的处理能力在国产模型里是第一梯队回答质量稳定尤其适合内容生成、客服问答、信息抽取这类业务场景。作为团队接 AI 的第一个模型它的综合表现不太容易“劝退”。其次它的 API 风格比较标准Spring AI 官方也提供了对应的 starter集成路径最短。我见过很多项目一开始就挑冷门模型结果官方 SDK 都没有只能自己写 HTTP client硬生生把一个月耗在适配层上。用千问打样可以快速验证整个链路。最后是成本和合规性。中文业务的数据敏感性不用多说模型部署在国内调用延迟和审批顾虑会更少。当你验证完 Spring AI 这套架构之后模型切换成本也很低后面真因为业务需求要换别的模型只需要换依赖、改配置业务代码依然是一行chatClient.call()。2. 环境准备与配置细节2.1 版本选择Spring Boot 和 Spring AI 别瞎配我接这个项目的时候第一件事就是查版本兼容性因为 Spring AI 这个框架目前迭代非常快版本之间 API 差异不小。如果你用最新版 Spring Boot 加旧版 Spring AI往往会出现ChatClient类找不到、配置属性不生效这种很尴尬的问题。我的建议是无脑选当前 Spring Boot 3.x 的稳定版本JDK 至少 17 往上。Spring AI 的版本以官方发布为准尽量别用快照版本虽然快照有最新功能但 API 说变就变写出来的代码过两周可能就废了。实际项目里我用的是 Maven 管理依赖。先把 Spring AI 的 BOM 引入进来避免自己手动控制每个模块的版本dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version1.0.0/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement这里版本号只是一个示例你实际使用时应该去 start.spring.io 或者官方仓库确认当前最新稳定版。版本对齐的最大好处是Spring AI 内部各模块之间的兼容性由 BOM 维护你不需要自己操心。2.2 Maven 依赖与仓库配置接着引入核心 starter。如果你使用的是 Spring AI 对千问模型的专门集成依赖大致长这样dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-qwen/artifactId /dependency引入这个依赖后Spring Boot 的自动配置会自动识别千问模型相关的配置项并生成ChatModel、ChatClient等 Bean。后面你只管注入使用不用写一行工厂代码。有一点需要特别提醒Spring AI 的部分模块在早期版本里不是放在 Maven 中央仓库的而是在 Spring 自己的里程碑仓库里。如果直接引入依赖后下载失败就需要在pom.xml里把仓库地址加上repositories repository idspring-milestones/id nameSpring Milestones/name urlhttps://repo.spring.io/milestone/url snapshots enabledfalse/enabled /snapshots /repository /repositories仓库地址这种事官方文档里写得清楚但很多新手就是会漏。你漏了也分不清是版本问题还是依赖问题排查起来浪费时间。2.3 API Key 的配置姿势从硬编码到环境变量每个大模型平台都会给你一个 API Key这相当于你的账号密码。我见过有人图省事直接写在application.yml里还顺手传到 Git 仓库。这里必须敲个警钟Key 一旦泄露等于别人拿着你的账单疯狂调模型刷几百上千块只是一瞬间的事。正确做法是通过环境变量注入然后在配置里引用spring: ai: model: chat: qwen: api-key: ${QWEN_API_KEY} model: qwen3.5没有环境变量的话也可以用配置中心或者启动参数传。在这个配置里model字段填的是模型在服务商那边的标识比如qwen3.5或者你在控制台开通的具体版本型号。每个人开通的资源不一样模型名并不通用最稳妥的方式是登录控制台确认自己的模型标识而不是照抄网上的案例。这一段配置配好之后核心工作就完成了大半。启动服务后Spring AI 会读取配置帮你创建客户端我们接下来见到的“一行代码”全靠这一步撑着。3. 一行代码接入的背后3.1 先说结论这一行代码写了什么在 Spring AI 里最基础的对话调用确实只有一行String answer chatClient.call(请用三句话介绍你的功能);就这么简单。chatClient.call()会同步等待模型返回完整结果然后把文本内容直接给你。如果你也想快速做接口验证把它丢进 Controller 就能跑通全流程。但这行代码能成立不是 Spring AI 会魔法而是前面这些事都已经被提前干完了依赖里已经引入了千问的 starterapplication.yml已经把 key 和模型名配好Spring Boot 启动时自动实例化了ChatClientchatClient底层封装了网络请求、认证、响应解析等逻辑。所以你在业务代码里看到的“一行”其实是框架把复杂度咽下去了。这也提醒我们永远不要真把大模型接入当成“一行代码”的工程量该配置的、该测试的一点都不能省。3.2 最简调用不写一行样板直接出文案实际在 Spring Boot 项目里我会写一个最简单的 ControllerRestController public class AiController { private final ChatClient chatClient; public AiController(ChatClient.Builder builder) { this.chatClient builder.build(); } GetMapping(/ai/chat) public String chat(RequestParam(defaultValue 你好) String message) { return chatClient.call(message); } }启动项目浏览器访问/ai/chat?message介绍一下Java就能看到模型返回结果。这个接口虽然简陋但证明了整条链路是通的后面所有复杂功能都在这条链路上扩展。这里有个很小的细节注入的是ChatClient.Builder不是直接注入ChatClient。因为框架希望你在构建时能额外设置系统提示词、默认参数等而不是拿着一个固定实例到处用。如果你直接注入ChatClient也可能可以但遇到多租户、多模型场景时不好扩展。3.3 把“超能力”封装成自己的工具类Controller 里直接裸露调用虽然 demo 很爽但真实项目不能这么干。模型调用是资源操作应该抽到 Service 层统一管理。我会定义一个AiAssistant把业务语义都收进来Service public class AiAssistant { private final ChatClient chatClient; public AiAssistant(ChatClient.Builder builder) { this.chatClient builder .defaultSystem(你是一个严谨的技术写作助手回答要简洁、准确、有条理。) .build(); } public String generateArticleOutline(String topic) { String prompt 请为下面的主题生成一份文章大纲包含 3 个章节。 主题%s .formatted(topic); return chatClient.call(prompt); } public String summarize(String content) { String prompt 请用 100 字以内总结下面的内容 %s .formatted(content); return chatClient.call(prompt); } }这个类把“角色设定”集中管理。以后要换提示词或者调整模型参数都只改这里不会污染 Controller。加粗提示一下在真实项目中ChatClient是线程安全的可以全局复用。不要每次请求都new一个客户端那是白烧性能。3.4 流式输出聊天框里的打字机效果如果只做一次性问答同步的call()就够用了。但你要是做聊天机器人、智能助手用户绝对忍受不了转圈等一大段文字一次性蹦出来。这时候要用流式输出。Spring AI 对流的支持非常自然GetMapping(value /ai/stream, produces text/event-stream) public FluxString streamChat(RequestParam String message) { return chatClient.prompt() .user(message) .stream() .content(); }前端用EventSource或fetch的 ReadableStream 就能实时接收内容体验和国内主流聊天产品差不多。这里要注意两点返回类型是FluxString需要引入响应式依赖但 Spring Boot WebFlux 下天然支持接口的produces要写成text/event-stream否则浏览器不按流式处理。流式模式并不是所有模型平台都支持得很好千问 3.5 这代模型的流式体验已经相当成熟断句和响应速度都跟得上。4. 参数调优与实际应用4.1 温度、最大 Token 这些参数怎么调大模型不是“给的提示词越多越好”很多参数是决定输出质量的关键最重要的两个就是temperature和max-tokens。temperature控制随机性。取值一般在 0 到 1 之间值越低越保守越高越发散。做客服机器人和信息抽取我建议 0.2 到 0.4保证答案稳定做文案创作、头脑风暴可以拉到 0.8 以上让模型更有“灵感”。max-tokens直接限制最大回复长度。它既影响质量也直接影响账单。你需要估算业务里最长回答可能超过多少 token不能无脑设成 4096 或 8192。比如一个商品简介生成场景设成 512 完全够了写长文才需要 2048 以上。在配置文件里这样设置spring: ai: model: chat: qwen: options: temperature: 0.4 max-tokens: 1024如果你希望不同接口使用不同参数可以在调用时通过Prompt单独覆盖Prompt prompt new Prompt( 写一篇产品推广文案, QwenChatOptions.builder() .withTemperature(0.9) .withMaxTokens(512) .build() ); String result chatClient.call(prompt);在未完全确认参数效果前不要“感觉差不多就行”。我建议把自己常见的问题整理成一组测试集跑对比挑出最合适的参数组合固化到配置里。4.2 多轮会话别让 AI 失去上下文默认情况下ChatClient每次调用都是独立的模型不记得你上一句说了什么。要做客服、助手这类多轮对话就必须手动把历史消息一起传进去。Spring AI 里多轮对话可以像拼消息列表一样写String result chatClient.prompt() .system(你是客服助手回答要耐心、简洁。) .user(history) .user(现在帮我查一下订单状态) .call() .getContent();你可以把最近几轮用户消息和助手消息拼接成一个上下文文本或者使用框架提供的消息接口构建列表。关键是上下文太长会占用大量 token还会拖慢响应。我一般只保留最近 6 到 8 轮对话超过就截断效果基本够用。自己维护对话历史的方案适合中小项目。真正到了多用户、高并发场景应该把会话数据丢进 Redis 或数据库而不是放在单机内存里否则服务一重启全部丢失。4.3 结构化输出让 AI 直接返回 Java 对象这个功能特别适合做信息抽取和表单填充。比如你让模型从一段简历里提取姓名、技能、工作经验以前你得自己写 JSON 解析现在可以直接让 Spring AI 帮你映射成 POJO。record PersonInfo(String name, ListString skills, int years) {} PersonInfo person chatClient.prompt() .user(从这段简历里提取人员信息...) .call() .entity(PersonInfo.class);这里 Spring AI 会在内部请求模型返回 JSON然后反序列化成PersonInfo。注意 record 的字段名要和模型返回的 JSON key 一致否则映射不出来。如果需要国内字段名可以在提示词里明确指定返回结构。结构化输出最大的价值在降本增效一段 500 字的简历人工录入至少要三分钟模型三秒就给出结构化结果。只要做好字段校验这条路非常稳。5. 踩坑记录与问题排查5.1 依赖下载失败、版本冲突我在项目里遇到最多的报错就是类找不到。比如NoClassDefFoundError: ChatClient基本就是版本冲突。先做三件事检查 Maven 是否成功拉取了所有依赖看mvn dependency:tree里有没有旧版本 Spring AI 被传递进来确认项目里没有同时引入多个模型 starter。同时引入两个模型 starter 的问题很隐蔽因为它们各自的自动配置都会尝试创建ChatModelBean轻则启动有警告重则直接启动失败。一个项目接入多个模型时最好明确限定各自 Bean 名称。5.2 模型名报错404、400 怎么判断大模型接口报 404 或 400大概率不是网络问题而是模型名没对上。排查思路很简单登录模型服务商控制台查看你当前账号能访问的模型列表。不同账号能用的模型不一样你在网上看到的教程模型名在自己项目里不一定有效。如果你确认模型名没错再看配置里的 key 是否有权限。很多新手把测试环境的 key 配到线上返回 401/403 也是一脸懵。5.3 超时问题从 5 秒到 60 秒默认情况下Spring Boot 内置的 HTTP 客户端超时时间可能很短长一点的生成任务很容易就断了。最典型的症状就是请求发了模型也接了但前端 5 秒后就收到超时钱还被扣了。解决思路是定制RestClient的超时参数connectTimeout连接建立超时一般 5 到 10 秒readTimeout读取响应超时建议 60 秒以上复杂任务甚至 120 秒。不同 Spring AI 版本的配置方式有差异核心是提供一个修改过超时配置的RestClient.BuilderBean让自动配置使用它。调整之后长文生成就不会半路断开了。5.4 并发场景下会有哪些坑大模型服务商普遍有 QPS 限制。你的服务并发一上来下一秒就会收到限流错误返回 429 或类似提示。应对办法一是做好业务层的限流比如按用户维度限制请求频率二是在调用 AI 的链路上做简单重试。重试时注意指数退避不要等几十个线程一起重试那不是解决问题是放大大问题。另外模型响应耗时不固定如果这是在 Web 请求线程里同步调用线程池很容易被占满。建议把 AI 调用放到独立的线程池或者用响应式编程方式避免把整个服务的线程资源拖垮。5.5 一个不算 bug 的坑提示词才是天花板很多团队换了大模型之后发现效果并没有明显提升就开始怀疑模型能力有问题。实际上一半以上的情况是提示词没写对。同样一个任务你用“帮我写个文案”和“你是一名资深品牌策划结合产品卖点和目标用户画像输出 3 条不同风格的推广短文案每条不超过 50 字”效果天差地别。Spring AI 的优势在于它把提示词和代码分离得很干净你用PromptTemplate统一管理提示词才是后续持续调优的正路。我在实际项目中体会最深的一件事是Spring AI 最大的价值不是省了那几行代码而是逼着整个 Java 团队用统一的模式去思考 AI 集成。以前每人一套接入方式现在大家共用一套抽象后续换模型、加功能、做监控都清晰很多。如果你正准备把 AI 能力接进 Java 服务别一上来就研究底层协议先把 Spring AI 和千问 3.5 这条链路跑通再针对业务做提示词和参数优化你会发现所谓“风口”落地起来比自己想象中稳得多。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询