Skip to content

About

LLM agent 的有界自纠错长期记忆层:把连续、含矛盾的项目交互日志蒸馏成有界、可自更新的记忆库。Bounded, self-correcting long-term memory for LLM agents — candidate pool + value dynamics + tension adjudication + causal-replay evals.

Topics

Resources

Stars

186 stars

Watchers

0 watching

Forks

Latest commit

 

History

90 Commits

Folders and files

Repository files navigation

Dynamics-memory

状态:现行 · N48–N52 已汇合(真实 CLI 首验、可观测性、L2/L3 抽检工具链与审计修正);决策登记见 analysis/target-architecture.md §9.3;PENDING-08 待人工验收。 本页是行为摘要;机械验证入口在 analysis/acceptance_check.py。

LLM agent 的有界长期记忆层

把连续、嘈杂、前后矛盾的项目交互,蒸馏成一个不会堆成"史山"的记忆库。
新会话里一句"接着搞",agent 就知道进行到哪、上次卡在哪。

engine protocol storage status

全景 · 架构分层 · 记忆动力学 · 可靠性 · 运行 · 配置


30 秒上手

pip install numpy pytest
cp .env.example .env          # ZAI_API_KEY=...

python -m pytest tests/                          # 本地测试;不是远程验证
python -m hybrid_memory.server --project <dir>   # 或被 opencode 插件自动拉起

接入 opencode(官方 CLI 即可,无需源码):

npm i -g opencode-ai
cd <本仓库> && opencode        # .opencode/plugin/memory-bridge.ts 自动加载并拉起 sidecar

给别的项目用:把 memory-bridge.ts 软链到 <项目>/.opencode/plugin/。插件的 @opencode-ai/plugin 依赖按软链的真实路径解析,所以要先在本仓库里跑一次 opencode (或 cd .opencode && npm i @opencode-ai/plugin)让依赖装好。

为什么不用现成的两条路

路线 死因
全量 log 塞 context 每轮付 O(log) 的 prefill+KV 扫描,随项目历史线性变贵
原文入向量库 冗余、过期、互相矛盾的副本堆成史山,旧状态压过新状态

log 不是记忆,log 是证据。 记忆是蒸馏产物,进池要过动力学与置信门控; 日志留在 L0 冷层,只在需要时按计量回展——永不整段进 prompt。


全景:一条对话的旅程

从主 agent 的一句"以后统一用 bun",到它成为一条可检索、可归因、可结算的记忆:

flowchart LR
    U("主 Agent<br/>OpenCode") -->|"① 会话事件"| BR["memory-bridge.ts<br/>插件桥"]
    BR -->|"POST /observe"| SVC["sidecar<br/>:17872"]
    SVC --> L0[("L0 证据库<br/>只增不删 · FTS")]
    SVC -.->|"② 信号入队"| Q[["任务机<br/>SQLite 持久交接"]]
    Q -->|"③ --file 文件通道"| H["Hauler<br/>抽候选"]
    H -->|"④ 候选 + 来源"| S["Selector<br/>五路裁决"]
    U -.->|"表达不满"| REV["Reviewer<br/>诊断 + 版本化规则"]
    REV -.->|"持久规则回喂"| H
    S -->|"CREATE"| ENG["记忆引擎<br/>三池动力学"]
    S -->|"CONFLICT"| HR{"human_reviews<br/>待人工审核"}
    HR -->|"accept_new / keep_old"| ENG
    S -->|"REJECT"| X(("不入库"))
    BR -->|"⑤ GET /recall"| SVC
    SVC -->|"⑥ relevant-memories 注入"| U
    BR -->|"⑦ POST /feedback"| SVC
    SVC -->|"useful-hit → V 值结算"| ENG

    classDef agent fill:#FFF3E0,stroke:#E8963C,color:#7A4A00
    classDef core fill:#E8F4FD,stroke:#2B8CBF,color:#0B4F6C
    classDef store fill:#F5F5F5,stroke:#9E9E9E,color:#424242
    classDef risk fill:#FDECEF,stroke:#D65F7F,color:#8A2444
    class H,S,REV agent
    class ENG,SVC core
    class L0,Q store
    class HR,X risk
Loading

