fix(memoir): 改善 story 合并决策,少生碎片篇
以前模型只看到很短预览,还容易被引导成新建 story。现在优先用已有摘要、 按需带正文片段,并区分「像续写同一主题」和「像换了一件事」; beliefs/summary 更鼓励接着写, career/童年等仍可按新事件新开。
This commit is contained in:
@@ -436,6 +436,40 @@ def get_narrative_merge_json_prompt(
|
||||
"""
|
||||
|
||||
|
||||
def story_route_merge_hint_for_category(chapter_category: str) -> str:
|
||||
"""按章节类目的 append/new 倾向(与 StoryRouteAgent 路由提示共用)。"""
|
||||
cc = (chapter_category or "").strip()
|
||||
if cc in ("beliefs", "summary"):
|
||||
return (
|
||||
"### 本章类别路由倾向(强主题容器)\n"
|
||||
"- 多条短感悟、同一价值维度、同一总结脉络的补充 → **优先 append_story**,"
|
||||
"选最匹配的一条候选 id。\n"
|
||||
"- 仅在用户明确讲述**与所有候选主题明显不相关**、且可独立成篇的长经历时,才用 new_story。"
|
||||
)
|
||||
if cc == "family":
|
||||
return (
|
||||
"### 本章类别路由倾向(家庭)\n"
|
||||
"- 原则性反思、关系模式、相处之道的补充 → **倾向 append_story**。\n"
|
||||
"- **明确的新事件链**(新场景、新时间线、不同人物组合的新经历)→ 可 new_story。"
|
||||
)
|
||||
if cc in (
|
||||
"childhood",
|
||||
"education",
|
||||
"career_early",
|
||||
"career_achievement",
|
||||
"career_challenge",
|
||||
):
|
||||
return (
|
||||
"### 本章类别路由倾向(经历叙事)\n"
|
||||
"- 以具体事件链为主:**不同事件 / 时期 / 地点** → 可 new_story。\n"
|
||||
"- 明显是**同一段经历的续叙、补充细节** → append_story。"
|
||||
)
|
||||
return (
|
||||
"### 本章类别路由倾向(一般)\n"
|
||||
"- 同时参考「主题连续性」与「事件切换」两类信号做判断。"
|
||||
)
|
||||
|
||||
|
||||
def get_story_route_prompt(
|
||||
*,
|
||||
chapter_category: str,
|
||||
@@ -448,15 +482,24 @@ def get_story_route_prompt(
|
||||
「故事」= 可独立讲述的一段人生经历;进入本步的批次已归入具体 chapter category
|
||||
(含模型返回 none 或零散档案启发式时映射的 summary)。
|
||||
"""
|
||||
return f"""你是回忆录编辑助手。根据本批用户口述与候选故事列表,决定:
|
||||
- append_story:内容明显延续、补充某一已有故事的主题与时间线,且能对应到具体 candidate id
|
||||
- new_story:新话题、新人生阶段片段,或与所有候选故事都不够贴合
|
||||
merge_hint = story_route_merge_hint_for_category(chapter_category)
|
||||
return f"""你是回忆录编辑助手。根据本批用户口述与【候选故事】决定 append_story 或 new_story。
|
||||
|
||||
**JSON 输出**:接口已启用 `response_format=json_object`,只输出下面 schema 的一个合法 JSON 对象,不要 markdown。
|
||||
|
||||
「故事」在此指:**可独立讲述的一段人生经历**——单一主题或同一事件链;不要假设本批里包含多个互不相关的故事(多段由系统其它步骤处理)。
|
||||
## 两层决策标准(必须先在心里过一遍)
|
||||
1. **主题连续性信号**:价值观、关系模式、长期总结、同一反思维度;口述是否像在**同一主题容器**里加厚?
|
||||
2. **事件切换信号**:是否出现**新人物组合、新地点、新时间段、新事件因果链**,与候选正文明显是**另一段经历**?
|
||||
|
||||
**路由边界(必须遵守)**:仅根据下方「本批口述合并文本」判断 new_story 与 append_story;不得将系统检索摘要、记忆摘录、图谱事实或其它非用户口述材料当作本批口述内容来匹配候选故事。
|
||||
- 类别 **beliefs / summary**:更重主题连续性;除非事件切换信号极强,否则倾向 append。
|
||||
- 类别 **career_* / childhood / education**:更重事件链;不同事件可 new,同一经历续聊则 append。
|
||||
- 类别 **family**:两类信号兼顾——原则/关系反思倾向 append;明确新事件链可 new。
|
||||
|
||||
{merge_hint}
|
||||
|
||||
**路由边界(必须遵守)**:仅根据下方「本批口述合并文本」判断;不得将系统检索摘要、记忆摘录等当作本批口述内容来匹配候选。
|
||||
|
||||
**候选故事说明**:列表项可能含 `summary` 或 `body_for_route`(正文摘要);仅含 `preview` 者为索引项,信息不全。**append 时优先匹配带 summary 或 body 的条目**;索引项仅作候选 id 备忘。
|
||||
|
||||
当前章节(写作容器):
|
||||
- category: {chapter_category}
|
||||
@@ -465,7 +508,7 @@ def get_story_route_prompt(
|
||||
【本批口述合并文本】
|
||||
{batch_transcript}
|
||||
|
||||
【候选故事】(仅允许在 append 时选择其中的 id;id 必须原样复制)
|
||||
【候选故事】(append 时 target_story_id 必须来自下列 id,且原样复制)
|
||||
{candidate_stories_json}
|
||||
|
||||
## 输出 JSON(仅此一个对象,不要 markdown)
|
||||
@@ -476,7 +519,8 @@ def get_story_route_prompt(
|
||||
}}
|
||||
|
||||
规则:
|
||||
- 若无法自信匹配某一候选,选 new_story
|
||||
- **不要**只因「不太确定」就选 new_story;在主题可并入某一候选时应 append_story。
|
||||
- 仅当口述与**所有**候选在两层标准下都明显不兼容时,才选 new_story。
|
||||
"""
|
||||
|
||||
|
||||
@@ -488,17 +532,28 @@ def get_story_batch_plan_prompt(
|
||||
candidate_stories_json: str,
|
||||
) -> str:
|
||||
"""同一章节类别下多 segment:划分为若干写入单元(每单元 new 或 append)。输出严格 JSON。"""
|
||||
merge_hint = story_route_merge_hint_for_category(chapter_category)
|
||||
return f"""你是回忆录编辑助手。下面同一章节类别下有一批**按时间顺序**的用户口述片段(每段有 id 与文本)。
|
||||
|
||||
**JSON 输出**:接口已启用 `response_format=json_object`,只输出下面 schema 的一个合法 JSON 对象,不要 markdown。
|
||||
|
||||
## 两层决策标准(每一块都要应用)
|
||||
1. **主题连续性信号**:价值观、关系模式、长期总结、同一反思维度。
|
||||
2. **事件切换信号**:新人物组合、新地点、新时间段、新事件因果链。
|
||||
|
||||
各类别倾向与单段路由一致:beliefs/summary 重主题连续性;career/childhood/education 重事件链;family 兼顾。
|
||||
|
||||
{merge_hint}
|
||||
|
||||
## 「故事」定义(必须遵守)
|
||||
一段「故事」= **可独立讲述的一段人生经历**:单一主题或同一事件链,能单独成篇。若话题切换、时间线跳到另一件事、人物/主线明显变化,应作为**新的故事**(new_story),而不是塞进同一段 append。
|
||||
一段「故事」= **可独立讲述的一段人生经历**。**同一主题容器内的连续口述**应并入同一块 append,而不是切碎成多个 new_story。
|
||||
|
||||
## 任务
|
||||
将本批 segment **划分为连续若干块**(每块包含至少一个 segment,顺序不能打乱;每个 segment 必须恰好属于一块)。对每一块决定:
|
||||
- **append_story**:内容明显延续、补充**某一已有候选故事**的主题与时间线,且能对应到具体 candidate id
|
||||
- **new_story**:新话题、与所有候选故事都不够贴合、或应独立成篇的片段
|
||||
将本批 segment **划分为连续若干块**(每块至少一个 segment,顺序不能打乱;每个 segment 必须恰好属于一块)。对每一块决定:
|
||||
- **append_story**:与某一候选在两层标准下可合并,且能对应到具体 candidate id
|
||||
- **new_story**:该块与**所有**候选都明显不兼容,或确认为独立新经历
|
||||
|
||||
**候选故事说明**:条目可能含 `summary`/`body_for_route`;仅 `preview` 者为索引项。**优先用带摘要/正文的条目做 append 目标**。
|
||||
|
||||
当前章节(写作容器):
|
||||
- category: {chapter_category}
|
||||
@@ -507,7 +562,7 @@ def get_story_batch_plan_prompt(
|
||||
【本批口述片段】(JSON 数组,顺序即口述顺序)
|
||||
{segments_json}
|
||||
|
||||
【候选故事】(仅允许在 append 时选择其中的 id;id 必须原样复制)
|
||||
【候选故事】(append 时 target_story_id 必须来自下列 id,且原样复制)
|
||||
{candidate_stories_json}
|
||||
|
||||
## 输出 JSON(仅此一个对象,不要 markdown)
|
||||
@@ -524,7 +579,7 @@ def get_story_batch_plan_prompt(
|
||||
|
||||
规则:
|
||||
- `units` 中所有 `segment_ids` 拼接后,必须**不重不漏**地覆盖本批全部 id,且顺序与【本批口述片段】数组一致
|
||||
- 若无法自信匹配某一候选,对该块选 new_story
|
||||
- **不要**仅因不确定就对整块选 new_story;能并入候选时应 append_story
|
||||
"""
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user