尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Java RAG 实战(第 3 篇):从交互式聊天到多轮上下文

Java RAG 实战(第 3 篇):从交互式聊天到多轮上下文 系列导航所属专栏《Java 开发者从零实现 RAG 知识库》学习位置第 3 篇 / 共 12 篇上一篇《第2篇Java 调用 Ollama 并解析响应》下一篇《第4篇System Prompt 与模型参数》本篇先把写死的问题改为终端输入再在 Java 中保存 user 与 assistant 消息让连续提问从“多次独立请求”升级为真正的多轮对话。完成进度1. 从终端连续读取用户问题2. 用 Java 对象安全生成请求 JSON3. 使用exit正常结束程序4. 在 Java List 中保存完整对话历史5. 验证第二轮能够理解第一轮6. 使用clear清空当前上下文为什么要学可交互和有上下文是聊天程序的两个连续层次终端循环解决“怎样反复提问”消息列表解决“怎样让下一轮知道上一轮”。放在同一篇更容易看出两版请求中messages的差异。第一阶段实现交互式聊天上一版的问题写在源代码中每换一个问题都需要修改和重新编译。交互式程序把“程序逻辑”和“用户输入”分开是从接口演示走向可用应用的第一步。本篇目标从终端读取问题。连续调用 Ollama。输入空行时继续等待。输入exit时正常退出。使用 Java 对象生成 JSON避免输入中的引号破坏请求格式。为什么使用 Java 对象生成 JSON如果直接把用户输入拼进 JSON 字符串下面的问题可能造成格式错误请解释 RAG这一版定义ChatRequest和ChatMessage再由 Jackson 的writeValueAsString负责正确转义。对应源码01-ollama-basics/src/main/java/com/example/ai/step03/InteractiveChat.java终端循环的关键代码如下try(ScannerscannernewScanner(System.in,StandardCharsets.UTF_8)){while(true){System.out.print(你);if(!scanner.hasNextLine()){break;}Stringquestionscanner.nextLine().trim();if(question.equalsIgnoreCase(exit)){break;}if(question.isEmpty()){continue;}StringansweraskOllama(client,objectMapper,question);System.out.println(AIanswer\n);}}每一轮只产生一个当前问题再交给askOllama()。请求对象也只包含这一条user消息ChatRequestchatRequestnewChatRequest(MODEL,List.of(newChatMessage(user,question)),false,false);StringrequestBodyobjectMapper.writeValueAsString(chatRequest);这解释了两个现象程序可以反复提问是因为while循环一直读取输入模型不能理解上一轮是因为每次messages中只有当前问题。stream和think请求中暂时设置stream false think falsestream: false等待完整回答后一次显示。think: false关闭 Qwen3 的深度思考输出提高基础聊天速度。后面的迭代会单独学习流式输出和模型参数。运行mvn-f01-ollama-basics/pom.xml compile exec:java\-Dexec.mainClasscom.example.ai.step03.InteractiveChat输入一个问题例如请用一句话解释 Embedding结束程序exit成功标准程序可以连续接受问题每次都显示模型回答并在输入exit后输出“对话已结束”。当前限制每次请求只发送当前问题。模型不会自动知道上一轮问了什么下一篇将通过保存消息列表解决这个问题。第二阶段加入多轮对话上下文聊天接口通常是无状态的模型只知道本次请求中携带的消息不会自动记住 Java 程序上一次发送的内容。如果第一轮问“Java 17 有什么特点”第二轮只问“它和 21 有什么区别”模型必须同时收到第一轮消息才能知道“它”指的是 Java 17。消息角色对话历史由按顺序排列的消息组成user: Java 17 有什么特点 assistant: Java 17 是…… user: 它和 21 有什么区别user表示用户输入。assistant表示模型之前的回答。后面还会学习用于规定模型身份和行为的system。Java 如何保存上下文程序创建一个消息列表ListChatMessageconversationnewArrayList();每轮执行以下流程把用户问题加入 conversation - 把完整 conversation 发给 Ollama - 得到模型回答 - 把模型回答加入 conversation如果请求失败程序会移除刚加入的用户问题避免留下没有对应回答的不完整历史。对应源码01-ollama-basics/src/main/java/com/example/ai/step04/ContextChat.java关键逻辑是ListChatMessageconversationnewArrayList();conversation.add(newChatMessage(user,question));Stringanswer;try{// 每轮发送的是完整 conversation不是只发当前问题。answeraskOllama(client,objectMapper,conversation);}catch(Exceptionexception){// 失败时撤回本轮 user 消息避免留下残缺历史。conversation.remove(conversation.size()-1);throwexception;}// 成功后才保存 assistant 回答。conversation.add(newChatMessage(assistant,answer));这段代码就是“多轮记忆”的真相记忆在 Java 的List中Ollama 每次只处理本次请求收到的消息。清空上下文在终端输入clearJava 会执行conversation.clear()。这只清空当前程序内存中的聊天记录不会删除模型或停止 Ollama。运行和验证mvn-f01-ollama-basics/pom.xml compile exec:java\-Dexec.mainClasscom.example.ai.step04.ContextChat依次输入请记住今天的测试词是蓝色。 我刚才让你记住的测试词是什么如果第二轮回答“蓝色”就说明上下文已经生效。再输入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 协议可自由学习与二次创作。
返回列表