系列导航
- 所属专栏:《Java 开发者从零实现 RAG 知识库》
- 学习位置:第 3 篇 / 共 12 篇
- 上一篇:《第2篇:Java 调用 Ollama 并解析响应》
- 下一篇:《第4篇:System Prompt 与模型参数》
本篇先把写死的问题改为终端输入,再在 Java 中保存 user 与 assistant 消息,让连续提问从"多次独立请求"升级为真正的多轮对话。
完成进度
- 1. 从终端连续读取用户问题
- 2. 用 Java 对象安全生成请求 JSON
- 3. 使用
exit正常结束程序 - 4. 在 Java List 中保存完整对话历史
- 5. 验证第二轮能够理解第一轮
- 6. 使用
clear清空当前上下文
为什么要学
可交互和有上下文是聊天程序的两个连续层次:终端循环解决"怎样反复提问",消息列表解决"怎样让下一轮知道上一轮"。放在同一篇更容易看出两版请求中 messages 的差异。
第一阶段:实现交互式聊天
上一版的问题写在源代码中,每换一个问题都需要修改和重新编译。交互式程序把"程序逻辑"和"用户输入"分开,是从接口演示走向可用应用的第一步。
本篇目标
- 从终端读取问题。
- 连续调用 Ollama。
- 输入空行时继续等待。
- 输入
exit时正常退出。 - 使用 Java 对象生成 JSON,避免输入中的引号破坏请求格式。
为什么使用 Java 对象生成 JSON
如果直接把用户输入拼进 JSON 字符串,下面的问题可能造成格式错误:
text
请解释 "RAG"
这一版定义 ChatRequest 和 ChatMessage,再由 Jackson 的 writeValueAsString 负责正确转义。
对应源码:
text
01-ollama-basics/src/main/java/com/example/ai/step03/InteractiveChat.java
终端循环的关键代码如下:
java
try (Scanner scanner = new Scanner(System.in, StandardCharsets.UTF_8)) {
while (true) {
System.out.print("你:");
if (!scanner.hasNextLine()) {
break;
}
String question = scanner.nextLine().trim();
if (question.equalsIgnoreCase("exit")) {
break;
}
if (question.isEmpty()) {
continue;
}
String answer = askOllama(client, objectMapper, question);
System.out.println("AI:" + answer + "\n");
}
}
每一轮只产生一个当前问题,再交给 askOllama()。请求对象也只包含这一条 user 消息:
java
ChatRequest chatRequest = new ChatRequest(
MODEL,
List.of(new ChatMessage("user", question)),
false,
false
);
String requestBody = objectMapper.writeValueAsString(chatRequest);
这解释了两个现象:程序可以反复提问,是因为 while 循环一直读取输入;模型不能理解上一轮,是因为每次 messages 中只有当前问题。
stream 和 think
请求中暂时设置:
text
stream = false
think = false
stream: false:等待完整回答后一次显示。think: false:关闭 Qwen3 的深度思考输出,提高基础聊天速度。
后面的迭代会单独学习流式输出和模型参数。
运行
bash
mvn -f 01-ollama-basics/pom.xml compile exec:java \
-Dexec.mainClass=com.example.ai.step03.InteractiveChat
输入一个问题,例如:
text
请用一句话解释 Embedding
结束程序:
text
exit
成功标准
程序可以连续接受问题,每次都显示模型回答,并在输入 exit 后输出"对话已结束"。
当前限制
每次请求只发送当前问题。模型不会自动知道上一轮问了什么,下一篇将通过保存消息列表解决这个问题。
第二阶段:加入多轮对话上下文
聊天接口通常是无状态的:模型只知道本次请求中携带的消息,不会自动记住 Java 程序上一次发送的内容。
如果第一轮问"Java 17 有什么特点",第二轮只问"它和 21 有什么区别",模型必须同时收到第一轮消息才能知道"它"指的是 Java 17。
消息角色
对话历史由按顺序排列的消息组成:
text
user: Java 17 有什么特点?
assistant: Java 17 是......
user: 它和 21 有什么区别?
user表示用户输入。assistant表示模型之前的回答。- 后面还会学习用于规定模型身份和行为的
system。
Java 如何保存上下文
程序创建一个消息列表:
java
List<ChatMessage> conversation = new ArrayList<>();
每轮执行以下流程:
text
把用户问题加入 conversation
-> 把完整 conversation 发给 Ollama
-> 得到模型回答
-> 把模型回答加入 conversation
如果请求失败,程序会移除刚加入的用户问题,避免留下没有对应回答的不完整历史。
对应源码:
text
01-ollama-basics/src/main/java/com/example/ai/step04/ContextChat.java
关键逻辑是:
java
List<ChatMessage> conversation = new ArrayList<>();
conversation.add(new ChatMessage("user", question));
String answer;
try {
// 每轮发送的是完整 conversation,不是只发当前问题。
answer = askOllama(client, objectMapper, conversation);
} catch (Exception exception) {
// 失败时撤回本轮 user 消息,避免留下残缺历史。
conversation.remove(conversation.size() - 1);
throw exception;
}
// 成功后才保存 assistant 回答。
conversation.add(new ChatMessage("assistant", answer));
这段代码就是"多轮记忆"的真相:记忆在 Java 的 List 中,Ollama 每次只处理本次请求收到的消息。
清空上下文
在终端输入:
text
clear
Java 会执行 conversation.clear()。这只清空当前程序内存中的聊天记录,不会删除模型或停止 Ollama。
运行和验证
bash
mvn -f 01-ollama-basics/pom.xml compile exec:java \
-Dexec.mainClass=com.example.ai.step04.ContextChat
依次输入:
text
请记住:今天的测试词是蓝色。
我刚才让你记住的测试词是什么?
如果第二轮回答"蓝色",就说明上下文已经生效。
再输入:
text
clear
程序应提示"上下文已清空"。输入 exit 结束。
上下文不是永久记忆
当前消息只保存在 Java 进程的内存中:
- 退出程序后记录消失。
- 历史越长,请求携带的 Token 越多。
- 超过模型上下文窗口后,需要截断、摘要或持久化管理。
后面构建完整应用时会逐步处理这些问题。
本篇自测
- 为什么不应把终端输入直接拼进 JSON 字符串?
- 交互式程序为什么能连续提问,却仍然不理解上一轮?
- 多轮聊天为什么必须同时保存 user 和 assistant 消息?
- 请求失败时为什么要撤回刚加入的用户消息?
- 退出程序后上下文为什么会消失?
参考答案:输入中的引号和换行可能破坏 JSON;每次只发送当前问题;完整问答共同构成后续语境;避免留下没有对应回答的残缺历史;消息只保存在当前 Java 进程内存中。
本篇小结
Scanner和循环让同一个 Java 程序可以反复接受问题。- Java 对象配合 Jackson 可以安全生成包含用户输入的 JSON。
- 模型不会自动记住历史,多轮上下文依靠 Java 维护并重复发送完整消息列表。
clear只清除当前进程内存中的对话,不会删除模型或 Ollama 数据。
下一篇
👉 本专栏下一篇:《第4篇:System Prompt 与模型参数》
完整代码都在 GitHub(欢迎 Star ⭐)
本专栏的全部示例代码都已开源,包含 5 个可独立运行的 Maven 模块、自动化测试和完整分篇教程。建议 Fork / Clone 下来,边读边跑:
🔗 https://github.com/bysbsh/ai-rag-learning-guide
- 代码与教程同步更新,对照每一篇动手实践效果最好。
- 如果这份教程帮到了你,点个 Star 就是对我最大的支持,也方便你之后找回最新版本。
- 遇到问题或发现错漏,欢迎在仓库提 Issue / PR。项目采用 MIT 协议,可自由学习与二次创作。