feat(memoir): 路由阶段不要求标题,按正文字数门闸延迟 LLM 标题

- 从 story 路由 prompt/校验中移除 new_story_title,改由叙事管线在正文足够长时生成
- 新增 story_title_min_body_chars;短正文使用章节类别占位标题
- CATEGORY_TO_CHAT_STAGE 对齐访谈 state.slots 的 stage 键
- 删除相对口述长度的叙事回退,仅保留 merge JSON 极端缩水类 fallback
- evidence_format:解析 object_json 并优化事实条目标点符号
- 更新 narrative / experience 相关单测
This commit is contained in:
Kevin
2026-04-02 14:38:40 +08:00
parent bb16d3a5c9
commit 3ae39838c0
8 changed files with 125 additions and 132 deletions

View File

@@ -401,8 +401,6 @@ def get_story_route_prompt(
「故事」在此指:**可独立讲述的一段人生经历**——单一主题或同一事件链;不要假设本批里包含多个互不相关的故事(多段由系统其它步骤处理)。
**new_story_title 与 reason 只能依据口述中已有信息概括,不得编造口述未出现的人、事、地、物。**
**路由边界(必须遵守)**:仅根据下方「本批口述合并文本」判断 new_story 与 append_story不得将系统检索摘要、记忆摘录、图谱事实或其它非用户口述材料当作本批口述内容来匹配候选故事。
当前章节(写作容器):
@@ -419,13 +417,11 @@ def get_story_route_prompt(
{{
"decision": "new_story" | "append_story",
"target_story_id": "<uuid 或 nullappend 时必填且必须来自候选>",
"new_story_title": "<短标题6-20 字new_story 时必填append 时可 null>",
"reason": "<一句中文理由>"
}}
规则:
- 若无法自信匹配某一候选,选 new_story
- new_story_title 应概括本批新内容,不要与候选标题重复
"""
@@ -444,8 +440,6 @@ def get_story_batch_plan_prompt(
## 「故事」定义(必须遵守)
一段「故事」= **可独立讲述的一段人生经历**:单一主题或同一事件链,能单独成篇。若话题切换、时间线跳到另一件事、人物/主线明显变化,应作为**新的故事**new_story而不是塞进同一段 append。
**new_story_title 与 reason 只能依据各 segment 文本中已有信息,不得编造口述未出现的事实。**
## 任务
将本批 segment **划分为连续若干块**(每块包含至少一个 segment顺序不能打乱每个 segment 必须恰好属于一块)。对每一块决定:
- **append_story**:内容明显延续、补充**某一已有候选故事**的主题与时间线,且能对应到具体 candidate id
@@ -468,7 +462,6 @@ def get_story_batch_plan_prompt(
"segment_ids": ["<按顺序列出本块包含的 segment id>"],
"decision": "new_story" | "append_story",
"target_story_id": "<uuid 或 nullappend 时必填且必须来自候选>",
"new_story_title": "<短标题6-20 字new_story 时必填append 时可 null>",
"reason": "<一句中文理由,可选>"
}}
]
@@ -477,7 +470,6 @@ def get_story_batch_plan_prompt(
规则:
- `units` 中所有 `segment_ids` 拼接后,必须**不重不漏**地覆盖本批全部 id且顺序与【本批口述片段】数组一致
- 若无法自信匹配某一候选,对该块选 new_story
- new_story_title 应概括该块内容,不要与候选标题重复
"""

View File

@@ -116,7 +116,8 @@ def validate_story_batch_plan(
valid_story_ids: set[str],
) -> tuple[bool, str | None]:
"""
校验segment 全覆盖、顺序一致、append 目标合法、new_story 有标题
校验segment 全覆盖、顺序一致、append 目标合法。
标题由 NarrativeAgent 延迟生成,路由阶段不再要求 new_story_title。
返回 (ok, error_code)。
"""
if not plan.units:
@@ -135,10 +136,6 @@ def validate_story_batch_plan(
tid = u.target_story_id
if not tid or tid not in valid_story_ids:
return False, "invalid_append_target"
else:
title = (u.new_story_title or "").strip()
if not title:
return False, "missing_new_title"
return True, None
@@ -196,10 +193,6 @@ class StoryRouteAgent:
new_story_title=decision.new_story_title,
reason="invalid_target",
)
if decision.decision == "new_story" and not (
decision.new_story_title and decision.new_story_title.strip()
):
decision.new_story_title = None
return decision
def plan_batch(