dsh-anagenesis
Đã xác minhdsh-anagenesis · v0.2.1 · Apache-2.0
anagenesis —— DeepSeek Harness 上的可编程记忆编排层 + 自我进化引擎:自带闭环记忆存储(不依赖任何外部记忆插件)、17 个面向 Agent 的语义记忆工具(召回/提交/提升/降级/拆分/锁定/过期/反事实重思)、运行时可切换的注入策略、带审计与回滚的元策略自调节、全程可逆效应、自动注册 `anagenesis` Agent 预设,以及零依赖可视化层(终端仪表盘 + mermaid/d2/ascii 文本图表 + 可选桌面窗口)。
Cài đặt
dsh plugin add dsh-anagenesis Xác nhận layer đã áp bằng dsh --profile default --dump-config — xem hướng dẫn cài plugin.
Mã nguồn
Thẻ
Tác giả
Readme
dsh-anagenesis
给 Agent 一套它自己管得住、你也看得见的记忆。
不是又一个"自动记忆黑箱":记忆操作是 Agent 手里的工具,注入策略运行时可换, 每次变更都带逆操作,自我调参有边界、有审计、能回滚 —— 而整个存储自包含、离线、零依赖。

0.2.0 新增:记忆按项目隔离,预设成为权限开关
这一版解决两件真事:A 项目的经验不再在 B 项目里被召回;不启用预设时,模型连写入工具都看不到。
| 新增 | 一句话 | 你能看到什么 |
|---|---|---|
| 记忆作用域 | 每条记忆都带 global / project(默认)/ session 标签;检索默认只召回当前项目 + 全局 + 当前会话 |
仪表盘新增「作用域」分区:当前项目青色、别的项目黄色、全局与旧记忆一目了然 |
| 项目指纹 | 由 git remote(优先)或工作目录算出 p1_<hash>,纯函数、跨重启稳定 —— 同一份代码的多个检出是同一个项目 |
换目录、换机器、开新会话都不会认错项目 |
| 跨项目要授权 | 传 crossProject: true 才纳入别的项目,命中被降权并逐条标注「⚠ 其他项目经验,请勿盲从」 |
注入块里直接写明哪些不能盲从 |
| 冲突自动降权 | 与当前项目记忆语义相似但内容相反时,跨项目那条的有效置信度当场减半,并提示以当前环境为准 | 只改这一次的投影,绝不回写存储 |
| 物理隔离 | 日志按命名空间分文件(journal-<ns>-*.jsonl),全局记忆有自己的文件;旧存储原样可读 |
node tools/scope-report.mjs 一眼看到"谁占了多少、在哪个文件里" |
| 预设 = 权限层 | 写入类工具只在启用 anagenesis 预设时才注册;档位 passive(只读)/ assisted(可写)/ autonomous(可自动调度) |
ana_preset action="status" 就是权威答案:你现在到底有哪些工具 |
| 执行期检查 | ctx.tools.guard() + 每个写入工具自带的授权校验:没注册就调不到,授权撤销后连缓存的定义也拒绝执行 |
提示词不是唯一防线 |
| 状态脉冲 | 每一步都有一段 <anagenesis-pulse>:当前项目指纹、档位、可用工具集 |
模型自己就能核对"这条记忆能不能用" |
| 会话即弃 | 会话级记忆默认 24h 过期;ana_scope action="drop-session" 一键回收(普通事务、可回滚) |
临时任务的中间状态不会变成永久信念 |
| 新工具 | ana_list(按作用域列出)、ana_scope(status / list / namespaces / retag / adopt / drop-session) |
retag 可回滚;把项目记忆提升为全局需要用户显式授权 |
升级须知(破坏性):存储结构 v6 → v7 自动迁移。迁移把带 workspace 的旧记录归入正确项目,其余标为
migrated-global —— 继续可召回但被降权,可用 ana_scope action="adopt" 收回到当前项目。建议重启桌面端
以加载新的工具分层。
它在同类里的独特之处
- 作用域是存储的一等公民,不是检索时的一个过滤器:写入、日志分段、召回过滤、按 id 读取、可视化 五处共用同一个命名空间判定,所以"这条经验属于谁"在文件系统层面也成立。
- 预设不是提示词集合,是权限开关:档位决定写入工具存不存在,而不是"该不该用"。宿主侧没有权限字段
可用(
ToolDefinition里没有readOnly),所以我们用唯一真正可靠的那把锁:注册 / 不注册。 - 单一 seq 空间 + 声明式 patch:正因为日志没有按项目分库,
revert(seq)、审计轨迹与工具返回的句柄 才仍然全局唯一 —— 隔离做在文件上,可逆性做在计数器上。 - 物理隔离与旧数据兼容同时成立:每个命名空间有自己的日志段与归档段,而全局命名空间保留原有的无前缀 命名,升级前写下的存储一个字节都不用改。
- 契约可被证伪:95 条主测试 + 87 条窗口测试 + 一个真 Cordis / 真
defineTool/ 真预设注册表的开机沙箱 96 项检查,跑的都是真实行代码,不是 mock 的复制品。
三句话说明它是什么
- 它是一座你自己操作的记忆库:按意图召回、按主张提交、按证据提升,全部由 Agent 主动调用 —— 没有黑盒注入。
- 它的注入策略是一栈纯函数,运行时可换(explore / exploit / debug / distill),还能依据自己的结果做元调参,每一步都可回滚。
- 它的记忆按项目隔离、按档位授权:写下来的经验只属于当前项目,没启用预设时模型连写入工具都看不到。
作用域:记忆属于一个项目
每条记忆都带一个作用域标签,这是它默认的行为,不需要你配置:
| 层级 | 何时使用 | 谁能召回 |
|---|---|---|
global |
跨项目通用的事实(团队约定、工具用法) | 任何项目 |
project(写入默认) |
只在这个项目成立的结论 | 只有当前项目 |
session |
本次任务的临时状态,默认 24h 后自动过期 | 只有写它的那个会话 |
- 项目指纹由 git remote(优先)或工作目录的规范化绝对路径算出:
p1_<hash>,纯函数、跨会话稳定 —— 同一份代码的两个检出是同一个项目,换台机器也是。 - 默认只召回当前项目 + 全局 + 当前会话。跨项目检索必须显式传
crossProject: true:命中会被降权, 并在注入块里逐条标注「⚠ 其他项目经验,请勿盲从」。 - 冲突会被指出来:跨项目的记忆与当前项目记忆语义相似但内容相反时,那条跨项目记忆的有效置信度当场减半, 注入块与状态脉冲都会提示「建议忽略历史经验,以当前环境为准」—— 只改这一次的投影,绝不回写存储。
- 物理上也分开了:日志按命名空间分文件(
journal-<ns>-*.jsonl),全局记忆有自己的文件; 隔离之前写的存储原样可读,那些记录被标成migrated-global并自动降权,可用ana_scope action="adopt"收回到当前项目。 - 体检一座存储:
node tools/scope-report.mjs(只读:命名空间分布、已知项目、物理文件、档位解释)。
预设是权限开关,不是建议
装上插件只给你眼睛:默认注册的全部是只读工具(ana_recall / ana_list / ana_audit /
ana_dashboard / ana_diagram / ana_window,以及 ana_scope / ana_preset / ana_strategy /
ana_tune 的查看动作)。写入类工具只在启用 anagenesis 预设时才存在 ——
不是"被劝阻",而是没被注册,模型看不到它们。想写记忆就启用预设,这是唯一的路。
| 档位 | 写入工具 | 额外能力 |
|---|---|---|
passive |
不注册 | 只读:召回、审计、可视化、策略状态 |
assisted(预设默认) |
注册 | 每次写入都由 Agent 显式调用工具 |
autonomous |
注册 | 策略可自动调度(报告失败后自动切 debug)、被反复引用的草稿可自动结晶为 active;两者都带审计与 seq |
- 档位在预设配置里选(
gear:),运行时可用ana_preset action="gear"查看与降级; 向上升级需要宿主授权,Agent 不能自己扩大自己的权限。 - 切换与注销都精确回滚:降回
passive时写入工具被逐个注销;卸载预设后工具集回到只读那一套。 - 权限检查在执行时生效(
ctx.tools.guard()+ 每个写入工具自带的assertGrant): 即使有人缓存了工具定义,撤销授权之后它一样拒绝执行。提示词约束只是第二道,不是唯一一道。 - Agent 每一步都会看到一段
<anagenesis-pulse>:当前项目、档位、它手上到底有哪些工具。
和典型「自动记忆」插件不一样在哪
- 自带闭环存储:
journal/*.jsonl追加式日志 + 原子快照。不调用、不桥接、不代理任何外部记忆服务 —— 没有数据库、没有云、没有模型调用。 - 记忆是 Agent 主动调用的工具(17 个
ana_*):按意图召回(orient/recall_precedent/avoid_mistake/reuse_procedure/ …),而不是靠后台自动抽取。 - 它不只存记忆,还管自己的行为:注入策略可换栈、元层可自调参、护栏单调收紧、每次变更可回滚 —— 并且这三件事都留痕、可审计。
| 维度 | 典型自动记忆插件 | anagenesis |
|---|---|---|
| 谁决定记什么 | 后台抽取,Agent 无感 | Agent 用工具显式决定:ana_remember / ana_promote / ana_split / ana_rethink / ana_forget |
| 怎么召回 | 关键词或向量相似度 | 意图驱动:7 种意图 → 种类 / 状态 / 置信度下限 / 权重 / 粒度 / token 预算 / 多样性 |
| 谁看得见 | 所有项目共用一座库 | 按项目隔离:写入默认属于当前项目,跨项目检索必须显式授权并降权标注 |
| 谁能写 | 装了就都能写 | 预设即权限层:没启用预设时写入工具根本不存在;档位 passive / assisted / autonomous |
| 注入策略 | 固定 | 运行时可换栈(6 个具名栈),且按作用域存栈,一个 Agent 换栈不影响另一个 |
| 变更的后果 | 多数不可逆 | 每笔事务返回逆函数;逆操作与正向 patch 同写日志,重启后仍可回滚 |
| 自我调节 | 无 | 元层依据反馈自调参:参数包络约束 + UCB1 选臂 + 审计 + 评估 + 回滚 |
| 失控风险 | — | 单调护栏 + 熔断 + safeMode;能自改的只有 tier-1,外环冻结 |
| 依赖 | 常常需要外部服务或向量库 | 零运行时依赖、离线、无子进程、无网络 |
| 可见性 | 一个黑箱 | TUI 仪表盘(含作用域分区)+ mermaid/d2/ascii 文本图表 + 可选桌面窗口 |
安装
全家桶(推荐:内核 + 桌面窗口一次装齐)
两个包都已发布在 npm:dsh-anagenesis · dsh-anagenesis-window —— dsh plugin add 直接取 npm 上的最新版。
dsh plugin add dsh-anagenesis # 内核:记忆 + 策略 + 护栏 + 可视化工具
dsh plugin add dsh-anagenesis-window # 桌面窗口(可选,但推荐一起装)
装完重启 profile。安装会自动注册名为 anagenesis 的 Agent 预设 —— 新会话里选中它即可。
只想要内核?第一条命令就够了。窗口不装也完全可用:预设知道这个能力存在,但从不假设它被安装。
从源码安装(想改代码、或跟进 main)
git clone https://github.com/3likofj/dsh-anagenesis.git
cd dsh-anagenesis
dsh plugin --profile desktop add link:<仓库绝对路径> # 主包
dsh plugin --profile desktop add link:<仓库绝对路径>/window # 可选:桌面窗口
五分钟上手
- 安装并重启 profile,新建会话时选
anagenesis预设(默认策略栈guard + exploit)。 - 正常干活就行:Agent 会自己调
ana_recall与ana_remember—— 你不需要写查询语言。 - 想看一眼记忆库:让 Agent 调
ana_dashboard(一帧 TUI 仪表盘,直接出现在回答里)或ana_diagram(可粘贴进 Markdown 的图)。 - 想在真实终端里持续刷新:
node tools/viz-watch.mjs --watch(只读、独立进程)。 - 想要桌面窗口:装上第二个包并重启,然后让 Agent 调
ana_window,或直接点界面上的入口。
能力地图(19 个工具,按权限分层)
只读层(装上插件就有)
| 分组 | 工具 | 干什么 |
|---|---|---|
| 召回 | ana_recall · ana_list |
按意图取回(默认只搜当前项目 + 全局 + 当前会话);按作用域列出库里有什么 |
| 治理查看 | ana_audit · ana_scope · ana_preset · ana_strategy · ana_tune |
状态 / 日志 / 审计 / 某条记忆;作用域报告;档位与权限;策略清单;调参指标(变更动作需要相应档位) |
| 可视化 | ana_dashboard · ana_diagram · ana_window |
终端仪表盘(含作用域分区)、文本图表、桌面窗口(后两个工具各自属于可视化行与窗口行,行没装工具就不存在) |
写入层(只在启用 anagenesis 预设时存在)
| 分组 | 工具 | 干什么 |
|---|---|---|
| 写入与生命周期 | ana_remember · ana_promote · ana_demote · ana_lock · ana_expire · ana_forget |
写入默认落在当前项目;draft → active → verified → locked,或降级 / 过期 / 删除(删除只留可审计的墓碑) |
| 结构化 | ana_link · ana_split · ana_rethink |
建立关系;把信息过载的记忆拆窄(子记录继承父作用域);反事实重思 |
| 反馈与修正 | ana_feedback · ana_scope action="retag"/"adopt" · ana_strategy·ana_tune 的变更动作 |
回报实际使用;重新归档作用域(可回滚);换栈 / 元调参(admin 档位) |
注入策略:什么时候用哪副脑子
| 具名栈 | 组成 | 适合 |
|---|---|---|
explore |
guard + explore | 问题还在摸清阶段:高召回、低门槛,写入落为草稿 |
exploit |
guard + exploit | 执行已知方案:只注入已验证 / 已锁定的,写入直接生效 |
debug |
guard + debug | 出事那一刻:失败与未决假设优先,关闭时间衰减 |
distill |
guard + distill | 长会话要省 token:压缩优先,只注入要点 |
recon |
guard + explore + distill | 先铺开再收紧 |
crisis |
guard + debug + exploit | 连续失败时:失败与已验证事实同时注入 |
guard 是不变量:永远在栈底、自己不注入内容,只做"锁定信念加权 / 草稿降权 / retired 永不注入"。
策略是纯函数包 + 有界参数:Agent 只能"点名一个内置实现 + 参数差分"来派生新策略 —— 能持久化任意代码的 Agent,也就是能把自己弄砖的 Agent。
每一次变更都可以撤销
- 变更不是闭包,是声明式 JSON patch;存储把所有写者串行化,先追加日志、再换入冻结快照(读者因此无锁)。
transact()返回revert(reason):它把逆操作作为补偿事件提交,与正向 patch 一起进日志 —— 所以重启之后回滚依然有效。ana_strategy action:"revert"与ana_tune action:"rollback"只是这个原语上的薄封装。- 日志有三条上界:段数超限时合并最老的归档段(合并不丢 seq)、检查点只留最新、以及唯一有损的保留策略(默认关闭;一旦丢过东西,状态视图会显式报告,而不是假装那个 seq 从没存在过)。
自我引导的边界(它为什么不会跑偏)
能自我引导 —— 但外环是冻的。
- tier 1(可自改):记忆、策略栈、可调参数。Agent 能召回自己过去的失败、从内置策略派生新策略、用自己收集的反馈调整置信度下限与 token 预算。
- tier 2(冻结):参数包络、可调命名空间白名单、
guard的存在、工具 schema、以及插件代码本身。运行中的 Agent 改不了其中任何一项。
理由很直接:能改写自己适应度函数与刹车的 Agent,会漂向"得分高"而不是"真管用",而且没有可恢复的状态可以回滚。
这条边界是可执行的(8 条单调收紧的不变量 + safeMode 整体冻结),不是口号。
看得见



- TUI 仪表盘(
ana_dashboard):总览、生命周期分布、类型分布、策略栈与健康度、偏离默认值的调参旋钮、日志尾部、重要度排行、渲染器自身状态。按显示宽度精确对齐(中日韩标签不会把边框撕开),颜色只有被要求时才上。 - 文本图表(
ana_diagram):Mermaid(默认)/ D2 / ASCII 三种格式;三种图 —— 记忆关系图(含supports/contradicts/supersedes等关系)、策略时间线、生命周期流转(只画日志真实记录到的迁移,lock/expire这类"只记录目的态"的操作会如实说明,而不是编造一条来源边)。 - 桌面窗口(可选兄弟包):同一批纯函数产出的中文卡片 + 自研内联 SVG 有向图(横向 / 纵向 + 缩放),三个入口席位(better-sidebar 侧栏行 / 官方右侧边栏 / 对话顶部栏),只读镜像存储。
- 渲染是只读投影:一次渲染不是一次事务。唯一可选的写入
auditRenders默认关闭;另一个只读进程tools/viz-watch.mjs可以在真实终端里持续刷新。
数据在哪、隐私如何
$DSH_HOME/anagenesis/
journal/journal-000001.jsonl 追加式事件日志(全局命名空间,保留原命名)
journal/journal-<ns>-000001.jsonl 每个项目/会话命名空间自己的段(物理隔离)
journal/archive-<ns>-<seq>.jsonl 折叠后的归档,按命名空间分开(保留 undo)
journal/checkpoint-<seq>.json 边界上的冻结状态(缓存,整库一份)
snapshot.json 原子启动缓存
- 记忆按命名空间分文件:
project:<指纹>与session:<id>的事件写进各自命名的段, 全局记忆留在无前缀的journal-*.jsonl里 —— 所以"这条经验属于谁"在文件系统层面也成立, 而不只是查询时过滤一次。 - 全本地:不联网、不下载模型、不调用模型、不启动子进程。
- 零运行时依赖:检索是内置 BM25 倒排索引 + 确定性哈希向量化器(192 维),真正的语义后端可以在运行时注入。
- 脱敏默认开:工具与窗口的输出默认
secrets—— 抹掉凭据形状的文本、省略正文;strict连标签一起遮挡;none是显式的本地调试逃生门,产物本身会就此发出警告。 - 旧目录兼容:默认
$DSH_HOME/anagenesis;若检测到改名前的$DSH_HOME/evolution数据更完整,会继续沿用旧目录并在日志里说明,一个字节都不搬。要搬就npm run migrate:store(复制 + 逐文件 sha256 校验,源目录不动)。
配置(全部可选,全部有安全默认值)
内核行的关键旋钮:
| 键 | 默认 | 作用 |
|---|---|---|
rootDir |
$DSH_HOME/anagenesis |
存储根目录;显式设了就完全听它的(不再回退旧目录) |
safeMode |
false |
冻结策略注册、切换与调参 |
defaultScopeTier |
project |
没有显式指定作用域时,记忆落在哪一层(project / global / session) |
sessionTtlMs |
86400000 |
会话级记忆的默认存活时间;0 = 不过期 |
recallCrossProjectDefault |
false |
是否默认纳入其它项目的记忆(默认关闭:跨项目必须显式授权) |
workspace |
空 | 显式指定"当前项目"的工作目录;留空时用工具调用携带的 cwd |
recallDefaultTokenBudget |
1600 |
召回注入的默认 token 预算 |
hookBudgetMs |
8 |
单个策略钩子的时间预算(超时按失败计,不拖住召回) |
compactAfterEvents |
2000 |
活跃事件超过它就压缩日志;0 关闭 |
archiveMaxSegments |
16 |
归档段数上界(合并最老的段,不丢 seq);0 不设界 |
retainEvents |
0 |
唯一有损策略:只保留最近 N 条事件的归档段;0 = 全留 |
embedProvider |
hash |
启动时用哪个向量后端;语义后端可在运行时装入 |
reflectionEnabled |
true |
定时反思:质疑证据已明显衰减的既有信念(只归档为草稿假设) |
其余:工具行 exposeAuditTool / exposeTuneTool;可视化行 lang / redaction / width / auditRenders 等;窗口包见 window/README.md。
常见问题
会拖慢每次召回吗? 策略钩子有 8ms 预算、超时按失败计;读取走冻结快照,不上锁。
记忆会越写越乱吗? 生命周期状态、置信度、重要度衰减、过期清扫、反事实重思都是显式工具,可以随时收拾。
卸载会留残留吗? 每一行释放自己创建的效应(工具、服务、定时器、路由、席位);卸载后 journal 句柄关闭、存储目录可以正常删除。
能换成真正的语义检索吗? 能。运行时 service.useEmbedder(...) 装入后端,再 reembed() 把已存向量重算一遍;在那之前状态里会一直标记向量"陈旧"。
为什么桌面窗口是单独的包? 声明 dsh.client 的包只能有一个活跃 Loader 行,而内核是五行(预设还会再挂一次)。这是 DSH 的硬约束,所以窗口做成单行兄弟包。
许可证
Apache License 2.0 © 2026 dsh-anagenesis contributors