我把「记忆」接入了「小爱」,成功搞定多轮对话!

向量数据库大模型关系型数据库

猴哥的第 105 期分享,欢迎追看

前段时间,搞了个微信 AI 小助理-小爱(AI),爸妈玩的不亦乐乎。

目前小爱(AI)仍在持续迭代中,受到了很多粉丝朋友的关注,故新建了一个体验群,邀请大家免费体验。

最近收到了很多需求和反馈,人力有限,只能按照优先级进行安排。

最近,把文生图的能力接入了进来:

不过,每次都要输入完整提示词,要让它基于生成图片进行调整,就搞不赢了👇

picture.image

因为:目前小爱只支持单轮对话,没有上下文信息,它怎能听懂你在说什么呢

这个需求刚的很,必须尽快安排上!

前两天,已经在开发板上把记忆功能给机器人加上了:

基本思路是一致的,但实操起来,发现差别还挺大。。。

今日分享,带大家实操:利用本地数据库,为小爱接入记忆功能 ,实现多轮对话

  1. 数据库实现

本次实现,数据库依然选用 SQLite,自己玩完全足够。

1.1 数据表结构设计

和上篇语音对话机器人不一样,微信中的聊天记录分为:私聊群聊两种,二者的对话逻辑不完全一样,所以最好解耦开。

原打算放在一个消息表中,后面发现逻辑较为复杂,所以最终实现方案:一张用户表+两张消息表

用户表:用于存放用户相关信息;

  
class User(Base):  
    __tablename__ = 'users'  
    id = Column(Integer, primary_key=True, index=True)  
    uid = Column(String, index=True)  # id 字段,唯一标识,建立索引  
    name = Column(String, index=True) # name 字段,建立索引  
    alias = Column(String) # 备注名  
  
    room_messages = relationship("RoomMessage", back_populates="user", cascade="all, delete-orphan")  
    single_messages = relationship("SingleMessage", back_populates="user", cascade="all, delete-orphan")  

群聊消息表:通过uid和用户表进行关联,存放群聊消息;

  
class RoomMessage(Base):  
    __tablename__ = 'room\_messages'  
    id = Column(Integer, primary_key=True, index=True)  # 自增主键  
    uid = Column(String, ForeignKey('users.uid', ondelete='CASCADE'), index=True)  # 外键关联 uid  
    uname = Column(String)  # 发送方 name  
    room_name = Column(String, index=True)  # 群名  
    content = Column(String)  # 文本内容  
    timestamp = Column(String)  # 时间戳  
  
    user = relationship("User", back_populates="room\_messages")  

私聊消息表:通过uid和用户表进行关联,存放私聊消息;

  
class SingleMessage(Base):  
    __tablename__ = 'single\_messages'  
    id = Column(Integer, primary_key=True, index=True)  # 自增主键  
    uid = Column(String, ForeignKey('users.uid', ondelete='CASCADE'), index=True)  # 发送方 uid  
    uname = Column(String)  # 发送方 name  
    to_name = Column(String, index=True)  # 接收方 name  
    content = Column(String)  # 文本内容  
    timestamp = Column(String)  # 时间戳  
  
    user = relationship("User", back_populates="single\_messages")  

1.2 定义请求体模型

上一步定义的数据库模型,用于与数据库交互。

接下来,还需定义请求体模型,用于描述和验证 FastAPI 中接收到的数据。

比如,对应 User 的Pydantic 模型,定义如下:

  
class UserCreate(BaseModel):  
    uid: str = Field(..., description="user ID,required")  
    name: str = Field(default="", description="name")  
    alias: str = Field(default="", description="alias")  

1.3 实现增删改查

接下来,实现用户表消息表增删改查的基本功能。

比如要实现用户新增:

  
@app.post("/users/", response_model=UserCreate)  
def add_user(user: UserCreate, db: Session = Depends(get_db)):  
    # 先查询是否存在该用户  
    db_user = db.query(User).filter(User.uid == user.uid).first()  
    if not db_user:  
        db_user = User(uid=user.uid, name=user.name, alias=user.alias)  
        db.add(db_user)  
    else:  
        db_user.name = user.name  
        db_user.alias = user.alias  
    db.commit()  
    db.refresh(db_user)  
    return db_user  

