接入 DeepSeek
本教程共 45 篇 · 第 13 篇 · 更新于 2026-08-16 · 约 6 分钟阅读
本节目标:用官方 starter 接入 DeepSeek,理解它与 OpenAI 的兼容关系,学会流式调用、前缀补全和推理模型的思维链读取。
13.1 为什么选 DeepSeek
DeepSeek 是国内热度最高的大模型厂商之一。它的卖点很直接:能力接近一线模型,价格便宜很多,对中文支持好。
官方文档给 DeepSeek 的定位是”OpenAI-proxy”类型:API 规范完全兼容 OpenAI。这意味着你既可以用官方 starter,也可以用 OpenAI 的客户端连它的地址。两条路都通,后面分别讲。
先到 platform.deepseek.com 注册账号,充值后创建 API Key。DeepSeek 平台需要先实名认证才能充值。
13.2 方式一:官方 starter
Spring AI 提供专门的 DeepSeek starter,依赖坐标:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-deepseek</artifactId>
</dependency>
配置前缀是 spring.ai.deepseek:
spring.ai.deepseek.api-key=${DEEPSEEK_API_KEY}
spring.ai.deepseek.base-url=https://api.deepseek.com
spring.ai.deepseek.chat.model=deepseek-v4-flash
spring.ai.deepseek.chat.temperature=0.8
可用的模型名有四个:
| 模型名 | 定位 |
|---|---|
| deepseek-v4-flash | 默认模型,快,便宜 |
| deepseek-v4-pro | 更强,适合复杂任务 |
| deepseek-chat | 通用对话模型 |
| deepseek-reasoner | 推理模型,输出思维链 |
模型名可以在运行时通过 DeepSeekChatOptions 覆盖:
ChatResponse response = chatModel.call(new Prompt(
"列出 5 种常见前端框架",
DeepSeekChatOptions.builder()
.model(DeepSeekApi.ChatModel.DEEPSEEK_V4_PRO.getValue())
.temperature(0.8)
.build()));
13.3 方式二:OpenAI 兼容接入
网上大量 DeepSeek 教程用的是这条路:引入 OpenAI starter,把 base-url 指向 DeepSeek。原因就是前面说的,DeepSeek 完全兼容 OpenAI 规范。
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
spring.ai.openai.api-key=${DEEPSEEK_API_KEY}
spring.ai.openai.base-url=https://api.deepseek.com
spring.ai.openai.chat.model=deepseek-chat
代码里注入的是 OpenAiChatModel 或 ChatClient,调用方式和第 11 章完全一样。
两条路的区别在抽象层级:官方 starter 的模型叫 DeepSeekChatModel,响应里能直接拿到 DeepSeek 特有的思维链字段;OpenAI 方式没有这个类型,但可以通过元数据读到。日常对话场景,两条路体验没差别。
Tip同一份代码想同时兼容多个 OpenAI 规范厂商(DeepSeek、通义千问、Moonshot),用 OpenAI 方式最省事,只改 base-url 和模型名。
13.4 流式响应
DeepSeek 流式输出用 ChatClient 一行搞定,这也是网上博客最常见的需求。1.x 博客里写的是 chatClient.prompt(input).stream().content(),这套 API 在 2.0 依然是 ChatClient 的一等公民,写法不变:
@GetMapping(value = "/ai/stream", produces = "text/html;charset=UTF-8")
public Flux<String> stream(@RequestParam(defaultValue = "讲个笑话") String message) {
return chatClient.prompt()
.user(message)
.stream()
.content();
}
浏览器直接访问这个接口,能看到逐字输出的打字机效果。接入层代码只有这么点,剩下的解析和推流都由框架完成。
13.5 前缀补全
DeepSeek 有个特色功能叫前缀补全(prefix completion):你给模型一个”开头的半句话”,它接着往下写。典型场景是强制输出格式,比如让模型只写 Python 代码。
用法是构造一个带 prefix 标记的 DeepSeekAssistantMessage,放在消息列表最后:
@RestController
public class CodeController {
private final DeepSeekChatModel chatModel;
public CodeController(DeepSeekChatModel chatModel) {
this.chatModel = chatModel;
}
@GetMapping("/ai/python")
public String python(@RequestParam(defaultValue = "写一个快速排序") String message) {
UserMessage userMessage = new UserMessage(message);
Message assistantMessage = DeepSeekAssistantMessage.builder()
.content("```python\n")
.prefix(true)
.build();
Prompt prompt = new Prompt(List.of(userMessage, assistantMessage),
ChatOptions.builder().stopSequences(List.of("```")).build());
return chatModel.call(prompt).getResult().getOutput().getText();
}
}
这里给模型喂了”python\n"这个前缀,模型会从代码块开始写。stop 参数设成 ,模型写完代码碰到结束标记就停,不会追加多余解释。
Note前缀补全要求消息列表最后一条必须是 DeepSeekAssistantMessage,并且 prefix 置为 true。普通对话不要加这个标记。
13.6 推理模型与思维链
deepseek-reasoner 是推理模型,回答前会先输出一段思维链(CoT)。这段内容通过 DeepSeekAssistantMessage 读取:
DeepSeekChatOptions options = DeepSeekChatOptions.builder().build();
Prompt prompt = new Prompt("9.11 和 9.8 哪个大?", options);
ChatResponse response = chatModel.call(prompt);
DeepSeekAssistantMessage message = (DeepSeekAssistantMessage) response.getResult().getOutput();
String reasoningContent = message.getReasoningContent(); // 思维链
String text = message.getText(); // 最终答案
思维链和最终答案是分开的两个字段。
走 OpenAI 兼容方式也能拿到思维链。DeepSeek 的兼容端点会返回 reasoning_content 字段,Spring AI 自动映射到响应元数据的 reasoningContent:
spring.ai.openai.api-key=${DEEPSEEK_API_KEY}
spring.ai.openai.base-url=https://api.deepseek.com
spring.ai.openai.chat.model=deepseek-reasoner
ChatResponse response = chatModel.call(new Prompt("9.11 和 9.8 哪个大?"));
AssistantMessage message = response.getResult().getOutput();
String reasoning = message.getMetadata().get("reasoningContent");
流式调用时思维链会跨多个 chunk 累积,每个 chunk 都从元数据里取,拼起来就是完整推理过程。
Note官方 OpenAI 模型不暴露思维链,
reasoningContent元数据只对 DeepSeek 这类兼容服务有效。读不到时检查模型名是不是 deepseek-reasoner。
推理模型的多轮对话有个特点:历史轮次的思维链不会拼进下一轮上下文。每次请求只带之前的最终答案,模型重新推理。这是 DeepSeek 的既定设计,能省 token,也避免模型被自己之前的推理过程带偏。需要长对话时,把多轮消息列表完整传给 Prompt 即可,框架会处理好角色映射。
13.7 工具调用
DeepSeek 支持工具调用,走统一的 ToolCallback 机制。ChatClient 自动注册 ToolCallingAdvisor,闭环处理工具调用循环。
工具调用的完整写法与第 12 章相同:定义 FunctionToolCallback,通过 .tools() 注册进请求。唯一要改的是把示例里的 chatModel 换成 DeepSeekChatModel,其余代码一字不动。完整示例回到 12.8 看。
13.8 重试与限流
DeepSeek 官方 starter 的重试配置和 OpenAI 共用一套前缀 spring.ai.retry。默认最多重试 10 次,指数退避从 2 秒开始,最大间隔 3 分钟。
spring.ai.retry.max-attempts=5
spring.ai.retry.on-client-errors=false
4xx 客户端错误默认不重试,这类错误重试也没用。限流(429)和超时属于瞬时错误,重试策略对它们有效。
DeepSeek 是预付费模式,账户余额不足会直接报错。开发调试阶段建议小额充值,控制每次调用的 max-tokens,避免一次测试烧掉太多额度。
13.9 网上博客经验的映射
DeepSeek 的博客教程大多基于 1.x,看的时候对照这张表转换:
| 1.x 写法 | 2.0 写法 |
|---|---|
| spring-ai-openai-spring-boot-starter | spring-ai-starter-model-openai |
| spring.ai.openai.chat.options.model | spring.ai.openai.chat.model |
| new Prompt(message) 手拼消息 | ChatClient.prompt().user() |
| chatModel.stream(prompt) 手动 map | chatClient.prompt().stream().content() |
核心经验不受版本影响:DeepSeek 兼容 OpenAI 规范,OpenAI 的客户端可以连 DeepSeek;流式响应返回 Flux,前端按流消费;系统提示词用 SystemMessage 设定人设。这些在 2.0 里依然成立,只是依赖名和属性路径变了。
13.10 常见问题排查
DeepSeek 的报错和 OpenAI 兼容服务基本同源,几个高频问题:
401 认证失败,检查 api-key。DeepSeek 是预付费模式,余额不足时请求会被直接拒绝,平台充值后立即恢复。
429 限流,触发并发限制。spring.ai.retry 对这类瞬时错误有效,配置见 13.8;持续被限就查官网的额度说明。
思维链读不到,先确认模型名是 deepseek-reasoner。普通对话模型不输出思维链,元数据里自然没有 reasoningContent,规则见 13.6。
前缀补全不生效,检查消息列表最后一条:必须是 DeepSeekAssistantMessage 且 prefix 置为 true,普通消息结尾没有效果。
模型名报不存在,对照官网模型列表核对。教程里写的名字可能过时,以 platform.deepseek.com 的文档为准。
13.11 小结
DeepSeek 接入有官方和兼容两条路。官方 starter 类型更完整,能直接读思维链;OpenAI 方式一套代码兼容多家厂商。流式、前缀补全、工具调用都是它的可用能力。下一章接入 Ollama,把模型跑在本地。