大模型:临时会话

大模型的临时会话

临时会话 指的是在一次对话会话(Session)期间,大模型能够记住之前交流过的内容,从而理解上下文、进行连贯对话的能力。会话结束后,这些记忆通常会被丢弃。


核心机制

1. 上下文窗口(Context Window)
  • 大模型本身是无状态的,每次调用都是独立的。
  • 所谓的"记忆",实际上是把历史对话记录拼接在每次请求中,一起发送给模型。
  • 模型根据上下文窗口内的全部内容进行推理和生成。
  • 上下文窗口大小有限(如 128K、200K、1M tokens),超出部分会被截断或丢失。
2. 消息列表(Message List)
  • 每次对话由一组消息组成,每条消息包含角色(system/user/assistant)和内容。
  • 新消息不断追加到列表末尾,形成对话历史。
  • 下次请求时,将整个消息列表(或截取最近的一部分)传给模型。
3. Checkpoint / State(状态持久化)
  • 在 Agent 或复杂工作流中,临时会话的本质是状态管理:每一步执行都会更新状态,下一次调用从最新状态继续。
  • 状态不仅包含消息列表,还包含中间变量、工具调用结果、流程控制信息等。
  • 通过将状态保存在内存或外部存储中,实现会话的持续和恢复。

临时会话的典型实现方式

1. 手动维护消息列表(最基础)
python 复制代码
messages = [
    {"role": "system", "content": "你是一个友好的助手。"}
]

while True:
    user_input = input("你: ")
    messages.append({"role": "user", "content": user_input})
    response = model.invoke(messages)
    messages.append({"role": "assistant", "content": response})
    print("助手:", response)
2. 使用 RunnableWithMessageHistory(LangChain 风格)
  • 自动管理消息历史的存储和注入。
  • 通过 session_id 区分不同会话。
  • 支持多种历史存储后端(内存、Redis、文件等)。
python 复制代码
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_core.chat_history import InMemoryChatMessageHistory

store = {}

def get_history(session_id):
    if session_id not in store:
        store[session_id] = InMemoryChatMessageHistory()
    return store[session_id]

conversation = RunnableWithMessageHistory(
    chain,
    get_history,
    input_messages_key="input",
    history_messages_key="chat_history"
)

result = conversation.invoke(
    {"input": "你好"},
    {"configurable": {"session_id": "user_001"}}
)
3. LangGraph 的 State 管理
  • 图(Graph)的执行过程中,State 是全局共享的。
  • 每次节点更新 State,下一次调用从上次的 State 继续。
  • 结合 Checkpointer 可实现会话持久化和恢复。
python 复制代码
from langgraph.graph import StateGraph, MessagesState
from langgraph.checkpoint.memory import MemorySaver

graph = builder.compile(checkpointer=MemorySaver())

# 第一次调用
result = graph.invoke(
    {"messages": [HumanMessage(content="你好")]},
    {"configurable": {"thread_id": "session_001"}}
)

# 第二次调用(同一 thread_id,自动恢复历史)
result = graph.invoke(
    {"messages": [HumanMessage(content="我刚才说了什么?")]},
    {"configurable": {"thread_id": "session_001"}}
)

临时会话 vs 长期记忆

