SpringAI集成DeepSeek原生供应商并实现think模式
项目中一直用 Spring AI 的 OpenAI 兼容层调用 DeepSeek API。这种方式能跑但有几个痛点拿不到 reasoning_contentDeepSeek 的推理过程CoT不会以结构化字段返回只能让模型把思考过程包在 think 标签里前端再用状态机做标签解析极其脆弱缺失 DeepSeek 特有 APIPrefix Completion、DeepSeek 特有的参数等都无法使用语义不清晰配置里写着 openai实际调的却是 DeepSeek维护成本高Spring AI 在 1.x 版本已经官方支持了 DeepSeek本文记录完整的迁移过程。一、添加依赖在 pom.xml 中添加 DeepSeek Starter版本由 BOM 1.1.3 统一管理xml 代码解读复制代码dependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-starter-model-deepseek/artifactId/dependency二、配置供应商在 application-dev.yml 中添加 DeepSeek 配置块yaml 代码解读复制代码spring:ai:deepseek:api-key: sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxchat:options:model: deepseek-v4-flashtemperature: 1.0API Key 建议通过环境变量注入避免硬编码。三、注册 Bean在 AiConfig.java 中注册 DeepSeek 的 ChatModel 和 ChatClientjava 代码解读复制代码import org.springframework.ai.deepseek.DeepSeekChatModel;Bean(deepseekChatModel)public ChatModel deepseekChatModel(DeepSeekChatModel deepSeekChatModel) {return deepSeekChatModel;}Bean(deepseekChatClient)public ChatClient deepseekChatClient(Qualifier(deepseekChatModel) ChatModel deepseekChatModel,MessageFormatAdvisor messageFormatAdvisor,LifecycleToolCallAdvisor lifecycleToolCallAdvisor,TaskProgressAdvisor taskProgressAdvisor,RetryAdvisor retryAdvisor) {return ChatClient.builder(deepseekChatModel).defaultToolContext(new HashMap(Map.of(debug, true))).defaultAdvisors(messageFormatAdvisor,lifecycleToolCallAdvisor,taskProgressAdvisor,retryAdvisor).build();}四、Controller 改造 — 原生推理流式输出改造前的痛点每个 SSE Chunk 拿到的是 AssistantMessagethink 标签可能被切碎在多个 Chunk 里需要维护复杂的状态机做拼接。改造后使用 DeepSeekAssistantMessagereasoningContent 和 text 是两个独立的字段java 代码解读复制代码import org.springframework.ai.deepseek.DeepSeekAssistantMessage;// 流式处理核心逻辑.concatMap(response - {AssistantMessage output response.getResult().getOutput();ListServerSentEventChatChunk events new ArrayList();// 工具调用if (output.getToolCalls() ! null !output.getToolCalls().isEmpty()) {// ... handle tool callsreturn Flux.fromIterable(events);}// DeepSeek 原生推理内容if (output instanceof DeepSeekAssistantMessage dsMsg) {String reasoning dsMsg.getReasoningContent();if (reasoning ! null !reasoning.isEmpty()) {// 缓冲后发送见下文state.accumulateReasoning(reasoning, events);}}// 文本内容String text output.getText();if (text ! null !text.isEmpty()) {state.flushReasoning(events);events.add(createEvent(message, state.messageId(), text, null));}return Flux.fromIterable(events);})五、推理内容缓冲优化reasoningContent 以 Token 粒度到达每个 SSE Chunk 可能只有一个字/词直接推给前端会导致渲染碎片化。需要在服务端做缓冲按语义边界批量下发。核心实现累积推理内容到 StringBuilder遇到句子结束标点时切分发出java 代码解读复制代码private static class StreamState {private static final int REASONING_FLUSH_THRESHOLD 50;private static final Pattern SENTENCE_BOUNDARY Pattern.compile([。.!?\\n]);private final StringBuilder reasoningBuffer new StringBuilder();public void accumulateReasoning(String delta,ListServerSentEventChatChunk target) {reasoningBuffer.append(delta);// 按标点切分整句发出String buf reasoningBuffer.toString();var matcher SENTENCE_BOUNDARY.matcher(buf);int lastEnd 0;while (matcher.find()) {String segment buf.substring(lastEnd, matcher.end()).trim();if (!segment.isEmpty()) {target.add(createEvent(thought, reasoning, segment, null));}lastEnd matcher.end();}reasoningBuffer.delete(0, lastEnd);// 无标点时强制 flush避免长思考无反馈if (reasoningBuffer.length() REASONING_FLUSH_THRESHOLD) {String forced reasoningBuffer.toString();reasoningBuffer.setLength(0);target.add(createEvent(thought, reasoning, forced, null));}}}触发策略场景行为遇到句号/问号/感叹号/换行按标点切分www.ycsjb.com整句发出缓冲区积累超过 50 字符无标点强制整块发出切换到文本输出或工具调用排空缓存六、效果对比改造前 前端收到的是逐个单词的 thought 事件需要前端做拼接渲染json 代码解读复制代码event: thoughtdata: {content:The, role:thought}event: thoughtdata: {content:user, role:thought}event: thoughtdata: {content:wants, role:thought}改造后 前端收到完整的语义段落直接展示json 代码解读复制代码event: thoughtdata: {content:The user wants me to add a new feature., role:thought}event: thoughtdata: {content:Let me think about the best approach., role:thought}总结Spring AI 官方 DeepSeek Starter 带来的核心收益结构化推理内容DeepSeekAssistantMessage.getReasoningContent() 直接获取 CoT无需 think 标签 hack服务端缓冲按语义边界批量下发前端零改动即可获得平滑渲染配置语义化配置即文档spring.ai.deepseek.* 一目了然扩展性后续可以无缝使用 DeepSeek 特有功能Prefix Completion、Reasoning 多轮对话等