liquid-loop 1.9.0__tar.gz → 2.0.0__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.
Files changed (70) hide show
  1. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/PKG-INFO +11 -8
  2. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/README.md +10 -7
  3. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/__init__.py +2 -2
  4. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/selfspin.py +87 -3
  5. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/textutil.py +1 -1
  6. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop.egg-info/PKG-INFO +11 -8
  7. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop.egg-info/SOURCES.txt +14 -0
  8. liquid_loop-2.0.0/liquid_loop_exp/__init__.py +0 -0
  9. liquid_loop-2.0.0/liquid_loop_exp/error_loop/__init__.py +0 -0
  10. liquid_loop-2.0.0/liquid_loop_exp/error_loop/low_stability_recall.py +70 -0
  11. liquid_loop-2.0.0/liquid_loop_exp/multigran/__init__.py +0 -0
  12. liquid_loop-2.0.0/liquid_loop_exp/multigran/ab_multigran.py +95 -0
  13. liquid_loop-2.0.0/liquid_loop_exp/multigran/hard_ab_multigran.py +156 -0
  14. liquid_loop-2.0.0/liquid_loop_exp/multigran/multigran_core.py +178 -0
  15. liquid_loop-2.0.0/liquid_loop_exp/multigran/sim_structured.py +40 -0
  16. liquid_loop-2.0.0/liquid_loop_exp/multigran/test_multigran.py +50 -0
  17. liquid_loop-2.0.0/liquid_loop_exp/r16_repro/__init__.py +0 -0
  18. liquid_loop-2.0.0/liquid_loop_exp/r16_repro/compare_rar.py +89 -0
  19. liquid_loop-2.0.0/liquid_loop_exp/r16_repro/r16_repro.py +204 -0
  20. liquid_loop-2.0.0/liquid_loop_exp/skill_refine/__init__.py +0 -0
  21. liquid_loop-2.0.0/liquid_loop_exp/skill_refine/skill_refine_loop.py +128 -0
  22. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/pyproject.toml +1 -1
  23. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/LICENSE +0 -0
  24. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/__main__.py +0 -0
  25. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/audit.py +0 -0
  26. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/cli.py +0 -0
  27. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/cognitive_budget.py +0 -0
  28. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/context_compress.py +0 -0
  29. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/cpe.py +0 -0
  30. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/entropy.py +0 -0
  31. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/guard.py +0 -0
  32. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/liquid_reweight.py +0 -0
  33. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/procedural_memory.py +0 -0
  34. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/rar.py +0 -0
  35. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/recall_filter.py +0 -0
  36. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/self_eval.py +0 -0
  37. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/self_refine.py +0 -0
  38. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/session.py +0 -0
  39. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/storage.py +0 -0
  40. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop/workspace.py +0 -0
  41. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop.egg-info/dependency_links.txt +0 -0
  42. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop.egg-info/entry_points.txt +0 -0
  43. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop.egg-info/requires.txt +0 -0
  44. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop.egg-info/top_level.txt +0 -0
  45. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop_exp/liquid_persist_ab.py +0 -0
  46. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/liquid_loop_exp/liquid_recall_ab.py +0 -0
  47. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/setup.cfg +0 -0
  48. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_attention_gain.py +0 -0
  49. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_auth_guard.py +0 -0
  50. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_cli_version.py +0 -0
  51. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_consensus_expansion.py +0 -0
  52. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_context_compress.py +0 -0
  53. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_entropy.py +0 -0
  54. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_guard_session_recall.py +0 -0
  55. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_layer1_persistence.py +0 -0
  56. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_lifecycle.py +0 -0
  57. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_liquid_reweight.py +0 -0
  58. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_nucleate_dual_track.py +0 -0
  59. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_peek_seal.py +0 -0
  60. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_perception_gate.py +0 -0
  61. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_procedural_memory.py +0 -0
  62. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_rar.py +0 -0
  63. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_recall_filter.py +0 -0
  64. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_replay_pressure.py +0 -0
  65. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_seal_persistence.py +0 -0
  66. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_self_eval.py +0 -0
  67. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_self_evolve.py +0 -0
  68. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_selfspin.py +0 -0
  69. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_semantica_borrow.py +0 -0
  70. {liquid_loop-1.9.0 → liquid_loop-2.0.0}/tests/test_workspace.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: liquid-loop
