Files
life-echo/.cursor/plans/story_route_append_context.plan.md
Kevin b853b986dd fix(memoir): 改善 story 合并决策,少生碎片篇
以前模型只看到很短预览,还容易被引导成新建 story。现在优先用已有摘要、
按需带正文片段,并区分「像续写同一主题」和「像换了一件事」;
beliefs/summary 更鼓励接着写, career/童年等仍可按新事件新开。
2026-04-03 11:02:05 +08:00

8.1 KiB
Raw Blame History

name, overview, todos, isProject
name overview todos isProject
Story route append context 候选载荷增胖summary 优先 + 可配置预算)+ category-aware prompt 纠偏 + 最小测试集;不扩大路由体系、不改 schema、不接离线合并。
id content status
config-budget Add Settings — story_route_candidate_body_max_chars, total_max, head/tail, summary_min_len (optional) completed
id content status
payload-builder build_route_candidate_rows — fixed sort, summary-first body rules, total budget downgrade to index rows completed
id content status
prompts-merge-bias get_story_route_prompt + get_story_batch_plan — two-layer criteria, category blocks, remove default-to-new_story completed
id content status
wire-agent StoryRouteAgent decide/plan_batch use new builder + prompts; validate_story_batch_plan unchanged; no pipeline signature change completed
id content status
tests Builder tests + prompt contains + beliefs append smoke + career new_story smoke + test_story_route_oral_invariant completed
false

Story Route候选上下文增胖 + category-aware append 纠偏

Ticket / PR 一句话

用更富的候选 JSONsummary 优先、再按需补正文)与 按类目纠偏 的提示词,修复 StoryRouteAgent 在强主题类目下过度 new_story;预算 Settings 化,默认值 保守不改 memoir 流水线签名与 DB schema。

根因(代码事实)

  • [api/app/agents/memoir/story_route_agent.py](api/app/agents/memoir/story_route_agent.py)preview_chars=220,同类目下多条短感悟几乎不可区分。
  • [api/app/agents/memoir/prompts.py](api/app/agents/memoir/prompts.py)「若无法自信匹配某一候选,选 new_story」 → 与「主题容器逐步加厚」产品预期相反。
  • Story.summary 列存在,路由未用;仅截 canonical_markdown

本轮 scope

交付物 说明
[story_route_agent.py](api/app/agents/memoir/story_route_agent.py) 新增 candidate payload builder_build_candidate_json 改为走 builder
[prompts.py](api/app/agents/memoir/prompts.py) get_story_route_promptget_story_batch_plan_prompt 纠偏 + 两层决策标准 + 三类 category 规则
[config.py](api/app/core/config.py) 34 个预算相关字段(见下)
测试 builder 单测、prompt 片段断言、2 条类目行为样例[test_story_route_oral_invariant.py](api/tests/test_story_route_oral_invariant.py) 回归

本轮 scope不做

  • 离线 / admin 合并历史垃圾 story
  • schema 变更、二次 merge worker、family 细分子策略扩写、时间跨度阈值
  • 扩大路由体系(多模型级联、新端口签名等)

1. 候选行结构summary 主角)

每条候选字典 必带idtitlechar_countversion_countupdated_atISOlinked_chapters(保持现有拼接逻辑)。

内容优先级,严格顺序:

  1. Story.summary 非空且达到 summary 最小长度阈值(可配置,如 ≥30 字或复用现有惯例),则带 summary本轮不带 body_for_route(避免长正文冲淡摘要)。
  2. 若 summary 缺失或过短,再构造 body_for_route短正文尽量全文;超长用 head + tail(中间省略说明),长度受 story_route_long_body_head_chars / tail 与单篇 cap 约束。
  3. 总预算 时,将该条 降级为索引行(仅 idtitlechar_count、极短 preview,提示中说明索引项优先匹配带 summary/body 的条目)。

初版默认值(保守,可线上调大):

  • story_route_candidate_body_max_chars12002000(落地取单值如 1600
  • story_route_candidate_total_max_chars1200018000(如 16000
  • head/tail按现有「长文才切」思路配一对合理默认如各 600800

2. 排序规则写死tie-break

在进入 builder 之前candidate_stories 排序(同 stage 列表):

has_summary(desc) → updated_at(desc) → version_count(desc) → char_count(desc) → id(asc)

其中 has_summarysummary strip 后长度 ≥ 配置的 summary 最小长度。

3. 提示词

3.1 去掉保守偏置

删除「拿不准就 new_story」;改为:先看是否与某候选在主题/事件层级上可合并,再决定

3.2 两层决策标准(显式写在 prompt 里)

  • 主题连续性信号:价值观、关系模式、长期总结、同一反思维度。
  • 事件切换信号:新人物组合、新地点、新时间段、新事件因果链。

指引:beliefs / summary 更看主题连续性career_* / childhood / education 更看事件链

3.3 类目规则(第一版只三件)

  • **beliefssummary**强容器 → 多条短感悟、同一句式起笔、同价值维度 → 强烈倾向 append_story(指向最匹配的一条候选 id
  • **career_*childhoodeducation**强 episode → 明确不同事件链可 new_story;同一经历续问可 append。
  • **family**中性 → 一句话:原则/关系反思倾向 append明确的新事件链可 new展开长列表例外。

get_story_batch_plan_promptget_story_route_prompt 对齐上述规则。

4. 接线

  • [story_pipeline_sync.py](api/app/features/memoir/story_pipeline_sync.py) 不改 StoryRouteAgent 调用签名。
  • validate_story_batch_plan、Pydantic 模型 不变

5. 测试(最小集 + 2 条行为)

测试 目的
Builder summary 优先不带 bodysummary 短则带 body总预算降级排序稳定
Prompt 类目块、两层标准、beliefs/family 中性句等 包含断言
行为 A mock LLMbeliefs + 两则短感悟口述 + 已有 1 条 story → 期望 append(或断言传给 mock 的 payload 含足够 summary/body 且 prompt 强调强容器;实现时二选一并写死断言)
行为 B mock LLMcareer_achievement(或 childhood+ 两起明确不同事件 → 允许/期望 new_story
回归 [test_story_route_oral_invariant.py](api/tests/test_story_route_oral_invariant.py):路由输入仍 不含 evidence

行为测试若不便绑定真实 LLM采用 mock invoke_json_object / StoryRouteAgent 固定返回或 断言 prompt + candidate JSON 形状,与现有 [test_story_route_oral_invariant.py](api/tests/test_story_route_oral_invariant.py) 风格一致。

6. 风险与验收

  • Token:默认保守;观察 staging 日志 route_decision / is_append 再调 Settings
  • 过度合并:靠 episode 类与「事件切换信号」段落缓解。

实施顺序

  1. config.py 字段
  2. Builder + builder 单测 + 排序单测
  3. Prompt 改造 + prompt 断言
  4. StoryRouteAgent 接线
  5. 行为 A/B + oral invariant + 相关 memoir 测试