作为 Java 开发者,想在本地搭建一个能理解代码、支持多轮对话的 AI 机器人?DeepSeek-R1 这款开源大模型绝对值得一试。今天就带大家用 Ollama+Java 实现本地化部署,全程实操,新手也能跟着做!
一、先搞懂:为什么选 DeepSeek-R1?
这款模型有三个核心优势,特别适合开发者:
- 代码理解强:对 Java 语法、框架原理的解析准确率比同类模型高 15%+
- 对话不 "失忆":支持 50 轮以上多轮对话,上下文连贯性远超基础模型
- 本地能跑:7B 参数版在 16GB 内存的普通电脑上就能流畅运行,不用高配显卡
硬件要求放这里了,对照着看:
- 最低配置:CPU 8 核 +,16GB 内存(纯 CPU 推理能跑,但响应稍慢)
- 推荐配置:NVIDIA 显卡(8GB 显存以上),支持 CUDA 加速,响应速度提升 3 倍
二、环境搭建:3 步搞定 Ollama 和模型
1. 安装 Ollama
官网下载对应系统版本:Download Ollama on macOS
安装完成后打开终端,输入ollama --version
,能看到版本号就说明成功了。
2. 拉取 DeepSeek-R1 模型
终端执行命令:
# 推荐先装7B参数版,平衡性能和资源
ollama pull deepseek-r1:7b
拉取过程可能需要几分钟(看网速),耐心等一下。
3. 测试模型是否能用
输入ollama run deepseek-r1:7b
进入交互模式,试试问它:"用 Java 写个单例模式",能得到正确回复就没问题了。
三、Java 代码实战:从依赖到接口
1. 项目依赖(pom.xml)
先把必要的依赖加上,都是 Spring 生态常用的:
<dependencies>
<!-- Spring Web核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- HTTP客户端 -->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.3</version>
</dependency>
<!-- JSON处理 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- Lombok简化代码 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
2. 数据模型:4 个类搞定请求响应
这些类是用来封装数据的,直接抄就行:
// 接收用户输入的模型
@Data
public class ChatRequest {
private String message; // 用户输入的消息
private String sessionId; // 会话ID,多轮对话用
}
// 发给Ollama的请求参数
@Data
public class DeepSeekRequest {
private String model = "deepseek-r1:7b"; // 模型名
private List<Message> messages; // 对话历史
private Float temperature = 0.6f; // 0.6适合对话,不生硬
private Boolean stream = false; // 非流式响应
@Data
public static class Message {
private String role; // "user"或"assistant"
private String content; // 消息内容
}
}
// Ollama返回的响应
@Data
public class DeepSeekResponse {
private String model;
private List<ResponseMessage> messages;
private Boolean done;
@Data
public static class ResponseMessage {
private String role;
private String content; // 模型回复的内容
}
}
// 给前端的最终响应
@Data
public class ChatResponse {
private String reply; // 回复内容
private String sessionId; // 会话ID
private long timestamp; // 时间戳
}
3. 会话管理:让机器人记住上下文
这个服务用来存对话历史,不然每次对话都是新的:
@Service
public class SessionManager {
// 用ConcurrentHashMap存会话,key是sessionId
private final Map<String, List<DeepSeekRequest.Message>> sessionHistory = new ConcurrentHashMap<>();
// 获取某个会话的历史消息
public List<DeepSeekRequest.Message> getHistory(String sessionId) {
return sessionHistory.computeIfAbsent(sessionId, k -> new ArrayList<>());
}
// 添加用户消息到历史
public void addUserMessage(String sessionId, String message) {
DeepSeekRequest.Message msg = new DeepSeekRequest.Message();
msg.setRole("user");
msg.setContent(message);
getHistory(sessionId).add(msg);
}
// 添加机器人回复到历史
public void addAssistantMessage(String sessionId, String message) {
DeepSeekRequest.Message msg = new DeepSeekRequest.Message();
msg.setRole("assistant");
msg.setContent(message);
getHistory(sessionId).add(msg);
}
// 清理会话(可选)
public void clearHistory(String sessionId) {
sessionHistory.remove(sessionId);
}
}
4. 核心服务:调用 Ollama 接口
这部分是关键,负责把用户消息发给模型,再把回复拿回来:
@Service
public class DeepSeekService {
// Ollama的API地址,本地部署固定这个
private static final String OLLAMA_API_URL = "http://localhost:11434/api/chat";
private final CloseableHttpClient httpClient;
private final ObjectMapper objectMapper;
private final SessionManager sessionManager;
// 构造函数注入依赖
public DeepSeekService(SessionManager sessionManager) {
this.httpClient = HttpClients.createDefault();
this.objectMapper = new ObjectMapper();
this.sessionManager = sessionManager;
}
// 处理用户消息,返回回复
public ChatResponse processMessage(ChatRequest request) {
// 生成或复用sessionId
String sessionId = request.getSessionId();
if (sessionId == null || sessionId.isEmpty()) {
sessionId = UUID.randomUUID().toString();
}
// 构建发给模型的请求
DeepSeekRequest deepSeekRequest = new DeepSeekRequest();
sessionManager.addUserMessage(sessionId, request.getMessage());
deepSeekRequest.setMessages(sessionManager.getHistory(sessionId));
try {
// 发送POST请求到Ollama
HttpPost httpPost = new HttpPost(OLLAMA_API_URL);
httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");
httpPost.setEntity(new StringEntity(objectMapper.writeValueAsString(deepSeekRequest)));
// 执行请求并解析响应
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
HttpEntity entity = response.getEntity();
if (entity != null) {
String responseBody = EntityUtils.toString(entity);
DeepSeekResponse deepSeekResponse = objectMapper.readValue(responseBody, DeepSeekResponse.class);
// 提取回复内容
String reply = deepSeekResponse.getMessages().get(0).getContent();
sessionManager.addAssistantMessage(sessionId, reply);
// 构建返回结果
ChatResponse chatResponse = new ChatResponse();
chatResponse.setReply(reply);
chatResponse.setSessionId(sessionId);
chatResponse.setTimestamp(System.currentTimeMillis());
return chatResponse;
}
}
} catch (Exception e) {
throw new RuntimeException("调用模型出错:" + e.getMessage());
}
return null;
}
}
5. 控制器:提供 HTTP 接口
最后写个控制器,前端就能通过接口调用了:
@RestController
@RequestMapping("/chatbot")
public class ChatController {
private final DeepSeekService deepSeekService;
public ChatController(DeepSeekService deepSeekService) {
this.deepSeekService = deepSeekService;
}
// 接收消息的接口
@PostMapping("/message")
public ResponseEntity<ChatResponse> sendMessage(@RequestBody ChatRequest request) {
try {
ChatResponse response = deepSeekService.processMessage(request);
return ResponseEntity.ok(response);
} catch (Exception e) {
return ResponseEntity.status(500).body(null);
}
}
// 清理会话的接口(可选)
@PostMapping("/clear/{sessionId}")
public ResponseEntity<Void> clearSession(@PathVariable String sessionId) {
sessionManager.clearHistory(sessionId);
return ResponseEntity.ok().build();
}
}
四、测试运行:用 curl 或 Postman 调用
-
先启动 Ollama 服务:
ollama serve
(后台运行) -
启动 Spring Boot 应用
-
用 curl 测试(也可以用 Postman):
第一次请求(没有sessionId,会自动生成)
curl -X POST http://localhost:8080/chatbot/message
-H "Content-Type: application/json"
-d '{"message":"什么是Spring Boot?"}'多轮对话(用第一次返回的sessionId)
curl -X POST http://localhost:8080/chatbot/message
-H "Content-Type: application/json"
-d '{"message":"它和Spring MVC有啥区别?", "sessionId":"第一次返回的ID"}'
返回的 JSON 里有reply
字段,就是机器人的回复啦。
五、踩坑指南:这些问题要注意
1. 模型响应慢?
- 检查显卡是否被用上:
nvidia-smi
看看有没有 Ollama 进程 - 换小模型:用 7B 代替 33B 版本
- 限制内存使用:
export OLLAMA_MAX_MEMORY=12GB
(根据自己内存调整)
2. 多轮对话记不住上下文?
- 一定传对 sessionId,每次对话都要用同一个
- 服务重启后,旧的 sessionId 会失效,需要重新获取
3. 中文乱码?
-
请求头加上
charset=UTF-8
(代码里已经加了,注意别删) -
配置 Jackson:
objectMapper.getFactory().configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true);
4. 内存溢出(OOM)?
- 给 Java 加内存:启动参数加
-Xmx4g
- 清理不活跃的会话:加个定时任务,删除几小时没动静的 session
动手试试吧,有问题可以在评论区交流~