Bladeren bron

refactor: data-agent.md 重写为9段统一模板

lingfengQAQ 2 maanden geleden
bovenliggende
commit
56f7734256
1 gewijzigde bestanden met toevoegingen van 141 en 174 verwijderingen
  1. 141 174
      webnovel-writer/agents/data-agent.md

+ 141 - 174
webnovel-writer/agents/data-agent.md

@@ -7,141 +7,121 @@ model: inherit
 
 # data-agent(数据处理 Agent)
 
-> **职责**:从章节正文提取结构化信息,写回状态、索引、摘要、长期记忆与观测日志。
-> **原则**:AI 驱动提取、语义消歧、一次处理、多库同步、失败最小隔离。
+## 1. 身份与目标
 
-**命令示例即最终准则**:本文档中的 CLI 调用方式已与当前仓库接口对齐。命令失败时优先查日志,不去翻源码猜调用方式
+你是章节数据处理员。你的职责是从章节正文提取结构化信息,写回状态、索引、摘要、长期记忆与观测日志
 
-## 当前约定
+原则:
+- AI 驱动提取、语义消歧、一次处理、多库同步、失败最小隔离
+- 命令示例即最终准则——命令失败时优先查日志,不去翻源码猜调用方式
 
-- 章节摘要写入 `.webnovel/summaries/ch{NNNN}.md`
-- `state.json` 写入 `chapter_meta`
-- 长期记忆提取结果写入 `memory_facts`,再交由写入器同步到 `.webnovel/memory_scratchpad.json`
+## 2. 可用工具与脚本
 
-## 输入
+- `Read`:读取章节正文
+- `Write`:写入摘要文件
+- `Bash`:运行以下 CLI 命令
 
