Skip to content

第 11 章 · 记忆与会话连续性

pixiu 锚点:agent/conversation.py(对话持久化)、tools.py:remember(记忆工具)、prompts.py:_build_memory_context(记忆注入) 关键案例:W2-6(会话→记忆反向缺口)、Q2(空壳识别:系统核实"定义了不等于在跑")

开篇:对话不是孤岛

很多人做 agent,对话功能是这么实现的:用户发消息 → 调 LLM → 返回回复 → 结束。下次对话,agent 两眼一抹黑,什么都不记得。

这种 agent 像个没有记忆的金鱼——每次对话都是全新的。对玩具 demo 够用,对真实产品是致命的。用户上周跟你说过"我不再追涨",这周你又开始给他推追涨建议,体验直接崩塌。

pixiu 在记忆这件事上踩过两个方向的坑,这一章都讲:一个是"对话本身没存下来",一个是"存下来的东西没变成记忆"。

坑一:对话得先能存下来

最基础的连续性,是对话本身要持久化。pixiu 用 agent/conversation.pyConversationStore 把对话存成 JSON 文件:

data/conversations/
  20260601_103000_贵州茅台分析.json
  20260601_140500_新对话.json

这里有两个细节值得说:

一是截断策略。 每个对话文件最多保留 MAX_MESSAGES_PER_CONV = 2000 条消息,超了就截掉最旧的(conv["messages"][-2000:])。为什么?因为对话无限增长,文件会越来越大,加载越来越慢,最后拖垮系统。截断是记忆管理的第一道闸门——你不能什么都留。

二是文件名按"日期_时间_标题"组织。 这不是为了好看,是为了人和程序都能按时间检索。记忆不只是"存下来",还要"找得到"。

坑二:存了对话 ≠ 有了记忆(W2-6)

对话存下来了,是不是就有记忆了?不是。pixiu 发现过一个更隐蔽的缺口,标注 W2-6

原来的 pixiu 有个不对称——工具触发的 event(买卖、回测)会回流进 memory_event,但用户在自由对话里随口说的观点、计划、纪律("海康估值偏高,回踩 30 元再加仓""我以后不再追涨杀跌")不落库。对话成了"只写文件不进记忆"的孤岛。

什么意思?对话 JSON 里存着这些话,但它们没有被结构化进记忆系统。下次开新对话,_build_memory_context 注入的是 memory_event,用户随口说的那些观点根本不在里面——agent 还是不知道。

修复是加了一个 remember 工具(第 4 章见过它的 schema):

python
"remember": {
    "description": "记住用户在对话中表达的投资观点/计划/纪律……"
                   "当用户明确表达一个值得长期记住的判断/计划/规则时调用;"
                   "不记录临时或无关内容。"
}

当 agent 识别到用户说了一句"值得长期记住"的话,它主动调用 remember,把这句话写进 memory_event(user_note),带上分类(view 观点 / plan 计划 / rule 纪律)。然后 _build_memory_context 会注入近 30 天的 user_note(第 5 章那张表的第 6 类)。

这样就形成了闭环:

用户说"海康回踩30再加"

agent 识别 → 主动调 remember

写入 memory_event(user_note, category=plan)

下次对话 → _build_memory_context 注入

agent 记得 → 不会乱推追涨建议

会话不再是孤岛。 这是个高阶认知:记忆不是"系统有什么就给模型看什么",还包括把散落在对话里的信息主动沉淀成结构化记忆。对话是流水,记忆是蓄水池——你得主动把流水引进池子。

方法论:空壳识别(Q2)

讲完记忆,这一章还要讲一个贯穿 pixiu 工程的方法论——空壳识别(课题 Q2)。它跟记忆直接相关,因为记忆功能特别容易"写了个壳但没真接上"。

pixiu 在做一轮巡检时,列了一份"待核实项"清单:

  • scheduler 是否真被启动?(定义了不跑?)
  • alert → 钉钉链路是否真通?
  • conversation 持久化是否真接入 agent 循环?(core.py 似乎只用 memory_store,没用 conversation 存储)
  • report_qc 是否在所有报告路径启用?

注意第三个——"对话历史功能可能是空壳"。这正是本章主题的风险点:你写了 ConversationStore,但 agent 循环可能根本没调它,对话功能形同虚设。

pixiu 的做法叫系统识别法——不是凭感觉认为"应该接上了",而是逐个核实。核实结果(findings Q2-1/Q2-2):

  • conversation 连续性:经核实,Web 层已用 ConversationStore 落盘 + _build_historyagent.run(history=)多轮连续性已通,不是空壳。原来标"待处理"是高估了,降级。
  • report_qc:经核实,所有定时报告生成路径都经 evaluate_report + 失败重写,已全覆盖,关闭。

这个方法论的精髓是:功能不是写了就算数,要系统核实它真的在跑。 很多 bug 不是"写错了",而是"写了个壳没接上"——代码读着像那么回事,但调用链是断的。系统识别法就是把这些"伪连接"一个个揪出来。

你做自己的 agent 时,值得建一份类似的"待核实清单":你以为在跑的功能,逐个验证调用链是否真的闭合。尤其是记忆、持久化、通知这类"写了不报错、但静默失效"的功能。

会话→记忆→注入:完整闭环

把这一章合起来,pixiu 的记忆体系是个三层闭环:

职责实现
会话层原始对话留存(截断+检索)conversation.py
记忆层结构化沉淀(event/user_note)memory_eventremember 工具
注入层按需注入到下次决策_build_memory_context

三层缺一不可:只有会话层,是金鱼;有记忆层没注入层,是"记了但用不上";有注入层没记忆层,是"想给但没货"。pixiu 是把三层都接上,并用 W2-6 这种 eval/巡检驱动的方式,把断点一个个补上,才形成闭环。

这一章的工具:记忆自检

  • [ ] 你的 agent 对话能持久化吗?还是关掉就忘?
  • [ ] 对话有截断策略吗?(无限增长的对话迟早拖垮系统)
  • [ ] 用户在对话里表达的观点/偏好,有没有沉淀成结构化记忆?(还是聊完就丢)
  • [ ] 你以为"接上了"的记忆/持久化/通知功能,你系统核实过调用链闭合吗?(空壳识别)
  • [ ] 记忆注入是"按需限量"的吗?(全塞会污染上下文)

小结

记忆是 agent 从"一次性工具"变成"长期伙伴"的关键。而记忆工程最容易被忽视的,是两个断点:对话没存下来(金鱼),和存了没变成记忆(孤岛)。pixiu 用 remember 工具 + _build_memory_context 注入 + 系统识别法核实,把这两个断点都补上了。

记住一句话:会话是流水,记忆是蓄水池。你不主动把流水引进池子,agent 永远是金鱼。

下一章

第 12 章 · 错误分流与韧性 —— 熔断器是怎么根治"空转一整夜"的。