第7课:管理长期记忆的关键架构决策 - 学习笔记_7

第7课:管理长期记忆的关键架构决策 - 学习笔记

📚 课程核心主题

本节课通过实际代码演示,深入讲解管理长期记忆的关键架构决策,包括生产环境中的注意事项、thread_id的动态生成、用户偏好的存储和检索等核心实现细节。


🎯 第一部分:生产环境中的关键问题

问题1:thread_id不能写死

问题背景

演示场景:

  • 代码中写死了 thread_id = 1
  • 所有对话都使用同一个thread_id
  • 导致所有消息都混在一起

实际生产中的问题:

  • ❌ 每个用户都应该有独立的会话
  • ❌ thread_id必须动态生成
  • ❌ 不能所有用户共享同一个thread_id

正确的做法

是什么:

  • thread_id 应该像 session_id 一样
  • 每次新建会话时,动态生成新的thread_id
  • 每个会话都有唯一的标识

代码示例:

python 复制代码
# ❌ 错误做法:写死thread_id
thread_id = "1"  # 所有用户都用这个

# ✅ 正确做法:动态生成
import uuid
thread_id = str(uuid.uuid4())  # 每次生成新的唯一ID
# 或者
thread_id = generate_session_id()  # 自定义生成函数

类比理解:

  • 就像Web开发中的session_id
  • 每个用户登录后,都会生成一个新的session_id
  • 不同用户的session_id是不同的
  • thread_id也是一样的道理

问题2:消息加载的问题

演示场景分析

场景:

  • 使用写死的 thread_id = 1
  • 消息累积到了17条
  • 每次新对话都会加载所有17条消息

问题:

  • ❌ 在实际生产中,会不会出现加载17条消息的情况?
  • ❌ 如果thread_id是动态生成的,就不会有这个问题

答案:

  • :如果thread_id写死,就会加载所有消息
  • 不会:如果thread_id动态生成,新会话就是全新的,不会加载旧消息

关键理解:

  • 动态生成thread_id后,每个新会话都是独立的
  • 不会加载之前会话的消息
  • 这是正常且正确的行为

💾 第二部分:长期记忆的存储和检索实现

存储用户偏好

步骤1:提取用户偏好信息

是什么:

  • 从用户的输入中提取偏好信息
  • 可以使用AI模型自动提取
  • 也可以手动提取

代码示例:

python 复制代码
# 从用户输入中提取偏好
user_input = "我要预订酒店,需要有窗户,有WIFI"

# 提取偏好信息
preferences = {
    "住宿偏好": "有窗户,有WIFI",
    "用户姓名": "KEVIN"
}

关键点:

  • 偏好信息可以是结构化的数据
  • 可以包含多个字段
  • 需要根据业务需求设计数据结构

步骤2:存储到长期记忆

是什么:

  • 使用 store.put() 方法存储用户偏好
  • 基于 user_id 存储,不是 thread_id
  • 存储到数据库的 store 表中

代码示例:

python 复制代码
from langgraph.checkpoint.postgres import PostgresStore

# 创建store实例
store = PostgresStore.from_conn_string(connection_string)

# 存储用户偏好
store.put(
    user_id="1",  # 用户ID,不是thread_id
    data={
        "住宿偏好": "有窗户,有WIFI"
    }
)

数据库变化:

  • 执行后,数据库中的 store 表会新增记录
  • 每条记录对应一个偏好项
  • 可以通过 user_id 查询

关键点:

  • ✅ 使用 user_id,不是 thread_id
  • ✅ 可以存储多条记录
  • ✅ 每条记录都是独立的

检索用户偏好

步骤1:从长期记忆中检索

是什么:

  • 使用 store.search() 方法检索用户偏好
  • 根据 user_id 检索
  • 返回该用户的所有偏好信息

代码示例:

python 复制代码
# 检索用户偏好
preferences = store.search(
    user_id="1"  # 根据用户ID检索
)

# 返回结果可能是:
# [
#     {"住宿偏好": "有窗户,有WIFI"},
#     {"用户姓名": "KEVIN"}
# ]

关键点:

  • 检索是基于 user_id
  • 返回的是该用户的所有偏好
  • 可能返回多条记录

步骤2:应用偏好到当前任务

是什么:

  • 将检索到的偏好应用到当前任务中
  • 在AI生成回复时,包含偏好信息
  • 让AI知道用户的个性化需求

实际流程:

复制代码
用户:"帮我预订酒店"
    ↓
检索长期记忆(store.search)
    ↓
找到偏好:"有窗户,有WIFI"
    ↓
将偏好信息传递给AI
    ↓
AI生成回复:"已成功为您预订了汉庭酒店,并确保房间有窗户和WIFI"

🔄 第三部分:跨会话使用长期记忆

实际演示场景

场景设置

会话1(thread_id = 4):

  • 用户:"我要预订酒店,需要有窗户,有WIFI"
  • 系统提取偏好并存储到长期记忆
  • 数据库中的 store 表新增2条记录

会话2(thread_id = 5,新会话):

  • 用户:"帮我预订酒店"
  • 系统从长期记忆中检索用户偏好
  • 检索到:"有窗户,有WIFI"
  • AI回复:"已成功为您预订了汉庭酒店,并确保房间有窗户和WIFI"

关键验证点

验证1:thread_id不同,但能检索到偏好

  • ✅ thread_id从4变成5(新会话)
  • ✅ 但user_id没变(还是1)
  • ✅ 仍然能检索到之前存储的偏好