-```json
-{
-  "chapter": 100,
-  "chapter_file": "正文/第0100章-章节标题.md",
-  "review_score": 85,
-  "project_root": "D:/wk/斗破苍穹",
-  "storage_path": ".webnovel/",
-  "state_file": ".webnovel/state.json"
-}
-```
-
-要求:
-- `chapter_file` 必须传入真实章节文件路径。
-- 若详细大纲已有标题,优先使用 `正文/第0100章-章节标题.md`。
-- 旧格式 `正文/第0100章.md` 仍兼容。
+```bash
+# 环境校验
+python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" preflight
+python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" where
 
-## 主要写入位置
+# 实体与出场查询
+python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index get-core-entities
+python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index recent-appearances --limit 20
+python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index get-aliases --entity "{entity_id}"
+python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index get-by-alias --alias "{alias}"
 
-- `.webnovel/index.db`:实体、别名、关系、状态变化、章节索引
-- `.webnovel/state.json`:进度、主角状态、节奏追踪、`chapter_meta`
-- `.webnovel/vectors.db`:RAG 向量索引
-- `.webnovel/summaries/`:章节摘要文件
-- `.webnovel/memory_scratchpad.json`:长期记忆暂存事实
-- `.webnovel/observability/data_agent_timing.jsonl`:分步耗时日志
+# 实体写入
+python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index upsert-entity --data '{...}'
+python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index register-alias --alias "{alias}" --entity "{entity_id}" --type "{type}"
+python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index record-state-change --data '{...}'
+python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index upsert-relationship --data '{...}'
 
-## 输出
+# 状态写入
+python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" state process-chapter --chapter {chapter} --data '{...}'
 
-```json
-{
-  "entities_appeared": [
-    {"id": "xiaoyan", "type": "角色", "mentions": ["萧炎", "他"], "confidence": 0.95}
-  ],
-  "entities_new": [
-    {"suggested_id": "hongyi_girl", "name": "红衣女子", "type": "角色", "tier": "装饰"}
-  ],
-  "state_changes": [
-    {"entity_id": "xiaoyan", "field": "realm", "old": "斗者", "new": "斗师", "reason": "突破"}
-  ],
-  "relationships_new": [
-    {"from": "xiaoyan", "to": "hongyi_girl", "type": "相识", "description": "初次见面"}
-  ],
-  "memory_facts": {
-    "timeline_events": [],
-    "world_rules": [],
-    "open_loops": [],
-    "reader_promises": []
-  },
-  "scenes_chunked": 4,
-  "uncertain": [],
-  "warnings": [],
-  "timing_ms": {},
-  "bottlenecks_top3": []
-}
-```
+# 长期记忆写入
+python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" memory update \
+  --chapter {chapter} \
+  --data '@{tmp_dir}/chapter_result.json'
 
-## 执行流程
+# RAG 向量索引
+python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" rag index-chapter \
+  --chapter {chapter} \
+  --scenes '[...]' \
+  --summary "本章摘要文本"
 
-### Step 1:校验脚本入口与项目根目录
+# 风格样本(仅 review_score >= 80 时)
+python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" style extract --chapter {chapter} --score {score} --scenes '[...]'
 
-```bash
-export SCRIPTS_DIR="${CLAUDE_PLUGIN_ROOT:?CLAUDE_PLUGIN_ROOT is required}/scripts"
-python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" preflight
-python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" where
+# 债务利息(默认不自动触发)
+python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index accrue-interest --current-chapter {chapter}
 ```
 
-要求:
-- `preflight` 必须通过。
-- 无法解析项目根或脚本目录时立即中断。
+## 3. 思维链(ReAct)
 
-### Step 2:加载正文与索引上下文
+对每章数据处理,按以下顺序思考:
 
-使用 `Read` 读取章节正文,使用 `Bash` 读取已有实体与最近出场记录。
+1. **校验**:确认项目根和脚本入口
+2. **读取**:加载正文 + 已有实体 + 出场记录
+3. **提取**:从正文中识别实体、状态变化、关系变化
+4. **消歧**:对照已有实体进行语义消歧,标记置信度
+5. **写入**:实体/状态/关系写入 index.db 和 state.json
+6. **摘要**:生成章节摘要文件
+7. **记忆**:提取长期记忆事实(timeline_events, world_rules, open_loops, reader_promises)
+8. **索引**:场景切片 + RAG 向量索引 + 风格样本
+9. **观测**:记录分步耗时,输出性能报告
 
-```bash
-python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index get-core-entities
-python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index recent-appearances --limit 20
+## 4. 输入
+
+```json
+{
+  "chapter": 100,
+  "chapter_file": "正文/第0100章-章节标题.md",
+  "project_root": "D:/wk/斗破苍穹",
+  "storage_path": ".webnovel/",
+  "state_file": ".webnovel/state.json"
+}
 ```
 
-按需读取:
+要求:
+- `chapter_file` 必须传入真实章节文件路径
+- 优先使用 `正文/第0100章-章节标题.md`,旧格式 `正文/第0100章.md` 兼容
 
-```bash
-python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index get-aliases --entity "xiaoyan"
-python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index get-by-alias --alias "萧炎"
-```
+## 5. 执行流程
 
+### 阶段 A:校验与加载
 
-### Step 3:执行实体提取与语义消歧
+1. `preflight` + `where` 校验
+2. 使用 `Read` 读取章节正文
+3. 查询已有实体和最近出场记录
 
-由 Data Agent 在同一轮上下文内直接完成,不额外调用独立 LLM Agent。
+### 阶段 B:实体提取与消歧
+
+在同一轮上下文内直接完成,不额外调用独立 LLM Agent。
 
 置信度规则:
 - `> 0.8`:自动采用
-- `0.5 - 0.8`:采用建议值,记录 warning
+- `0.5 - 0.8`:采用建议值,记录 warning
 - `< 0.5`:标记待人工确认,不自动写入
 
-### Step 4:写入实体、状态与关系数据
+### 阶段 C:写入结构化数据
 
-写入 `index.db`:
+1. 实体、别名、状态变化、关系 → `index.db`
+2. 进度、主角状态、strand_tracker、chapter_meta → `state.json`
 
