找回密码
 立即注册
首页 业界区 业界 AI开发-python-langchain框架(3-19-智能问答-保留会话 ...

AI开发-python-langchain框架(3-19-智能问答-保留会话历史)

栓州 6 小时前
基于RunnableWithMessageHistory实现多会话隔离与持久化记忆

在构建LLM对话应用时,多会话隔离与对话历史持久化是从demo走向生产级的关键。本文基于ReAct智能体实践,拆解RunnableWithMessageHistory的会话隔离实现,及可扩展的数据库持久化方案,助力快速落地稳定对话应用。一、核心需求:为什么需要会话隔离与持久化记忆?

LLM本身无状态,无法记住历史交互,实际应用中需解决两个核心问题:  1. 多用户会话隔离:确保不同用户对话互不干扰,每个用户拥有独立“记忆空间”;  2. 对话历史持久化:保障服务重启后历史不丢失,用户可跨会话续聊,无需重复说明背景。二、实践核心:用RunnableWithMessageHistory实现多会话隔离

RunnableWithMessageHistory是会话管理核心工具,可自动关联历史、注入提示词,简化开发,核心逻辑如下:  1. 分配唯一会话ID(session_id),作为区分不同会话的核心标识;  2. 用户发起对话时,传入session_id,工具自动读取对应历史,填充至提示词{chat_history}占位符;  3. 对话结束后,自动将新消息(用户输入+AI回复)追加至对应会话历史,实现记忆延续。优势:开发者无需关注历史拼接、存储逻辑,可专注智能体核心功能开发。三、扩展升级:对话历史持久化(数据库落地方案)

基础场景的字典内存存储,重启服务会丢失数据,需替换为持久化数据库,核心是修改会话历史获取函数,适配不同存储场景。(一)主流持久化方案选型

根据业务场景灵活选择,无需局限单一方案:  1. Redis:适配高并发、低延迟场景(如在线客服),读写快、支持过期策略,通过langchain-redis快速集成;  2. 关系型数据库(PostgreSQL/MySQL):适配数据安全、需审计场景(如企业内部系统),支持事务,通过langchain-community集成;  3. SQLite:适配小型应用、本地部署/测试,轻量无独立服务,快速落地降低成本;  4. MongoDB:适配非结构化数据场景(如多模态对话),文档型存储,通过langchain-mongodb集成。(二)持久化通用实现步骤

所有方案流程一致,可直接复用:  1. 安装对应存储依赖包,确保环境齐全;  2. 重写会话历史获取函数:根据session_id从数据库查询,无记录则初始化并写入;  3. 将新函数传入RunnableWithMessageHistory,替换内存存储逻辑;  4. 配置存储连接参数(地址、端口等),适配生产环境。(三)持久化核心设计要点

避免数据混乱、性能瓶颈,需注意4点:  1. 会话与消息映射:通过session_id关联,保持消息时间顺序,还原完整对话;  2. 异常处理:数据库连接失败时,降级为内存存储,保障服务可用并记录日志;  3. 数据清理:设置会话过期策略(如30天未活跃删除),支持用户主动删除,符合合规;  4. 序列化兼容:将LLM消息对象(HumanMessage等)序列化为JSON存储,读取时反序列化。四、生产级落地建议

聚焦性能、安全、可扩展性,确保应用稳定:  1. 性能优化:高并发配置数据库连接池,关系型数据库建立索引,用对话摘要压缩历史减少token消耗;  2. 安全合规:加密存储敏感信息,明确数据生命周期,支持用户删除历史;  3. 可扩展性:继承BaseChatMessageHistory实现自定义存储,通过配置动态切换存储方案,增加监控指标。五、总结

RunnableWithMessageHistory通过session_id实现多会话隔离,自动管理历史注入,大幅简化开发;对话历史持久化核心是替换存储层,根据业务场景选择合适数据库,即可快速落地生产级记忆能力,实现LLM“有记忆、多会话”的连续对话。 代码实现(要持久化存储修改如下代码中存储和获取会话历史的方法即可实现,需要的自行修改,这里就演示核心的功能):
  1. from langchain_openai import ChatOpenAI
  2. from langchain_core.tools import Tool
  3. from langchain.agents import create_react_agent  # 改用 ReAct 智能体
  4. from langchain.agents import AgentExecutor
  5. from langchain_core.prompts import PromptTemplate  # ReAct 用 PromptTemplate 而非 ChatPromptTemplate
  6. from langchain_core.messages import AIMessage, HumanMessage
  7. from langchain_community.chat_message_histories import ChatMessageHistory
  8. from langchain_core.runnables.history import RunnableWithMessageHistory
  9. # 1. 初始化 LLM(保持不变)
  10. DEEPSEEK_API_KEY = "123"  # 替换为实际的 API Key
  11. llm = ChatOpenAI(
  12.     api_key=DEEPSEEK_API_KEY,
  13.     base_url="http://172.25.133.51:8085/v1",
  14.     model="qwen3.5-27b-awq",
  15.     temperature=0.3,
  16.     max_tokens=1024,
  17. )
  18. # 2. 工具函数
  19. def huawei_mall_search(query: str) -> str:
  20.     """华为商城搜索工具"""
  21.     print(f"[DEBUG] 工具被调用!搜索关键词:{query}")
  22.     search_results = {
  23.         "众测活动": "华为商城众测活动是让用户体验新品并反馈意见的活动。目前有Mate 60系列众测,参与可赢取礼品。",
  24.         "手机": "华为商城最新手机:Mate 60系列、P60系列、nova系列等。",
  25.         "笔记本": "华为MateBook X Pro、MateBook D系列笔记本电脑。",
  26.         "手表": "华为Watch 4、Watch GT系列智能手表。",
  27.         "默认": "请在华为商城官网查看详细信息或联系客服。"
  28.     }
  29.     for keyword in search_results:
  30.         if keyword in query:
  31.             return f"华为商城搜索结果:{search_results[keyword]}"
  32.     return search_results["默认"]
  33. # 3. 创建工具
  34. huawei_tool = Tool(
  35.     name="huawei_mall_search",
  36.     description="查询华为商城相关信息,包括产品、活动、政策等",
  37.     func=huawei_mall_search,
  38. )
  39. tools = [huawei_tool]
  40. # 4. 定义 ReAct 提示词模板(关键修改!)
  41. react_prompt = PromptTemplate.from_template("""
  42. Answer the following questions as best you can. You have access to the following tools:
  43. {tools}
  44. Use the following format:
  45. Question: the input question you must answer
  46. Thought: you should always think about what to do
  47. Action: the action to take, should be one of [{tool_names}]
  48. Action Input: the input to the action
  49. Observation: the result of the action
  50. ... (this Thought/Action/Action Input/Observation can repeat N times)
  51. Thought: I now know the final answer
  52. Final Answer: the final answer to the original input question
  53. Begin!
  54. Previous conversation history:
  55. {chat_history}
  56. Question: {input}
  57. Thought: {agent_scratchpad}
  58. """)
  59. #上面提示词中{chat_history}是记录历史会话记录的不能少
  60. # 5. 创建 ReAct 智能体(关键修改!)
  61. try:
  62.     agent = create_react_agent(llm=llm, tools=tools, prompt=react_prompt)
  63.     print("Agent 创建成功")
  64. except Exception as e:
  65.     print(f"创建 Agent 失败: {e}")
  66.     exit()
  67. # 6. 创建执行器(保持不变)
  68. agent_executor = AgentExecutor(
  69.     agent=agent,
  70.     tools=tools,
  71.     verbose=True,
  72.     max_iterations=3,
  73.     handle_parsing_errors=True,
  74.     return_intermediate_steps=True
  75. )
  76. # 7. 测试(保持不变)
  77. print("\n" + "=" * 60)
  78. print("测试 Agent 工具调用")
  79. print("=" * 60)
  80. # 1. 用字典存储每个 session_id 的独立历史
  81. session_histories = {}
  82. # 2. 会话存储函数:为每个 session_id 创建/返回独立的历史
  83. def get_session_history(session_id: str) -> ChatMessageHistory:
  84.     if session_id not in session_histories:
  85.         session_histories[session_id] = ChatMessageHistory()
  86.     return session_histories[session_id]
  87. # 3. 创建带历史的智能体
  88. agent_with_chat_history = RunnableWithMessageHistory(
  89.     agent_executor,
  90.     get_session_history,  # 使用新的会话存储函数
  91.     input_messages_key="input",
  92.     history_messages_key="chat_history",
  93. )
  94. # 4. 测试不同 session_id
  95. chat1 = agent_with_chat_history.invoke(
  96.     {"input": "你好,我是小老虎"},
  97.     config={"configurable": {"session_id": "tiger"}},
  98. )
  99. chat2 = agent_with_chat_history.invoke(
  100.     {"input": "你好,我是小兔子"},
  101.     config={"configurable": {"session_id": "rabbit"}},
  102. )
  103. # 5. 查看特定 session_id 的会话记录
  104. print("tiger 的会话记录:")
  105. for msg in session_histories["tiger"].messages:
  106.     print(f"{msg.type}: {msg.content}")
  107. print("\nrabbit 的会话记录:")
  108. for msg in session_histories["rabbit"].messages:
  109.     print(f"{msg.type}: {msg.content}")
复制代码
输出结果:

Agent 创建成功

============================================================
测试 Agent 工具调用
============================================================
Parent run 5a054763-47a5-4360-b529-78012bbde271 not found for run 7b1f1b02-d9ac-4da8-b935-034ee28d0b7c. Treating as a root run.


> Entering new AgentExecutor chain...
l.


Thought: 用户只是在打招呼自我介绍,这是一个简单的问候,不需要使用华为商城搜索工具来查询信息。我应该友好地回应用户的问候。

Final Answer: 你好,小老虎!很高兴认识你。我是你的智能助手,有什么我可以帮助你的吗?比如查询华为商城的产品信息、优惠活动或者相关政策等,都可以告诉我哦!

> Finished chain.
Parent run b6d86ca8-bcb5-4e4e-8182-080f8381338e not found for run a05acc86-23a1-4fcc-9d89-ea8209b9a02e. Treating as a root run.


> Entering new AgentExecutor chain...
r.


Thought: 用户只是在打招呼并自我介绍,这是一个简单的问候,不需要使用华为商城搜索工具来查询任何信息。我应该友好地回应用户的问候。

Final Answer: 你好,小兔子!很高兴认识你~有什么我可以帮助你的吗?
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册