验证2:长期记忆的跨会话特性

  • ✅ 即使关闭了会话1
  • ✅ 开启新的会话2
  • ✅ 偏好信息仍然存在

验证3:让AI更懂你

  • ✅ 不管什么时候预订酒店
  • ✅ 都会自动应用用户的偏好
  • ✅ 实现了个性化的用户体验

🎯 第四部分:架构决策的关键点

决策1:thread_id vs user_id

thread_id(线程ID):

  • 用于短期记忆(Checkpointer)
  • 每个会话都有独立的thread_id
  • 会话关闭后,可以丢弃

user_id(用户ID):

  • 用于长期记忆(Store)
  • 同一个用户的所有会话共享同一个user_id
  • 跨会话持久保存

关键理解:

  • 短期记忆 = thread_id级别
  • 长期记忆 = user_id级别
  • 两者配合使用,实现完整的记忆系统

决策2:存储时机

什么时候存储长期记忆?

  • ✅ 用户明确表达偏好时
  • ✅ AI识别到用户偏好时
  • ✅ 用户确认设置时

什么时候检索长期记忆?

  • ✅ 每次对话开始时
  • ✅ 需要个性化服务时
  • ✅ 执行相关任务前

关键点:

  • 存储和检索的时机很重要
  • 需要根据业务场景设计
  • 避免过度检索,影响性能

决策3:数据结构设计

用户偏好应该存储什么?

  • 个人基本信息(姓名、联系方式等)
  • 业务偏好(住宿偏好、出行偏好等)
  • 历史行为(浏览记录、购买记录等)

数据结构示例:

python 复制代码
{
    "user_id": "1",
    "preferences": {
        "住宿偏好": "有窗户,有WIFI",
        "出行偏好": "商务舱",
        "饮食偏好": "素食"
    },
    "metadata": {
        "created_at": "2024-01-01",
        "updated_at": "2024-01-15"
    }
}

关键点:

  • 数据结构要灵活
  • 支持扩展
  • 便于检索和更新

💡 关键概念总结

概念 简单理解
thread_id动态生成 每次新建会话时生成新的唯一ID,不能写死
user_id 用户标识,用于长期记忆的区分,跨会话使用
store.put() 存储用户偏好到长期记忆的方法
store.search() 从长期记忆中检索用户偏好的方法
跨会话特性 长期记忆可以在不同会话之间共享
个性化服务 通过长期记忆实现"让AI更懂你"的目标

❓ 思考题

  1. 为什么生产环境中thread_id不能写死?

    • 答:因为每个用户都应该有独立的会话。如果写死thread_id,所有用户会共享同一个会话,导致消息混乱。thread_id应该像session_id一样,每次新建会话时动态生成。
  2. 如何实现跨会话的用户偏好?

    • 答:使用长期记忆(Store),将用户偏好存储到数据库中,基于user_id而不是thread_id。这样无论用户开启多少个新会话,都能通过user_id检索到之前存储的偏好信息。
  3. store.put()和store.search()的区别是什么?

    • 答:store.put()用于存储用户偏好到长期记忆,需要提供user_id和数据;store.search()用于从长期记忆中检索用户偏好,根据user_id检索,返回该用户的所有偏好信息。
  4. 短期记忆和长期记忆在标识上的区别?

    • 答:短期记忆使用thread_id(线程ID)区分不同会话,每个会话都有独立的thread_id;长期记忆使用user_id(用户ID)区分不同用户,同一个用户的所有会话共享同一个user_id。
  5. 如何让AI更懂用户?

    • 答:通过长期记忆存储用户的偏好和历史行为,在每次对话时检索这些信息,让AI能够根据用户的个性化需求提供服务,实现"让AI更懂你"的目标。

📌 本节课重点回顾

生产环境注意: thread_id必须动态生成,不能写死,每个会话都应该有独立的标识

长期记忆存储: 使用store.put()存储用户偏好,基于user_id,可以存储多条记录

长期记忆检索: 使用store.search()检索用户偏好,根据user_id检索,返回该用户的所有偏好

跨会话特性: 长期记忆可以在不同会话之间共享,实现个性化的用户体验

架构决策: thread_id用于短期记忆,user_id用于长期记忆,两者配合使用


笔记整理时间:2024年
建议:理解thread_id和user_id的区别是构建生产级AI系统的关键,需要通过实际代码演示加深理解

相关推荐
koo3642 小时前
pytorch深度学习笔记15
pytorch·笔记·深度学习
爱装代码的小瓶子2 小时前
【c++进阶】c++11下类的新变化以及Lambda函数和封装器
java·开发语言·c++
乌萨奇也要立志学C++2 小时前
【Linux】线程同步 条件变量精讲 + 生产者消费者模型完整实现
java·linux·运维
澄澈青空~2 小时前
病毒木马侵入系统内核的底层运作机理
java·linux·服务器
FAFU_kyp2 小时前
Rust 所有权(Ownership)学习
开发语言·学习·rust
2501_942326442 小时前
科学开发大脑潜能,提升学习效率
学习
lkbhua莱克瓦242 小时前
进阶-存储对象2-存储过程上
java·开发语言·数据库·sql·mysql
杨杨杨大侠2 小时前
深入理解 LLVM:从编译器原理到 JIT 实战
java·jvm·编译器
deng-c-f2 小时前
Linux C/C++ 学习日记(60):redis(一):基本介绍
学习