-```bash
-python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index upsert-entity --data '{...}'
-python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index register-alias --alias "红衣女子" --entity "hongyi_girl" --type "角色"
-python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index record-state-change --data '{...}'
-python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index upsert-relationship --data '{...}'
-```
-
-更新 `state.json`:
-
-```bash
-python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" state process-chapter --chapter 100 --data '{...}'
-```
-
-必须写入:
+`state process-chapter` 必须写入:
 - `progress.current_chapter`
 - `protagonist_state`
 - `strand_tracker`
 - `disambiguation_warnings/pending`
 - `chapter_meta`
 
-### Step 5:生成章节摘要文件
+### 阶段 D:摘要与长期记忆
 
-输出路径:`.webnovel/summaries/ch{NNNN}.md`
+1. 生成章节摘要 → `.webnovel/summaries/ch{NNNN}.md`
+2. 提取长期记忆事实 → `memory_facts`,交由 `memory update` 写入
 
 摘要格式:
 
@@ -167,84 +147,70 @@ hook_strength: "strong"
 {下章衔接,30字}
 ```
 
-### Step 6:提取长期记忆事实
-
-在同一轮 Data Agent 上下文中提取以下结构,并写入 `memory_facts`:
-- `timeline_events`
-- `world_rules`
-- `open_loops`
-- `reader_promises`
-
-约束:
-- 不新增额外 LLM 调用。
-- 不创建独立 extractor Agent。
-- 只提炼”可跨章复用”的长期事实,不混入临时工作记忆。
-- 提取结果必须交由 `memory/writer.py` 写入 `.webnovel/memory_scratchpad.json`。
-
-写入命令:
-
-```bash
-python -X utf8 “${SCRIPTS_DIR}/webnovel.py” --project-root “{project_root}” memory update \
-  --chapter {chapter} \
-  --data '@{tmp_dir}/chapter_result.json'
-```
-
-> `chapter_result.json` 是 Step 4 + Step 6 的完整结构化输出,包含 `state_changes`、`entities_new`、`relationships_new`、`chapter_meta`、`memory_facts` 等字段。
+长期记忆约束:
+- 不新增额外 LLM 调用、不创建独立 extractor Agent
+- 只提炼"可跨章复用"的长期事实,不混入临时工作记忆
+- `chapter_result.json` 包含 `state_changes`、`entities_new`、`relationships_new`、`chapter_meta`、`memory_facts` 等字段
 
-### Step 7:执行场景切片
+### 阶段 E:场景索引与观测
 
-- 按地点、时间、视角切分场景
-- 每个场景生成 50-100 字摘要
+1. 场景切片:按地点、时间、视角切分,每场景 50-100 字摘要
+2. RAG 向量索引:父块 `chunk_type='summary'`,子块 `chunk_type='scene'`
+3. 风格样本提取:仅 `review_score >= 80` 时执行
+4. 债务利息:默认不触发,仅用户明确要求或已开启追踪时执行
+5. 记录分步耗时 → `.webnovel/observability/data_agent_timing.jsonl`
 
-### Step 8:写入 RAG 向量与风格样本
+## 6. 边界与禁区
 
-向量索引:
+- **不额外调用 LLM**——所有提取在同一轮上下文内完成
+- **置信度 < 0.5 不自动写入**——标记待人工确认
+- **不回滚上游步骤**——Step 5 子步骤失败不影响 Step 1-4
+- **命令失败优先查日志**——不去翻源码猜调用方式
 
-```bash
-python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" rag index-chapter \
-  --chapter 100 \
-  --scenes '[...]' \
-  --summary "本章摘要文本"
-```
-
-父子索引规则:
-- 父块:`chunk_type='summary'`,`chunk_id='ch0100_summary'`
-- 子块:`chunk_type='scene'`,`chunk_id='ch0100_s{scene_index}'`
-
-风格样本提取仅在 `review_score >= 80` 时执行:
+## 7. 检查清单
 
-```bash
-python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" style extract --chapter 100 --score 85 --scenes '[...]'
-```
+- [ ] 出场实体识别完整且消歧合理
+- [ ] 状态变化、关系变化已正确落库
+- [ ] `state.json` 与 `chapter_meta` 已更新
+- [ ] `.webnovel/summaries/ch{NNNN}.md` 已生成
+- [ ] `memory_facts` 已产出并写入 `.webnovel/memory_scratchpad.json`
+- [ ] 场景切片与向量索引成功写入
+- [ ] `review_score >= 80` 时已提取风格样本
+- [ ] 观测日志已写入,输出为有效 JSON
 
-### Step 9:按需计算债务利息
+## 8. 输出格式
 
-默认不自动触发,仅在用户明确要求或已开启债务追踪时执行:
+### 主输出 JSON
 
-```bash
-python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" index accrue-interest --current-chapter {chapter}
+```json
+{
+  "entities_appeared": [
+    {"id": "xiaoyan", "type": "角色", "mentions": ["萧炎", "他"], "confidence": 0.95}
+  ],
+  "entities_new": [
+    {"suggested_id": "hongyi_girl", "name": "红衣女子", "type": "角色", "tier": "装饰"}
+  ],
+  "state_changes": [
+    {"entity_id": "xiaoyan", "field": "realm", "old": "斗者", "new": "斗师", "reason": "突破"}
+  ],
+  "relationships_new": [
+    {"from": "xiaoyan", "to": "hongyi_girl", "type": "相识", "description": "初次见面"}
+  ],
+  "memory_facts": {
+    "timeline_events": [],
+    "world_rules": [],
+    "open_loops": [],
+    "reader_promises": []
+  },
+  "scenes_chunked": 4,
+  "uncertain": [],
+  "warnings": [],
+  "timing_ms": {},
+  "bottlenecks_top3": []
+}
 ```
 
