Repository navigation
Open
Labels
Description
背景
巩固(autoDream)与蒸馏(autoSummarize)目前是写入驱动 + 排除式时段窗:
- 写入累积到阈值(
dreamThresholdCount10 /dreamThresholdChars5000,且相对上次成功轮有净增长)→ 2 秒后跑一轮;dreamMinIntervalMinutes是频率下限; dreamPeakHours是排除窗:命中就顺延到「下一个非高峰时刻」,最多顺延dreamPeakMaxDeferMinutes(默认 120 分钟,上限 1440)。
这套机制能「避开某段时间」,但做不到「每天在一个固定点跑一次」,而后者才是省 token 的大头:写入驱动下巩固一天跑约 14.6 轮,每轮输入仍是 top-200 快照(平均约 37.8K token),大量轮次的输入高度重叠。
实测证据(现状的三个坑)
- 写错静默失效,且失效方向是多花钱。 想用补集表达「只在 03:00–04:00 跑」时,
"00:00-03:00,04:00-24:00"里的24:00非法 →parsePeakSpec整体返回null,而null等价于「未配置」= 不限制。写错的人是奔着省钱去的,结果回到全天候。 - 能用的补集写法反直觉且带缝。
"00:00-03:00,04:00-00:00"解析为[{start:0,end:180},{start:240,end:0}],允许窗 = 03:00–04:00(实测 03:30 放行、12:00/23:58 拦),但23:59:00–23:59:59这一分钟不落在任何窗内,是个缝。 - 只改
dreamPeakHours会白设。dreamPeakMaxDeferMinutes默认 120 会让顺延在高峰期中间bypassPeak开跑——想真正定点,必须把它一起抬到不小于窗口跨度。
另外,插件侧没有任何手动触发口:CLI 只有 config/status/list/search/get/add/delete/reclaim,HTTP 面只有 dream-status 读端点,runDream 目前只能被调度器调用。
提案
- 正向维护窗口:新增「允许跑」的窗口配置(默认空 = 不限制,opt-in 默认关),语义是正向的——填
03:00-04:00就读作「每天这一点跑」,不再要求用户做补集;底层复用现有parsePeakSpec时段语法与面板入口。 - 债务上限安全阀:待巩固规模超过硬顶(如 200 条 / 60K 字符)或距上次成功超过 N 小时 → 提前跑一轮,别让「一天一次」在异常写入量下把记忆准确度饿死。
- 定点靠事件搭便车,不引入常驻 cron(
src/dream/sleep.js:683已写明 DSH 插件没有常驻定时器):每次写入/空闲事件做一次 O(1) 判断「今天那一轮跑了吗」,没跑且已过点就补跑——这样关机、休眠、DSH 没开都能在下次唤醒时补上;纯setTimeout挂 24 小时在休眠/时钟跳变下不可靠。 - 失败短重试:一天一次时「一次失败 = 浪费一整天」。近 7 天 102 轮里 12 轮失败(11.8%),需要保留失败后的短重试(与现有
failureBackoff对齐)。 - 手动触发入口:斜杠命令 +
POST /api/dsh-mneme/dream/run(安全阀、排障与「我现在就想清理一下」共用同一个入口)。
收益与代价(样例库实测 + 同口径估算)
| 方案 | 7 天巩固输入 token | 相对现状 |
|---|---|---|
| A 现状(写入驱动,约 14.6 轮/天) | 3,856,785 | — |
| B 一天一次定点,仍送 top-200 窗口 | ~264,681 | −93% |
| C 一天一次定点,只送当天变更 | ~398,297 | −90% |
代价要说清:重复记忆的滞留窗口从约 99 分钟拉长到 ≤24 小时;近 7 天约 13% 的轮次 applied=0(跑了等于白跑),改成一天一次后这类浪费更贵,所以第 2、4 项安全阀不是可选项。
与 #239 的关系
#239 第 4 项「错峰队列」已落地为 dreamPeakHours / summarizePeakHours(排除式 + 顺延补跑)。本 issue 是它的下一步:正向窗口语义 + 债务上限 + 补跑语义 + 手动入口,与 #239 其余四项(成本感知级联、零 LLM 构建、有界检查点、不确定性驱动读路径)正交。
验收
- 正向维护窗口可配置,默认不改行为(opt-in 默认关)
- 窗口外不发起巩固/蒸馏 LLM 调用,且债务不丢
- 硬顶/N 小时安全阀可配置并有审计行
- 关机/休眠跨过窗口后能在下次唤醒补跑一次
- 手动触发入口可用(斜杠命令 + HTTP)
- 默认配置下 LLM 调用量较现状可量化下降
附:今天就能用的临时办法
dreamPeakHours = "00:00-03:00,04:00-00:00" + dreamPeakMaxDeferMinutes = 1440 可以近似「每天 03:00–04:00 一次」。之所以建议不要长期依赖它,见上文第 1–3 条坑。
(相关但可另开的一条:parsePeakSpec 对非法串返回 null 且无任何告警,建议在面板与日志侧给出「时段串未生效」的显式提示——本 issue 不吞并它。)
Activity
modusensus commentedon Oct 20, 2026
现状(2026-10-21 对照
main实测)零实现。四个关键词全 0 命中,也没有任何提交引用过 #424。
实测
git log --grep "#424"→ 0 条(main 与所有分支均无)。相关的既有能力只有:
a7874e0存储无损回收(手动)、config.js:692retentionDays默认 90(时间维度保留)、summarizeMaxRunsPerSession与错峰队列(#239,成本维度)。没有「维护窗口 / 债务上限 / 正向定点」这一层。还缺什么
issue 提的三件,一件都没做:
#489),但那触发的是沉淀(distill),不是巩固(dream),两者不要混。接手建议
这条的价值在「债务上限」:现在巩固失败会重试、会退避(
d2df61d指数退避),但没有「积压到多少就该停手」的判定。建议先只做债务度量(只读、进/health),再谈上限与强制整理。louisjar commentedon Nov 4, 2026
00:00-03:00,04:00-24:00,中的逗号貌似也需要分全角半角,之前全高峰期在巩固,应该是写了全角逗号。
modusensus commentedon Nov 4, 2026
复核了这条线索,方向对,但成因比「逗号全角半角」宽一层。用
main上的src/peak-hours.js直接跑parsePeakSpec(纯函数,不需要起插件):00:00-03:00,04:00-06:0000:00-03:00,04:00-06:00(全角逗号)00:00-03:00,04:00-06:00(全角冒号)00:00-03:00(全角数字)00:00~03:00(波浪号)09.00-18.00(点号当冒号)00:00-03:00,04:00-24:0024:00小时越界)只要串里出现任何非 ASCII 的等价符号,整串就解析成 null,而 null 等价于「未配置 = 不限制」,于是巩固/蒸馏回到全天候——正是 @louisjar 描述的现象。
根因两处
parsePeakSpec按rest.split(",")切段(src/peak-hours.js:59),只认 ASCII 逗号。全角,切不开,整串会作为一个 part 去匹配下一行的正则,必然失败。/^\s*(\d{1,2}):(\d{2})\s*-\s*(\d{1,2}):(\d{2})\s*$/(src/peak-hours.js:60)只认 ASCII 数字、半角冒号、半角连字符;\s*只吃空白,不吃这些等价符号。关于举例的那条串
00:00-03:00,04:00-24:00其实同时踩了两个坑:24:00本身非法(:63的eh > 23直接判 null),所以即便逗号写成半角也照样失效。想表达「只在 03:00–04:00 跑」,正确写法是:
04:00-00:00是跨零点段(end=0),解析为{start:240, end:0},允许窗 = 03:00–04:00。已知的缝(本 issue 正文第 13 行也提过):这种写法下
23:59:00–23:59:59不落在任何窗内。关于静默失效
「解析失败无任何告警」本 issue 正文第 53 行已注明不吞并、建议另开。确认它值得单开一条可观测性 issue——解析失败时在日志与面板给显式提示,零行为变化、不新增配置键。本 issue 的五项提案(正向窗口 / 债务上限 / 定点搭便车 / 失败短重试 / 手动入口)不受影响。
fix(peak-hours): 全角符号归一 (#621)