3
- Version: 1.9.0
3
+ Version: 2.0.0
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.0`**(2026-08-24 统一版号里程碑,详见 [CHANGELOG.md](CHANGELOG.md)。数据 schema `0.4.0` 与 workspace state `0.5.1` 为记忆层数据格式版本,独立于包发布版本)。
47
+
46
48
  [![PyPI](https://img.shields.io/pypi/v/liquid-loop.svg)](https://pypi.org/project/liquid-loop/)
47
49
  [![Python](https://img.shields.io/pypi/pyversions/liquid-loop.svg)](https://pypi.org/project/liquid-loop/)
48
50
  [![License](https://img.shields.io/pypi/l/liquid-loop.svg)](https://opensource.org/licenses/MIT)
@@ -120,9 +122,9 @@ RED (entropy ≥ 0.6) — 需清理
120
122
 
121
123
  ---
122
124
 
123
- ## v0.8 反证轨 + 时间动力学(液态循环核心)
125
+ ## 核心机制:反证轨 + 时间动力学(液态循环核心)
124
126
 
125
- 液环 v0.8 从"静态结晶"升级为**自调节记忆动力学**:记忆不是对象,而是过程。
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] **[v0.8] 反证轨(Evidence Graph)**:Evidence 分 support / contradiction,一致增稳、冲突降稳,驱动 memory stability score(不再"一致即真")
368
- - [x] **[v0.8] 显式时间动力学**:`M(t+1) = M(t) + reinforcement − decay − contradiction_penalty`,让记忆成为"过程"而非"对象"(真正的液态循环)
369
- - [x] **[v0.8] 三实验全 PASS**:E2 错误记忆恢复 → E3 多 agent 冲突 → E1 长期漂移(见上节)
370
- - [x] **[v0.9] 冲突检测 O(g²)→O(d²)**:`_detect_conflicts` 按 content 去重后只对 distinct 内容求两两重叠(d≤g),overlap_cache 复用;语义更纯净(度量不同论点分歧),大规模高频写入性能提升(非正确性变更)
371
- - [x] **[v0.9] 液态算法正式落地**:时间动力学 / 反证轨 / 双轨成核在 v0.8 已实现并经 E1/E2/E3 三实验背书,v0.9 作为稳定版正式发布(README 顶部 Hero Banner 已上线)
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.0`**(2026-08-24 统一版号里程碑,详见 [CHANGELOG.md](CHANGELOG.md)。数据 schema `0.4.0` 与 workspace state `0.5.1` 为记忆层数据格式版本,独立于包发布版本)。
8
+
7
9
  [![PyPI](https://img.shields.io/pypi/v/liquid-loop.svg)](https://pypi.org/project/liquid-loop/)
8
10
  [![Python](https://img.shields.io/pypi/pyversions/liquid-loop.svg)](https://pypi.org/project/liquid-loop/)
9
11
  [![License](https://img.shields.io/pypi/l/liquid-loop.svg)](https://opensource.org/licenses/MIT)
@@ -81,9 +83,9 @@ RED (entropy ≥ 0.6) — 需清理
81
83
 
82
84
  ---
83
85
 
84
- ## v0.8 反证轨 + 时间动力学(液态循环核心)
86
+ ## 核心机制:反证轨 + 时间动力学(液态循环核心)
85
87
 
86
- 液环 v0.8 从"静态结晶"升级为**自调节记忆动力学**:记忆不是对象,而是过程。
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] **[v0.8] 反证轨(Evidence Graph)**:Evidence 分 support / contradiction,一致增稳、冲突降稳,驱动 memory stability score(不再"一致即真")
329
- - [x] **[v0.8] 显式时间动力学**:`M(t+1) = M(t) + reinforcement − decay − contradiction_penalty`,让记忆成为"过程"而非"对象"(真正的液态循环)
330
- - [x] **[v0.8] 三实验全 PASS**:E2 错误记忆恢复 → E3 多 agent 冲突 → E1 长期漂移(见上节)
331
- - [x] **[v0.9] 冲突检测 O(g²)→O(d²)**:`_detect_conflicts` 按 content 去重后只对 distinct 内容求两两重叠(d≤g),overlap_cache 复用;语义更纯净(度量不同论点分歧),大规模高频写入性能提升(非正确性变更)
332
- - [x] **[v0.9] 液态算法正式落地**:时间动力学 / 反证轨 / 双轨成核在 v0.8 已实现并经 E1/E2/E3 三实验背书,v0.9 作为稳定版正式发布(README 顶部 Hero Banner 已上线)
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 v1.9.0 (禁向量·活态液态神经网络:成核门槛/反证轨/老化回收/原理优先成核/因果演化/软取代supersede+治理查询state_at/impact/duplicates+程序性记忆层procedural_memory+PerceptionGate因果共生门控)"""
2
- __version__ = "1.9.0"
1
+ """Liquid Loop — Workspace Cognitive Runtime v2.0.0 (禁向量·活态液态神经网络:成核门槛/反证轨/老化回收/原理优先成核/因果演化/软取代supersede+治理查询state_at/impact/duplicates+程序性记忆层procedural_memory+PerceptionGate因果共生门控)"""
2
+ __version__ = "2.0.0"
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
  对中文「同义改写」鲁棒:只要较短句的核心字集被较长句覆盖即判近义,
@@ -177,6 +225,23 @@ class LiquidSelfSpin:
177
225
  self.liquid_cache_dir = os.path.expanduser("~/.liquidloop")
178
226
  self._persist_errors = 0 # 持久化失败计数(去吞错:让故障可观测)
179
227
  self._lr = None # 持久化 LiquidReweight 实例(懒构造,复用跨 recall)
228
+ self._idf = None # IDF 表缓存(评测零向量加权召回用,懒构造)
229
+
230
+ # ── IDF 表(零向量加权召回)──
231
+ def _build_idf(self) -> dict:
232
+ """基于已摄入 facts 计算文档频率 → IDF(与 run_locomo TfidfBaseline 同公式:
233
+ idf = log((N+1)/(df+1)) + 1)。零向量:纯标量词频权重,非 embedding。
234
+ 每个记忆库(selfspin 实例)独立计算,匹配真实 agent 按自身语料加权。"""
235
+ if self._idf is not None:
236
+ return self._idf
237
+ n = sum(len(fs) for fs in self._facts.values())
238
+ df: dict = {}
239
+ for fs in self._facts.values():
240
+ for f in fs:
241
+ for t in set(t.lower() for t in _tokens(f)):
242
+ df[t] = df.get(t, 0) + 1
243
+ self._idf = {t: math.log((n + 1) / (c + 1)) + 1.0 for t, c in df.items()}
244
+ return self._idf
180
245
 
181
246
  # ── 本地快自转:摄入 ──
182
247
  def ingest(self, report_id: str, text: str, facts: list = None):
@@ -186,6 +251,7 @@ class LiquidSelfSpin:
186
251
  持久化失败静默降级(观测增强非关键路径,极致稳态:主流程不受拖累)。
187
252
  """
188
253
  self._raw[report_id] = text
254
+ self._idf = None # facts 将被改写 → 使已建 IDF 表失效(默认余弦召回依赖它)
189
255
  self._facts[report_id] = list(facts) if facts is not None else self.extractor(text)
190
256
  if self.liquid_persist:
191
257
  try:
@@ -314,8 +380,26 @@ class LiquidSelfSpin:
314
380
  return out
315
381
 
316
382
  # ── 自述性:本地回忆(不碰 8790)──
317
- def recall_local(self, query: str, top_k: int = 5, liquid: bool = False) -> list:
318
- scored = [(_jaccard(query, f), rid, f)
383
+ def recall_local(self, query: str, top_k: int = 5, liquid: bool = False,
384
+ idf: bool = False, idf_cosine: bool = True) -> list:
385
+ """本地液态召回。
386
+
387
+ **默认 idf_cosine=True**:零向量 tf-idf 余弦(IDF+TF+余弦归一,纯词频标量权重,
388
+ 非 embedding)作为召回归一化。与 LoCoMo/LongMemEval 的 TF-IDF 基线逐字节同口径,
389
+ 在两者上精确追平词频向量基线——收复「纯字符 jaccard 稀释稀有关键词」的召回代价,
390
+ 全程零 embedding、零语义向量,守禁向量公理(WHY_NO_VECTOR §六)。
391
+ idf=False 且 idf_cosine=False:回退到无加权纯字符 jaccard(历史 v1 基准口径,
392
+ 仍保留用于对照,但非默认)。
393
+ idf=True:IDF 加权 jaccard(零向量,纯标量权重)——idf_cosine 优先时不生效。
394
+ """
395
+ idf_tab = self._build_idf() if (idf or idf_cosine) else None
396
+ if idf_cosine:
397
+ sim = lambda a, b: _idf_cosine(a, b, idf_tab)
398
+ elif idf:
399
+ sim = lambda a, b: _idf_jaccard(a, b, idf_tab)
400
+ else:
401
+ sim = _jaccard
402
+ scored = [(sim(query, f), rid, f)
319
403
  for rid, fs in self._facts.items() for f in fs]
320
404
  scored.sort(key=lambda x: x[0], reverse=True)
321
405
  base = [{"report_id": rid, "fact": f, "score": round(s, 3)}
@@ -334,7 +418,7 @@ class LiquidSelfSpin:
334
418
  for rid, fs in self._facts.items():
335
419
  for f in fs:
336
420
  a_id = self._liquid_anchor_id(f)
337
- lit = _jaccard(query, f)
421
+ lit = sim(query, f)
338
422
  wake = lr.beta * lr.activation.get(a_id, 0.0)
339
423
  sc = lit + wake
340
424
  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", "1.8.4")
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: 1.9.0
3
+ Version: 2.0.0
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.0`**(2026-08-24 统一版号里程碑,详见 [CHANGELOG.md](CHANGELOG.md)。数据 schema `0.4.0` 与 workspace state `0.5.1` 为记忆层数据格式版本,独立于包发布版本)。
47
+
46
48
  [![PyPI](https://img.shields.io/pypi/v/liquid-loop.svg)](https://pypi.org/project/liquid-loop/)
47
49
  [![Python](https://img.shields.io/pypi/pyversions/liquid-loop.svg)](https://pypi.org/project/liquid-loop/)
48
50
  [![License](https://img.shields.io/pypi/l/liquid-loop.svg)](https://opensource.org/licenses/MIT)
@@ -120,9 +122,9 @@ RED (entropy ≥ 0.6) — 需清理
120
122
 
121
123
  ---
122
124
 
123
- ## v0.8 反证轨 + 时间动力学(液态循环核心)
125
+ ## 核心机制:反证轨 + 时间动力学(液态循环核心)
124
126
 
125
- 液环 v0.8 从"静态结晶"升级为**自调节记忆动力学**:记忆不是对象,而是过程。
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] **[v0.8] 反证轨(Evidence Graph)**:Evidence 分 support / contradiction,一致增稳、冲突降稳,驱动 memory stability score(不再"一致即真")
368
- - [x] **[v0.8] 显式时间动力学**:`M(t+1) = M(t) + reinforcement − decay − contradiction_penalty`,让记忆成为"过程"而非"对象"(真正的液态循环)
369
- - [x] **[v0.8] 三实验全 PASS**:E2 错误记忆恢复 → E3 多 agent 冲突 → E1 长期漂移(见上节)
370
- - [x] **[v0.9] 冲突检测 O(g²)→O(d²)**:`_detect_conflicts` 按 content 去重后只对 distinct 内容求两两重叠(d≤g),overlap_cache 复用;语义更纯净(度量不同论点分歧),大规模高频写入性能提升(非正确性变更)
371
- - [x] **[v0.9] 液态算法正式落地**:时间动力学 / 反证轨 / 双轨成核在 v0.8 已实现并经 E1/E2/E3 三实验背书,v0.9 作为稳定版正式发布(README 顶部 Hero Banner 已上线)
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
@@ -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()
@@ -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()
@@ -0,0 +1,156 @@
1
+ """v2.0 难场景对照实验:语义等价字面不重叠查询 + 相近主题干扰项。
2
+
3
+ 设计意图(区分度核心):
4
+ 1. 5 个难查询用同义/释义表达,不含原文关键词——考验非字面检索能力
5
+ 2. 5 条干扰项与目标记忆主题相近、且与难查询部分字面重叠——考验区分能力
6
+ 3. 常规查询 15 个(字面重叠)作为基线对照
7
+
8
+ 隔离运行,不碰生产。输出 Top-1 / Top-3 分场景。
9
+ """
10
+ import sys, os
11
+ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
12
+ from liquid_loop_exp.multigran.multigran_core import MultigranMemory
13
+ from liquid_loop_exp.multigran.sim_structured import structured_sim
14
+
15
+ # ── 记忆库:15 条原文 + 5 条干扰项 ──────────────────────
16
+ DOCS = [
17
+ "军师调研 #358 PINN+LSTM 融合架构时序物理预测通用解决方案:PINN 嵌入物理准则损失约束+LSTM 时序依赖,年谐波振荡+ERA5 先验,PINT arXiv:2502.04018",
18
+ "军师调研 #361 SkillX 自动构建技能知识库:三层技能(战略计划/功能/原子)+迭代改进+探索扩展,弱模型 +10 分,arXiv:2604.04804",
19
+ "军师调研 #359 IceBreaker 对话破冰:RID 共鸣感知兴趣蒸馏+ISG 交互导向开场生成,冷启动首条消息壁垒,ACL26 字节",
20
+ "军师调研 #360 TDMA 动作分割数据集压缩:DDIM 潜在轨迹锚定+自适应锚点分配,Breakfast 2.4% 追平全量,ECCV26",
21
+ "军师调研 #362 重整化群:粗粒化+重标度+场重标度三步,2D 不动点 K*≈0.336,d=4 分水岭,Wilson 理论",
22
+ "军师调研 #366 ai-memory 编程CLI长期记忆:本地存储+按需召回+省token,akitaonrails/ai-memory ★3007",
23
+ "军师调研 #371 MemGAS 多粒度记忆:四粒度(session/turn/summary/keyword)+GMM关联+熵路由+PPR,超 HippoRAG2",
24
+ "军师调研 #373 奖励大小决定强化学习效率:100μL vs 5μL 学习提速一个数量级,多巴胺信号时长,Science 2026",
25
+ "军师调研 #374 预测编码:ε=x-μ 预测误差,能量最小化局部学习替代反向传播,IJCAI22 综述",
26
+ "军师调研 #376 Skill路由四路口:可见入口/职责边界/执行门槛/真实路由测试,主编排者,100 skills 选对",
27
+ "军师调研 #357 AI表情小球:纯 SVG+JS 零依赖桌面宠物,32 种表情状态追鼠标",
28
+ "军师调研 #363 Cumora 多智能体协作:AI 作团队成员(身份/记忆/领任务)+看板/日历,BYOA Claude Code/Codex",
29
+ "军师调研 #365 TimesFM 时序基础模型:Google 开源 Apache-2.0 200M 参数零样本预测",
30
+ "军师调研 #367 Tabularis 数据库工作台:一键直连 Postgres/MySQL 多库,SQL 辅助+可视化图表",
31
+ "军师调研 #369 常见神经网络科普:CNN/RNN/GNN/GAN/Transformer,按数据结构选网络",
32
+ # ── 干扰项(主题相近,与难查询部分字面重叠)──────────
33
+ "LSTM 气象温度时间序列预测:长短期记忆网络处理时序依赖,纯数据驱动无物理约束,训练集 ERA5 再分析数据",
34
+ "提示词工程技巧合集:写更好的 prompt 让大模型输出更准,指令模板与少样本示例,token 效率优化",
35
+ "寒暄问候语大全:早晨好/下午好/吃了吗,日常见面打招呼话术模板,社交破冰第一步",
36
+ "反向传播算法详解:梯度下降训练深度网络的标准方法,链式法则逐层计算梯度,BP 是深度学习基石",
37
+ "SKILL.md 编写规范:如何把工作流写成可复用技能文件,frontmatter 元数据与工具调用约定",
38
+ ]
39
+
40
+ # ── 查询:15 常规(字面重叠)+ 5 难(语义等价不重叠)──
41
+ # (query, gold_idx)
42
+ QUERIES = [
43
+ # 常规查询(字面重叠基线)
44
+ ("物理约束时序预测 谐波振荡", 0),
45
+ ("技能知识库 蒸馏 弱模型", 1),
46
+ ("对话冷启动 个性化开场", 2),
47
+ ("动作分割 数据压缩 轨迹", 3),
48
+ ("粗粒化 相变 临界指数", 4),
49
+ ("AI 编程 CLI 长期记忆", 5),
50
+ ("多粒度记忆 检索 熵路由", 6),
51
+ ("奖励大小 学习效率 多巴胺", 7),
52
+ ("预测误差 局部学习 反向传播替代", 8),
53
+ ("skill 选择 路由 职责边界", 9),
54
+ ("SVG 表情小球 桌面宠物", 10),
55
+ ("多智能体协作 看板 团队成员", 11),
56
+ ("时序基础模型 零样本 预测", 12),
57
+ ("数据库工作台 SQL 可视化", 13),
58
+ ("卷积 循环 图 神经网络", 14),
59
+ # ── 难查询(语义等价,字面不重叠)────────────────────
60
+ ("预报天气总是不准,想让模型把物理定律嵌进去训练,误差能降三成", 0),
61
+ ("把干过的活沉淀成可调用的技能,让笨一点的模型也能变聪明十分", 1),
62
+ ("第一次聊天不知道说啥,想根据对方兴趣爱好自动生成开场白避免尬聊", 2),
63
+ ("人脑不用反向传播也能学习,是靠什么机制逐层微调权重的", 8),
64
+ ("装了上百个技能,怎么保证每次任务都挑到对的那一个而不选错", 9),
65
+ ]
66
+
67
+ def run():
68
+ docs, queries = DOCS, QUERIES
69
+ n_all = len(queries)
70
+ n_hard = 5
71
+ hard_idx = list(range(15, 20))
72
+
73
+ # ── baseline:单粒度(session 全文)──
74
+ b_top1 = b_top3 = 0
75
+ b_hard_top1 = 0
76
+ for qi, (q, g) in enumerate(queries):
77
+ sims = [(i, structured_sim(q, d, "mix")) for i, d in enumerate(docs)]
78
+ sims.sort(key=lambda x: -x[1])
79
+ top = [i for i, s in sims[:3] if s > 0]
80
+ if top and top[0] == g:
81
+ b_top1 += 1
82
+ if qi in hard_idx:
83
+ b_hard_top1 += 1
84
+ if g in top:
85
+ b_top3 += 1
86
+
87
+ # ── multigran RRF:多路召回融合 ──
88
+ m_rrf = MultigranMemory()
89
+ for d in docs:
90
+ m_rrf.add([d])
91
+ r_top1 = r_top3 = 0
92
+ r_hard_top1 = 0
93
+ r_hits = []
94
+ for qi, (q, g) in enumerate(queries):
95
+ hits = m_rrf.retrieve(q, topk=3, fusion="rrf")
96
+ idxs = [h["idx"] for h in hits]
97
+ if idxs and idxs[0] == g:
98
+ r_top1 += 1
99
+ if qi in hard_idx:
100
+ r_hard_top1 += 1
101
+ if g in idxs:
102
+ r_top3 += 1
103
+ if qi in hard_idx:
104
+ r_hits.append((q[:18], g, idxs, [h.get("via") for h in hits]))
105
+
106
+ # ── multigran:四粒度+熵路由+图传播 ──
107
+ m = MultigranMemory()
108
+ for d in docs:
109
+ m.add([d])
110
+ mg_top1 = mg_top3 = 0
111
+ mg_hard_top1 = 0
112
+ mg_hits = []
113
+ for qi, (q, g) in enumerate(queries):
114
+ hits = m.retrieve(q, topk=3)
115
+ idxs = [h["idx"] for h in hits]
116
+ if idxs and idxs[0] == g:
117
+ mg_top1 += 1
118
+ if qi in hard_idx:
119
+ mg_hard_top1 += 1
120
+ if g in idxs:
121
+ mg_top3 += 1
122
+ if qi in hard_idx:
123
+ mg_hits.append((q[:18], g, idxs, hits[0].get("g_weights") if hits else None))
124
+
125
+ print(f"{'场景':<14} {'方法':<14} {'Top-1':>7} {'Top-3':>7}")
126
+ print("-" * 46)
127
+ print(f"{'全部(20)':<14} {'单粒度':<14} {b_top1/n_all*100:6.1f}% {b_top3/n_all*100:6.1f}%")
128
+ print(f"{'全部(20)':<14} {'多粒度+熵路由':<14} {mg_top1/n_all*100:6.1f}% {mg_top3/n_all*100:6.1f}%")
129
+ print(f"{'全部(20)':<14} {'多粒度+RRF':<14} {r_top1/n_all*100:6.1f}% {r_top3/n_all*100:6.1f}%")
130
+ print(f"{'难查询(5)':<14} {'单粒度':<14} {b_hard_top1/5*100:6.1f}% {'-':>6}")
131
+ print(f"{'难查询(5)':<14} {'多粒度+熵路由':<14} {mg_hard_top1/5*100:6.1f}% {'-':>6}")
132
+ print(f"{'难查询(5)':<14} {'多粒度+RRF':<14} {r_hard_top1/5*100:6.1f}% {'-':>6}")
133
+ # 单粒度难查询逐条(对照)
134
+ print("── 难查询单粒度 Top3(对照)──")
135
+ for qi in hard_idx:
136
+ q, g = queries[qi]
137
+ sims = [(i, structured_sim(q, d, "mix")) for i, d in enumerate(docs)]
138
+ sims.sort(key=lambda x: -x[1])
139
+ top = [i for i, s in sims[:3] if s > 0]
140
+ mark = "✓" if top and top[0] == g else f"✗(→{top})"
141
+ print(f" [{mark}] gold={g} top={top} Q: {q[:20]}")
142
+ print()
143
+ print("── 难查询逐条审计(多粒度)──")
144
+ for q, g, idxs, via in r_hits:
145
+ mark = "✓" if idxs and idxs[0] == g else f"✗(→{idxs})"
146
+ print(f" [RRF {mark}] gold={g} top={idxs} via={via}")
147
+ print(f" Q: {q}")
148
+ for q, g, idxs, w in mg_hits:
149
+ mark = "✓" if idxs and idxs[0] == g else f"✗(→{idxs})"
150
+ print(f" [{mark}] gold={g} top={idxs}")
151
+ print(f" Q: {q}")
152
+ if w:
153
+ print(f" 粒度权重 session={w['session']} summary={w['summary']} keyword={w['keyword']}")
154
+
155
+ if __name__ == "__main__":
156
+ run()