七步读法:① 每轮对话先落 L0(幂等回执,request_id 重放不重复入库); ② 证据到位才发 hauler_due 任务;③ Hauler 在真 OpenCode 进程里跑(Windows 默认常驻 serve + run --attach,其余平台默认 run 自举;OPENCODE_SPAWN_MODE 可覆盖),输入经 --file 私有附件传递、调用前封存上下文;④ 候选必须引用它见过的窗口内证据, Selector 逐条裁决;⑤ 检索时相似度 + 压制 + 因果界过滤;⑥ 命中记忆按 token 预算 注入;⑦ 反馈经 recognizer 归因,只有真被答案用上的记忆拿到 useful-hit。

信号只负责持久交接、租约和幂等;三份 .opencode/agent/*.md 定义负责语义判断。 重叠滑窗按 L0 来源单元去重,冲突须人审。默认模式下主 agent 不能绕过 Selector 直接调用 /propose 或 /resolve。 完整协议、审核入口、恢复及已知边界见 OpenCode 三 Agent 文档。

旧的单轮 candgen 和 sidecar 内调查员是待退役的兼容路径(仅 MEMORY_PIPELINE=legacy 显式启用;删除条件见 PENDING-05),其设计记录见衔尾蛇说明, 不能把旧记录当作默认模式的验证。

架构分层

依赖严格单向向下;模型调用与向量计算永远在服务锁外:

flowchart TB
    subgraph T["transport/ · 传输"]
        HTTP["HTTP 服务 · auth · dto<br/>bootstrap 组装 · review CLI"]
    end
    subgraph SV["service/ · 门面"]
        SVC["MemoryService<br/>observe · recall · feedback · propose · resolve · 人审<br/>预算准入 · 因果界 · telemetry"]
    end
    subgraph DP["dispatch/ · 调度"]
        W["DispatchWorker<br/>+ 语义循环"]
        EF["effects 效果事务<br/>容量收口 · 完整回滚"]
        POL["policy 策略表<br/>SEM 5/5 · WF 5/5 · INV 2/3"]
    end
    subgraph AG["agents/ · 角色"]
        TRIO["Hauler · Selector · Reviewer"]
        OCR["OpenCodeRunner 文件通道<br/>+ 调用上下文封存"]
    end
    subgraph SEM["semantics/ · 语义"]
        SP["SemanticsProvider 双通路<br/>judge · relevant_set · consolidate"]
    end
    subgraph CO["core/ · 引擎(无 LLM)"]
        ENG["三池动力学 · ingest 去重<br/>张力与裁决 · 巩固蒸馏 · plan_capacity"]
    end
    subgraph ST["store/ · 存储"]
        EDB[("L0 证据库")]
        TDB[("任务库 + checkpoint")]
        SCH["schema 三库身份版本"]
    end
    EXT["OpenCode CLI 真进程"]
    LLM["LLM / Embedding"]

    HTTP --> SVC
    SVC --> W
    W --> TRIO
    TRIO --> OCR --> EXT
    W --> EF
    EF --> ENG
    ENG --> SP --> LLM
    SVC --> EDB
    EF --> TDB
    SCH -.- EDB
    SCH -.- TDB

    classDef layer fill:#FAFAFA,stroke:#BDBDBD,color:#424242
    class T,SV,DP,AG,SEM,CO,ST layer
Loading

单进程内一条铁律:锁内不做慢事——模型、向量、文件 IO 全在锁外完成, 锁内只剩纯内存变更与事务提交(见 prepare_effect 的锁外预计算设计)。

记忆动力学

记忆 = 有版本的信念。每条携带 src(溯源到 L0 单元)与 superseded_by / aggregated_into(版本谱系),在三个池之间流动:

stateDiagram-v2
    direction TB
    [*] --> C: CREATE / reflection 入池
    state "C 候选池(cap 200)" as C
    state "M 常用池(cap 8 · 检索主力)" as M
    state "A 冷归档池(cap 2000)" as A

    C --> M: V 超过 θp 且有容量
    M --> C: V 跌破 θd(θp>θd 滞回防抖)
    C --> A: 闲置 / 容量收口迁出
    A --> C: EXIST 复活 / 低先验召回
    M --> A: 旧版退役(加指针 + 时间戳)
    A --> [*]: 无保护版本 FIFO 物理回收
Loading
机制 一句话
价值 × 置信分离 V ← V·e^(−λ) + η·hit + η_s·shadow;高价值定半衰期,置信达标才服务——高价值低置信"活着但不用"
滞回 + 驱逐 + 归档 θp>θd 防抖,容量封顶,闲置进冷层——M 池有界且自我更新
压制即检测 过相似未入选对自动进 tension backlog,冲突检索时自然暴露
矛盾不静默 同实体矛盾聚合收编(全版本+时间戳),未决 conflict 不许自信出场(contested co-serve)
容量背压 非退役版本总数超 cap_context 时按 FIFO 收口;全 pin 收不了口 → 503 拒收,绝不静默超限或解除保护
可溯源 每条记忆携带源单元 id,可回 L0 查证;origin 纯审计不给 V 加成

可靠性骨架

一切变更走持久任务机——崩溃后 kill -9 重启,已提交的证据不丢、租约过期的 任务重跑、快照落后以日志为准:

stateDiagram-v2
    direction LR
    [*] --> pending: enqueue(同 key 合并去重)
    pending --> running: claim(租约 + 版本 CAS)
    running --> ready: 产物落库(可重放)
    running --> pending: 失败退避(计数保持)
    ready --> applying: 领取(apply_attempts+1)
    applying --> done: 效果事务提交
    applying --> ready: 应用失败退避(产物保留)
    running --> dead: 重试耗尽(上限见策略表)
    pending --> dead: 过期恢复后耗尽
    done --> [*]
Loading

效果事务是唯一写入口:内存引擎变更、任务状态、checkpoint 与回执同一笔 SQLite 事务,失败深备份完整回滚。模型产物(ready 的 result)在应用失败时 保留退避,只有应用耗尽才 dead——绝不因收口失败清空合法产物重跑模型。

冲突裁决不删数据:CONFLICT 落 human_reviews 队列并 pin 保护目标, 人工持独立 token 二选一,其余待审自动标 stale——记忆不接受单方面改写。

flowchart LR
    S["Selector 裁 CONFLICT"] --> PIN["目标 pin 保护<br/>落 human_reviews"]
    PIN --> HUM{"人工审核<br/>独立 token"}
    HUM -->|"accept_new"| NEW["新版本入库<br/>旧版退役指向新版本"]
    HUM -->|"keep_old"| OLD["候选拒绝<br/>旧版保留解除 pin"]
    NEW --> T["张力消解"]
    OLD --> T

    classDef risk fill:#FDECEF,stroke:#D65F7F,color:#8A2444
    classDef ok fill:#E8F5E9,stroke:#43A047,color:#1B5E20
    class S,PIN,HUM risk
    class NEW,OLD,T ok
Loading

评测

评测平台 TIDE 与引擎完全分离(只经 HTTP 协议通信,真值不越过边界)。 设计见 docs/benchmark-design.md, 第一版可运行实现在 eval/(场景驱动器 + 离线 mock + 基线报告)。

sidecar 为评测提供的两个能力:

参数 端点 作用
passive GET /recall?passive=1 / POST /search {"passive": true} 在引擎副本上检索:不改任何状态、不登记 retrieval_id(评测探针用)
budget_tokens 同上 上下文按 approx_tokens 计数截断整行(CJK 单字 / ASCII 词 / 符号各记 1)

旧的 experiments/ 评测已整体移除:其仿真与引擎共用真值对象、口径无法识别聚合输出、 样本量不足以支持结论,数字不再引用。

配置

环境变量 默认 作用
MEMORY_PIPELINE opencode legacy 启用旧单轮 candgen 和进程内调查员;其他值拒绝启动
MEMORY_AGENT on off 暂停后台 agent,任务仍持久等待
MEMORY_AGENT_DAILY_CAP 200 仅 legacy 调查员的日调用上限
MEMORY_AGENT_MODEL glm-5.3-flash 仅 legacy 调查员模型
MEMORY_OPENCODE_BIN opencode OpenCode CLI 路径(需配置自己的模型 provider)
OPENCODE_SPAWN_MODE 按平台 OpenCode 调用模式:Windows 默认 serve+attach(常驻 serve + run --attach),其余平台默认 bootstrap(run 自举);非法值拒绝启动
MEMORY_BRIDGE_PORT 17872 sidecar 端口
ZAI_API_KEY — 原引擎向量编码等依赖;三 Agent 使用 OpenCode 自身 provider 配置
ZAI_BASE_URL https://open.bigmodel.cn/api/paas/v4 OpenAI 兼容端点(chat / embeddings),可换代理或本地 mock

MEMORY_PIPELINE=legacy 下,旧调查员才在有 API key 时自动消费旧信号; trio 队列、结果及 Reviewer 规则保存在 tasks.sqlite。

验证状态

Python 与 Bun 测试覆盖服务端、插件和 mock HTTP 不变量;手工 smoke 用真实 OpenCode CLI + 本地假模型完成三 Agent 任务交接;端到端穿透回归覆盖"observe→Hauler→Selector→效果落库→recall→feedback→信用结清"、"CONFLICT→人审双分支"与"kill -9 两库崩溃恢复"三条链。N48 已用真实 OpenCode CLI + 智谱 glm-5.3-flash 验证小样本 Hauler→Selector→落库。N51 五链实际走 inline runner;L3 全为开发日志引述,100 行评分是 Agent 单评,不能等同于真实会话与人工验收;抽检报告记载证据与限制;独立人工的真实会话 L3 验收尚未做,PENDING-08 仍保留。GET /health 的 validation 固定为 unverified:进程在听,不等于已经验证。

当前本机门禁:pytest 534 passed / 1 skipped(平台条件用例);checker 170 模块 / 1602 符号 / 0 failures;acceptance --full 25 PASS / 0 SKIP / 0 FAIL;Bun 26 pass;L2/L3 mock 全链自检贯通(194 轮喂入 → 导出 → 抽样 → 结算)。

ok: true 只表示没有 checkpoint fault,插件可以复用这个进程。它不表示快照干净,也不表示逐单元效果已经补齐。看 snapshot 和 units_pending。snapshot=quarantined 表示坏快照已被隔离成 state.corrupt,服务空启动,记忆没有从那份快照恢复。

运行

停机后再备份整个状态目录:log.sqlite、tasks.sqlite、它们的 WAL、state.pkl,以及同目录的 bridge-outbox.json。不要只回滚其中一个库。本批没有检测这种不配套,也不能靠旧副本找回备份之后的新数据。回滚要插件和 sidecar 一起回到旧版本。

坏的 state.pkl 会被隔离,服务仍会起来。这是为了不让桥瘫痪,不是数据还在。state.corrupt 留在目录里,启动声明不会把它说成合法空库。

目录结构
hybrid_memory/
├── core/          引擎本体:types · engine · ingest · retrieval · dynamics ·
│                  consolidation · maintenance · signals(动力学全在锁内纯计算)
├── store/         三库与恢复:evidence(L0) · tasks(任务机) · schema(三库身份版本)
│                  · state(快照受限反序列化)
├── dispatch/      调度:worker(两路径) · effects(效果事务+容量收口) · policy(策略表)
├── agents/        三角色:hauler · selector · reviewer · payload(封存上下文)
│                  · opencode(文件通道) · protocol
├── semantics/     语义判断:real · llm · provider(SemanticsProvider 双通路+健康观测)
├── guards/        输入防线:provenance(溯源) · grounding(落地校验) · bounds
├── service/       MemoryService 门面:observe · recall · feedback · operate ·
│                  review · tools · budgets · lifecycle · telemetry · context
├── transport/     传输:http · auth · dto · bootstrap · review_cli
├── embed/         向量:cache(SQLite) · zhipu
├── legacy/        旧调查员回路(兼容路径,仅 MEMORY_PIPELINE=legacy;待退役)
├── config.py      Cfg / Settings / resolve_pipeline(未知值拒绝启动)
├── errors.py      错误域:Rejected / Degraded / Fatal + HTTP 码表
└── telemetry.py   健康与信号观测(地基层)
.opencode/         plugin/memory-bridge.ts · agent/{hauler,selector,reviewer}.md
analysis/          target-architecture.md(唯一设计)· architecture_contract.py(冻结契约)
                   · check_architecture.py · acceptance_check.py · docs/
docs/              opencode-trio.md · ouroboros.md · benchmark-design.md · architecture-inventory.md
eval/tide/         TIDE 评测(与引擎经 HTTP 分离)
eval/l2l3/         L2/L3 抽检工具链(跑链·导出·盲序·结算;报告见 REPORT.md)
tests/             pytest 回归:unit / integration / characterization / …

OpenCode 三 Agent 协议

默认的 Hauler → Selector / 不满触发 Reviewer 协议、人工冲突审核、部署与恢复边界见 docs/opencode-trio.md。

About

LLM agent 的有界自纠错长期记忆层:把连续、含矛盾的项目交互日志蒸馏成有界、可自更新的记忆库。Bounded, self-correcting long-term memory for LLM agents — candidate pool + value dynamics + tension adjudication + causal-replay evals.

Topics

Resources

Stars

186 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages