Download agentframe/memory/incremental.py from ljsysfurry/AgentFrame-v4: direct link, hf CLI and curl.
- Browser
- Download file 4.9 kB
-
https://huggingface.co/ljsysfurry/AgentFrame-v4/resolve/main/agentframe/memory/incremental.py
- Command line
-
hf download hf://ljsysfurry/AgentFrame-v4/agentframe/memory/incremental.py
-
curl -L -o incremental.py https://huggingface.co/ljsysfurry/AgentFrame-v4/resolve/main/agentframe/memory/incremental.py
4.9 kB
| """ | |
| IncrementalKVStore — 增量追加持久化 (colibrì kv_persist.h 移植) | |
| ================================================================= | |
| colibrì 做法: 每轮对话后把压缩 MLA KV 增量 append 到 .coli_kv, | |
| nrec 计数最后写 = crash-safe, 重启直接恢复不用重新 prefill。 | |
| AgentFrame 移植: | |
| - 每次 ingest 的新 chunk 追加为一行 JSON (不重写全量快照) | |
| - 行级独立 = 崩溃时最多丢最后一条, 坏行跳过 (crash-safe) | |
| - load() 读全部记录重建 chunk + 自动重建 landmark 摘要 | |
| - 与全量快照 (StateStore) 互补: 增量管内容, 快照管运行时热度状态 | |
| v4.5.1 增强 (memory-system 协议启发): | |
| - 每行 content checksum (MD5 前 8 位): 篡改/静默损坏的行整行跳过, | |
| 杜绝"corruption is silent and permanent" (读到的就是错的) | |
| - 旧格式兼容: 无 checksum 的历史行仍接受, 新写入全部带校验 | |
| """ | |
| import json | |
| import os | |
| import hashlib | |
| import numpy as np | |
| class IncrementalKVStore: | |
| """增量追加 KV 日志 (colibrì kv_persist 思想 + checksum 防损坏)""" | |
| MAGIC = "AFKV1" | |
| def __init__(self, path: str): | |
| self.path = path | |
| # ============ 校验和 ============ | |
| def _checksum(payload: dict) -> str: | |
| """内容校验和: 对记录主体做 MD5, 取前 8 位 hex""" | |
| body = json.dumps(payload, sort_keys=True, ensure_ascii=False) | |
| return hashlib.md5(body.encode("utf-8")).hexdigest()[:8] | |
| def _verify(rec: dict) -> bool: | |
| """校验一条记录: 有 checksum 则验证; 无 checksum 视为旧格式接受""" | |
| cs = rec.pop("checksum", None) | |
| if cs is None: | |
| return True # 旧格式行 (无校验): 兼容接受 | |
| payload = {k: v for k, v in rec.items() if k != "checksum"} | |
| return IncrementalKVStore._checksum(payload) == cs | |
| # ============ 写入 ============ | |
| def append(self, chunk_id: int, q4: np.ndarray, scales: np.ndarray, | |
| latent: np.ndarray, quant_bits: int, size_bytes: int, | |
| meta: dict) -> int: | |
| """ | |
| 追加一条 chunk 记录 (每行一个 JSON, 带 content checksum). | |
| 返回当前记录数 (类似 colibrì 的 nrec). | |
| """ | |
| payload = { | |
| "magic": self.MAGIC, | |
| "chunk_id": int(chunk_id), | |
| "quant_bits": int(quant_bits), | |
| "size_bytes": int(size_bytes), | |
| "q4": q4.tobytes().hex() if q4 is not None else None, | |
| "scales": scales.tolist() if scales is not None else None, | |
| "latent": latent.tolist(), | |
| "meta": meta, | |
| } | |
| rec = dict(payload) | |
| rec["checksum"] = self._checksum(payload) | |
| os.makedirs(os.path.dirname(self.path) or ".", exist_ok=True) | |
| with open(self.path, "a") as f: | |
| f.write(json.dumps(rec, ensure_ascii=False) + "\n") | |
| return self.count() | |
| def count(self) -> int: | |
| """统计有效记录数 (跳过坏行)""" | |
| return len(self._read_raw()) | |
| # ============ 读取 ============ | |
| def _read_raw(self) -> list: | |
| """读全部行: 跳过损坏/不完整行 + checksum 不匹配行 (防静默损坏)""" | |
| if not os.path.exists(self.path): | |
| return [] | |
| recs = [] | |
| with open(self.path) as f: | |
| for line in f: | |
| line = line.strip() | |
| if not line: | |
| continue | |
| try: | |
| rec = json.loads(line) | |
| if rec.get("magic") != self.MAGIC: | |
| continue | |
| if not self._verify(rec): | |
| continue # checksum 不匹配: 内容被篡改/损坏, 跳过 | |
| recs.append(rec) | |
| except Exception: | |
| continue # 崩溃残留的半行: 跳过 | |
| return recs | |
| def load(self) -> list: | |
| """ | |
| 读全部有效记录, 反序列化为可重建的数据结构. | |
| 返回: [{chunk_id, q4, scales, latent, quant_bits, size_bytes, meta}, ...] | |
| """ | |
| out = [] | |
| for rec in self._read_raw(): | |
| q4 = None | |
| if rec.get("q4"): | |
| q4 = np.frombuffer(bytes.fromhex(rec["q4"]), dtype=np.uint8) | |
| scales = None | |
| if rec.get("scales"): | |
| scales = np.asarray(rec["scales"], dtype=np.float32) | |
| out.append({ | |
| "chunk_id": int(rec["chunk_id"]), | |
| "quant_bits": int(rec.get("quant_bits", 4)), | |
| "size_bytes": int(rec.get("size_bytes", 0)), | |
| "q4": q4, | |
| "scales": scales, | |
| "latent": np.asarray(rec.get("latent", [0.0]), dtype=np.float32), | |
| "meta": rec.get("meta", {}), | |
| }) | |
| return out | |
| def exists(self) -> bool: | |
| return os.path.exists(self.path) | |