主题
第 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.py 的 ConversationStore 把对话存成 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_history传agent.run(history=),多轮连续性已通,不是空壳。原来标"待处理"是高估了,降级。 - report_qc:经核实,所有定时报告生成路径都经
evaluate_report+ 失败重写,已全覆盖,关闭。
这个方法论的精髓是:功能不是写了就算数,要系统核实它真的在跑。 很多 bug 不是"写错了",而是"写了个壳没接上"——代码读着像那么回事,但调用链是断的。系统识别法就是把这些"伪连接"一个个揪出来。
你做自己的 agent 时,值得建一份类似的"待核实清单":你以为在跑的功能,逐个验证调用链是否真的闭合。尤其是记忆、持久化、通知这类"写了不报错、但静默失效"的功能。
会话→记忆→注入:完整闭环
把这一章合起来,pixiu 的记忆体系是个三层闭环:
| 层 | 职责 | 实现 |
|---|---|---|
| 会话层 | 原始对话留存(截断+检索) | conversation.py |
| 记忆层 | 结构化沉淀(event/user_note) | memory_event、remember 工具 |
| 注入层 | 按需注入到下次决策 | _build_memory_context |
三层缺一不可:只有会话层,是金鱼;有记忆层没注入层,是"记了但用不上";有注入层没记忆层,是"想给但没货"。pixiu 是把三层都接上,并用 W2-6 这种 eval/巡检驱动的方式,把断点一个个补上,才形成闭环。
这一章的工具:记忆自检
- [ ] 你的 agent 对话能持久化吗?还是关掉就忘?
- [ ] 对话有截断策略吗?(无限增长的对话迟早拖垮系统)
- [ ] 用户在对话里表达的观点/偏好,有没有沉淀成结构化记忆?(还是聊完就丢)
- [ ] 你以为"接上了"的记忆/持久化/通知功能,你系统核实过调用链闭合吗?(空壳识别)
- [ ] 记忆注入是"按需限量"的吗?(全塞会污染上下文)
小结
记忆是 agent 从"一次性工具"变成"长期伙伴"的关键。而记忆工程最容易被忽视的,是两个断点:对话没存下来(金鱼),和存了没变成记忆(孤岛)。pixiu 用 remember 工具 + _build_memory_context 注入 + 系统识别法核实,把这两个断点都补上了。
记住一句话:会话是流水,记忆是蓄水池。你不主动把流水引进池子,agent 永远是金鱼。
下一章
第 12 章 · 错误分流与韧性 —— 熔断器是怎么根治"空转一整夜"的。