你手上有 Spring Boot 项目,想把 DeepSeek 接进来做个问答或业务助手,但一搜全是 Python 示例,Java 侧够不着;或者接上了,一到流式输出、超时重试、密钥管理就散架。这篇按「先跑通、再接顺、最后才谈上线」的顺序,把 Spring AI 接 DeepSeek 的关键动作和判断标准列清楚,价格、模型规格这类会变的数字一律指到站内页面现查,不写死。
你手上有个 Spring Boot 项目,想接 DeepSeek 做个问答或业务助手,结果一搜全是 Python 示例,Java 侧够不着;或者照着博客接上了,一到流式输出、超时重试、密钥管理就散架,上线前一天集体加班。这篇不吹概念,按「先跑通、再接顺、最后才谈上线」的顺序,把 Spring AI 接 DeepSeek 的关键动作和判断标准列清楚。
有个前提先说好:价格、模型规格这类会变的数字,本文一个都不写死,一律指到站内页面现查,免得你照抄半个月前的博客踩坑。下面按工程骨架、核心调用写法、上线前清单、以及什么情况下不该硬上,逐节讲。
先把工程骨架和密钥这两件事弄干净
依赖只加两处:Spring AI 的核心 starter 和对应模型 starter,版本交给 Spring Boot 的依赖管理对齐,别自己在 pom 里手写互不兼容的版本号。跑通的第一目标不是流式、不是多轮,而是能收到一句完整回复。收不到的时候别急着改代码,先核对 base-url、模型名、网络出口这三样。
- base-url
- 指到服务方的接入地址,写错会直接连不上或返回鉴权错误,官方口径到站内 oficial 页面核对
- 模型名
- 字符串写错通常报模型不存在,不同接入方的命名规范可能不一致,别照抄上一个项目的配置
- 网络出口
- 公司内网常需要代理或白名单,本地能通线上不通,八成卡在这
- 密钥注入
- 走环境变量或配置中心,不进 Git、不进前端、不写进 application.yml 明文
- 本地开发用 .env 或 IDE 运行配置注入密钥,别让每个人把 key 散在自己机器的同一个文件里
- 团队统一密钥注入方式:要么配置中心,要么启动参数,别一个人一种写法,排查时没人说得清生效的是哪个
- 官方接口的接入口径、模型名与计费方式到 /official-api/providers/deepseek 核对,别照抄博客里的旧参数
- 把密钥管理写进新人上手文档,比在群里贴截图靠谱得多
流式输出、多轮上下文、函数调用三块怎么写
流式输出
Controller 返回流式响应类型,前端用 EventSource 或 fetch 流式读取。最容易踩的坑不是 Java 代码,而是反向代理的缓冲开关——Nginx 默认会把响应攒起来,用户要等整段生成完才看到字,体验跟非流式没区别。另外服务端的读超时要单独放大,流式连接的持续时间比普通请求长得多。
多轮上下文
把历史消息按条塞进消息列表就行,关键在截断策略:按轮数截、按 token 估算截、或者只留最近若干轮再加一条摘要。别无条件全量拼接,聊到几十轮之后不仅贵,模型也容易被前面的内容带偏。截断策略要写成一个独立方法,方便后面按实际用量调。
函数调用
把要暴露给模型的方法用注解声明清楚参数和描述,方法内部自己做参数校验和权限判断。记住一条:模型给的参数和用户输入的内容一样不可信,该查库的查库、该鉴权的鉴权,别直接把模型输出拼进 SQL 或系统命令。
| 场景 | 常见做法 | 验证方式 |
|---|---|---|
| 流式输出 | 返回流式响应,前端流式读取 | 本地直连能流式、过代理后仍能流式 |
| 多轮上下文 | 消息列表加截断策略 | 长对话跑几十轮看响应耗时和费用变化 |
| 函数调用 | 注解声明加方法内校验 | 构造越权参数看是否被拦住 |
| 提示词模板 | 模板单独放文件 | 改文案后不重新编译即可生效 |
上生产前按这份清单过一遍
- 超时与重试给连接和读取分别设超时;重试只对幂等的失败做,并加退避。重试次数设上限,不然模型端抖动时会把账单和下游一起拖垮。
- 降级方案模型不可用时返回什么——读缓存答案、开关关掉该功能、还是转人工,提前定好并写进代码,别等出事再临时决定。
- 可观测把每次请求的耗时、token 用量、失败原因记到日志或指标里。没有这些数据,调优和算成本都是盲猜;接口延迟基线可以用 /tools/speed-test 先量一遍。
- 成本与用量单价和额度到 /official-api 与 /usage 看当时的数字,把用量按功能维度拆开统计,才知道钱花在哪个功能上。
- 灰度与开关新功能先小流量跑,配一个能立刻关掉的开关,比事后回滚代码快得多。
清单过完还有一条容易被忽略:把密钥轮换和额度告警也纳入值班流程。额度快用完时系统应该主动报警,而不是等用户反馈「怎么突然不回话了」才发现。
什么情况下别硬上 Spring AI
框架不是越全越好,下面三种情况引入 Spring AI 反而增加排查成本,先想清楚再动手。
- 团队已经在用别的编排框架,链路里还混着别的语言服务,硬塞 Spring AI 会让调用链更难排查,不如统一走一层网关
- 任务需要频繁切换多家厂商的模型,抽象层直接依赖某一家 SDK 会很别扭,先用一层薄封装把模型调用隔开更稳
- 只是偶尔调一次接口做内部小工具,引入完整框架属于过度设计,一个 HTTP 客户端就够了
- 如果项目连基础的可观测和配置管理都没有,先补这两样,再谈接大模型
顺便提醒:接哪家、用哪个接入方,不能只看能不能跑通。稳定性和计费口径差异很大,可以先到站内页面横向比一遍再定,跑通之后再用同样的方法接第二家做备份。
下一步把接入方横向比一遍,再回来写代码,比接完发现选错再迁移省事得多。→常见问题
Spring AI 和直接写 HTTP 调 DeepSeek 接口,该选哪个?
看项目里模型调用的密度。一个项目里只有一两处调用,直接写 HTTP 更省事;如果要多轮对话、流式、工具调用、向量检索混着用,Spring AI 能把样板代码收掉,但你也得接受它的抽象和版本节奏。折中的做法是:先用它跑通一条链路,确认合适再铺开。
多轮对话历史越攒越长怎么办?
别等它自然变长。常见做法是保留最近若干轮原文,更早的部分压成一条摘要塞进系统消息;或者用向量检索按相关性挑回几段历史。具体留几轮要看你的任务长短和模型上下文上限,上限口径到站内模型库和术语词典核对,别按记忆里的数字写死。
调用报模型不存在或参数错误,先查什么?
按这个顺序:一是模型名和 base-url 是否匹配(第三方中转和官方地址不能混用);二是密钥有没有多余空格或换行;三是依赖版本是否和 Spring Boot 版本对得上。三步都没问题,再抓一次原始请求体和响应体看服务端到底说了什么,比看异常栈快得多。