当 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 节点------以及显式的编辑操作。细节不是被删除了,而是被压缩、替换了;而模型只看得到投影后的结果,所以表现得像失了忆。

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

相关推荐
刘立军1 小时前
依赖注入:禁止 AI 硬编码实例化,提升可测试性与扩展性
架构·ai编程
Dr.kangder2 小时前
嵌入式面试总结(二十一)——C语言关键字
c语言·开发语言·面试·职场和发展·架构·虚拟化
凤山老林3 小时前
高可靠消息驱动架构:Spring Boot 对接 MQ 的防丢失、防重放与积压治理
spring boot·后端·架构
cxr8283 小时前
HyperMind Lab M1 架构地基 Implementation Plan <二>
开发语言·人工智能·架构
AINative软件工程3 小时前
Agent 上下文账本工程:别让工具结果把 128K 窗口塞成垃圾场
后端·架构·ai编程
卡布叻_星星4 小时前
后端架构笔记之Maven多模块与微服务
笔记·架构
特立独行的猫a12 小时前
一切皆插件:DeepSeek Harness 的架构哲学,以及与主流 Agent 的对比
人工智能·架构·agent·deepseek·harness
雨白13 小时前
我的 UML 学习笔记:结合 Android 实例看懂 4 种常用图表
android·架构
heimeiyingwang13 小时前
【架构实战】OpenTelemetry链路追踪实战:从零到生产的完整指南
架构