129 lines
8.1 KiB
Markdown
129 lines
8.1 KiB
Markdown
|
|
---
|
|||
|
|
name: Story route append context
|
|||
|
|
overview: 候选载荷增胖(summary 优先 + 可配置预算)+ category-aware prompt 纠偏 + 最小测试集;不扩大路由体系、不改 schema、不接离线合并。
|
|||
|
|
todos:
|
|||
|
|
- id: config-budget
|
|||
|
|
content: Add Settings — story_route_candidate_body_max_chars, total_max, head/tail, summary_min_len (optional)
|
|||
|
|
status: completed
|
|||
|
|
- id: payload-builder
|
|||
|
|
content: build_route_candidate_rows — fixed sort, summary-first body rules, total budget downgrade to index rows
|
|||
|
|
status: completed
|
|||
|
|
- id: prompts-merge-bias
|
|||
|
|
content: get_story_route_prompt + get_story_batch_plan — two-layer criteria, category blocks, remove default-to-new_story
|
|||
|
|
status: completed
|
|||
|
|
- id: wire-agent
|
|||
|
|
content: StoryRouteAgent decide/plan_batch use new builder + prompts; validate_story_batch_plan unchanged; no pipeline signature change
|
|||
|
|
status: completed
|
|||
|
|
- id: tests
|
|||
|
|
content: Builder tests + prompt contains + beliefs append smoke + career new_story smoke + test_story_route_oral_invariant
|
|||
|
|
status: completed
|
|||
|
|
isProject: false
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Story Route:候选上下文增胖 + category-aware append 纠偏
|
|||
|
|
|
|||
|
|
## Ticket / PR 一句话
|
|||
|
|
|
|||
|
|
用更富的候选 JSON(**summary 优先**、再按需补正文)与 **按类目纠偏** 的提示词,修复 `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_prompt`、`get_story_batch_plan_prompt` 纠偏 + **两层决策标准** + **三类 category 规则** |
|
|||
|
|
| `[config.py](api/app/core/config.py)` | **3–4 个**预算相关字段(见下) |
|
|||
|
|
| 测试 | 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 主角)
|
|||
|
|
|
|||
|
|
每条候选字典 **必带**:`id`、`title`、`char_count`、`version_count`、`updated_at`(ISO)、`linked_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. 超 **总预算** 时,将该条 **降级为索引行**(仅 `id`、`title`、`char_count`、极短 `preview`,提示中说明索引项优先匹配带 `summary`/`body` 的条目)。
|
|||
|
|
|
|||
|
|
**初版默认值(保守,可线上调大):**
|
|||
|
|
|
|||
|
|
- `story_route_candidate_body_max_chars`:**1200–2000**(落地取单值如 **1600**)
|
|||
|
|
- `story_route_candidate_total_max_chars`:**12000–18000**(如 **16000**)
|
|||
|
|
- head/tail:按现有「长文才切」思路配一对合理默认(如各 **600–800**)
|
|||
|
|
|
|||
|
|
## 2. 排序规则(写死,tie-break)
|
|||
|
|
|
|||
|
|
在进入 builder **之前**对 `candidate_stories` 排序(同 stage 列表):
|
|||
|
|
|
|||
|
|
`has_summary(desc) → updated_at(desc) → version_count(desc) → char_count(desc) → id(asc)`
|
|||
|
|
|
|||
|
|
其中 `has_summary`:summary strip 后长度 ≥ 配置的 `summary` 最小长度。
|
|||
|
|
|
|||
|
|
## 3. 提示词
|
|||
|
|
|
|||
|
|
### 3.1 去掉保守偏置
|
|||
|
|
|
|||
|
|
删除「拿不准就 `new_story`」;改为:**先看是否与某候选在主题/事件层级上可合并,再决定**。
|
|||
|
|
|
|||
|
|
### 3.2 两层决策标准(显式写在 prompt 里)
|
|||
|
|
|
|||
|
|
- **主题连续性信号**:价值观、关系模式、长期总结、同一反思维度。
|
|||
|
|
- **事件切换信号**:新人物组合、新地点、新时间段、新事件因果链。
|
|||
|
|
|
|||
|
|
指引:`beliefs` / `summary` **更看主题连续性**;`career_*` / `childhood` / `education` **更看事件链**。
|
|||
|
|
|
|||
|
|
### 3.3 类目规则(第一版只三件)
|
|||
|
|
|
|||
|
|
- `**beliefs`、`summary`**:**强容器** → 多条短感悟、同一句式起笔、同价值维度 → **强烈倾向 `append_story`**(指向最匹配的一条候选 id)。
|
|||
|
|
- `**career_*`、`childhood`、`education**`:**强 episode** → 明确不同事件链可 `new_story`;同一经历续问可 append。
|
|||
|
|
- `**family`**:**中性** → 一句话:原则/关系反思倾向 append;**明确的新事件链**可 new;**不**展开长列表例外。
|
|||
|
|
|
|||
|
|
`get_story_batch_plan_prompt` 与 `get_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 优先不带 body;summary 短则带 body;总预算降级;**排序**稳定 |
|
|||
|
|
| Prompt | 类目块、两层标准、`beliefs`/`family` 中性句等 **包含断言** |
|
|||
|
|
| **行为 A** | mock LLM:`beliefs` + 两则短感悟口述 + 已有 1 条 story → 期望 **append**(或断言传给 mock 的 payload 含足够 summary/body 且 prompt 强调强容器;实现时二选一并写死断言) |
|
|||
|
|
| **行为 B** | mock LLM:`career_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 测试
|
|||
|
|
|