流畅稳定的会话交互与合理高效的记忆管理,是决定Agent 龙虾使用体验与智能上限的核心关键。实际中常会遇到对话上下文错乱、历史消息冗余堆积、多轮会话状态丢失、长对话响应卡顿、不同用户会话互相干扰等一系列实际问题。
本文围绕 Nanobot 会话和记忆主要介绍: 1)一套完整的会话生命周期管理体系, 2)短期实时对话记忆与长期持久化记忆兼顾交互的设计流程。
彻底弄懂框架记忆管理设计,实现长对话稳定交互、个性化记忆留存,优化龙虾对话体验。
会话管理可以直接导航到 session 目录下。
具体是由两个分工明确的类承接,并采用了:工厂+仓储(Factory + Repository)的设计模式。
会话 session 的创建和使用方式。从 Manager 取出 session 后,直接在 session 上操作,Manager退出视野。
session = self.sessions.get_or_create(key)
history = session.get_history(max_messages=0) # 直接操作 session
#... 运行 agent 1oop ...
self._save_turn(session, all_msgs, ...) # 直接写 session. messages
session.updated_at = datetime.now()
self.sessions.save(session) # 最后才回到 Manager 持久化优势:
以 key(channel:chat_id)唯一标识一个会话。存储字段有:
@dataclass
class Session:
"""A conversation session."""
key: str # channel:chat_id
messages: list[dict[str, Any]] = field(default_factory=list)
created_at: datetime = field(default_factory=datetime.now)
updated_at: datetime = field(default_factory=datetime.now)
metadata: dict[str, Any] = field(default_factory=dict)
last_consolidated: int = 0 # Number of messages already consolidated to files实现功能有:
向会话追加一条消息(含时间戳),消息只增不改 (append-only),以保证 LLM 缓存效率
返回提交给 LLM 的历史消息,核心逻辑包含两个保护:
截断保护:只取 last_consolidated 之后未整合的消息,最多 max_messages 条,且从第一条 user 消息开始
合法性校验 (_find_legal_start):过滤掉因滑动窗口截断导致的 ”孤儿 tool result”,确保每个tool 消息都能找到对应的 assistant tool_calls,避免部分 LLM Provider 拒绝请求。
SessionManager 基础设施层,Manager 只负责会话的生命周期和存储,与具体消息内容无关。其同时扮演两个角色:
外部代码,SessionManager.get_or_create(key) 返回 Session。这确保了 Session 创建时 key 格式正确,同一个key在内存中只有一个实例(单例缓存,防止并发写入时两个对象指向同一文件)遗留数据迁移对外透明。
实现的功能函数有:save() - 写盘。invalidate() - 逐出缓存(下次重新从磁盘加载)。list_sessions() - 查询所有。
这是典型的关注点分离(SoC),领域逻辑在领域对象里,基础设施逻辑在 Manager里。

图1,会话和记忆时序图
小结:
Session 是被管理的会话聚合根,SessionManager 是它的仓储 Repository ,控制 Session 的创建、查找、持久化。外部代码只通过 Manager 获取 Session,获取后直接持有对象引用并调用其方法,不需要再经过Manager。
这种模式的核心约束是:构造权在 Manager,操作权在Session 自身,两层分工清晰,互不越界。
会话 Session 是短期工作记忆,完整但有限。Memory 是长期持久记忆,存在磁盘,有损但无界。
在 Nanobot 中有三种的记忆存储方式。
runtime 的记忆存在一个根本矛盾:
LLM 上下文窗口有限,但对话可以无限长。
如何解决?
一种方案是短期和长期记忆的结合。
当所有的记忆放不下时候,需要将短期的记忆转换为长期记忆,触发的时机和结合点就是 session.last_consolidated 它是长短期记忆的接缝。

图 2,session 和记忆的结合
Session 的 get_history() 只返回 last_consolidated 之后的消息,已整合的部分通过 MEMORY.md 以摘要形式回流到 LLM 的系统提示里,从而实现 “滑动窗口+长期记忆” 的效果。两者通过 last_consolidated 指针解耦协作,共同解决LLM 上下文窗口有限而对话无限长的根本矛盾。
触发的时序流程:
maybe_consolidate_by_tokkns(session)
→ 估算当前 prompt token 数
→ 超过阈值 → pick_consolidation_boundary()
→ 找到一个 user-turn 边界
→ 取出 session.messages[last_consolidated:boundary]
→ 调用 LLM 生成摘要一写入 MEMORY.md + HISTORY.md
→ session.last_consolidated = boundary
→ sessions.save(session) - 指针持久化回 Session 文件记忆的实现由两个类承接 MemoryStore 和 MemoryConsolidator,两个类共同属于记忆子域,与Session 会话子域通过 last_consolidated 指针作为防腐层接口交互,互不侵入内部结构。
角色定义:
仓储的职责是:封装对持久化存储的访问,让领域层不感知存储细节。即,外部只需调用语义化方法,不感知文件路径、编码格式。
store. read_long_term() #读取长期记忆
store.write_long_term(text) #覆写长期记忆
store.append_history(entry) #追加历史日志
store.get_memory_context() #封装成 LLM 可用的上下文字符串领域服务的特征是,行为跨越多个聚合根,自身无状态,或只有协调状态。它协调 Session (聚合根)、MemoryStore(仓储)、LLMProvider(外部服务)三者。它自身不持有业务数据,只持有策略参数和协调核心行为。
maybe_consolidate_by_tokens 是一个跨聚合的决策过程:
Session(聚合根)
提供 messages + last_consolidated
Memoryconsolidator (领域服务)
决策:是否需要整合?整合哪段?
Memorystore (仓储)
执行:LLM 摘要-写 MEMORY.md / HISTORY.md
Session.last_consolidated 更新
sessionManager. save(session)) 持久化指针last_consolidated 指针,两层的精妙接缝。这是整个设计最关键的一个字段。它同时承担三个角色:
这样设计的优势:
MemoryStore 绑定 workspace,不绑定具体 Session。每次新 Session 启动,build_system_prompt() 自动读取
MEMORY.md 注入系统提示,旧Session 沉淀的知识自动流入新 Session,无需任何显式”记忆传递”操作。
Session 消息只追加不修改,整合过程不改变消息列表,只移动last.consolidated 指针。这使得相同的历史前缀可以命中 LLM Provider 的 prompt cache,降低延迟和费用。
Append-Only 的本质是用”不动历史“换”稳定前缀”。只要相邻两轮对话的历史部分没有变化,那部分 token 就不需要重新计算,直接从 Provider 缓存读取——对话越长,节省越多。

图 3,记忆管理UML 类图
清晰掌握 Nanobot 会话机制与记忆管理逻辑,是做好二次开发、深度定制 AI 对话能力的必备基础。合理运用框架原生的会话隔离策略,搭配灵活的记忆存取、过期清理、状态恢复能力,既能保障多用户同时在线时对话互不冲突,也能让龙虾精准承接上下文语义,延续连贯对话思路。
在实际项目开发中,可结合自身业务需求,对原生记忆模块进行轻量化改造,拓展长期记忆归档、用户专属记忆标签、敏感对话过滤、对话内容精简压缩等实用功能,进一步降低内存占用,提升长轮次对话运行效率。