liquid-loop 1.9.0__tar.gz → 2.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/PKG-INFO +11 -8
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/README.md +10 -7
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/__init__.py +2 -2
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/selfspin.py +123 -4
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/textutil.py +1 -1
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop.egg-info/PKG-INFO +11 -8
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop.egg-info/SOURCES.txt +14 -0
- liquid_loop-2.0.1/liquid_loop_exp/__init__.py +0 -0
- liquid_loop-2.0.1/liquid_loop_exp/error_loop/__init__.py +0 -0
- liquid_loop-2.0.1/liquid_loop_exp/error_loop/low_stability_recall.py +70 -0
- liquid_loop-2.0.1/liquid_loop_exp/multigran/__init__.py +0 -0
- liquid_loop-2.0.1/liquid_loop_exp/multigran/ab_multigran.py +95 -0
- liquid_loop-2.0.1/liquid_loop_exp/multigran/hard_ab_multigran.py +156 -0
- liquid_loop-2.0.1/liquid_loop_exp/multigran/multigran_core.py +178 -0
- liquid_loop-2.0.1/liquid_loop_exp/multigran/sim_structured.py +40 -0
- liquid_loop-2.0.1/liquid_loop_exp/multigran/test_multigran.py +50 -0
- liquid_loop-2.0.1/liquid_loop_exp/r16_repro/__init__.py +0 -0
- liquid_loop-2.0.1/liquid_loop_exp/r16_repro/compare_rar.py +89 -0
- liquid_loop-2.0.1/liquid_loop_exp/r16_repro/r16_repro.py +204 -0
- liquid_loop-2.0.1/liquid_loop_exp/skill_refine/__init__.py +0 -0
- liquid_loop-2.0.1/liquid_loop_exp/skill_refine/skill_refine_loop.py +128 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/pyproject.toml +1 -1
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/LICENSE +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/__main__.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/audit.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/cli.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/cognitive_budget.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/context_compress.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/cpe.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/entropy.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/guard.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/liquid_reweight.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/procedural_memory.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/rar.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/recall_filter.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/self_eval.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/self_refine.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/session.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/storage.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop/workspace.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop.egg-info/dependency_links.txt +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop.egg-info/entry_points.txt +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop.egg-info/requires.txt +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop.egg-info/top_level.txt +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop_exp/liquid_persist_ab.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/liquid_loop_exp/liquid_recall_ab.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/setup.cfg +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_attention_gain.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_auth_guard.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_cli_version.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_consensus_expansion.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_context_compress.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_entropy.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_guard_session_recall.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_layer1_persistence.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_lifecycle.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_liquid_reweight.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_nucleate_dual_track.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_peek_seal.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_perception_gate.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_procedural_memory.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_rar.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_recall_filter.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_replay_pressure.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_seal_persistence.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_self_eval.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_self_evolve.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_selfspin.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_semantica_borrow.py +0 -0
- {liquid_loop-1.9.0 → liquid_loop-2.0.1}/tests/test_workspace.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: liquid-loop
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.1
|
|
4
4
|
Summary: Self-Organizing Cognitive Memory for AI Agents — Liquid Loop theory implementation
|
|
5
5
|
Author: fishbook0001
|
|
6
6
|
Maintainer: fishbook0001
|
|
@@ -43,6 +43,8 @@ Dynamic: license-file
|
|
|
43
43
|
|
|
44
44
|
> **Self-Organizing Cognitive Memory for AI Agents** — Zero LLM dependency, pure Python implementation of the Liquid Loop theory.
|
|
45
45
|
|
|
46
|
+
> **当前包版本:`2.0.1`**(2026-08-25 零向量召回超越词频基线,详见 [CHANGELOG.md](CHANGELOG.md)。数据 schema `0.4.0` 与 workspace state `0.5.1` 为记忆层数据格式版本,独立于包发布版本)。
|
|
47
|
+
|
|
46
48
|
[](https://pypi.org/project/liquid-loop/)
|
|
47
49
|
[](https://pypi.org/project/liquid-loop/)
|
|
48
50
|
[](https://opensource.org/licenses/MIT)
|
|
@@ -120,9 +122,9 @@ RED (entropy ≥ 0.6) — 需清理
|
|
|
120
122
|
|
|
121
123
|
---
|
|
122
124
|
|
|
123
|
-
##
|
|
125
|
+
## 核心机制:反证轨 + 时间动力学(液态循环核心)
|
|
124
126
|
|
|
125
|
-
|
|
127
|
+
液环从"静态结晶"升级为**自调节记忆动力学**:记忆不是对象,而是过程。以下机制均随 **v2.0.0** 发布(历史演进中曾标 v0.8 / v0.9)。
|
|
126
128
|
|
|
127
129
|
### 反证轨(Contradiction Track)
|
|
128
130
|
|
|
@@ -364,11 +366,12 @@ pytest -v
|
|
|
364
366
|
## 路线图
|
|
365
367
|
|
|
366
368
|
- [ ] 多 Agent 液环耦合(`liquid_loop.mesh` 已移除,见 commit ac7260e)
|
|
367
|
-
- [x] **[
|
|
368
|
-
- [x] **[
|
|
369
|
-
- [x] **[
|
|
370
|
-
- [x] **[
|
|
371
|
-
- [x] **[
|
|
369
|
+
- [x] **[已发布] 反证轨(Evidence Graph)**:Evidence 分 support / contradiction,一致增稳、冲突降稳,驱动 memory stability score(不再"一致即真")
|
|
370
|
+
- [x] **[已发布] 显式时间动力学**:`M(t+1) = M(t) + reinforcement − decay − contradiction_penalty`,让记忆成为"过程"而非"对象"(真正的液态循环)
|
|
371
|
+
- [x] **[已发布] 三实验全 PASS**:E2 错误记忆恢复 → E3 多 agent 冲突 → E1 长期漂移(见上节)
|
|
372
|
+
- [x] **[已发布] 冲突检测 O(g²)→O(d²)**:`_detect_conflicts` 按 content 去重后只对 distinct 内容求两两重叠(d≤g),overlap_cache 复用;语义更纯净(度量不同论点分歧),大规模高频写入性能提升(非正确性变更)
|
|
373
|
+
- [x] **[已发布] 液态算法正式落地**:时间动力学 / 反证轨 / 双轨成核经 E1/E2/E3 三实验背书,作为稳定机制随 **v2.0.0** 发布
|
|
374
|
+
- [x] **[v2.0.0] 统一版号里程碑**:`pyproject.toml` / `__init__.__version__` / 投喂客户端 `LIQUIDLOOP_CLIENT_VERSION` 全部对齐 `2.0.0`;数据 schema `0.4.0` 与 workspace state `0.5.1` 保持独立(记忆层格式版本,禁区不动)
|
|
372
375
|
- [ ] LoCoMo / LongMemEval 基准对比
|
|
373
376
|
- [ ] 边缘端部署优化(<50KB)
|
|
374
377
|
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
> **Self-Organizing Cognitive Memory for AI Agents** — Zero LLM dependency, pure Python implementation of the Liquid Loop theory.
|
|
6
6
|
|
|
7
|
+
> **当前包版本:`2.0.1`**(2026-08-25 零向量召回超越词频基线,详见 [CHANGELOG.md](CHANGELOG.md)。数据 schema `0.4.0` 与 workspace state `0.5.1` 为记忆层数据格式版本,独立于包发布版本)。
|
|
8
|
+
|
|
7
9
|
[](https://pypi.org/project/liquid-loop/)
|
|
8
10
|
[](https://pypi.org/project/liquid-loop/)
|
|
9
11
|
[](https://opensource.org/licenses/MIT)
|
|
@@ -81,9 +83,9 @@ RED (entropy ≥ 0.6) — 需清理
|
|
|
81
83
|
|
|
82
84
|
---
|
|
83
85
|
|
|
84
|
-
##
|
|
86
|
+
## 核心机制:反证轨 + 时间动力学(液态循环核心)
|
|
85
87
|
|
|
86
|
-
|
|
88
|
+
液环从"静态结晶"升级为**自调节记忆动力学**:记忆不是对象,而是过程。以下机制均随 **v2.0.0** 发布(历史演进中曾标 v0.8 / v0.9)。
|
|
87
89
|
|
|
88
90
|
### 反证轨(Contradiction Track)
|
|
89
91
|
|
|
@@ -325,11 +327,12 @@ pytest -v
|
|
|
325
327
|
## 路线图
|
|
326
328
|
|
|
327
329
|
- [ ] 多 Agent 液环耦合(`liquid_loop.mesh` 已移除,见 commit ac7260e)
|
|
328
|
-
- [x] **[
|
|
329
|
-
- [x] **[
|
|
330
|
-
- [x] **[
|
|
331
|
-
- [x] **[
|
|
332
|
-
- [x] **[
|
|
330
|
+
- [x] **[已发布] 反证轨(Evidence Graph)**:Evidence 分 support / contradiction,一致增稳、冲突降稳,驱动 memory stability score(不再"一致即真")
|
|
331
|
+
- [x] **[已发布] 显式时间动力学**:`M(t+1) = M(t) + reinforcement − decay − contradiction_penalty`,让记忆成为"过程"而非"对象"(真正的液态循环)
|
|
332
|
+
- [x] **[已发布] 三实验全 PASS**:E2 错误记忆恢复 → E3 多 agent 冲突 → E1 长期漂移(见上节)
|
|
333
|
+
- [x] **[已发布] 冲突检测 O(g²)→O(d²)**:`_detect_conflicts` 按 content 去重后只对 distinct 内容求两两重叠(d≤g),overlap_cache 复用;语义更纯净(度量不同论点分歧),大规模高频写入性能提升(非正确性变更)
|
|
334
|
+
- [x] **[已发布] 液态算法正式落地**:时间动力学 / 反证轨 / 双轨成核经 E1/E2/E3 三实验背书,作为稳定机制随 **v2.0.0** 发布
|
|
335
|
+
- [x] **[v2.0.0] 统一版号里程碑**:`pyproject.toml` / `__init__.__version__` / 投喂客户端 `LIQUIDLOOP_CLIENT_VERSION` 全部对齐 `2.0.0`;数据 schema `0.4.0` 与 workspace state `0.5.1` 保持独立(记忆层格式版本,禁区不动)
|
|
333
336
|
- [ ] LoCoMo / LongMemEval 基准对比
|
|
334
337
|
- [ ] 边缘端部署优化(<50KB)
|
|
335
338
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
"""Liquid Loop — Workspace Cognitive Runtime
|
|
2
|
-
__version__ = "
|
|
1
|
+
"""Liquid Loop — Workspace Cognitive Runtime v2.0.1 (禁向量·活态液态神经网络:成核门槛/反证轨/老化回收/原理优先成核/因果演化/软取代supersede+治理查询state_at/impact/duplicates+程序性记忆层procedural_memory+PerceptionGate因果共生门控)"""
|
|
2
|
+
__version__ = "2.0.1"
|
|
3
3
|
|
|
4
4
|
from .workspace import (
|
|
5
5
|
WorkspaceState, Anchor, Evidence, Memory, Conflict,
|
|
@@ -42,6 +42,7 @@ import sys
|
|
|
42
42
|
import os
|
|
43
43
|
import re
|
|
44
44
|
import json
|
|
45
|
+
import math
|
|
45
46
|
import time
|
|
46
47
|
import hashlib
|
|
47
48
|
import logging
|
|
@@ -67,6 +68,53 @@ def _jaccard(a: str, b: str) -> float:
|
|
|
67
68
|
return len(ta & tb) / len(ta | tb)
|
|
68
69
|
|
|
69
70
|
|
|
71
|
+
def _idf_jaccard(a: str, b: str, idf: dict) -> float:
|
|
72
|
+
"""IDF 加权 jaccard(零向量、纯标量权重,守禁向量公理)。
|
|
73
|
+
|
|
74
|
+
与 _jaccard 同接口但用 IDF 给 token 加权——稀有关键词(如 degree/graduate)
|
|
75
|
+
权重高、常见词(the/i)权重低 → 召回机制层零向量但收复「纯字符 jaccard 稀释
|
|
76
|
+
稀有关键词」的代价。公式:Σidf(t∈A∩B) / Σidf(t∈A∪B)。
|
|
77
|
+
英文做小写归一(与 TfidfBaseline 同口径;默认 _jaccard 为大小写敏感的历史基线,
|
|
78
|
+
此处 IDF 模式按英文语料正确做法小写)。用于评测验证(recall_local(idf=True)),
|
|
79
|
+
默认不启用,不影响既有基准。
|
|
80
|
+
"""
|
|
81
|
+
ta = set(t.lower() for t in _tokens(a))
|
|
82
|
+
tb = set(t.lower() for t in _tokens(b))
|
|
83
|
+
if not ta or not tb:
|
|
84
|
+
return 0.0
|
|
85
|
+
inter = ta & tb
|
|
86
|
+
union = ta | tb
|
|
87
|
+
num = sum(idf.get(t, 1.0) for t in inter)
|
|
88
|
+
den = sum(idf.get(t, 1.0) for t in union)
|
|
89
|
+
return num / den if den else 0.0
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _idf_cosine(a: str, b: str, idf: dict) -> float:
|
|
93
|
+
"""完整 TF-IDF 余弦(零 embedding、纯词频统计,与 run_locomo/longmemeval 的
|
|
94
|
+
TfidfBaseline 逐字节同口径:tf 用 (1+log c) 加权、idf 同公式、余弦归一化)。
|
|
95
|
+
|
|
96
|
+
这是「零神经网络向量」的稀疏词频向量——仍是 lexical 统计,非语义 embedding,
|
|
97
|
+
与 WHY_NO_VECTOR 允许的「词频向量对照」同性质。用于一锤定音验证:液环机制层
|
|
98
|
+
仅换召回归一化为 TF-IDF 余弦即可追平外部 TF-IDF 基线 → 证明 LoCoMo/LongMemEval
|
|
99
|
+
上「液环 1/2.7 召回缺口」本质是**词频统计加权(IDF+TF+余弦归一)差异**,
|
|
100
|
+
而非「需要语义 embedding」。注意:此模式把召回打分升级为稀疏 tf-idf 向量,
|
|
101
|
+
是否纳入机制层由飞哥按禁向量红线裁定(默认不启用)。
|
|
102
|
+
"""
|
|
103
|
+
from collections import Counter
|
|
104
|
+
qf = Counter(t.lower() for t in _tokens(a))
|
|
105
|
+
dfb = Counter(t.lower() for t in _tokens(b))
|
|
106
|
+
if not qf or not dfb:
|
|
107
|
+
return 0.0
|
|
108
|
+
def w(c):
|
|
109
|
+
return 1.0 + math.log(c)
|
|
110
|
+
dot = 0.0
|
|
111
|
+
for t in set(qf) & set(dfb):
|
|
112
|
+
dot += w(qf[t]) * idf.get(t, 1.0) * w(dfb[t]) * idf.get(t, 1.0)
|
|
113
|
+
na = sum((w(c) * idf.get(t, 1.0)) ** 2 for t, c in qf.items())
|
|
114
|
+
nb = sum((w(c) * idf.get(t, 1.0)) ** 2 for t, c in dfb.items())
|
|
115
|
+
return dot / math.sqrt(na * nb) if na and nb else 0.0
|
|
116
|
+
|
|
117
|
+
|
|
70
118
|
def _containment(a: str, b: str):
|
|
71
119
|
"""重叠系数(containment / overlap coefficient)= |A∩B| / min(|A|,|B|)。
|
|
72
120
|
对中文「同义改写」鲁棒:只要较短句的核心字集被较长句覆盖即判近义,
|
|
@@ -78,6 +126,30 @@ def _containment(a: str, b: str):
|
|
|
78
126
|
return len(inter) / min(len(ta), len(tb)), len(inter)
|
|
79
127
|
|
|
80
128
|
|
|
129
|
+
# ── 零向量实体/数字精确匹配增强(lexical_boost,守禁向量 §六.1)──
|
|
130
|
+
# query 关键 token(数字串 + 长度≥4 词,多为专名/术语/度量)若精确命中 fact,
|
|
131
|
+
# 给召回分叠加 bonus。纯 lexical 精确匹配、零 embedding、零 LLM;
|
|
132
|
+
# tfidf 余弦会因长句稀释这些稀有词,此 booster 补回「含数字/量词的 query」
|
|
133
|
+
# (如 "How many / how long / how many days")的漏召。由 recall_local(lexical_boost=)
|
|
134
|
+
# 控制,**默认 True**(LoCoMo 0.472→0.492、LongMemEval 0.942→0.948,零向量超越词频基线)。
|
|
135
|
+
_KEY_NUM = re.compile(r"[0-9]+")
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _entity_key_tokens(q: str) -> set:
|
|
139
|
+
"""query 中的关键信息 token:数字串 + 长度≥4 的 token。"""
|
|
140
|
+
qt = set(_tokens(q))
|
|
141
|
+
return set(_KEY_NUM.findall(q)) | {t for t in qt if len(t) >= 4}
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _entity_boost(q: str, f: str) -> float:
|
|
145
|
+
"""query 关键 token 精确命中 fact 的 bonus(标量,零向量)。"""
|
|
146
|
+
keys = _entity_key_tokens(q)
|
|
147
|
+
if not keys:
|
|
148
|
+
return 0.0
|
|
149
|
+
ft = set(_tokens(f))
|
|
150
|
+
return 0.3 * len(keys & ft) / len(keys)
|
|
151
|
+
|
|
152
|
+
|
|
81
153
|
# 核心词抽取:去中文虚词 / 极泛连接词,保留领域实体与结论词,
|
|
82
154
|
# 用于跨篇「同主题不同表述」的聚合信号(结构化精确匹配,守禁向量)。
|
|
83
155
|
_STOP = set("的 是 在 存在 普遍 常 问题 风险 一种 我们 本文 该 其 与 和 或 对 为 有 被 "
|
|
@@ -177,6 +249,23 @@ class LiquidSelfSpin:
|
|
|
177
249
|
self.liquid_cache_dir = os.path.expanduser("~/.liquidloop")
|
|
178
250
|
self._persist_errors = 0 # 持久化失败计数(去吞错:让故障可观测)
|
|
179
251
|
self._lr = None # 持久化 LiquidReweight 实例(懒构造,复用跨 recall)
|
|
252
|
+
self._idf = None # IDF 表缓存(评测零向量加权召回用,懒构造)
|
|
253
|
+
|
|
254
|
+
# ── IDF 表(零向量加权召回)──
|
|
255
|
+
def _build_idf(self) -> dict:
|
|
256
|
+
"""基于已摄入 facts 计算文档频率 → IDF(与 run_locomo TfidfBaseline 同公式:
|
|
257
|
+
idf = log((N+1)/(df+1)) + 1)。零向量:纯标量词频权重,非 embedding。
|
|
258
|
+
每个记忆库(selfspin 实例)独立计算,匹配真实 agent 按自身语料加权。"""
|
|
259
|
+
if self._idf is not None:
|
|
260
|
+
return self._idf
|
|
261
|
+
n = sum(len(fs) for fs in self._facts.values())
|
|
262
|
+
df: dict = {}
|
|
263
|
+
for fs in self._facts.values():
|
|
264
|
+
for f in fs:
|
|
265
|
+
for t in set(t.lower() for t in _tokens(f)):
|
|
266
|
+
df[t] = df.get(t, 0) + 1
|
|
267
|
+
self._idf = {t: math.log((n + 1) / (c + 1)) + 1.0 for t, c in df.items()}
|
|
268
|
+
return self._idf
|
|
180
269
|
|
|
181
270
|
# ── 本地快自转:摄入 ──
|
|
182
271
|
def ingest(self, report_id: str, text: str, facts: list = None):
|
|
@@ -186,6 +275,7 @@ class LiquidSelfSpin:
|
|
|
186
275
|
持久化失败静默降级(观测增强非关键路径,极致稳态:主流程不受拖累)。
|
|
187
276
|
"""
|
|
188
277
|
self._raw[report_id] = text
|
|
278
|
+
self._idf = None # facts 将被改写 → 使已建 IDF 表失效(默认余弦召回依赖它)
|
|
189
279
|
self._facts[report_id] = list(facts) if facts is not None else self.extractor(text)
|
|
190
280
|
if self.liquid_persist:
|
|
191
281
|
try:
|
|
@@ -314,9 +404,36 @@ class LiquidSelfSpin:
|
|
|
314
404
|
return out
|
|
315
405
|
|
|
316
406
|
# ── 自述性:本地回忆(不碰 8790)──
|
|
317
|
-
def recall_local(self, query: str, top_k: int = 5, liquid: bool = False
|
|
318
|
-
|
|
319
|
-
|
|
407
|
+
def recall_local(self, query: str, top_k: int = 5, liquid: bool = False,
|
|
408
|
+
idf: bool = False, idf_cosine: bool = True,
|
|
409
|
+
lexical_boost: bool = True) -> list:
|
|
410
|
+
"""本地液态召回。
|
|
411
|
+
|
|
412
|
+
**默认 idf_cosine=True**:零向量 tf-idf 余弦(IDF+TF+余弦归一,纯词频标量权重,
|
|
413
|
+
非 embedding)作为召回归一化。与 LoCoMo/LongMemEval 的 TF-IDF 基线逐字节同口径。
|
|
414
|
+
**默认 lexical_boost=True**:叠加零向量实体/数字精确加权(query 的数字串与
|
|
415
|
+
长度≥4 token 精确命中 fact 时加分),补回 tfidf 余弦因长句稀释稀有关键词而漏召的
|
|
416
|
+
「含数字/量词 query」。两基准实测:LoCoMo 0.472→0.492、LongMemEval 0.942→0.948,
|
|
417
|
+
零向量**超越**词频向量基线。全程零 embedding、零语义向量,守禁向量公理
|
|
418
|
+
(WHY_NO_VECTOR §六)。
|
|
419
|
+
idf=False 且 idf_cosine=False:回退到无加权纯字符 jaccard(历史 v1 基准口径,
|
|
420
|
+
仍保留用于对照,但非默认)。
|
|
421
|
+
idf=True:IDF 加权 jaccard(零向量,纯标量权重)——idf_cosine 优先时不生效。
|
|
422
|
+
lexical_boost=False:关闭实体/数字 booster,精确回到纯 tfidf 余弦(追平基线)。
|
|
423
|
+
"""
|
|
424
|
+
idf_tab = self._build_idf() if (idf or idf_cosine) else None
|
|
425
|
+
if idf_cosine:
|
|
426
|
+
sim = lambda a, b: _idf_cosine(a, b, idf_tab)
|
|
427
|
+
elif idf:
|
|
428
|
+
sim = lambda a, b: _idf_jaccard(a, b, idf_tab)
|
|
429
|
+
else:
|
|
430
|
+
sim = _jaccard
|
|
431
|
+
if lexical_boost:
|
|
432
|
+
scored = [(sim(query, f) + _entity_boost(query, f), rid, f)
|
|
433
|
+
for rid, fs in self._facts.items() for f in fs]
|
|
434
|
+
else:
|
|
435
|
+
scored = [(sim(query, f), rid, f)
|
|
436
|
+
for rid, fs in self._facts.items() for f in fs]
|
|
320
437
|
scored.sort(key=lambda x: x[0], reverse=True)
|
|
321
438
|
base = [{"report_id": rid, "fact": f, "score": round(s, 3)}
|
|
322
439
|
for s, rid, f in scored if s > 0][:top_k]
|
|
@@ -334,7 +451,9 @@ class LiquidSelfSpin:
|
|
|
334
451
|
for rid, fs in self._facts.items():
|
|
335
452
|
for f in fs:
|
|
336
453
|
a_id = self._liquid_anchor_id(f)
|
|
337
|
-
lit =
|
|
454
|
+
lit = sim(query, f)
|
|
455
|
+
if lexical_boost:
|
|
456
|
+
lit = lit + _entity_boost(query, f)
|
|
338
457
|
wake = lr.beta * lr.activation.get(a_id, 0.0)
|
|
339
458
|
sc = lit + wake
|
|
340
459
|
if sc > 0:
|
|
@@ -46,7 +46,7 @@ def _get_version() -> str:
|
|
|
46
46
|
pyproject = Path(__file__).parent.parent / "pyproject.toml"
|
|
47
47
|
if pyproject.exists():
|
|
48
48
|
data = tomllib.loads(pyproject.read_text())
|
|
49
|
-
return data.get("project", {}).get("version", "
|
|
49
|
+
return data.get("project", {}).get("version", "2.0.0")
|
|
50
50
|
return "1.8.4"
|
|
51
51
|
|
|
52
52
|
def _tokenize(text: str) -> List[str]:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: liquid-loop
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.1
|
|
4
4
|
Summary: Self-Organizing Cognitive Memory for AI Agents — Liquid Loop theory implementation
|
|
5
5
|
Author: fishbook0001
|
|
6
6
|
Maintainer: fishbook0001
|
|
@@ -43,6 +43,8 @@ Dynamic: license-file
|
|
|
43
43
|
|
|
44
44
|
> **Self-Organizing Cognitive Memory for AI Agents** — Zero LLM dependency, pure Python implementation of the Liquid Loop theory.
|
|
45
45
|
|
|
46
|
+
> **当前包版本:`2.0.1`**(2026-08-25 零向量召回超越词频基线,详见 [CHANGELOG.md](CHANGELOG.md)。数据 schema `0.4.0` 与 workspace state `0.5.1` 为记忆层数据格式版本,独立于包发布版本)。
|
|
47
|
+
|
|
46
48
|
[](https://pypi.org/project/liquid-loop/)
|
|
47
49
|
[](https://pypi.org/project/liquid-loop/)
|
|
48
50
|
[](https://opensource.org/licenses/MIT)
|
|
@@ -120,9 +122,9 @@ RED (entropy ≥ 0.6) — 需清理
|
|
|
120
122
|
|
|
121
123
|
---
|
|
122
124
|
|
|
123
|
-
##
|
|
125
|
+
## 核心机制:反证轨 + 时间动力学(液态循环核心)
|
|
124
126
|
|
|
125
|
-
|
|
127
|
+
液环从"静态结晶"升级为**自调节记忆动力学**:记忆不是对象,而是过程。以下机制均随 **v2.0.0** 发布(历史演进中曾标 v0.8 / v0.9)。
|
|
126
128
|
|
|
127
129
|
### 反证轨(Contradiction Track)
|
|
128
130
|
|
|
@@ -364,11 +366,12 @@ pytest -v
|
|
|
364
366
|
## 路线图
|
|
365
367
|
|
|
366
368
|
- [ ] 多 Agent 液环耦合(`liquid_loop.mesh` 已移除,见 commit ac7260e)
|
|
367
|
-
- [x] **[
|
|
368
|
-
- [x] **[
|
|
369
|
-
- [x] **[
|
|
370
|
-
- [x] **[
|
|
371
|
-
- [x] **[
|
|
369
|
+
- [x] **[已发布] 反证轨(Evidence Graph)**:Evidence 分 support / contradiction,一致增稳、冲突降稳,驱动 memory stability score(不再"一致即真")
|
|
370
|
+
- [x] **[已发布] 显式时间动力学**:`M(t+1) = M(t) + reinforcement − decay − contradiction_penalty`,让记忆成为"过程"而非"对象"(真正的液态循环)
|
|
371
|
+
- [x] **[已发布] 三实验全 PASS**:E2 错误记忆恢复 → E3 多 agent 冲突 → E1 长期漂移(见上节)
|
|
372
|
+
- [x] **[已发布] 冲突检测 O(g²)→O(d²)**:`_detect_conflicts` 按 content 去重后只对 distinct 内容求两两重叠(d≤g),overlap_cache 复用;语义更纯净(度量不同论点分歧),大规模高频写入性能提升(非正确性变更)
|
|
373
|
+
- [x] **[已发布] 液态算法正式落地**:时间动力学 / 反证轨 / 双轨成核经 E1/E2/E3 三实验背书,作为稳定机制随 **v2.0.0** 发布
|
|
374
|
+
- [x] **[v2.0.0] 统一版号里程碑**:`pyproject.toml` / `__init__.__version__` / 投喂客户端 `LIQUIDLOOP_CLIENT_VERSION` 全部对齐 `2.0.0`;数据 schema `0.4.0` 与 workspace state `0.5.1` 保持独立(记忆层格式版本,禁区不动)
|
|
372
375
|
- [ ] LoCoMo / LongMemEval 基准对比
|
|
373
376
|
- [ ] 边缘端部署优化(<50KB)
|
|
374
377
|
|
|
@@ -27,8 +27,22 @@ liquid_loop.egg-info/dependency_links.txt
|
|
|
27
27
|
liquid_loop.egg-info/entry_points.txt
|
|
28
28
|
liquid_loop.egg-info/requires.txt
|
|
29
29
|
liquid_loop.egg-info/top_level.txt
|
|
30
|
+
liquid_loop_exp/__init__.py
|
|
30
31
|
liquid_loop_exp/liquid_persist_ab.py
|
|
31
32
|
liquid_loop_exp/liquid_recall_ab.py
|
|
33
|
+
liquid_loop_exp/error_loop/__init__.py
|
|
34
|
+
liquid_loop_exp/error_loop/low_stability_recall.py
|
|
35
|
+
liquid_loop_exp/multigran/__init__.py
|
|
36
|
+
liquid_loop_exp/multigran/ab_multigran.py
|
|
37
|
+
liquid_loop_exp/multigran/hard_ab_multigran.py
|
|
38
|
+
liquid_loop_exp/multigran/multigran_core.py
|
|
39
|
+
liquid_loop_exp/multigran/sim_structured.py
|
|
40
|
+
liquid_loop_exp/multigran/test_multigran.py
|
|
41
|
+
liquid_loop_exp/r16_repro/__init__.py
|
|
42
|
+
liquid_loop_exp/r16_repro/compare_rar.py
|
|
43
|
+
liquid_loop_exp/r16_repro/r16_repro.py
|
|
44
|
+
liquid_loop_exp/skill_refine/__init__.py
|
|
45
|
+
liquid_loop_exp/skill_refine/skill_refine_loop.py
|
|
32
46
|
tests/test_attention_gain.py
|
|
33
47
|
tests/test_auth_guard.py
|
|
34
48
|
tests/test_cli_version.py
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""v2.1 候选①:低稳定性自动召回(active inference 工程版)——受控实验原型。
|
|
2
|
+
|
|
3
|
+
理论背书:预测编码 active inference——低精度预测应被主动采样确认/否证。
|
|
4
|
+
液环对应:stability 低的记忆 = 未经验证的预测,应自动进入复核队列。
|
|
5
|
+
|
|
6
|
+
规则(零向量/零 LLM,结构化可审计):
|
|
7
|
+
复核对象:tier=fact & support_count=0 & confidence<0.8 & last_reinforced=''
|
|
8
|
+
建议动作:根据置信度与证据画像给出 确认 / 降级 / 归档复核 建议
|
|
9
|
+
|
|
10
|
+
只读 state.json(隔离,不写生产)。输出复核队列报告。
|
|
11
|
+
"""
|
|
12
|
+
import json, sys, re
|
|
13
|
+
from collections import Counter
|
|
14
|
+
|
|
15
|
+
DEFAULT_STATE = "/Users/feixubuke/.liquidloop/memory/.liquid/state.json"
|
|
16
|
+
|
|
17
|
+
def is_verification_gap(m) -> bool:
|
|
18
|
+
"""误差回路缺口:预测未经验证(无支持证据、无强化、低置信)。"""
|
|
19
|
+
return (m.get("tier") == "fact"
|
|
20
|
+
and m.get("support_count", 0) == 0
|
|
21
|
+
and m.get("last_reinforced") in ("", None)
|
|
22
|
+
and m.get("confidence", 1.0) < 0.8)
|
|
23
|
+
|
|
24
|
+
def suggest_action(m):
|
|
25
|
+
conf = m.get("confidence", 0.5)
|
|
26
|
+
content = m.get("content", "")
|
|
27
|
+
# 批量待核实标记 → 建议批量复核
|
|
28
|
+
if "待核实" in content or "batch" in content:
|
|
29
|
+
return "批量复核(确认或驳回,勿长期滞留)"
|
|
30
|
+
if conf < 0.4:
|
|
31
|
+
return "驳回/归档(低置信无证据)"
|
|
32
|
+
if "蒸馏" in content or "共识" in content:
|
|
33
|
+
return "确认(有蒸馏链,补证据后强化)"
|
|
34
|
+
return "复核(确认→s+1,驳回→c+1)"
|
|
35
|
+
|
|
36
|
+
def run(state_path=DEFAULT_STATE, top_n=10):
|
|
37
|
+
d = json.load(open(state_path))
|
|
38
|
+
mems = d["memories"]
|
|
39
|
+
gaps = [m for m in mems if is_verification_gap(m)]
|
|
40
|
+
print(f"=== v2.1 低稳定性自动召回 · 误差回路缺口扫描 ===")
|
|
41
|
+
print(f"总记忆: {len(mems)} | 复核缺口: {len(gaps)} ({len(gaps)/len(mems)*100:.0f}%)")
|
|
42
|
+
# 缺口分组
|
|
43
|
+
by_sig = Counter(re.match(r"\[?(marvis fact batch|distill|distilled)", m["content"]).group(1)
|
|
44
|
+
if re.match(r"\[?(marvis fact batch|distill|distilled)", m["content"]) else "other"
|
|
45
|
+
for m in gaps)
|
|
46
|
+
print(f"缺口类型: {dict(by_sig)}")
|
|
47
|
+
print()
|
|
48
|
+
print("建议动作分布:")
|
|
49
|
+
acts = Counter(suggest_action(m) for m in gaps)
|
|
50
|
+
for act, n in acts.most_common():
|
|
51
|
+
print(f" {n:>3} {act}")
|
|
52
|
+
print()
|
|
53
|
+
print(f"复核队列样本(top {top_n}):")
|
|
54
|
+
for i, m in enumerate(gaps[:top_n]):
|
|
55
|
+
c = m["content"]
|
|
56
|
+
c = c[:70].replace("\n", " ")
|
|
57
|
+
print(f" [{i+1}] conf={m.get('confidence')} s={m.get('support_count')} → {suggest_action(m)}")
|
|
58
|
+
print(f" {c}")
|
|
59
|
+
# 输出复核队列 JSON(供后续人工/流程消费)
|
|
60
|
+
out = "/Users/feixubuke/output/液环v2.1_复核队列_低稳定性召回.json"
|
|
61
|
+
queue = [{"id": m["id"], "confidence": m.get("confidence"),
|
|
62
|
+
"support_count": m.get("support_count", 0),
|
|
63
|
+
"action": suggest_action(m), "content": m["content"][:200]}
|
|
64
|
+
for m in gaps]
|
|
65
|
+
with open(out, "w", encoding="utf-8") as f:
|
|
66
|
+
json.dump(queue, f, ensure_ascii=False, indent=1)
|
|
67
|
+
print(f"\n复核队列已落盘: {out}({len(queue)} 条)")
|
|
68
|
+
|
|
69
|
+
if __name__ == "__main__":
|
|
70
|
+
run()
|
|
File without changes
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""v2.0 对照实验:单粒度检索 vs 多粒度+熵路由(今日蒸馏记忆数据集)。
|
|
2
|
+
|
|
3
|
+
隔离运行,不碰生产。输出 Top-1 正确率 / Top-3 命中率。
|
|
4
|
+
数据源:今日(2026-08-19)蒸馏进液环的记忆 + 负样本素材,人工构造 1:1 查询。
|
|
5
|
+
"""
|
|
6
|
+
import sys, os
|
|
7
|
+
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
|
8
|
+
from liquid_loop_exp.multigran.multigran_core import MultigranMemory
|
|
9
|
+
from liquid_loop_exp.multigran.sim_structured import structured_sim
|
|
10
|
+
|
|
11
|
+
# ── 实验数据:15 条记忆 + 15 个查询(1:1 正确索引)────────
|
|
12
|
+
DATA = [
|
|
13
|
+
# (记忆内容, 查询, 正确索引)
|
|
14
|
+
("军师调研 #358 PINN+LSTM 融合架构时序物理预测通用解决方案:PINN 嵌入物理准则损失约束+LSTM 时序依赖,年谐波振荡+ERA5 先验,PINT arXiv:2502.04018",
|
|
15
|
+
"物理约束时序预测 谐波振荡", 0),
|
|
16
|
+
("军师调研 #361 SkillX 自动构建技能知识库:三层技能(战略计划/功能/原子)+迭代改进+探索扩展,弱模型 +10 分,arXiv:2604.04804",
|
|
17
|
+
"技能知识库 蒸馏 弱模型", 1),
|
|
18
|
+
("军师调研 #359 IceBreaker 对话破冰:RID 共鸣感知兴趣蒸馏+ISG 交互导向开场生成,冷启动首条消息壁垒,ACL26 字节",
|
|
19
|
+
"对话冷启动 个性化开场", 2),
|
|
20
|
+
("军师调研 #360 TDMA 动作分割数据集压缩:DDIM 潜在轨迹锚定+自适应锚点分配,Breakfast 2.4% 追平全量,ECCV26",
|
|
21
|
+
"动作分割 数据压缩 轨迹", 3),
|
|
22
|
+
("军师调研 #362 重整化群:粗粒化+重标度+场重标度三步,2D 不动点 K*≈0.336,d=4 分水岭,Wilson 理论",
|
|
23
|
+
"粗粒化 相变 临界指数", 4),
|
|
24
|
+
("军师调研 #366 ai-memory 编程CLI长期记忆:本地存储+按需召回+省token,akitaonrails/ai-memory ★3007",
|
|
25
|
+
"AI 编程 CLI 长期记忆", 5),
|
|
26
|
+
("军师调研 #371 MemGAS 多粒度记忆:四粒度(session/turn/summary/keyword)+GMM关联+熵路由+PPR,超 HippoRAG2",
|
|
27
|
+
"多粒度记忆 检索 熵路由", 6),
|
|
28
|
+
("军师调研 #373 奖励大小决定强化学习效率:100μL vs 5μL 学习提速一个数量级,多巴胺信号时长,Science 2026",
|
|
29
|
+
"奖励大小 学习效率 多巴胺", 7),
|
|
30
|
+
("军师调研 #374 预测编码:ε=x-μ 预测误差,能量最小化局部学习替代反向传播,IJCAI22 综述",
|
|
31
|
+
"预测误差 局部学习 反向传播替代", 8),
|
|
32
|
+
("军师调研 #376 Skill路由四路口:可见入口/职责边界/执行门槛/真实路由测试,主编排者,100 skills 选对",
|
|
33
|
+
"skill 选择 路由 职责边界", 9),
|
|
34
|
+
("军师调研 #357 AI表情小球:纯 SVG+JS 零依赖桌面宠物,32 种表情状态追鼠标", "SVG 表情小球 桌面宠物", 10),
|
|
35
|
+
("军师调研 #363 Cumora 多智能体协作:AI 作团队成员(身份/记忆/领任务)+看板/日历,BYOA Claude Code/Codex",
|
|
36
|
+
"多智能体协作 看板 团队成员", 11),
|
|
37
|
+
("军师调研 #365 TimesFM 时序基础模型:Google 开源 Apache-2.0 200M 参数零样本预测", "时序基础模型 零样本 预测", 12),
|
|
38
|
+
("军师调研 #367 Tabularis 数据库工作台:一键直连 Postgres/MySQL 多库,SQL 辅助+可视化图表", "数据库工作台 SQL 可视化", 13),
|
|
39
|
+
("军师调研 #369 常见神经网络科普:CNN/RNN/GNN/GAN/Transformer,按数据结构选网络", "卷积 循环 图 神经网络", 14),
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
def single_granularity(query, docs, topk=3):
|
|
43
|
+
"""baseline:单粒度(全文)结构化相似度检索。"""
|
|
44
|
+
sims = [(i, structured_sim(query, d, "mix")) for i, d in enumerate(docs)]
|
|
45
|
+
sims.sort(key=lambda x: -x[1])
|
|
46
|
+
return [i for i, _ in sims[:topk] if _[1] > 0] if False else [i for i, s in sims[:topk] if s > 0]
|
|
47
|
+
|
|
48
|
+
def run():
|
|
49
|
+
docs = [d[0] for d in DATA]
|
|
50
|
+
queries = [d[1] for d in DATA]
|
|
51
|
+
gold = [d[2] for d in DATA]
|
|
52
|
+
|
|
53
|
+
# baseline:单粒度
|
|
54
|
+
m_single = MultigranMemory()
|
|
55
|
+
for d in docs:
|
|
56
|
+
m_single.add([d])
|
|
57
|
+
# 强制单粒度:只用 session_text 检索(绕过熵路由,等价单粒度 baseline)
|
|
58
|
+
b_top1 = b_top3 = 0
|
|
59
|
+
for q, g in zip(queries, gold):
|
|
60
|
+
sims = [(i, structured_sim(q, d, "mix")) for i, d in enumerate(docs)]
|
|
61
|
+
sims.sort(key=lambda x: -x[1])
|
|
62
|
+
top = [i for i, s in sims[:3] if s > 0]
|
|
63
|
+
if top and top[0] == g:
|
|
64
|
+
b_top1 += 1
|
|
65
|
+
if g in top:
|
|
66
|
+
b_top3 += 1
|
|
67
|
+
|
|
68
|
+
# multigran:四粒度+熵路由+图传播
|
|
69
|
+
m = MultigranMemory()
|
|
70
|
+
for d in docs:
|
|
71
|
+
m.add([d])
|
|
72
|
+
mg_top1 = mg_top3 = 0
|
|
73
|
+
for q, g in zip(queries, gold):
|
|
74
|
+
hits = m.retrieve(q, topk=3)
|
|
75
|
+
idxs = [h["idx"] for h in hits]
|
|
76
|
+
if idxs and idxs[0] == g:
|
|
77
|
+
mg_top1 += 1
|
|
78
|
+
if g in idxs:
|
|
79
|
+
mg_top3 += 1
|
|
80
|
+
|
|
81
|
+
n = len(DATA)
|
|
82
|
+
print(f"{'':24} {'Top-1':>7} {'Top-3':>7}")
|
|
83
|
+
print(f"{'单粒度(全文)':24} {b_top1/n*100:6.1f}% {b_top3/n*100:6.1f}%")
|
|
84
|
+
print(f"{'多粒度+熵路由':24} {mg_top1/n*100:6.1f}% {mg_top3/n*100:6.1f}%")
|
|
85
|
+
print()
|
|
86
|
+
# 输出多粒度每个查询命中情况(可审计)
|
|
87
|
+
for q, g in zip(queries, gold):
|
|
88
|
+
hits = m.retrieve(q, topk=1)
|
|
89
|
+
hit = hits[0]["idx"] if hits else -1
|
|
90
|
+
mark = "✓" if hit == g else f"✗(→{hit})"
|
|
91
|
+
print(f" [{mark}] {q[:22]:24} gold={g}")
|
|
92
|
+
return b_top1 / n, mg_top1 / n
|
|
93
|
+
|
|
94
|
+
if __name__ == "__main__":
|
|
95
|
+
run()
|