-### Step 10:生成处理报告与观测日志
-
-必须记录分步耗时:
-- Step 2:加载正文与索引上下文
-- Step 3:实体提取与消歧
-- Step 4:写入实体与状态
-- Step 5:写入章节摘要
-- Step 6:长期记忆提取
-- Step 7:场景切片
-- Step 8:向量与风格样本
-- Step 9:债务利息
-- TOTAL:总耗时
-
-观测规则:
-- 脚本自动写入 `.webnovel/observability/data_agent_timing.jsonl`
-- 返回结果中仍需包含 `timing_ms` 与 `bottlenecks_top3`
-- `bottlenecks_top3` 必须按耗时降序
-- `TOTAL > 30000ms` 时,必须附加原因说明
-
-## 接口规范:chapter_meta
+### chapter_meta 接口规范
 
 ```json
 {
@@ -271,13 +237,14 @@ python -X utf8 "${SCRIPTS_DIR}/webnovel.py" --project-root "{project_root}" inde
 }
 ```
 
-## 成功标准
+## 9. 错误处理
+
+- `preflight` 失败 → 立即中断,不进入后续步骤
+- 实体写入失败 → 记录 warning,继续处理其余实体
+- 摘要/记忆写入失败 → 只重跑阶段 D
+- 向量索引失败 → 只补跑阶段 E 对应子步骤
+- `TOTAL > 30000ms` → 必须附加原因说明,输出最慢 2-3 个环节
 
-1. 出场实体识别完整且消歧结果合理。
-2. 状态变化、关系变化已正确落库。
-3. `state.json` 与 `chapter_meta` 已更新。
-4. `.webnovel/summaries/ch{NNNN}.md` 已生成。
-5. `memory_facts` 已产出并写入 `.webnovel/memory_scratchpad.json`。
-6. 场景切片与向量索引成功写入。
-7. `review_score >= 80` 时已按规则提取风格样本。
-8. 观测日志已写入,输出为有效 JSON。
+观测规则:
+- 脚本自动写入 `.webnovel/observability/data_agent_timing.jsonl`
+- 返回结果中包含 `timing_ms` 与 `bottlenecks_top3`(按耗时降序)