实现群聊消息新增:

  
@app.post("/messages/room/", response_model=RoomMessageCreate)  
def add_message_room(message: RoomMessageCreate, db: Session = Depends(get_db)):  
    db_message = RoomMessage(uid=message.uid, uname=message.uname, room_name=message.room_name, content=message.content, timestamp=message.timestamp)  
    db.add(db_message)  
    db.commit()  
    db.refresh(db_message)  
    return db_message  

基本功能实现后,就可以参考上篇教程,启动数据库服务端。

  1. 多轮对话实现

多轮对话的核心就是接入数据库,从库中检索到一段时间内的聊天记录,统一送给大模型进行答复。

所以,在原来应用的基础上,主要有三点改造:

  • 新增好友信息
  • 新增聊天记录
  • 检索聊天记录

我们来一一搞定它!

2.1 新增好友信息接口

当有好友发消息后,首先需要将用户信息更新到用户表中,为此可以编写一个接口函数,去请求数据库:

  
def add_user(payload): # source['from']['payload']  
    response = requests.post(f"{db\_base\_url}/users/", json={  
        "uid": payload['id'],  
        "name": payload['name'],  
        "alias": payload['alias']  
    })  
    if response.status_code == 200:  
        logger.info(f"Add/update user {payload['name']} into user table")  
    else:  
        logger.error(f"Failed to add user {payload['name']} into user table, {response.text}")  

2.2 新增聊天记录

当有用户消息过来时,需要将其保存到数据库中:

  
def add_message_room(uid, uname, room_name, content, timestamp):  
    response = requests.post(f"{db\_base\_url}/messages/room/", json={  
        "uid": uid,  
        "uname": uname,  
        "room\_name": room_name,  
        "content": content,  
        "timestamp": timestamp,  
    })  
    if response.status_code == 200:  
        logger.info(f"Add message {content} from {uname} into message table")  
    else:  
        logger.error(f"Failed to add message {content} from {uname} into message table, {response.text}")  

2.3 检索聊天记录

在大模型回答之前,需要从数据库中检索到相关聊天记录:

  
def get_message_room(uid='', room_name='', limit=6, start_time='', end_time=''):  
    param = {  
        "uid": uid,  
        "room\_name": room_name,  
        "limit": limit,  
        "start\_time": start_time,  
        "end\_time": end_time  
    }  
    response = requests.get(f"{db\_base\_url}/messages/room/", params=param)  
    if response.status_code == 200:  
        return response.json()  
    else:  
        return []  

最后,把以上功能嵌入到原有对话流程中,测试成功,就可以上线啦。

2.4 效果展示

还是本文开头的例子:

picture.image

从润色提示词上可以发现,已经把实现了我要重绘的细节 wearing an official hat。不过,从结果来看,绘画模型怕是不知道王阳明是明朝的吧

最后,我们来看下日志:

picture.image

再看一个连续对话的例子:

picture.image

我问他清朝有和王阳明齐名的思想家么,你看,对阳明先生的认知还是相当到位的。

写在最后

本文通过数据库接入,成功为小爱接入了多轮对话能力。

如果对你有帮助,不妨点赞 收藏 备用。

大家有更好的想法,欢迎来聊👇


为方便大家交流,新建了一个 AI 交流群,欢迎感兴趣的小伙伴加入。

小爱也在群里,公众号后台「联系我」,拉你进群。

👇 关注猴哥,快速入门AI工具

picture.image

# AI 工具:

本地部署大模型?看这篇就够了,Ollama 部署和实战

盘点9家免费且靠谱的AI大模型 API,统一封装,任性调用!

# AI应用** :**

弃坑 Coze,我把 Dify 接入了个人微信,AI小助理太强了

我把「FLUX」接入了「小爱」,微信直接出图,告别一切绘画软件!

# 效率工具:

电脑微信双开/多开?两种方法任你挑,1分钟搞定

装什么虚拟机,Oracle Cloud 永久免费云主机不香?附配置指南!

0
0
0
0
关于作者

文章

0

获赞

0

收藏

0

相关资源
字节跳动 NoSQL 的实践与探索
随着 NoSQL 的蓬勃发展越来越多的数据存储在了 NoSQL 系统中,并且 NoSQL 和 RDBMS 的界限越来越模糊,各种不同的专用 NoSQL 系统不停涌现,各具特色,形态不一。本次主要分享字节跳动内部和火山引擎 NoSQL 的实践,希望能够给大家一定的启发。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论