对比维度 临时会话 长期记忆
作用范围 单次会话内(同一 session_id / thread_id 跨会话、跨用户
存储内容 对话历史、当前状态、中间变量 用户画像、知识图谱、持久化偏好
生命周期 会话结束或程序重启后可能丢失 永久保存
实现方式 消息列表、State、Checkpointer 外部存储(数据库、向量库)
访问方式 自动注入(框架管理) 需手动读写

临时会话的局限性

  1. 上下文窗口限制:对话过长时会丢失早期信息。
  2. Token 成本:每次请求都携带全部历史,成本线性增长。
  3. 信息遗忘:模型对长文本中间部分的内容"注意力"会减弱(Lost-in-the-Middle 问题)。

应对策略

  • 消息裁剪 :只保留最近 N 轮对话(ConversationBufferWindowMemory)。
  • 摘要压缩 :使用 LLM 对旧消息生成摘要(ConversationSummaryMemory)。
  • 向量记忆 :将历史消息向量化,按需检索相关片段(VectorStoreRetrieverMemory)。
  • 状态快照:使用 Checkpointer 保存完整状态,支持时间旅行和故障恢复。

应对策略代码示例

下面分别给出四种策略的代码示例,帮助你直观理解每种方式如何实现。


1. 消息裁剪(ConversationBufferWindowMemory

适用框架 :LangChain

原理:只保留最近 K 轮对话,超出部分自动丢弃。

python 复制代码
from langchain.memory import ConversationBufferWindowMemory
from langchain.chains import ConversationChain
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-3.5-turbo")

# 只保留最近 2 轮对话(即 2 次 user + 2 次 assistant)
memory = ConversationBufferWindowMemory(k=2)

conversation = ConversationChain(
    llm=llm,
    memory=memory,
    verbose=True
)

conversation.predict(input="我叫小明,我喜欢编程。")
conversation.predict(input="你还记得我叫什么吗?")
# 此时 memory 中只包含最近两轮消息,之前的"我叫小明"可能被丢弃(取决于 k 值)
print(memory.buffer)  # 查看当前存储的对话历史

2. 摘要压缩(ConversationSummaryMemory

适用框架 :LangChain

原理:每次调用 LLM 将历史对话压缩成一段摘要,保留核心信息,节省 Token。

python 复制代码
from langchain.memory import ConversationSummaryMemory
from langchain.chains import ConversationChain
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-3.5-turbo")

# 使用 LLM 生成摘要
memory = ConversationSummaryMemory(llm=llm)

conversation = ConversationChain(
    llm=llm,
    memory=memory,
    verbose=True
)

conversation.predict(input="我叫小明,我喜欢编程。")
conversation.predict(input="我还喜欢打篮球。")
conversation.predict(input="你还记得我的爱好吗?")

# 查看当前存储的摘要
print(memory.load_memory_variables({})["history"])
# 输出可能类似:"Human 说他的名字是小明,喜欢编程和打篮球。"

3. 向量记忆(VectorStoreRetrieverMemory

适用框架 :LangChain

原理:将历史消息向量化存入向量库,查询时只检索最相关的片段,适合超长对话。

python 复制代码
from langchain.memory import VectorStoreRetrieverMemory
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
from langchain.chains import ConversationChain
from langchain_openai import ChatOpenAI

# 初始化向量库
embedding = OpenAIEmbeddings()
vectorstore = Chroma(
    collection_name="memory",
    embedding_function=embedding,
    persist_directory="./chroma_memory"
)

# 创建检索器(每次检索返回最相似的 2 条记忆)
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})

# 创建向量记忆
memory = VectorStoreRetrieverMemory(retriever=retriever)

# 保存记忆(每次对话后调用)
memory.save_context(
    {"input": "我叫小明,我喜欢编程。"},
    {"output": "好的,我记住了。小明喜欢编程。"}
)
memory.save_context(
    {"input": "我还喜欢打篮球。"},
    {"output": "记住了,小明还喜欢打篮球。"}
)

# 查询相关记忆
result = memory.load_memory_variables({"input": "小明有什么爱好?"})
print(result["history"])
# 输出会包含"小明喜欢编程"和"小明喜欢打篮球"的相关片段

4. 状态快照(Checkpointer)

适用框架 :LangGraph

原理:在图的每个节点执行后,自动保存整个 State 的快照。支持恢复、回退和会话持久化。

4.1 内存版(MemorySaver
python 复制代码
from langgraph.graph import StateGraph, MessagesState
from langgraph.checkpoint.memory import MemorySaver
from langchain_core.messages import HumanMessage

# 构建一个简单图
builder = StateGraph(MessagesState)
builder.add_node("chat", lambda state: {"messages": [llm.invoke(state["messages"])]})
builder.set_entry_point("chat")
graph = builder.compile(checkpointer=MemorySaver())

# 第一次调用,保存状态
config = {"configurable": {"thread_id": "user_001"}}
result = graph.invoke(
    {"messages": [HumanMessage(content="我叫小明")]},
    config=config
)

# 第二次调用,从同一 thread_id 恢复状态
result = graph.invoke(
    {"messages": [HumanMessage(content="我叫什么名字?")]},
    config=config
)
print(result["messages"][-1].content)  # 模型会回答"小明"
4.2 持久化版(SqliteSaver
python 复制代码
import sqlite3
from langgraph.checkpoint.sqlite import SqliteSaver

# 创建 SQLite 存储
conn = sqlite3.connect("checkpoints.db", check_same_thread=False)
checkpointer = SqliteSaver(conn)

# 编译图时传入 checkpointer
graph = builder.compile(checkpointer=checkpointer)

# 之后的使用与 MemorySaver 完全一致,只是状态会持久化到磁盘
# 程序重启后,相同 thread_id 仍能恢复历史

策略对比总结

策略 适用场景 优点 缺点
消息裁剪 对话轮次可控,不关心早期内容 实现简单,Token 可控 可能丢失重要早期信息
摘要压缩 长对话但需保留核心信息 节省 Token,保留语义摘要 摘要可能丢失细节,需额外 LLM 调用
向量记忆 超长对话或知识库场景 可扩展至海量历史,按需检索 实现复杂,有额外检索延迟
状态快照 Agent 工作流、故障恢复 保存完整状态,支持时间旅行 存储开销大,需持久化支持

根据你的实际场景,可以组合使用这些策略,例如:短对话用消息裁剪,长对话用摘要+向量记忆,关键工作流用状态快照。

相关推荐
努力中的编程者2 小时前
STL-vector的模拟实现
开发语言·c++·算法·stl·vector
山海云端有限公司2 小时前
实战指南:用豆包图片生成API快速搭建AI绘画能力
python·ai绘画·api调用·图片生成·豆包api
ganbingfenxiang2 小时前
山西干冰零售
大数据·人工智能·python·零售
薛定猫AI2 小时前
【深度解析】GLM-5.2 与 Z-Code:AI 编程智能体的原理拆解与 Python 调用实战
开发语言·人工智能·python
没文化的阿浩2 小时前
【C++】详解继承机制
开发语言·c++
冰暮流星2 小时前
flask之定义URL
后端·python·flask
文祐3 小时前
C语言用双向链表实现单调递减(递增)队列
c语言·开发语言·链表
雪的季节3 小时前
OCR: windows 环境基于c++的 paddle ocr 编译【CPU版本】编译成dll ,在QT、VS中调用
开发语言
蒟蒻的贤3 小时前
python搭建MiniDL
开发语言·python·深度学习