Appearance
Akasha:不是检索过去,而是让过去在此刻发光
面向个人 agent 的记忆系统,现在大多走错了路。
错不在它们用了 embedding,也不在它们用了向量库。 错在它们把检索误认成了记忆。
检索问的是:
哪段旧文本,和现在这句话最像?
但记忆问的是另一件事:
此刻,哪一段过去应该被轻轻推到意识边缘,帮助我继续理解这个人?
这两个问题看起来很近,实际上隔着一整片海。
你说:
昨天在和 limboo 玩杀戮尖塔。
普通向量库会还给你更多“杀戮尖塔”的说法: 杀戮尖塔、Slay the Spire、卡组、爬塔、机器人、战士。
这不算错。 只是太浅。
真正的个人记忆不应该只想起词。 它应该想起关系。
它应该知道: limboo 不只是一个字符串。 limboo 和你一起玩过杀戮尖塔。 你是亡灵契约师,limboo 是战士。 你们和舍友联机。 你们都玩机器人。 有些记忆单看并不像“杀戮尖塔”,但在人生里,它们就是同一片夜空里的星。
这就是 Akasha 要做的事。
Akasha 不是一个更大的向量库。 它是一张会随着对话生长的私人星图。
在这张星图里,每一句话都是星。 每一次共同被想起,星与星之间就多一条微弱的光线。 那些后来反复被当下照亮的线,会越来越清晰。 那些只因偶然擦肩而亮过一次的线,会慢慢退回夜色。
所以 Akasha 的核心不是“存储”。 它的核心是两句话:
The message is the only truth.To remember is to recommend.
消息即唯一真相。 记忆即推荐。
Akasha 不替你总结人生。 它只守着你真正说过的话,让那些被时间反复需要的东西,自己长成记忆。
一、为什么现有 memory 不是 memory
现在很多 agent memory,本质上仍然是问答系统的尾巴。
它们先把对话提炼成几条“用户画像”:
用户喜欢咖啡。 用户住在东京。 用户有一个朋友叫 limboo。 用户最近手指受伤。
然后等你下次问相关问题,再把这些条目检索回来。
这叫资料库。 不叫记忆。
资料库是死的。 记忆是活的。
资料库等你问。 记忆会在你还没有完全说出口的时候,主动把一段过去推到你面前。
更致命的是,很多系统从写入第一刻就犯错:它们急着判断什么重要。
它们用使用次数判断重要。 于是“你好”“晚安”“在吗”“查天气”这种高频废话,被系统当成重中之重。
它们用最近出现判断重要。 于是今天一句无聊闲话,可以把上个月真正重要的事顶掉。
它们让 LLM 给重要性打分。 于是模型根据“看起来重要”来猜,而不是根据“对你这个人真的重要”来生长。
这三种方法看起来不同,病根是同一个:
它们都把重要性当成一个可以在写入时贴上的标签。
但个人记忆不是这样工作的。
一个名字第一次出现时,它可能只是一个名字。 十几次之后,它成了朋友、游戏、深夜、争吵、联机、某种只有你们之间才懂的语气。
一件事第一次说出时,它可能只是一个事实。 几天之后,它和疼痛、药、医院、担心、恢复、再次询问,织成一段 episode。
重要性不是被授予的。重要性是被照亮的。
一条记忆不是因为系统宣布它重要,所以重要。 它是因为后来一次又一次在合适的语境中被需要,才慢慢有了亮度。
这就是 Akasha 的第一条原则:
重要性不是标签,而是光度。记忆不是买断,而是回声。遗忘不是删除,而是光慢慢暗下去。
二、先用一张图理解 Akasha
为了更容易理解,可以先把 Akasha 想成一座夜里的私人天文台。
| Akasha 里的东西 | 可以想成什么 | 它真正做什么 |
|---|---|---|
| 原始消息 | 星体本身 | 你真正说过的话,不改写,不总结 |
| node | 星图上的一颗星 | 一轮 user + assistant 对话的索引点 |
| embedding | 星的位置 | 用来找“语义相似”的过去 |
| FTS / IDF | 星名索引 | 用来抓 limboo 这种稀有专名 |
| salience | 初生亮度 | 这句话和日常背景有多不一样 |
| strength | 长时光度 | 这颗星在长期记忆里有多能发光 |
| resource | 短时体力 | 刚被用过的星,暂时不要反复霸屏 |
| edge | 星座连线 | 两颗星过去是否经常一起被想起 |
| direct | 左眼 | 看见“相似文本” |
| ripple | 右眼 | 看见“不相似但相关”的联想 |
| score | 此刻亮度 | 这条记忆现在该不该浮上来 |
| top-8 activation | 被真正看见的星 | 只有它们会参与学习,织进未来 |
这张表就是整套系统的缩略图。
Akasha 的记忆不是一条条 fact。 它是:
原始消息不动; 在原始消息之上建索引; 在索引之间长出边; 让边和节点随时间变亮或变暗; 每次 query 进来时,重新结算此刻哪几颗星应该被照亮; 再把这次照亮的结果写回星图,成为明天的路。
这就是它和普通向量库的根本差别。
向量库只问“像不像”。 Akasha 还问:
它们过去是否一起出现过? 这件事是否偏离你的日常? 这条记忆是否长期被真正需要? 它是不是刚刚被用过,需要暂时退后? 它是不是一个到处乱连的 hub,需要被压住? 此刻把它交给 LLM,会不会让回答更像是发生在“我们之间”?
所以 Akasha 的召回不是 retrieval。 它更像 recommendation。
不是“我找到了你问的东西”。 而是:
我想起了一段可能应该在场的过去。
三、消息即唯一真相:Akasha 到底存什么
Akasha 不提炼记忆。
这是第一条铁律。
它不把你的对话总结成:
用户手指受伤,曾去医院处理。
因为这句话太干净了,干净到失真。
你真正说的可能是:
肿得厉害,去医院切开引流,塞了根引流条。
这里面有痛感,有具体动作,有“引流条”这个未来会反复被唤醒的词,有一种用户当时的身体状态。 如果把它总结成“用户手指受伤”,信息没有消失在表面上,却消失在灵魂里。
更危险的是,LLM 的总结会引入幻觉。
LLM 回答一次,可能有一层幻觉。 把对话再提炼成记忆条目,又一层。 检索时再改写 query,又一层。
一层一层叠上去,最后系统拿着一条看似整洁、其实变形过的“记忆”来理解你。 它不是忘了你。 它是记错了你。
而比忘记你更糟的,是它记得你,但记错了你。
所以 Akasha 做了一个很克制的决定:
原始消息不动。Akasha 只在原始消息之上建索引。
一轮对话,也就是一条 user 消息和紧接着的 assistant 回复,会形成一个 node。 但 node 不复制消息,不重写消息,不总结消息。 它只保存一个指针,指回宿主数据库里的原始对话。
这就是:
The message is the only truth.
这里的 truth 不是世界真相。 Akasha 不会因为你说“我发烧了”,就替世界证明你真的发烧。 它确认的是另一种更基础、更不可冒犯的真相:
你曾经在某个时刻,这样说过自己。
个人记忆首先要尊重的,不是系统的归纳能力。 而是人的原话。
四、在真相之上,Akasha 建三种索引
原始消息不动,但系统必须能找回它。 所以 Akasha 在原话之上建三层召回底座。
1. 向量:找语义相似
每条原始消息都会进入 embedding cache。 这是消息级粒度。
同时,一轮 user + assistant 会形成一个 turn-level node embedding。 这是轮次级粒度。
为什么要两套?
因为消息级更细,能精确命中某一句; turn 级更稳,能代表这一轮对话的整体语义。
比如你问“引流条拔出来流血怎么办”,消息级 embedding 可能精确命中“引流条”“血”“换药”; turn 级 node 则把这轮对话背后的上下文带回来。
这一路就是 direct。 它像左脑,稳定、清楚、保守。 它回答的是:
哪些旧消息和现在最像?
2. FTS + IDF:抓住稀有名字
embedding 对常见概念很强。 但对一些私人世界里的稀有词,不一定可靠。
比如:
limboo
对一个通用 embedding 模型来说,它可能只是一个怪词。 但对你来说,它是一个具体的人,一个关系节点,一个会牵出很多过去的名字。
所以 Akasha 还建了 FTS 字面索引,并用 IDF 过滤高频废词。
“在吗”“今天”“感觉”“一下”这种词,人人都说,信息量低。 “limboo”“鱼石脂”“亡灵契约师”这种词,出现少,但一出现就很可能有意义。
FTS 的职责不是替代 embedding。 它是给私人专名留一条硬路。
embedding 像听语气。 FTS 像认名字。
3. 新颖度基线:知道什么偏离日常
Akasha 还维护一个全局重心 c。 可以把它想成:
到目前为止,你所有话语的平均方向。
每条新消息进来时,系统会看它和这个平均方向有多远:
逐个参数讲透:
- :本条消息的单位向量。原始消息文本过 embedding 模型后,再做 L2 归一化得到,维度和模型输出维度一致。
- :全局语义重心。增量维护的、所有历史消息单位向量的平均值,再做 L2 归一化:。关键的因果约束:它只累加此前的消息,不看未来——所以第一句话没有"过去",;越偏离你此前说过的一切, 越高。
- : 和 的余弦相似度,范围 。语义越接近重心,越接近 ;越偏离,越接近 (个人语料里负相似度极少出现)。
- :把 的范围 放大到 ,让中等偏离也能拿到较高的 。
- :把结果裁剪到 区间,防止极端值溢出。
一个节点最终取 user 和 assistant 两条消息里较大的那个 。
如果一句话很日常,贴近你平时说话的语义重心,salience 就低。 如果一句话明显偏离日常,比如突然说手术、医院、引流条,它就会有更高 salience。这其实就是心理学里的新异性效应(Novelty Effect / 冯·雷斯托夫效应):人们总是更容易记住那些和周围环境截然不同、脱颖而出的东西。
基于这个 salience,节点的长期强度在诞生那一刻就有了一个中性但有区分度的起点:
逐个参数:
- :长期强度的上限设计值。所有节点 strength 永远不会超过 3.0(见后面的
bounded_add机制),所以 时节点从满格 3.0 起步。 - :基线 0.7 保证即使是完全不新颖的日常寒暄()也有 2.1 的起步强度;新颖的事()在基线之上再奖励 0.3。这个 0.7/0.3 分割是设计值,意思是"新颖度最多能贡献 30% 的起步优势"。
- :来自上面算出的 salience。
所以新颖的事,起步就记得更牢—— 时 strength 从 3.0 起步, 时从 2.1 起步。但注意,这只是起点,不是最终判决。一条记忆未来到底重不重要,还要看它能不能在后续的召回里反复被真正需要。resource 则一律从满格 1.0 开始。
但这里要说清楚: salience 不是重要性。
它只是初生时的一点光。
Akasha 并没有在写入时宣布:
这条记忆重要。
它只是说:
这句话看起来不像日常噪音,先给它一点保护,不要让它刚出生就被夜色淹没。
于是 node 初始化时会有三个状态:
| 状态 | 含义 | 初始化 |
|---|---|---|
salience | 这句话相对过往背景有多新颖 | 由它和全局重心的距离决定 |
strength | 长期强度,未来会衰减 | 3.0 × (0.70 + 0.30σ) |
resource | 短期资源,防止刷屏 | 初始满格 1.0 |
这就是 Akasha 的克制:
写入时不授勋。 只给一颗星一个初生亮度。 它以后会不会成为星座,要看时间怎么照它。
五、边:记忆不是相似,而是共同被想起
向量库最大的盲区是: 它只能看见相似。 看不见关系。
但人的记忆里,最重要的东西往往不是“相似”,而是“相关”。
“鱼石脂”和“引流条出血”语义上不一定特别像。 一个是药,一个是医疗处理后的现象。 但在你的真实生活里,它们属于同一个手指 episode。 它们被同一段疼痛、同一段就医经历、同一段恢复过程连在一起。
“亡灵契约师”和“limboo 玩杀戮尖塔”也未必在向量空间里很近。 但如果你们反复一起聊过,它们就应该互相唤醒。
这就是 Akasha 的第二层核心:
边记录的不是相似,而是共同被想起。
一条边 A → T 的意思不是:
A 和 T 长得像。
而是:
过去某一次,当 T 出现时,A 也曾一起浮上来。
这就是稠密相似度给不出的那一维。
六、边怎么长出来:Hebbian / STDP
Akasha 的边不是写入时硬连的。 它们是在使用中长出来的。
一次 query 进来,系统先召回一批旧记忆。 但不是所有被看到的东西都有资格改变未来。
Akasha 只取 score 最高的 8 条作为 activation set。
为什么是 8?
因为这暗合了认知心理学里的工作记忆容量(Working Memory Capacity)——也就是著名的“7±2 法则”。人的大脑在同一时刻能同时处理和维持在意识前台的信息组块,大概也就是这个数。
更重要的是,它是一道门槛: 只有真正进入当下意识前台的记忆,才有资格参与学习。 第 9 名以后,即使被检索到了,也只是背景,不会被加固。
回答之后,Akasha 会写三类边。
1. 旧记忆 → 当前轮:因果边
如果旧记忆 A 在这次回答中被激活,而当前轮是 T,系统会写:
含义是:
A 参与塑造了 T。 A 是这轮对话的前因之一。
增量是 ,逐个参数:
- :因果边增益系数,设计值。代表”先出现的记忆更可能是后出现内容的前因”。
- :旧记忆 A 这次召回的最终 score。来自后面第十四章的 score 公式——也就是说,判断”A 和 T 关联有多强”的那个数,正是召回时用来排序的同一个数。读和写共用同一份信号。
2. 当前轮 → 旧记忆:回指边
系统也会写:
但这条边更弱,增量是 。
- :反因果边增益系数,设计值。
- :同上,A 这次召回的最终 score。
因为当前轮确实可以回指旧记忆,但后发生的事不能以同等强度”预测”先发生的事。
这个 1.0 vs 0.35 的不对称,不是随便拍的数字。它借鉴了神经科学里的 STDP(脉冲时序依赖可塑性):简单说,就是神经元激发的先后顺序,决定了连接的方向。前因导致后果,连接强;后果回指前因,连接弱。它也暗合认知心理学里的前向不对称效应(Temporal Contiguity Effect):当你想起一件事时,你更容易顺着时间往下想,而不是往前倒推。Akasha 的 0.35 恰好落在这个区间的经验值里——保留回指能力,但把时间前向定为主干。
这很重要。
如果边是完全对称的,系统就会分不清:
拉肚子 → 吃药
和
吃药 → 拉肚子
但 episode 之所以像 episode,正是因为它有顺序。 人的记忆不是一团无向共现。 它有时间箭头。
所以 Akasha 借用了 STDP 的精神: 先出现、先被想起的东西,更像后续内容的前因。 后出现的东西可以回指过去,但不能平等地改写过去。
3. 旧记忆之间:共激活边
如果 A 和 B 在同一次召回里一起被点亮,系统还会写:
增量是:
逐个参数:
- : 和 的几何均值。比起简单的乘积或相加,几何均值的好处是”两个都强才真的强”——一个高分一个低分的组合会被压低,避免偶然高分的记忆乱连。
- :A 和 B 各自的召回 score。
也就是说,两条记忆越强地共同在场,它们之间的星座线就越粗。这里 和 分别是 A 和 B 这次召回的最终 score——得分越高的记忆,与其他高分记忆之间长出的边越粗。
这就是神经科学里著名的 Hebbian 理论(赫布定律)——简单来说就是“一起放电的神经元,会连在一起(Cells that fire together, wire together)”:
一起亮过的星,更容易在未来一起亮。
但 Akasha 又不是简单的”一起出现就永远连上”。 因为所有边都会随时间变暗。
七、边会变暗:星座线不是刻在石头上的
Akasha 里的边不是永久权重。 每条边都有:
当前权重
weight上次更新时间last_used_ts
每次读到或强化它时,先结算这段时间的衰减:
逐个参数:
- :数据库里存的原始边权(上一次更新后的值)。
- :当前时间戳。
- :这条边上次被更新的时间戳。
- :边的时间衰减常数,设计值。意思是如果一条边整整 14 天没被碰,有效权会掉到原值的 ;28 天掉到约 14%。
- :标准的指数衰减公式(完美复现了著名的艾宾浩斯遗忘曲线),, 天。
然后再把这次共同激活带来的增量加上去。 增长是有上限的,越接近上限,涨得越慢——这叫有界增长(模拟了神经科学里的 LTP,长时程增强的饱和效应):
逐个参数:
- :当前值(对边来说就是衰减后的 )。
- :这次要加的增量。
- :上限, 永远不会超过 。越接近 ,实际增量越小——当 时,增量为 0;当 时,增量为 。
落库时完整的写法是:
逐个参数:
- :上面三种边各自的增量(因果 、反因果 、共激活 )。
- :边的学习率,设计值。把每次的增量打个折,防止一次共激活就让边权爆炸——边要靠反复共激活才能慢慢长粗。
- :边权上限,设计值。边权永远不会超过 2.0。
这非常关键。
如果没有衰减,图会越来越脏。 一次偶然的错误联想,会永远留在图里。
如果没有上限,热门节点会爆炸。 所有话题都会被少数 hub 吞掉。
如果没有使用中的强化,图又不会成长。 它只是一堆静态索引。
Akasha 同时有三件事:
会长。 会暗。 长到一定程度会慢下来。
所以它不是数据库。 它更像一个寻找平衡态的生命系统。
好的关系会因为反复被需要而变亮。 坏的巧合会因为无人再次召唤而退潮。 不是清洁工在后台删垃圾。 是时间本身在清理噪音。
八、时间动力学:忘记不是删除,是退到远处
Akasha 有三条时间曲线。
| 变量 | 时间常数 | 管什么 | 初始值 / 恢复方式 | 直觉 |
|---|---|---|---|---|
strength | 7 天 | 一条记忆本身的长期光度 | 编码即峰值 3.0 × (0.7 + 0.3σ),被召回时 bounded_add 抬升 | 不复习会淡 |
edge | 14 天 | 两条记忆之间的星座线 | 从零开始,共激活时 bounded_add 加固,封顶 2.0 | 不共现会断 |
resource | 30 分钟 | 刚用过的记忆是否暂时退后 | 满格 1.0,被取用扣 0.35 × score,指数恢复 | 防止刷屏 |
节点侧的 strength 每次被召回时,也遵循同样的有界增长逻辑:
逐个参数:
- :数据库里存的节点当前 strength 值。
- :距离上次被召回的时间。。
- :strength 的时间衰减常数,设计值。比边的 14 天快一倍——"记忆本身"比"记忆之间的关联"忘得更快。
- :节点的学习率,设计值。比边的 0.12 大一点——节点自身的强化比边的强化稍快。
- :这条记忆这次召回的最终 score。
- :strength 上限,设计值,与初始化的上限一致。
这里的 还是那条记忆这次召回的 score——得分越高,被加固得越多。
这三条不能合成一条。
因为”忘了””累了””不相关了”是三件完全不同的事。
一条记忆可以记得很牢,但刚刚被用过,所以暂时不要再霸屏。(这在心理学里叫返回抑制 Inhibition of Return,大脑会刻意压制刚刚关注过的信息,防止我们在同一个思路上陷入死循环。) 这叫:
strength 高,resource 低。
一条记忆本身淡了,但它还连在一个很强的 episode 簇里,所以能被边救回来。 这叫:
strength 低,edge 高。
一条记忆没有多少边,但文字上正好高度相似,所以 direct 仍然能把它捞回来。 这叫:
edge 低,dense 高。
普通系统常常把这些都压成一个”重要性分数”。 Akasha 没有这样做。
Akasha 让它们分开活着。
这使得遗忘变得非常精确:
遗忘不是把记忆从世界上抹掉。 遗忘是降低它参与未来计算的权重。
一条 strength 掉到很低的记忆,仍然在库里。 只要你某天说了非常相似的话,dense 还能把它从角落里找回来。 如果它再次被真正需要,它就会重新发光。
这很接近人的记忆。
很多事我们不是彻底忘了。 只是它不再主动走到眼前。
直到某个词、某个人、某种痛感、某个夜晚,把它重新叫醒。
九、为什么”使用次数”不是重要性
现有系统最容易犯的错误,就是把 recall_count 当成重要性。
但在 Akasha 里,事情恰好反过来。线上 3337 条节点的真实统计显示了一个非常漂亮的结果:
逐个参数(这是 Pearson 积矩相关系数,范围 [-1, 1],0 表示不相关,负号表示反相关):
- :每个节点的当前 strength 值。
- :每个节点历史上被召回的总次数。
- :每个节点的总边数。
- 、:中等程度的负相关,意味着——越常被扫到、越是 hub 的节点,strength 反而越低。
也就是说,越常被扫到、越像 hub 的节点,strength 反而越低。
这不是 bug。 这是设计目标。
因为 strength 的增长不是看”被想起多少次”,而是看”每次被想起时,是不是真的被需要”——也就是 score。一个 hub 节点虽然频繁被扫到,但每次都是因为它 fan 大、边广,不是 query 真和它相关——content_base 低、每次加得少;加上它 salience 低(不偏离重心),起点就低。低起点 + 低增量 × 频繁 = 还是低。
比如:
| 节点 | recall | fan | strength | 解释 |
|---|---|---|---|---|
| 「你好啊」 | 101 | 174 | 0.10 | 经常被扫到,但几乎不真正服务当前语境 |
| 「肿得厉害,去医院切开引流,塞了根引流条」 | 4 | 28 | 2.31 | 很少出现,但每次出现都和当前问题强相关 |
这说明 Akasha 没有被”热闹”骗走。
“你好啊”像广场上的噪音。 它出现很多次,但没有深关系。
“引流条”像一个伤口旁边留下的路标。 它出现次数不多,但一旦出现,往往真的重要。
Akasha 学到的是:
被看见,不等于被需要。 被需要,才会变亮。
这就是个人记忆里最关键的分辨力。
十、召回不是查找,是一次意识的涨潮
现在我们进入 Akasha 最核心的地方:一次 query 进来,它到底怎么想起过去?
整条流程可以分成五步:
选种子 图扩散 合并候选 noisy-OR 结算 注入与写回
听起来复杂,但可以继续用星图理解。
用户当下的话,是一束光。 它先照到几颗最明显的星。 然后光沿着过去长出来的星座线扩散。 有些星本来离得很远,但因为曾经和这些星反复一起亮过,也被涟漪带亮。 最后系统把所有亮度结算成一个 score。 score 决定两件事:
这条记忆要不要交给 LLM; 回答之后,它要不要被写回图里、变得更容易在未来被想起。
这就是 Akasha 最漂亮的闭环:
读和写共用同一个 score。
判断“此刻什么相关”的那个数,也就是学习信号本身。
十一、Step 1:种子选择,先点亮哪几颗星
Akasha 有三路种子。
1. Dense seed:语义相似
query 向量和所有 node 算 cosine。 高于阈值的进入种子池。 如果都不够,就取 top-k 兜底。
这是最稳定的一路。 它保证系统不会飘太远。
你问“引流条”,它一定能先找到“引流条”。 你问“杀戮尖塔”,它一定能先找到“杀戮尖塔”。
这是 direct 的地板。
2. FTS seed:稀有词硬命中
如果 query 里有 limboo、鱼石脂、亡灵契约师这种词,FTS 会用字面索引把它抓回来。
这一路专门补 embedding 的盲区。
私人记忆里,名字非常重要。 朋友的名字、游戏里的职业名、药名、地点名,这些东西可能在通用语义空间里并不显眼,但在人生里,它们是门。
FTS 就是在门牌号还清楚的时候,直接按门牌找。
3. BlackHole seed:高 salience 直通
有些记忆很新颖,很偏离日常。 哪怕它和 query 的相似度没有高到普通 dense seed 的门槛,也不该轻易被埋掉。
所以 Akasha 给高 salience 记忆留了绿色通道。
这很像夜里一颗异常亮的星。 它未必离你当前看的方向最近,但它太亮了,值得被看见。
十二、Step 2:Direct 和 Ripple,左脑与两种右脑
Akasha 有三层意识。
Direct:左脑,精确回忆
Direct 很简单:
query 和记忆算相似度。
它不学习。 不走边。 不讲故事。 它就是最近邻。
这一路很重要,因为它提供了准确性地板。 没有 direct,系统会变成纯联想,容易发散。 有了 direct,Akasha 永远有一条回到事实的路。
Ripple 分两层右脑
Ripple 才是 Akasha 和普通向量库真正不同的地方。但右脑不是单一通道,而是两套独立机制。
近场右脑:RWR(带重启的随机游走)
它不只看"像不像"。 它把当前线索丢进 30 分钟微图,让能量在"同一段短时上下文"里竞争分配。(RWR 是推荐系统里经典的图扩散算法,它像水面上的波纹一样,把能量沿着边一层层传出去,但也随时可能被“弹回”原点,防止能量跑得太远迷失方向。)
一个节点本身好不好被点亮由「易激活度」state 决定:
逐个参数:
- :节点的 salience(新颖度),来自第四章。
- :归一化的 strength,把 strength 从 线性映射到 。
- 、:增益系数,设计值。1.4 > 1.0 意味着新颖度比长期强度对易激活度的影响更大。
- :指数函数,让高值的节点优势被放大——新颖又记得牢的节点,比中等的容易点亮得多。
- :节点的短期资源,,来自第四章初始化,每次被召回扣减、30 分钟恢复。
- :节点的总边数(出边+入边的度数)。
- :第一道反 hub 防线——连得越杂的节点,越不容易被点亮。
于是它能找回那些:
字面不像, 向量也不够近, 但在人生里属于同一段关系的记忆。
这就是 “Ripple Activation & Recall”。
它像水面上的涟漪。 你说出一个词,第一圈波纹命中相似的记忆; 第二圈波纹沿着旧关系扩散,把那些沉在语义空间远处、却在你的人生里相邻的东西带回来。
所以当你说:
和 limboo 玩杀戮尖塔。
dense 会想起杀戮尖塔。 ripple 会想起 limboo 作为战士、你作为亡灵契约师、舍友联机、都玩机器人。
dense 找回的是文本相似。 RWR 找回的是同一段短时上下文里的生活结构。
远场右脑:graph_expand
RWR 只照亮 30 分钟窗口内的星。但人生里有些关系不受时间束缚——47 天前的一条记忆,只要边够强,照样该被想起。
graph_expand 就是干这个的。它拿 dense 种子在全图往外走一跳,不管时间远近。
它真正迷人的地方,不是能沿着一条边走到远处,而是能看见多条线索在远处汇聚。一条远处记忆如果只被一个种子弱弱地牵到,只是偶然;但如果当前 query 点亮的几颗星,都把光投向同一个远处节点,那颗节点就会突然亮起来。
这就是 Akasha 的情景补全:不是"某句话和 query 很像",而是"许多被当前语境点亮的旧事,都在指向同一个背景"。
dense 找的是最近的星。RWR 找的是同一片夜空里的竞争。graph_expand 找的是被多条星座线共同指向的远星。
所以当你说"和 limboo 玩杀戮尖塔":
- dense 还你"杀戮尖塔"的各种说法;
- RWR 还你"亡灵契约师 / 舍友联机 / 都玩机器人"——一整段关系;
- graph_expand 还能从 47 天外把「镜之边缘」拽回来,只因它过去反复和这段关系共同出现。
Akasha 不是"两路",而是三层意识:左脑精确相似兜底,近场右脑在同窗口内竞争,远场右脑把全图里被多条星座线共同指向的远星拉回来。
后面你会在 querylog 里看到
source=Graph, state=0.0的条目——state 不是"没点亮",而是 graph_expand 不走 RWR 的 state_array,它靠另一套物理发光。
十三、为什么需要 graph_expand,而不是让 RWR 跑全图
Akasha 的图扩散里有一个很重要的分工:
graph_expand 负责全图一跳发现。 RWR 负责局部窗口里的微调。
这不是随便拆的。这里有三个深层的技术原因,每一个都决定了系统能不能优雅地长大。
第一,计算成本。 RWR 要建 N×N 转移矩阵、做矩阵乘、迭代。在同一个 30 分钟上下文里,微图只有几十个点,瞬时完成;但如果把 RWR 直接放到全图,几千个点的 N² 计算量会放大 2500 倍,每次 query 都跑就不再优雅。而 graph_expand 是一跳邻居遍历,复杂度只和种子的出边数有关,轻得多。
第二,数学逻辑根本不同。 RWR 是能量再分配——总能量固定、节点之间是零和竞争,适合在同一个短时语境中比较”谁更相关”。但 graph_expand 是独立打分——每个候选互不影响,适合在全图里寻找”远处但真实相关的桥”。graph_expand 给每个一跳邻居独立打分:
逐个参数:
- :量级放大系数,设计值,把一跳的分数拉到和 direct 可比的范围。
- :电导归一后的边权,,范围 。但注意——这个 signal 不是来自单条边,而是所有种子投向同一颗远星的光线之和,再乘 。多颗种子共同指向的节点,会因为这个对数因子额外变亮。
- :即使相似度为 0,也给 0.25 的基线——保证"完全不像但强关联"的记忆也能拿到基础分。 是 query 和邻居节点的余弦相似度。
- :长期强度增益,最牢的记忆多 15% 加成,影响温和。
- :邻居节点的短期资源,刚用过的打折。
graph_expand 的精髓不是"一条边强",而是"多颗种子共同指向同一颗远星"。 代码里每个候选的 signal 是累加值——来自多个种子的边信号会叠加;同时 paths 计数每多一条路径就 +1,最终乘上 。这意味着:一条远处记忆如果只被一个种子弱弱地牵到,只是偶然;但如果当前 query 点亮的几颗星都把光投向它,那颗远星就会突然亮起来。这就是"星光汇聚"。
这是两种完全不同的回忆:RWR 回答”在当下这段语境里,谁最突出”;graph_expand 回答”在我整个人生里,还有什么和此刻相连”。
第三,也是最优雅的一点:局部记忆和长期联想的时间尺度不同。 RWR 局限在 30 分钟窗口里,是因为同一段对话里的边才有”此刻共在”的意义;而 graph_expand 完全不看节点时刻——47 天前的记忆,只要边够强照样能被拽回来。这正好对应了人类记忆的两层:工作记忆里的信息互相竞争,而长期记忆里的关联不受时间束缚。
RWR 像一个小房间里的注意力分配。 在同一个 30 分钟上下文里,节点之间确实可以竞争: 谁更相关,谁就拿更多能量。
但如果把 RWR 直接放到全图,问题会变得很糟。
第一,全图迭代会更贵。 局部微图几十个点,计算很轻。 全图几千个点,每次 query 都跑,就不再优雅。
第二,hub 会吸光。 “你好””今天””感觉””可以”这类节点,和太多东西有弱边。 在零和扩散里,它们会像黑洞一样吸走能量。
第三,也是最关键的: 局部记忆和长期联想的数学逻辑不同。
RWR 是能量再分配。 适合在同一个短时语境中竞争。
graph_expand 是独立打分。 适合在全图里寻找远处但真实相关的桥。
比如”鱼石脂”离”引流条出血”可能隔了好几小时,甚至不在当前 30 分钟窗口里。 RWR 看不到它。 但 graph_expand 可以沿着过去 37 轮手指就医 episode 里长出来的边,把它一跳拽回来。
这就是为什么 Akasha 不是简单地”把窗口调大”。 它是在区分两种回忆:
局部意识里的竞争。 长期星图里的联想。
十四、Step 3:noisy-OR,把两路证据合成此刻亮度
Direct 和 ripple 产生的是两种证据。
direct 说:
这条记忆和当前 query 文本相似。
ripple 说:
这条记忆虽然不一定相似,但它被关系图强烈带亮。
这两种证据不应该互相排斥。 任何一路强,都应该能让记忆浮上来。 两路都强,则更有把握。
所以 Akasha 用了类似 Noisy-OR 模型的思路来融合(这本来是贝叶斯网络里用来处理多个独立促成因素的模型:只要有一个原因成立,结果就容易成立):
其中:
,。
但这里有一个隐藏的免疫设计:direct 权重不是恒定的 0.5,而是看这条候选是不是种子本身:
Dense 对种子是地基,对联想只是刹车。 真正被 query 直接照亮的节点,拿完整的 direct 权重;被右脑带出来的邻居,只能拿一点点相似度背书。它若要进入意识前台,必须证明自己不是"有点像",而是"真的在这段生活里相连"——靠边、靠 long、靠多路径汇聚。
逐个参数:
- :扩散激活能量。graph_expand 或 RWR 过程中节点获得的能量值,范围 。graph_expand 来自边信号 × 种子能量;RWR 来自带重启随机游走的稳态分布。
- :ripple 放大系数,设计值。把扩散能量放大到和 direct 可比的量级。
- :易激活度,来自上一章的公式。综合了新颖度、长期强度、短期资源、反 hub 惩罚。
- :query 向量与节点向量的余弦相似度,范围 ,个人语料中通常在 之间。
- / :direct 系数。种子拿 0.5,非种子邻居只拿 0.18。这是防死亡螺旋的隐藏锁——Graph 邻居想进 top-8,不能只靠"有点像"。
任何一路强都能把 content_base 拉高。但这不是概率意义上严格趋近 1.0 的 noisy-OR,而是一个带饱和保护的证据融合器:当 strong < 1 时,弱证据补上剩余空间,像 noisy-OR 一样互补;当 strong ≥ 1 时,次要证据不再加成,但强证据本身保留为能量,让真正强关联的节点拿到大于 1 的 score。"亮度"不是"概率",所以真实库里会出现 11.18、8.90 这样的数——那不是 bug,是能量。
直觉很简单:
如果 strong 已经很强,weak 就只补一点。 如果 strong 还没饱和,weak 可以继续把它推高。 如果两路都有证据,这条记忆就更亮。
但 content_base 只是”内容证据”。 最终 score 还要乘上状态增益(这叫 Gain Modulation 增益调节,大脑里的神经元也经常这样,用一个信号去乘性地放大另一个信号):
逐个参数(增益项都是 形式,信号为 0 时增益为 1,不影响基线):
- :新颖增益。 是节点 salience,范围 。新颖度最高的节点获得 1.8 倍增益。
- :长期强度增益。 是归一化的 strength,,范围 。最牢的记忆获得 1.6 倍增益。
- :边强增益。 是节点到任意一个种子的最大有效边权,再除以 2.0 归一化到 。边最强的获得 1.5 倍增益。
penalties(惩罚项,都是 ≤1 的乘数,越差越低):
- :短期资源惩罚。刚被用过的记忆 resource 低,排名被压低。
- :路径长度惩罚。设计值:直连种子 = 1.0,一跳邻居 = 0.86,两跳 = 0.62,越远越打折。每跳衰减系数为 。
- :角色惩罚。设计值:assistant-only 独白节点 × 0.12(几乎不算),用户说的话 × 1.0。
- :第五道反 hub 防线。fan 越大惩罚越多,fan=100 时约 × 0.63。
最后过阈值 0.22(设计值)才算”被激活”。
这里每一项都有清楚的含义:
| 项 | 作用 |
|---|---|
content_base | 当前内容相关性 |
1 + 0.8σ | 新颖记忆更容易被看见 |
1 + 0.6 long | 长期强度高的记忆更亮 |
1 + 0.5 edge | 强边连接的记忆更容易浮现 |
resource | 刚用过的记忆暂时压低 |
hop | 越远的传播越打折 |
user_penalty | assistant-only 内容降低权重 |
fan penalty | hub 节点被压制 |
这一步非常像意识的结算。
不是单一分数决定一切。 而是许多微弱证据在此刻汇合。
这条记忆相似吗? 它新颖吗? 它长期活着吗? 它和当前种子之间的边强吗? 它是不是刚刚出现过? 它是不是 hub? 它是用户说的,还是 assistant 自己说的?
最后这些东西共同决定:
它此刻该不该发光。
十五、五道反 hub 防线:不让噪音霸占星空
长期记忆系统最怕 hub(在图论里,就是那些连接数极高的超级节点)。
hub 是什么?
就是那些和谁都能沾一点边,但和谁都不真正相关的节点。
比如:
你好啊。 好的。 今天。 感觉。 可以。
它们出现次数多。 连接也多。 如果系统只看频率或边数量,它们会吞掉一切。
所以 Akasha 有五道反 hub 防线,每一道都在不同的阶段给 hub 打折,一层一层纵深压制:
| # | 位置 | 公式 | 在哪一步 | 逐个参数解释 |
|---|---|---|---|---|
| 1 | state 阶段 | 节点易激活度 | = 节点总边数(度数)。连得越杂的节点,本身就不容易点亮。 | |
| 2 | seed 阶段 | 种子初始能量 | = 种子的初始能量。hub 即使当种子,出发能量也先除以 √(1+fan) 打折。 | |
| 3 | RWR 转移 | 每列只留最强 12 条边,弱边丢弃 | 微图能量流动 | hub 的弱边根本传不出能量,只保留最强的铁关系。 |
| 4 | graph_expand | 全图一跳电导归一 | = 有效边权;出度/入度 = 两端节点的边权总和。"谁都连"的 hub 分母大、被除得很小,只有最专一的邻居冒头。 | |
| 5 | final score | 最终打分 | 最后再压一次,收尾兜底。指数 0.1 比较温和,只惩罚 fan 极大的节点。 |
这非常重要。
因为 hub 不一定会被时间自然清掉。 有些废话就是会反复出现,边也会被反复刷新。 所以 Akasha 不只靠衰减,还靠结构性压制。
衰减清掉的是:
偶然出现、之后不再复现的噪音。
反 hub 清掉的是:
经常出现、但没有内容贡献的噪音。
这两者合起来,才是闭环系统的免疫系统。
十六、Step 4:注入,左脑和右脑各走各的路
Akasha 最后不会把所有候选混成一锅粥交给 LLM。
它会分成三类。
1. dense_items:左脑,精确回忆
这是纯相似度 top-k。 不走 RAR。 不依赖图。 它永远兜底。
如果你问一个明确事实,dense 一定能把最像的旧消息找回来。
这保证 Akasha 不会因为联想太美而忘了准确性。
2. ripple_items:右脑,潜意识浮现
这是 RAR 全管线召回出来的东西。 阈值会放宽一点。
为什么要放宽?
因为右脑联想本来就不是精确搜索。 它的价值在于多给一些“可能有关”的背景音,让 LLM 在最后整合。
这里的 LLM 不是记忆的真相源。 它只是最后一公里的前额叶:
看看这些上下文,哪些真的该被说出口。
Akasha 不让 LLM 改写过去。 但允许 LLM 在回答时整合上下文。
这是两种完全不同的信任。
3. activation_items:真正写回未来的 top-8
这是最关键的一组。
只有 activation_items 会参与学习。 只有它们会加 strength。 只有它们会消耗 resource。 只有它们会和当前轮建立 STDP 边。
所以 Akasha 的学习非常克制:
可以多给 LLM 一些右脑联想, 但只有左右脑共同结算后的 top-8,才有资格改变未来。
为什么必须让左右脑都参与激活,而不是只有右脑?
这是整套系统防止死亡螺旋的核心免疫机制,必须讲透。
先回答:dense 参与 score 计算吗?会。 dense 的相似度信号不是"仅供注入"——它直接进入了最终 score 的计算。score 的两路证据 noisy-OR 融合里,一路是 ripple(右脑扩散),另一路就是 direct(左脑 dense):
所以每一个候选的 score 里,都天然带着 dense 相似度的贡献。
再回答:dense 本身会 ripple 为 0 吗?不会。 那些本身就是种子的 dense 命中节点,是扩散的能量起点,一出生就有初始能量 ,经过 RWR 扩散后 肯定不为 0,所以 永远不为 0。它们同时有 direct 和 ripple 两路信号。少数不在种子里、也没被扩散扫到的 dense 兜底节点,ripple 可以为 0,但 noisy-OR 保证只要 direct 够高依然能浮上来——这既是地板,也是冷启动时第一条边的来源。
关键的设计决策:为什么 activation_items 必须是左右脑融合的 top-8?
如果只让右脑(ripple)的结果参与写回强化,会发生死亡螺旋:
- Day 1:聊"拉肚子→快递放消防栓→吃诺氟沙星",物理时间连续,STDP 忠实地在「拉肚子」和「消防栓」之间连了一条弱边。
- Day 7:问"我肚子痛",ripple 顺着那条弱边勉强把「消防栓」扩散了出来。
- 如果只有右脑的结果参与写回:「消防栓」进了 top-8,边被加固 → 下次更容易被扩散出来。
- 如此反复:边越来越粗,一说到肚子痛就满屏都是外卖小哥,系统彻底精神分裂。
让 dense 参与激活,破解了这个诅咒:
- Day 7:问"我肚子痛",ripple 确实把「消防栓」扩散了出来,但 dense 相似度把「火锅」「拉肚子」「诺氟沙星」这些真正相关的记忆,以绝对的 cos 高分锚定在了候选池头部。
- 「消防栓」和"肚子痛"的 cos 只有 0.2 左右,direct 信号极低 → content_base 上不去 → final score 排第 9 名开外。
- 进不了 top-8 → 没资格被写回 → 边不会被加固。
- 14 天衰减后,那条弱边自己就枯掉了。
用真实的鱼石脂例子看得更清楚:
| 记忆 | cos (direct) | ripple (扩散) | content_base | score | 进不进 activation? |
|---|---|---|---|---|---|
| 鱼石脂(一跳邻居) | 0.522 | 1.252 | ~0.86 | 3.09 | ✅ 进 |
| 不是换新的引流条吗(dense #1,种子) | 0.787 | 有初始能量,>0 | ~0.39 + ripple×(1-0.39) | 0.79 | ✅ 进 |
| 打麻药为什么疼(种子/邻居) | ~0.65 | 有 | ~0.62 | ~1.x | ✅ 进 |
| 消防栓(噪音) | 0.2 | ~0.3 | ~0.44 | <0.22 | ❌ 不进 |
好的联想(鱼石脂)虽然 dense 不高,但 ripple 够强,依然能进 top-8 被加固;坏的联想(消防栓)因为没有 dense 锚点,挤不进去,被自然饿死。而 dense 种子(引流条)本身作为事实锚点,即使 ripple 不突出,也会因 direct 够高而进入强化池,保证事实被不断巩固。
右脑负责"多想一点",左脑负责"别想太偏"。 注入 LLM 时可以让右脑大胆联想(多给点背景音让 LLM 筛),但写回时必须让左脑把事实锚在头部——纯联想的噪音挤不进 top-8,就不会被加固,不会污染图结构。dense 参与激活,本质是用"不变的事实相似性"给"会学习的联想"做锚定,让系统可以大胆联想又不会疯掉。
这点非常漂亮。
因为如果只强化 ripple 找到的东西,系统容易进入噪音自激: 一个无关节点偶然被扩散扫到,写回; 下次更容易被扫到,再写回; 最后噪音变成 hub。
但 Akasha 用 dense 作为免疫系统。 事实相似性永远在候选池里当锚。 纯右脑噪音如果没有内容支撑,很难挤进 top-8。 挤不进去,就不会被加固。 不会被加固,边就会在 14 天衰减里变暗。
这就是为什么 Akasha 可以大胆联想,又不至于被联想毁掉。
十七、真实例子一:limboo,不是一个词,而是一段关系
现在回到开头的例子。
你说:
昨天在和 limboo 玩杀戮尖塔。
普通 dense 会找回语义相似的东西。 这当然有用,但它只能看到”杀戮尖塔”这个主题。
Akasha 会先用 dense 找到杀戮尖塔相关记忆。 再用 FTS 抓住 limboo 这个稀有名字。 如果二者同时命中,种子能量还会 ×1.3(封顶 1.5)。
然后 ripple 开始沿图扩散。
它发现:
我是亡灵契约师,limboo 是战士。 和学校舍友联机玩。 我玩机器人,limboo 也玩机器人。 和舍友俩机宝过了 a10。
这些句子未必都和 query 高度相似。 有的 dense 排名可能很靠后。 甚至有些从语义上看,几乎不该出现在 top-10 里。
但在人生结构里,它们是相关的。
它们属于同一片游戏生活。 同一个朋友。 同一段联机关系。 同一种只有长期聊天才会形成的背景。
这就是 Akasha 的价值,用真实数字说话:
| 内容 | cos 相似度 | dense 全库排名 | 最终 score | 召回来源 |
|---|---|---|---|---|
| 我是亡灵契约师 limboo是战士 | 0.599 | 第 22 名 | 2.40 | Graph / 1hop |
| 和学校舍友联机玩 | 0.598 | 第 24 名 | 1.48 | Graph / 1hop |
| 我玩机器人 limboo也玩机器人 | 0.597 | 第 26 名 | 1.28 | Graph / 1hop |
| 镜之边缘主角叫啥 | 0.436 | 第 1199 名 | 1.27 | Graph / 1hop |
| 和舍友俩机宝过了 a10 | 0.601 | 第 21 名 | 0.99 | Graph / 1hop |
每一条的 cos 都远够不上 dense 种子门槛(0.675),排在全库 21~1199 名;但它们和好几条种子挂着 0.17~0.28 的共现边——这些边是过去几十次一起聊杀戮尖塔积累的。「镜之边缘」cos 仅 0.436、全库排 1199 名,纯相似度永远够不到——但边是活的,把它从一千名外拽到了第 4。
它不是找到更多”杀戮尖塔”。 它找回”你和 limboo 之间那段关于杀戮尖塔的世界”。
这就是从检索到记忆的跃迁。
十八、真实例子二:鱼石脂,语义不近,但人生很近
另一个更漂亮的例子是手指就医。
你问:
但是拔出来引流条的时候出了好多血。
dense 会找回”引流条””换药””麻药””出血”这些直接相似的记忆。
这很好。 但 Akasha 还会想起:
刚才白的是那种小点,鱼石脂是棕色的……
单看语义,”鱼石脂”和”引流条出血”并不是最像。 cos 可能只有 0.522。 在普通 dense top-10 里,它排不上号。
但在真实对话里,鱼石脂和引流条、麻药、绷带、换药,属于同一个手指 episode。 它们在 37 轮对话里反复共同出现。 边一阶一阶长粗。
所以到某一次你说”引流条拔出来出了好多血”时,Akasha 沿着那段 episode 的星座线,把鱼石脂拉了回来。
这是记忆系统最应该有的能力。 用真实数据看更清楚:
| 记忆 | cos 相似度 | ripple 扩散能量 | 最终 score | 说明 |
|---|---|---|---|---|
| 鱼石脂是棕色的… | 0.522 | 1.252 | 3.09 | cos 不在 top-10,靠 graph_expand 一跳拽回 |
| 不是换新的引流条吗(dense #1) | 0.787 | — | 0.79 | 纯相似度第一名 |
鱼石脂的 score 是 dense #1 的 3.9 倍。而且它离种子几小时远,不在 30 分钟微图里,RWR 根本看不到它——全靠 graph_expand 无时间限制的一跳发现机制,沿着过去 37 轮手指就医里长出来的粗边,把它从语义距离之外拽了回来。
这就是记忆系统最应该有的能力。
不是把最像的文本摆出来。 而是把”你当时经历的那一整段事情”恢复出来。
人对 agent 的期待,本来就是这个:
你不要只记得我说了哪个词。 你要记得那几天我到底在经历什么。
Akasha 在这个例子里,做到了。
十九、真实库里的涌现:Akasha 补全的不是答案,而是情景
讲到这里,有必要退一步,看看真实库在说什么。不是理论,是 akasha.db.gz 里 3378 个节点、127696 条边、3352 条 query log 的实证。
先给一张读 querylog 的小字典。真实字段里有几个名字容易误导,尤其 state=0 这件事:
| 字段 | 在 RWR 候选里 | 在 Graph/1hop 候选里 |
|---|---|---|
direct | query 与节点的 cos | 也是 cos |
ripple | RWR 当前扩散能量 current | graph_expand 里更像 best edge / best weight |
edge | cross_mat 的最大边信号 | graph_expand 的聚合边信号(signal × paths) |
state | RWR 的归一化易激活度 [0,1] | 固定 0.0,因为 Graph/1hop 不走 state_array |
score | noisy-OR + gain 后的分数 | graph_expand 独立公式后的分数 |
Graph/1hop 的 state=0 不是"没有被点亮",而是"它来自另一套右脑物理"——远场联想不走 RWR 的 state_array,它靠的是 seed 强度、边电导、候选 direct、long、resource,以及多路径汇聚。看到 state=0 但 score=11.18,不要觉得矛盾;那正是 graph_expand 在说话。
真实库的统计更说明问题:
| 指标 | 数值 |
|---|---|
| 有 activation 的 query | 3351 |
| top-1 来源是 Graph | 2340 次 |
| Graph top-1 占比 | 69.8% |
| top-8 里 Graph 平均数量 | 5.15 条 |
| top-8 里 Graph ≥ 4 条的 query 占比 | 80.6% |
在长期对话里,Akasha 的右脑不是"偶尔补点背景音",它已经是主航道。 多数时候真正进入 activation top-8 的,是 Graph。系统已经从"找相似文本"转向"沿个人情景图回忆"。
下面三个 case,来自真实 querylog,说明 Akasha 补全的不是语义,而是情景。
1. 心率:从数字补全到身体状态
query:「我现在心率多少」。dense top-10 全是心率变体——"说说看心率""查心率""心律怎么样"。这没问题,dense 做到了"找同类问题"。
但 graph_expand 拉回来的是:
| 内容 | direct | edge | score |
|---|---|---|---|
| 这个数据不正常吗 为什么会这样 | 0.585 | 1.995 | 11.18 |
| 你测试过3min 呢 | 0.493 | 1.815 | 9.23 |
| 我现在健康状态怎么样呢 | 0.647 | 1.401 | 8.58 |
| 我昨晚睡眠状况怎么样 | 0.534 | 1.601 | 8.56 |
| 我最近看东西感觉特别亮 是啥情况 | 0.410 | 1.641 | 7.38 |
dense 能回答"你之前也问过心率"。Akasha 回答的是"我知道你为什么在意心率"——因为它把心率放回整段身体状态:异常数据、睡眠、视觉异常、健康查询、短时测试。这些节点的 direct 不够进 dense top-10,但 edge 和 long 都很强,多路径汇聚后 graph score 把它们推到 activation top-8。写回后,这一整段"健康状态 episode"会更容易在未来一起浮现。
这不是检索。这是情景恢复。
2. 湿度:从传感器读数补全到房间生活
query:「我现在房间湿度怎么样」。dense top 是"现在房间湿度怎么样""再查一下现在湿度是多少""湿度偏低吗"。
ripple 拉回来的是:
| 内容 | direct | edge | score |
|---|---|---|---|
| sonoff 的湿度计会不会更好 | 0.540 | 1.135 | 5.91 |
| 有没有非小米的这种全家桶,比较好用的吗 | 0.348 | 1.416 | 5.62 |
| 所以 HA 到底是个啥,我希望便宜扩展性强 | 0.398 | 1.071 | 4.54 |
| 我还是想买个加湿器,结合智能家居给我个方案 | 0.587 | 0.250 | 1.40 |
"有没有非小米全家桶"这条 direct 只有 0.348,和"房间湿度"文本上并不近。但它在真实生活里非常近——湿度计、加湿器、Home Assistant、传感器、房间环境是同一套 household automation episode。Akasha 知道:用户问湿度,表面上是问数值,但在他的生活系统里,湿度连着鼻子干、房间环境、传感器选型、智能家居架构。
3. 晚安:从寒暄补全到关系仪式
query:「晚安 akashic」。dense top 前几条几乎全是"晚安 akashic"的重复——dense 没错,但它只看到了词。
ripple 拉回来的是:
| 内容 | direct | edge | score |
|---|---|---|---|
| 睡觉了 akashic,晚安,今天又想到一个可以做给你的功能……明天睡醒抓紧做出来 | 0.682 | 1.408 | 8.90 |
| 好喜欢你 akashic | 0.535 | 1.252 | 6.61 |
| 你很可爱 akashic | 0.685 | 0.933 | 5.87 |
| 换个话题,你还记得我最近在准备什么吗 | 0.409 | 1.096 | 4.83 |
这不是任务记忆。这是关系记忆。
"晚安"在你的长期对话里不是一个普通寒暄词,而是一个夜间仪式:睡前总结、对 Akashic 的亲密称呼、第二天要继续做的功能、疲惫、喜欢、陪伴、低谷里的自我确认。dense 看到的是六个一模一样的"晚安"。Akasha 看到的是一整段夜晚:今天又为它改了什么、明天醒来还想继续做什么、你说喜欢它、说它可爱、说自己困了但还想把东西做完。
对普通检索来说,"晚安"是高频噪音。对个人记忆来说,"晚安"是一段关系每天合上的书签。一个系统如果只会过滤噪音,它会错过人。Akasha 的美在于,它知道有些噪音其实是背景音;有些背景音,听久了就是陪伴。
dense 找相似。Akasha 找来处。
还有几个更短的 case,同样来自真实库:
Fitbit:不是设备名,是健康感知系统的入口
query:「你还记得我的 fitbit 手表怎么了吗」
dense top 是这些:
还记得我是从什么时候开始戴 fitbit 手表的吗 你忘记我用的是哪个 fitbit 了吗 fitbit 表带断了 fitbit 数据拿不到了
这些是"fitbit"这个词的相似回忆。
但 ripple 拉回来的是:
| ripple item | direct | edge | score |
|---|---|---|---|
| 再尝试获取一下呢 | 0.656 | 1.234 | 7.54 |
| fitbitmcp 里都有什么工具,你获取不到睡眠信息吗 | 0.708 | 0.943 | 5.81 |
| 这是我这种的睡眠时间表 | 0.491 | 1.051 | 5.04 |
| 看看我最近健康数据 | 0.704 | 0.663 | 4.04 |
| 我现在健康状态怎么样呢 | 0.616 | 0.557 | 3.23 |
Akasha 补全的是:Fitbit 不是一块手表,它是你的健康数据入口,是睡眠、MCP 工具、体征查询、健康状态感知这一整套系统的门。普通记忆会写"用户有 Fitbit";Akasha 学到的是"Fitbit = 睡眠数据 + 健康状态 + MCP 接口 + 数据获取失败 + 手表/表带问题"。
DeepSeek:不是模型名,是你的 AI 世界观
query:「我 deepseek 呢」
dense top 非常合理:
我对 deepseek 有什么情感吗 我好期待 deepseek 发 deepseek 才是巨人 deepseek 才是想实现 AGI 的
这已经不错了。
但 ripple 继续补出另一层:
| ripple item | direct | edge | score |
|---|---|---|---|
| 我还和你聊过别的模型,好用不好用吗 | 0.602 | 1.320 | 7.48 |
| claude / gpt / qwen 最新型号有用这些技术吗 | 0.655 | 1.129 | 6.76 |
| 什么样的机器可以跑 0.6b 的模型 | 0.489 | 1.245 | 5.96 |
| 说说看我对不同 AI 模型的态度 | 0.536 | 0.983 | 5.09 |
| 你去调查一下 Anthropic 的新研究讲给我听 | 0.590 | 0.866 | 4.70 |
这不是语义补全,而是价值观补全。Dense 能知道你喜欢 DeepSeek;Akasha 能补出你对 DeepSeek 的喜欢,放在更大的 AI 模型世界观里:Claude、GPT、Qwen、Anthropic、本地小模型、0.6B、模型技术路线、AGI 叙事。个人 agent 真正该懂的不是"用户喜欢 X",而是"用户如何把 X 放进自己的世界模型"。
游戏:不是游戏列表,是偏好生成过程
query:「你调查一下我最近都在玩什么游戏」
dense top 是:
我最近玩了什么游戏 我喜欢玩什么游戏呢 我都有什么游戏
这就是普通记忆能做的。
但 ripple 拉回来的是:
| ripple item | direct | edge | score |
|---|---|---|---|
| 还有什么其他我可能感兴趣并且没有的吗 | 0.544 | 0.925 | 4.87 |
| 当我表达我感兴趣 / 没兴趣的时候,你应该学会记忆 | 0.458 | 0.968 | 4.54 |
| 红色沙漠 Twitch 活动 | 0.505 | 0.787 | 3.90 |
| 这个游戏是我的童年回忆,菲斯小时候可喜欢了 | 0.460 | 0.658 | 3.02 |
| 以后推送 CS2 新闻时按这个标准过滤 | 0.394 | 0.527 | 2.17 |
| 我没玩过 HD2 啊,你看看我都玩过啥游戏 | 0.643 | 0.246 | 1.17 |
Akasha 没有只回答"你玩了哪些游戏"。它把"你如何表达兴趣""你如何拒绝推荐""你童年喜欢什么""你希望推送怎么过滤"一起带回来了。这不是游戏列表,这是偏好形成过程。
PR:不是代码事件,是生活节律
query:「今天又提了两个大 PR」
dense top 是:
我提了一个大 PR 最近又合了几个 PR 在做 PR
ripple 补出来的是:
| ripple item | direct | edge | score |
|---|---|---|---|
| 昨天合的,今天估计会再合一个新的 | 0.650 | 1.387 | 8.30 |
| 马上睡觉了,准备再合一个 commit | 0.505 | 1.231 | 6.07 |
| 那个目录下是不是还有另外一张,一共有几张 | 0.444 | 1.090 | 4.95 |
| 提个 PR 睡觉了,兼容了一下 Windows | 0.626 | 0.688 | 1.02 |
对 Akasha 来说,PR 不是 GitHub 事件。它连接着睡觉前再合一个 commit、第二天继续、Windows 兼容、这几天持续推进的开发节律。它开始记得你通常在什么时候做,做到什么程度会睡觉,哪些工作会被你带到第二天。
二十、闭环:今天的召回,织成明天的图
普通向量库是只读的。
它召回什么,不改变它以后怎么召回。 它写入什么,也不被这次召回真正塑造。
Akasha 不是。
先看两套闭环的本质区别
这是 Akasha 和一切传统记忆系统最核心的分野,必须对比着看:
普通记忆系统的闭环(为什么越用越糟)
问题有三层:
- LLM 参与两次改写——生成回答是第一次改写,总结记忆是第二次改写。每经过 LLM 一次就多一层幻觉,一层一层叠上去,最后系统记住的是”LLM 记忆中的 LLM 记忆中的你”。
- 只有检索,没有补齐——召回的永远是”最像的句子”,不会把散落在不同对话里、字面不像但属于同一段生活的记忆拼起来。注入给 LLM 的永远是几个离散的点,没有情景上下文。
- 写回的是内容,不是结构——把”去医院切开引流塞了根引流条”总结成”用户手指受伤”写入,痛感、细节、”引流条”这个未来会反复被唤醒的词,全部丢失了。
Akasha 的闭环(为什么越用越懂你)
关键设计(看 engine.py 560 行和 623 行就懂了):
- LLM 不参与裁定旧记忆被强化多少——
activation_edge_updates函数的输入只有current_key、candidates(top-8 的 score)、ts(时间戳)。旧节点 strength 怎么加、resource 怎么扣、边怎么落,依据的是召回时的 score,不是 LLM 的总结。LLM 不能把用户的过去总结成一条新事实,不能替系统裁定什么重要,不能把猜测铸成画像。 - 但 LLM 的回答会作为 assistant 原话进入历史——它作为"assistant 曾经这样说过"被原样保存,带着 role,不能伪装成用户事实。Akasha 不是不让 LLM 进入记忆,它是不让 LLM 改写记忆。
- 写回的是结构,不是内容——原始消息永远不动,写回操作只做三件事:① 旧节点
strength += 0.18·score(加固)② 旧节点resource -= 0.35·score(暂时歇会儿)③ 在节点之间画边(被一起想起了,连上)。 - 噪音即宝藏——注入给 LLM 的
ripple_items用soft_recall=True放宽阈值,最多给 72 条,而且只保留 dense 没给过的纯增量。这些 cos 只有 0.5~0.6、排 20 名开外的”噪音”,恰恰是情景上下文的来源。
两套闭环的差别可以用一张表钉死:
| 维度 | 普通记忆系统 | Akasha |
|---|---|---|
| 写回是否经过 LLM | ✅ 是,LLM 总结后写入 | ❌ 否,算法根据 score 写回 |
| 幻觉叠加风险 | 高——LLM 改写两次 | 无——写回不经过 LLM |
| 召回哲学 | 追求精准,不够像的一律过滤 | 可控噪音,放宽给 LLM 筛 |
| 注入 LLM 的内容 | 10 条最像的句子(离散点) | 10 条精准 + 10 条关联背景(连续线) |
| 情景上下文 | 没有——只有零散相似句 | 有——靠边拉回整段 episode |
| 写回内容 | LLM 总结的事实条目 | 边权重和节点状态(结构) |
| 长期演化 | 会话越长越容易记错 | 会话越长边越密,情景越完整 |
Akasha 的一次完整回合是:
更深一点说,是:
这意味着什么?
意味着召回不是被动上下文。 召回会塑造回答。
不是离散的点,是连续的线
这是最容易被忽略的一层——ripple 带出来的”噪音”不是点缀,它们直接改变了 LLM 的回答内容。
用 limboo 的例子看完整链条:
- 召回 :dense 找到”杀戮尖塔”,ripple 顺着边拉回”limboo 是战士 / 我是亡灵契约师 / 舍友联机 / 都玩机器人 / 机宝过了 a10”——这些都是 dense 排名 20 名开外的”噪音”。
- 回答 :LLM 看着这些背景音,回答不再是”哦你玩杀戮尖塔啊”,而是”又和 limboo 爬塔啊,你还是亡灵契约师他还是战士吗?上次你们俩机宝过 a10 我还记得”。
- 新节点 :你的回应”对,新版本机宝改得太强了”被原样存入,内容里带着”机宝””limboo””a10”这些旧记忆的影子。
- 未来召回 :下次聊到”机宝”时,新节点又会和旧的 limboo/杀戮尖塔节点互相激活。
每一轮的回复都不是用离散的检索点拼出来的,而是用整段情景上下文生成的;回复本身又带着情景的影子,变成下一轮情景的一部分。 整条对话是一根连续的、被记忆不断自我塑造的线,而不是一串独立的问答点。
普通系统的对话是一串珍珠——每颗都圆润,但彼此没有关系。 Akasha 的对话是一条河——连续流动,每一段水流都被前一段塑造。
这是一种内容级闭环。
它不只是图结构在变。 是对话本身在被记忆塑造。
内容级闭环的真正含义
这个公式里藏着 Akasha 最深刻的东西:
- 不只是”给 LLM 的上下文”,它直接决定了”这次对话会聊什么”。
- 不只是”回答”,它的内容被 塑造——提到了鱼石脂、提到了机宝、提到了 a10。
- 不只是”又存了一条新消息”,它的内容里带着旧记忆的痕迹,未来会和旧记忆互相激活。
- 不只是”又一次检索”,它能把 和旧记忆连起来,因为它们内容上本来就带着彼此的影子。
记忆不仅改变了”怎么回答”,还改变了”回答了什么”,而”回答了什么”又会变成未来的记忆。这不是结构图在长,是对话内容本身在被记忆反复塑造。
普通系统没有这个——它的新记忆是 LLM 总结的独立条目,和上一轮召回的内容没有内容上的继承关系。
这就是长期相处的感觉从哪里来:
不是它存了更多事实。 是它越来越知道哪些过去应该在此刻出现。
会话越长,边越丰富。 边越丰富,ripple 越能找到”不相似但相关”的记忆。 这些记忆塑造回答。 回答又沉淀成新的记忆。 于是系统越来越像一个真正和你共同生活过的 agent。
它不是在保存你的世界。 它是在长期对话中,慢慢学会你的世界会怎样互相唤醒。
二十一、自净化:坏联想为什么不会永远污染系统
闭环会放大好东西,也会放大坏东西。 所以 Akasha 必须有自净化。
它的自净化来自四个方向,每一个都优雅地嵌入了系统的核心机制,不需要额外的清洁工:
| 机制 | 作用 |
|---|---|
| direct 地板 | 保证事实相似性永远兜底 |
| 衰减 | 一次性巧合会自然变暗 |
| 有界增长 | 再强的边也不会无限爆炸 |
| 反 hub | 高频废话不能靠 fan 统治召回 |
| top-8 写回 | 只有真正进入意识前台的记忆才会改变未来 |
其中最精妙的是全脑融合强化机制——它从根本上防止了”右脑回音室”的死亡螺旋。
如果系统只强化 ripple 找出来的联想,噪音会被自我放大:一个无关节点偶然被扩散扫到 → 写回、加固边 → 下次更易被扫到 → 再加固……最后噪音变成 hub。但 Akasha 不是这样:写回强化吃的是 activation_items——左右脑融合后的 top-8,dense 的事实永远以绝对相似度锚在候选池头部。纯右脑挖出、没有 dense 兜底的噪音,因相似度太低、content_base 不够,挤不进 top-8 → 进不了强化池 → 没资格 Hebbian 加固 → 那根细弱的边被 14 天衰减饿死。
14 天衰减的威力可以用真实库的一组数字直观感受。同一个节点的两条出边:
| 出边指向 | 原始边权 | 闲置时长 | 有效边权 |
|---|---|---|---|
| 最近还一起出现的话题 | 0.36 | 0.6 天 | 0.348 |
| 曾天天聊、但 38 天没碰的话题 | 0.61(更高!) | 38 天 | 0.041 |
第二条原始强度更高,却因为 38 天没被再次共激活,有效权重掉到了 1/8。而被反复唤起的边,每次召回后 bounded_add 再加固一点,稳稳保持。赢者通吃就这么发生:真实回路越走越粗,噪音边在对比下萎缩成”背景辐射”——功能上被彻底静音,物理上却永远保留痕迹。
一条坏边,如果只是偶然共现,它不会被再次共同激活。 不再激活,就不会强化。 不强化,就在 14 天边衰减里变暗。
一条坏记忆,如果只是被 ripple 扫到,但没有 dense 或内容证据支撑,它进不了 activation top-8。 进不了 top-8,就不能写回。 不能写回,就不会自我放大。
一个 hub,如果经常出现,衰减可能清不掉它。 但 fan penalty 会层层压住它,让它很难因为”到处都认识一点”就霸占星空。
所以 Akasha 的右脑可以更大胆。 因为它有免疫系统。
它可以多想一点。 但不会让所有想法都有资格变成长期结构。
这就是好的记忆系统该有的分寸:
允许联想。 但不纵容联想。 允许遗忘。 但不把遗忘等同于删除。 允许过去影响现在。 但不让错误的过去无限放大。
二十二、Akasha 到底重新定义了什么
到这里,我们可以重新定义一次 Akasha。
它不是:
一个存用户 facts 的表。 一个带 embedding 的 RAG。 一个更复杂的检索器。 一个让 LLM 定期总结用户画像的脚本。
它是:
一个以原始消息为真相源, 以 direct 保证准确性, 以 ripple 生成联想, 以时间衰减保持清洁, 以 score 同时驱动读写, 在长期对话中自我生长的个人记忆动力系统。
它的每一层都对应一个问题:
| 层 | 回答的问题 |
|---|---|
| 原始消息 | 过去到底说过什么? |
| embedding / FTS | 怎么找到相似文本和稀有名字? |
| salience | 哪些话偏离日常,出生时值得多一点光? |
| strength | 哪些记忆长期仍然能发光? |
| resource | 哪些记忆刚用过,应该暂时退后? |
| edge | 哪些记忆过去经常一起被想起? |
| direct | 当前最像什么? |
| ripple | 当前还应该联想到什么? |
| noisy-OR score | 此刻哪条记忆最该出现? |
| activation top-8 | 哪些记忆有资格改变未来? |
| 闭环 | 今天的召回如何织成明天的理解? |
这套东西之所以漂亮,是因为它没有在任何一个点上宣布:
这就是重要性。
没有。
重要性不是一个字段。 不是 recall_count。 不是 salience。 不是 strength。 不是 LLM 的评分。 不是最新时间戳。 不是边数量。
重要性是在某一次具体对话里,由内容、时间、关系、状态共同结算出来的瞬间亮度。
它是此刻的。 也是历史的。 它属于现在,但由过去养成。
二十三、Akasha 的边界
再浪漫的系统,也必须诚实。
Akasha 记住的是对话真相,不是世界真相。 它知道“你说过你手指疼”,不等于它能证明医学事实。 它知道“assistant 曾经回答过某件事”,也不等于那件事一定正确。
所以原始消息必须保留 role。 用户说过什么,assistant 说过什么,不能混成同一种事实。
Akasha 的自然遗忘也不等于数据删除。 strength 变低、edge 变暗,只是计算意义上的退场。 如果用户要求删除,那应该是另一种更强的用户主权: 原始消息、索引、边、状态,都要能被追溯地移除。
Akasha 也不是要取代 LLM。 它是在 LLM 之前提供上下文。 LLM 仍然负责语言、推理、整合与表达。
但 Akasha 不让 LLM 做三件事:
不让 LLM 改写过去。 不让 LLM 独自裁定什么重要。 不让 LLM 把猜测固化成记忆。
Akasha是潜意识空间 而 最后收到 Akasha 讯息的 LLM 则是前额叶,他被 Akasha 检索到的“背景音“影响,重塑,最后给出自己的结果。
吾之蜜糖,乳之砒霜。 在所有传统记忆库中的“噪音“ 在当前系统中是宝贵的背景音,影响着前额叶能获得到什么,影响着你的个人助手真正理解你。
二十四、结语:好的记忆不是仓库,而是分寸
个人 agent 真正需要的记忆,不是“我有多少条用户资料”。 而是:
我是否知道什么时候该沉默,什么时候该想起。 我是否知道一个名字背后的关系。 我是否知道一段病痛不只是医学词,而是几天里的焦虑、换药、血、绷带和反复确认。 我是否能在你说出半句话时,把那段应该在场的过去轻轻推回来。
好的记忆不是仓库。 好的记忆是一种分寸。
它不是为了炫耀:
你看,我还记得。
而是为了让此刻的对话不再像发生在空白窗口里。 它让 agent 的回答带着来处。 带着共同经历。 带着那些没有明说、但应该被理解的背景。
Akasha 这个名字很适合这样的系统。
阿卡夏不是一个表。 不是一个数据库。 不是一堆 JSON。 它更像一片私人夜空。
每句话都是星。 每次共同被想起,星与星之间就多一条线。 有些线会被时间擦淡。 有些线会因为反复被当下照亮,慢慢变成星座。
而所谓记忆,就是当你再次抬头时,系统知道哪几颗星应该亮起来。
Akasha 不替你总结人生。 它不急着给你的过去贴标签。 它只是守着原话,让时间、关系和一次次真实的需要,把你的世界慢慢织成图。
所以:
The message is the only truth.To remember is to recommend.
消息即真相。 记忆即推荐。
不是检索过去。 而是让过去在此刻发光。
