大模型:临时会话

大模型的临时会话

临时会话 指的是在一次对话会话(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 工作流、故障恢复 保存完整状态,支持时间旅行 存储开销大,需持久化支持

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

相关推荐
牛奔5 小时前
Go 如何打印调试深层或嵌套的结构体
开发语言·后端·golang
geovindu5 小时前
go: Iterative Algorithms
开发语言·后端·算法·golang·迭代算法
学逆向的5 小时前
汇编——JCC指令
开发语言·汇编·网络安全
mayaairi6 小时前
JS循环语句深度解析:嵌套for、while与do...while
开发语言·前端·javascript
郭老二6 小时前
【Python】基本语法:装饰器语法糖@
python
kite01217 小时前
Go语言Map深度解析与最佳实践
开发语言·后端·golang
_Jimmy_8 小时前
Agent常用检索器的详细介绍
python·langchain
小柯南敲键盘8 小时前
图片翻译API接入与自动化实现指南
运维·python·自动化
l156469488 小时前
突围!图文混合知识库难以解析,Kimi-K3 原生视觉架构深耕知识工作,DMXAPI 统一接口,缩短项目开发周期
java·大数据·开发语言
旅僧8 小时前
Q-learning(自用)
python·机器学习