Skip to content

[蒸馏] type 枚举不对称:prompt 给 4 值、VALID 吃 7 值,滤空窗口被报成「没按格式写」并反复重放(#493 第二形态) #502

Closed

Description

@modusensus

是什么

#493 的第二种形态,与围栏无关、也不是解析器太严:社区报告(#493 19:12 追加)给出 0.9.4 生效后 28 分钟的审计——summarize_compress 失败行的 raw_has_bracket = true、raw_len 2574/3299,JSON 是合法的,条目却被 type 枚举全部滤掉。模型自造了中文分类("type": "环境/版本"、"用户需求")并多给 id/source 这类键。

于是 entries.length === 0 而 arr.length > 0 → ok:false → 记 invalid summary JSON → 游标不推进,整窗反复重放。一个只错在分类词上的窗口,被当成「模型没按格式写」。

根因是两套不一致(对照 main 已核)

  • src/summarize.js 的 VALID 接受 7 个类型;
  • src/lang.js 里普通 summary 的中英两版 prompt 只列 4 个(preference|project|decision|history),codingSummary 才列全 7 个;
  • 两个 prompt 都没有一句「只能用这些值 / 不要输出额外键」(grep 只能用这些值|枚举外的值|额外键 = 0 命中),枚举写成裸竖线串。

「喂给模型的菜单」和「卡内容的闸门」不一致,模型按最像中文标签的方式发挥是合理结果。

拟修(按侵入性从小到大,前两条零行为变更)

  1. 诊断先行的错误分叉:entries.length === 0 && arr.length > 0 时 error_message 写成 no valid summary entries (arr=N, valid=0),metadata 补 invalid_entries(被滤掉的条数)与 sample_types(前 5 个 type 原文),另补 raw_tail——有些模型先写几条合法条目再跑偏,头 300 字看不出来。
  2. prompt 侧对齐:summary 两版列全 7 个枚举,并写明「不要输出枚举外的值、不要输出 id/source 等额外键」,与 codingSummary 严格程度一致。
  3. type 归一化(暂缓):中文/近义词 → 枚举,未知落 project/history。它会把内容救回入库,但改变入库分类分布,等 1 的统计出来再判断值不值。

summarizeParseFailureMaxRetries 保持默认关是对的:这两种形态是「该被修的」,设成 2 会把它们连着窗口一起丢掉。护栏应在 1/2 落地之后再开。

Activity

  1. added
    bug功能异常、崩溃、数据错误(agent 诊断 → 人工确认)
    on Oct 21, 2026
  2. moved this from 📋 Backlog to 🔨 In Progress in dsh-mneme 任务看板on Oct 21, 2026
  3. added a commit that references this issue on Oct 29, 2026
  4. moved this from 🔨 In Progress to ✅ Done in dsh-mneme 任务看板on Oct 29, 2026
  5. added 2 commits that reference this issue on Oct 29, 2026
  6. strange2000 commented on Oct 30, 2026

    @strange2000

    0.9.5 上线 4 小时后的 filtered-empty 实测(第 2 步要的统计)

    环境:@modusensus/dsh-mneme 0.9.5,本机 Windows,2026-10-30 05:57Z 装好;模型 workbuddy2api:cn:deepseek-v4.1-flash;数据源 llm_audit_logs 只读查询。

    指标 值
    summarize_compress 调用 43(成功 5 / 失败 38)
    跨度 06:01Z → 10:16Z,4 小时 15 分
    failure_kind filtered-empty ×37;另 1 条是传输错误(metadata null)
    被滤条目 arr_count 累计 394,invalid_entries 累计 394,valid = 0
    raw_has_bracket=false 0(JSON 全程合法)
    streak 峰值 8
    失败消耗输入 318,384 tokens

    诊断分叉、failure_kind、arr_count、invalid_entries、sample_types、raw_head、streak 全部按设计工作。这次不用再猜了。

    sample_types 长什么样

    37 个失败窗口里 18 个带了 type 字段,取值去重后 78 种,没有收敛迹象:

    • EN:task verification finding fact action result lesson advice incident analysis change risk issue closure diagnostic root_cause state_change action_item …
    • ZH:根因 问题 版本状态 环境事实 事实 验收结果 配置现状 已完成任务 经验教训 约束规则 用户诉求 问题现象 证据 处置 故障定位 修复路径 操作 发现 验证 …

    这些值看着是「这条内容在说什么」,不是「这条记忆属于哪一类记忆」——模型把语义分类和记忆分类混在一起了。

    一个会改变第 2 步结论的点

    19/37(51%)的失败窗口根本不带 type 键。 它们把整个 schema 换掉了:

    { "类别": "变更-插件升级", "要点": "…", "证据": "…" }
    { "category": "依赖更新", "summary": "…", "details": ["…"] }
    { "type": "task", "id": "upgrade-plugins", "topic": "…", "status": "done", "changes": ["…"] }

    第三种有 type,但同样没有 title / content。也就是说失败有两类成因:type 不在枚举,和键名整体替换(topic/summary/要点/摘要 顶掉 title+content)。type 归一化只覆盖前者,也就是一半。

    对 78 种类型值做映射表我判断性价比不高:表要么很长,要么大面积落默认值,而默认值会把 decision / pitfall / constraint 这些高价值类型冲淡。

    如果要做,我推荐这两个方向

    1. 读入端别名归一(不依赖模型服从):title ← title|topic|标题|要点|摘要,content ← content|summary|details|正文|内容|证据;type 缺失时按关键词猜,猜不到落 project。上面三种形态都能收下,信息不丢,代价是字段判定变宽。
    2. 二段式:第一段自由输出(现状),第二段把该 JSON 当输入,问「改写成 [{type,title,content,importance}],只输出 JSON 数组」。多一次几百 token 的小调用,把「理解」和「格式化」拆开,服从率通常高得多。

    两条都不动 prompt 语义,也不影响已合入的 #503。

    顺带一句:dream 侧修得很干净,装后 12 次巩固 11 成功(此前 35 连败)。

    不用回,数据放这儿备查。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug功能异常、崩溃、数据错误(agent 诊断 → 人工确认)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions