当 AI 突然“失忆“:DeepSeek Harness 的 Session Log 怎么做单一事实源

这篇拆解 DeepSeek Harness 的 Session Log:把会话做成一条只追加的事件流,为什么能同时解决"记忆丢失"和"多视图不一致"这两个问题。

0. 一个很多人踩过的坑

你有没有遇到过这种情况:跟 AI 聊得好好的,它突然"失忆"------上一句你刚说的话,下一句它就不认了。

第一反应通常是:这模型不行,记性太差。

但问题大概率不在模型。先说结论:大多数 Agent 框架里的模型,根本没有"记忆"这件事。 它每轮能看到的上下文,都是临时从一条事件日志里投影出来的。那段一旦被压缩、替换,它就再也看不见了------它表现出的"失忆",只是因为那一段已经不在它看得见的上下文里。

下面拆开看:为什么大多数框架会丢记忆,Harness 又是怎么解决的。

1. 大多数框架的记忆是怎么丢的

很多框架图省事:把整个会话塞进一个会溢出的数组,当作模型的上下文。

这在短对话里没问题。可一旦任务跑得久------比如一个多轮、带工具调用的长篇任务------前面的对话就会因为数组满了被静默挤掉。没有报错,没有提示,旧内容就这么没了。

模型不是"忘了"。它本来就看的是那份上下文;那段被挤掉之后,它对发生过什么一无所知。你问它"刚才那步的结果呢",它只能含糊其辞,因为它手里真的没有。

根子上的设计选择是:上下文是唯一的事实载体,而上下文又是会变、会丢的。

2. Harness 的做法:真相只在一条日志里

DeepSeek Harness 换了个思路。它不把真相装进上下文,而是写进一条只追加(append-only)的事件流------Session Log。

几个关键点:

  • 会话是一串事件。每条事件有类型、序号和负载;turn、step、用户消息、工具调用、工具结果,全按发生顺序记下来。
  • 模型看到的是"投影",不是"存储" 。系统跑一次 deriveMessages(),按规则把日志映射成模型这轮能读的消息列表。模型不持有任何记忆,它每轮只是拿到一份刚从日志投影出来的上下文。
  • 一条硬性不变量model-visible means logged------模型能看到的,必然已经写进日志。想给模型加一种新的可见输入?正确的做法是先加一种新事件类型,再从日志里渲染出来。而不是在某个角落偷偷塞一段。

这就引出了"单一事实源"的含义:

真相只存一份,就躺在日志里。模型要看、界面要显示、调试要回放------谁需要,都从这份日志投影出来,而不是各处各存一份。

为什么强调"不另存副本"?因为如果真相在日志里只留一份,那么模型视图、UI 视图、调试回放、审计记录,全是从同一份投影出来的,不存在"两份对不上"的中间态------要么日志有,要么没有,没有模棱两可。

3. surface 与 log-only:什么算对话,什么只是记录

并不是所有事件都该进模型的上下文。Harness 把事件分成两类:

  • surface 类:用户消息、助手消息、工具结果------这些会进模型历史,是真正"对话"的一部分。
  • log-only 类:只进持久化、UI 或审计,不进模型历史。

这条线划清了一件事:什么算对话,什么只是记录。 把日志当成单一事实源,不等于把所有日志都喂给模型;投影规则决定哪些事件该露出来、哪些只留在底层。

4. 因为一切都是投影,fork 变得不可思议地简单

这是整件事里最反直觉、也最有用的一点。

既然模型上下文、回放、持久化全都是从同一条事件流投影出来的,那么派生出一个新会话,就只是从这条事件流里选个边界、重建出一份新的投影------不需要复制状态,不需要迁移数据库。

由此派生出来的一整套能力都变得轻量:

  • 回放(replay):重新投影同一段事件;
  • resume(续跑):从某个边界继续;
  • 转写、遥测:同一种数据源的不同视角。

这里有一个很关键的纪律:未识别的事件类型,默认必须拒绝重建,而不是悄悄丢弃。 日志是向前兼容设计的------遇到将来才定义的事件类型,老 reader 可以标记为 ignorable 跳过;但在做"重建会话"这种严肃操作时,不认识的类型必须显式报错,绝不把一个残缺的会话悄悄续上。跳过和拒绝,是两件事。

5. 回到开头的"失忆"

回到第 0 节那个场景。在 Harness 里,它不会再以那种"上一句不认"的方式失忆了------因为真相只存一份,谁都没法偷偷改上下文而不留下记录。

对开发者,这意味着三件具体的事:

  • 可复现:同样的事件流,投影出同样的上下文;
  • 可调试:出了 bug,翻日志就知道模型当时到底看到了什么,而不是去猜;
  • 可审计:谁在什么时候做了什么,日志里全在。

一句话收束这套设计:只要真相只留一份,出错的机会就少一份。

6. 一个容易被误会的点:日志不可变,但细节仍会消失

前面用"失忆"打比方,容易让人误以为用户"亲手删了话"。这里需要澄清一个边界:

日志本身是不可变 的,事件一旦写入就不会被修改或删除。真正让模型的视野里少了某些细节的,是compaction(上下文压缩)------用摘要替换掉原始的 surface 节点------以及显式的编辑操作。细节不是被删除了,而是被压缩、替换了;而模型只看得到投影后的结果,所以表现得像失了忆。

换句话说:"失忆"不是记忆被抹除,而是投影源被压缩后,细节不再可见。 这两者的区别,决定了调试时是去查日志(记录还在),还是去查压缩策略(内容被替换了)。

相关推荐
鲸能云7 小时前
【智慧能源】源储调售一体化架构与 EMS 滚动调度算法实践 —— 工商业光储收益提升 22% 的技术拆解
算法·架构·能源
Swift社区8 小时前
鸿蒙 App 如何设计 Memory Center?一文讲透 Agent 的长期记忆架构
华为·架构·harmonyos
许彰午8 小时前
24-MyBatisHelper与autoCount
java·低代码·架构
小马过河R8 小时前
微信小程序自定义登录态维护:从入门到生产级落地
后端·微信小程序·小程序·架构·登录态
努力努力再努力wz8 小时前
【Redis入门系列】:从 RESP 协议到 redis-plus-plus:Redis 客户端编程与 C++ 接口设计
开发语言·数据库·c++·redis·分布式·缓存·架构
Dawson Zhu8 小时前
Kafka 在 AI Agent 系统中的应用:任务队列与事件总线的角色辨析及工程实践
人工智能·语言模型·架构·aigc·agi
不爱运动的跑者9 小时前
架构可视化不是“画图“:让 AI 产出可追溯架构图的四层工程
人工智能·架构
乱码三千9 小时前
Open Knowledge Framework 一套让智能体越用越好用的成长框架
架构·github
mldong16 小时前
引擎从不发一条消息:jeeflow 的两类扩展点与消息模块的分工
java·架构
ZGIAI18 小时前
Agent 越来越强,企业为什么反而更需要“运行层”?
人工智能·架构