feat(memory): D3 第五态 defer(入库审查)+ 提取留存规则闸 + 临时 TTL 配置面
主人原话:「收窄提取器,确实要给他一个主动式的记忆留存规则,不能想到什么都 往记忆里写」「.env 只做兜底用 …这些键优先从面板配置上取」「临时记忆到期删除」。 按 design/23 §18(D3 第五态 defer)、§19(到期处置)、design/03 §9.6 (tempTtlSec 默认 7 天 + 坏值口径)、§10(提取留存规则)落地。 - IngestDecision 闭集加第五态 defer:照常 active 落库 + 写短 expires_at 落 临时层(不删行、不改正文,回滚 = 清空该列);IngestRuleVersion d3.2 → d3.3。 - 落点:ingestGatePlan 增 ExpiresAt + expiresAt()(走 expiryText/formatTime 的 定宽 30 字节 UTC,与读侧时效闸同一套文本口径),由 finishIngest 在 defer 一态 补写 expires_at(INSERT 与补写之间的短暂窗口如实登记,方向 = 宁可多留)。 非 defer 三态一笔都不多写。 - T0 提取留存规则闸(extract_retention.go):design/03 §10.5 的 N1~N5 纯规则, 接进 judgeIngest 的候选比对之前,命中即 defer + reason=t0_low_value,不进 T1; 两道护栏(显式「记住」/ 持久信号)一票放行,fail-safe 方向 = 宁可多留。 - T1 闭集扩为 merge/modify/keep/defer(同一个 prompt、同一次调用,绝不新增 第二次模型调用):只有关系判为真新时才问价值;defer 要求 target=0,否则判 非法回落 create(reason=t1_reply_invalid)。 - 提取器提示词加固(design/03 §10.3 B):正向清单 + 反例清单 + 「允许返回 []」。 - 临时记忆 TTL:代码默认 tempTtlSec = 604800(7 天);面板 $DATA_DIR/config/memory-tidy.json 的 tempTtlSec 优先(ApplyReviewTuning 逐键 解析,坏值回落默认 + WARN,绝不写进 cfg)。该键在 .env 里没有出处且不新增 (.env 已冻结)⇒ 实际生效链是「面板 > 代码默认」。启动播种同步该键(*int + omitempty,nil 省略、绝不写 null),保证播种文件与生效值逐字一致。 - preinsert_store.go 的 listReviewCandidatesSQL 原位注释:这条内部召回 SQL 刻意不过时效闸的裁定与理由(design/03 §11.2 第 3 条)。 - 测试:defer 落库带短 expires_at(闸 + T1 两条路径)、写入口径与时效闸同源、 TTL 坏值与回落、规则版本 d3.3、整理候选幂等键不含 IngestRuleVersion、 提取规则正例 11 条 / 反例 11 条。 验收:go build ./... + go vet ./... + go test ./... 全绿;windows/darwin 交叉 编译通过(GOOS=darwin GOARCH=arm64 / GOOS=windows GOARCH=amd64)。
This commit is contained in:
1 parent
68ba85389b
commit
21b906ffb0
18 files changed
+1352
-35
No files matched your search
@@ -35,6 +35,14 @@ import (
|
||||
// 调用还要先过**全局限速**(默认 120 次/小时,preinsert_t1_limit.go):
|
||||
// 超限即跳过 T1、回落 create + `t1_throttled`。
|
||||
// **同步入库闸(preinsert_gate.go)不碰 T1**,写入路径因此仍是零模型调用。
|
||||
// 4. **第五态 `defer` 的判定在两层各有一处来源**(design/23 §18.2):
|
||||
// **T0 提取留存规则闸**(`extract_retention.go` → `judgeIngest`,纯规则、
|
||||
// 零模型)拦「结构上显然不值得留」的(`reason=t0_low_value`);**T1 则把
|
||||
// defer 收进同一个闭集**(`merge/modify/keep/defer`,**同一次调用**、
|
||||
// 同一个 prompt、同一套候选编号),只在关系判为「真新」时才问「值不值得
|
||||
// 长期留」(`reason=t1_defer`)。**绝不新增第二次模型调用**。
|
||||
// 两条失败路径都回落 `create`(= 当作长期记住),fail-safe 方向恒为
|
||||
// 「**宁可多留,不可误弃**」(§18.3)。
|
||||
//
|
||||
// 代价(如实登记):极短窗口内库里会多一行待裁定的重复条目,随后被软合并
|
||||
// (status='merged' + merged_into,可 revert,绝不物理删除,design §8)。
|
||||
@@ -55,6 +63,19 @@ const (
|
||||
// IngestCreate 表示确属新条目(互不包含 / 被规则否决 / 没有召回):
|
||||
// 正常新建,不做任何改写(§15 D3-2 T0-3)。
|
||||
IngestCreate IngestDecision = "create"
|
||||
// IngestDefer 是**第五态**(design/23 §18.1):与既有记忆不冲突(真新),
|
||||
// 但不值得长期留存 ⇒ **照常插入**,只把 `expires_at` 写成「现在 + 临时 TTL」
|
||||
// (默认 7 天,见 tempTtlSec)落进**临时层**:到期由读侧时效闸隐藏
|
||||
// (design/03 §9.6)、再由后台清扫物理删除(design/23 §19)。
|
||||
//
|
||||
// 它与其余四态的正交关系(§18.2 的不变式):`defer` ≡「关系判为**真新**
|
||||
// ∧ 价值判为**短期**」。因此它**只在被判为真新时**才可能产生 —— 已被既有
|
||||
// 记忆代表的那条(merge/modify/skip)留不留由既有行决定,与价值判定无关。
|
||||
//
|
||||
// 🔴 仍是**软动作**:只写 `expires_at` 一列,**不删行、不改正文**;回滚 =
|
||||
// 清空该列(§18.4)。选 `defer` 而非 `drop` 是 fail-safe 取向的落点
|
||||
// (§18.3「宁可多留,不可误弃」):最坏后果只是「多留 7 天」。
|
||||
IngestDefer IngestDecision = "defer"
|
||||
)
|
||||
|
||||
// IngestRuleVersion 是入库前审查规则集的版本号,进每条审查留痕(§15 D3-8)。
|
||||
@@ -65,7 +86,11 @@ const (
|
||||
// - `d3.2` 加入 **T1 灰区模型判定**(preinsert_t1.go,design/23 §15.1 D3-2):
|
||||
// 灰区(相似、互不包含、未被规则否决)在模型出口接上时会被改判成
|
||||
// merge/modify,因此 `reason` 上出现了 `t1_*` 族。
|
||||
const IngestRuleVersion = "d3.2"
|
||||
// - `d3.3` 加入 **第五态 `defer`**(design/23 §18.1):T0 提取留存规则闸
|
||||
// (`t0_low_value`)与 T1 的同一次调用(`t1_defer`)都能给出它,落点 =
|
||||
// 照常插入 + 写短 `expires_at`。**升版是硬要求**:同一对条目在 d3.2 下是
|
||||
// `create`、在 d3.3 下可能是 `defer`,不升版新旧留痕无法区分(§18.4)。
|
||||
const IngestRuleVersion = "d3.3"
|
||||
|
||||
// 调优旋钮(ReviewConfig)与它们的默认值常量在 preinsert_config.go。
|
||||
|
||||
@@ -402,6 +427,16 @@ func (r *PreInsertReviewer) applyVerdict(ctx context.Context, v ingestVerdict, i
|
||||
if v.Decision == IngestCreate {
|
||||
return nil, nil
|
||||
}
|
||||
if v.Decision == IngestDefer {
|
||||
// 第五态(design/23 §18.1):条目**早已落库**(异步审查跑在写入之后),
|
||||
// 这里只把 `expires_at` 写成「现在 + 临时 TTL」把它放进临时层。
|
||||
// **不删行、不改正文、不碰任何其它行** ⇒ 回滚 = 清空该列(§18.4)。
|
||||
// 写不进去就如实返回错误(fail-safe:行留在长期层 = 宁可多留)。
|
||||
if err := r.deps.Store.setIngestExpiry(ctx, item.ID, expiryText(r.deferDeadline(now))); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
if v.Absorbed.ID == "" || v.Existing.ID == "" {
|
||||
return nil, fmt.Errorf("memory/review: %s without a matched existing item", v.Decision)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user