网站首页 > 博客文章 正文
一般情况下,我们实现一个聊天(或客服)机器人,都会支持多轮聊天。能够记住之前的几轮对话,对使用者来说,体验就会好很多。例如这样的对话:
用户:你好,我叫leo
AI机器人:嗨,leo,有什么可以帮您的吗?
用户:我叫什么名字?
AI机器人:你叫Leo。
本文手把手教你用langchain4j来实现这样的记忆功能。
STEP0:基本环境准备和编程入门回顾,请参考我的AI文章系列:
AI编程之手把手教你在CentOS安装Postgresql的Vector向量数据库
AI编程之手把手教你使用postgresql向量数据库建设知识库JAVA版
AI编程之手把手教你使用langchain和postgresql向量库Python版
STEP1: 安装Postgresql+pgvector向量库
请参考我之前的文章: AI编程之手把手教你在CentOS安装Postgresql的Vector向量数据库
STEP2: 建表存放记忆内容
CREATE TABLE chat_memory (
memory_id INT NOT NULL PRIMARY KEY,
chat_messages TEXT NULL
);
STEP3: 实现一个基于postgresql的记忆存储
LangChain4j提出了ChatMemory的概念,它的本质是ChatMessage的容器。
ChatMemory是一个接口定义,它内部封装了一个ChatMessage的容器,提供了追加条目和清除记忆存储两个方法。
LangChain4j提供了两种ChatMemory实现:
- MessageWindowChatMemory提供了一种简单的文本化存储方式,按照条数存储,FIFO模式,如果超出条数,最老的一条被淘汰。注意,只能存储一条SystemMessage,如果加入另一条SystemMessage,前一条SystemMessage会被淘汰。
- TokenWindowChatMemory提供了token化的存储方式,按照token数量存储,FIFO模式,如果超出token数量,最老的一条消息将会被淘汰。注意,只能存储一条SystemMessage,如果加入另一条SystemMessage,前一条SystemMessage会被淘汰。
ChatMemoryStore定义了一个用来持久化ChatMemory里存储的信息。
定义了查询、更新、删除持久化数据的能力。
我们主要需要实现的是使用Postgresql做为持久化的ChatMemoryStore。代码如下:
//ChatMemory存储具体实现
@Slf4j
@Service
public class PersistentChatMemoryStore implements ChatMemoryStore {
@Resource
ChatMemoryMapper chatMemoryMapper;
@Override
public List<ChatMessage> getMessages(Object memoryId) {
ChatMemoryEntity chatMemoryEntity = chatMemoryMapper.queryForChatMemory((Integer)memoryId);
if(null == chatMemoryEntity){
return messagesFromJson(null);
}
return messagesFromJson(chatMemoryEntity.getChatMessages());
}
@Override
public void updateMessages(Object memoryId, List<ChatMessage> messages) {
String json = messagesToJson(messages);
ChatMemoryEntity chatMemoryEntity = new ChatMemoryEntity();
chatMemoryEntity.setMemoryId((Integer) memoryId);
chatMemoryEntity.setChatMessages(json);
ChatMemoryEntity chatMemoryEntity1 = chatMemoryMapper.queryForChatMemory((Integer)memoryId);
if (null == chatMemoryEntity1){
chatMemoryMapper.insertChatMemory(chatMemoryEntity);
}else {
chatMemoryMapper.updateChatMemory(chatMemoryEntity);
}
}
@Override
public void deleteMessages(Object memoryId) {
chatMemoryMapper.deleteForChatMemory((Integer)memoryId);
}
}
数据库Mapper代码:
@Mapper
public interface ChatMemoryMapper extends BaseMapper<ChatMemoryEntity> {
ChatMemoryEntity queryForChatMemory(Integer memoryId);
void updateChatMemory(@Param("chatMemoryEntity") ChatMemoryEntity chatMemoryEntity);
void insertChatMemory(@Param("chatMemoryEntity") ChatMemoryEntity chatMemoryEntity);
void deleteForChatMemory(Integer memoryId);
}
Mybatis配置代码:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.leo.llm.dao.ChatMemoryMapper">
<!-- 定义 ResultMap -->
<resultMap id="chatmemoryResultMap" type="org.leo.llm.entity.ChatMemoryEntity">
<id property="memoryId" column="memory_id" />
<result property="chatMessages" column="chat_messages" />
</resultMap>
<select id="queryForChatMemory" resultMap="chatmemoryResultMap">
SELECT a.memory_id , a.chat_messages
FROM chat_memory a WHERE a.memory_id = #{memoryId}
</select>
<update id="updateChatMemory" >
UPDATE chat_memory SET chat_messages = #{chatMemoryEntity.chatMessages}
WHERE memory_id = #{chatMemoryEntity.memoryId}
</update>
<insert id="insertChatMemory" >
insert into chat_memory (memory_id , chat_messages)
values (#{chatMemoryEntity.memoryId},#{chatMemoryEntity.chatMessages})
</insert>
<delete id="deleteForChatMemory" >
delete from chat_memory
where memory_id = #{chatMemoryEntity.memoryId}
</delete>
</mapper>
STEP4: 实现一个有记忆的聊天机器人
我们仍然使用AiServices快速包装产生聊天机器人。
public String chatWithMemory(Integer userId,String chatMessage) {
OpenAiChatModel chatModel = OpenAiChatModel.builder().baseUrl("https://oneapi.xty.app/v1")
.apiKey("sk-1234567890abcdef").modelName("gpt-3.5-turbo").build();
ChatMemoryProvider chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder()
.id(memoryId)
.maxMessages(10)
.chatMemoryStore(persistentChatMemoryStore)
.build();
LLMAssistant agent = AiServices.builder(LLMAssistant.class)
.chatLanguageModel(chatModel)
.chatMemoryProvider(chatMemoryProvider)
.build();
return agent.chat(userId,chatMessage);
}
STEP5: 运行起来看看效果
经过几次对话,我们看看历史记录:
我:我叫leo
AI机器人:你好,leo!有什么可以帮助你的吗?
我:我叫什么名字?
AI机器人:你叫Leo。
--把应用重启了一遍。重启之后
我:我叫什么名字?
AI机器人:你叫Leo。
Postgresql里也存入了记忆数据:
通过引入聊天历史,这个简单的聊天机器人具备了记忆能力。
STEP6: 后续
后续将使用Langchain和postgresql实现更多的CASE,敬请关注。
作者简介:
leo,互联网大厂AI架构师,欢迎私信交流
我的Dify AI case by case系列文章:
dify.ai 学习 case by case 第二弹,爆款小红书内容生成Agent
dify.ai 学习 case by case 第三弹,调用dify的API运行流程
猜你喜欢
- 2024-10-23 Langchain发布Agent IDE,不同Dify/Coze设计理念,能否得开发者认可
- 2024-10-23 Langchain发布AgentIDE不同DifyCoze设计理念能否得开发者认可
- 2024-10-23 AI的开源助手API和GPT的替代方案,Dify.AI一个LLMOps平台
- 2024-10-23 Dify 大语言模型应用开发平台本地化部署
- 2024-10-23 利用开源Dify+ollama构建本地智能体
- 2024-10-23 Dify Release 0.7.2更新(附Ubuntu + Ollama + Dify教程)
- 2024-10-23 【Python大语言模型系列】云服务器部署dify大模型应用开发平台
- 2024-10-23 Dify Release v0.8.0更新!内有Ubuntu + Ollama + Dify全套教程
- 2024-10-23 Dify Release 0.7.1重磅更新(附Ubuntu + Ollama + Dify 0.6.16教程)
- 2024-10-23 ChatGPT+工作流自动化处理复杂任务 | Dify工作流完整教学 | 比肩Coze
你 发表评论:
欢迎- 最近发表
-
- 比GoPro 13更强的大疆Action 5 Pro,到底强在哪里?
- 信号和槽(信号和槽的实现原理)
- 在响应式项目中连接设计与开发(请简述实现响应式设计包括哪些技术点)
- 【C#】委托、Action、Func 和 Event 之间的关系
- 如何使用JavaScript实现Prompt弹窗?
- 谷歌Magic Actions功能曝光:AI革新安卓16通知交互
- 基于目标TPS的性能测试,如何通过手动设置场景进行测试?
- IOS基础学习之输出口和动作(io口输入输出实验总结及体会)
- 《Java语言程序设计》期末考试模拟试题——判断题和问答题
- Android学习之Touch事件的处理(android触摸事件实例)
- 标签列表
-
- powershellfor (55)
- messagesource (56)
- aspose.pdf破解版 (56)
- promise.race (63)
- 2019cad序列号和密钥激活码 (62)
- window.performance (66)
- qt删除文件夹 (72)
- mysqlcaching_sha2_password (64)
- ubuntu升级gcc (58)
- nacos启动失败 (64)
- ssh-add (70)
- jwt漏洞 (58)
- macos14下载 (58)
- yarnnode (62)
- abstractqueuedsynchronizer (64)
- source~/.bashrc没有那个文件或目录 (65)
- springboot整合activiti工作流 (70)
- jmeter插件下载 (61)
- 抓包分析 (60)
- idea创建mavenweb项目 (65)
- vue回到顶部 (57)
- qcombobox样式表 (68)
- vue数组concat (56)
- tomcatundertow (58)
- pastemac (61)
本文暂时没有评论,来添加一个吧(●'◡'●)