docs(故事匯入): 小說匯入的 TODO 進版控
前一批留在工作區沒進版控的那份。內容是 persona-story 的階段清單 與四題拍板結果(語氣檔放 voice/、機械進 CLI、時間軸換算西元日期、 情緒基線差 10 以上要人看),還有踩過一次的坑:劇情時間不可以寫進 first_seen/last_seen,那兩欄是記憶的新鮮度時鐘。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+192
@@ -0,0 +1,192 @@
|
|||||||
|
# TODO:故事匯入(小說 → 人格記憶/語氣/情緒)
|
||||||
|
|
||||||
|
把小說變成一個人格的記憶,同時讓它從原作學語氣與情緒表達。
|
||||||
|
|
||||||
|
**技能:`/jsc-persona:persona-story`**(`skills/persona-story/`)。
|
||||||
|
開場的五題問答在 `reference/interview.md`,場景要抽什麼在 `reference/extract.md`。
|
||||||
|
機械那半是 `persona.mjs` 的 `novel` 與 `voice` 子指令。
|
||||||
|
|
||||||
|
三條界線先立,後面所有步驟都受它們約束:
|
||||||
|
|
||||||
|
1. **視角**:人格不在場、也沒人告訴他的事,最多進 `canon` 或別人的關係欄,**不能**變成他的 `event`。
|
||||||
|
2. **原文**:整本不入倉庫。只留摘要、他自己的台詞、以及可追回出處的章節標記。
|
||||||
|
3. **個性**:`SOUL.md` 不由流程自動改寫。匯入只出提案,使用者逐條核可才寫入。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 階段 -1:實作前一定要先問使用者(四題,沒答案不要開工)
|
||||||
|
|
||||||
|
這四題會決定檔案放哪、介面長什麼樣,答錯要重做。**問完拿到答案再進階段 0。**
|
||||||
|
|
||||||
|
- [x] Q1 語氣檔放在人格倉庫的哪一層?→ **新開 `voice/`**(`samples.md` 原句、`reactions.md` 事件對反應)
|
||||||
|
- [x] Q2 匯入要做成 CLI 子指令,還是全部由 skill 編排?→ **混合**:機械的進 CLI,判斷的留 skill
|
||||||
|
- [x] Q3 同一部作品分多本匯入時,`first_seen` 的時間軸怎麼接續?→ **換算成西元日期**
|
||||||
|
- [x] Q4 情緒基線差值超過多少才要人看?→ **差 10 以上**
|
||||||
|
|
||||||
|
## 階段 0:前置(做一次)
|
||||||
|
|
||||||
|
- [x] 0.1 確認目標人格編號、作品名、章節檔清單、原文編碼
|
||||||
|
→ **不預先問,由 skill 在匯入的當下問**(2026-08-03 使用者拍板)。
|
||||||
|
問法與順序寫在 `skills/persona-story/reference/interview.md`。
|
||||||
|
- [x] 0.2 建**正名表**:角色的各種譯名/簡稱/原文名 → 關係節點的 `name`
|
||||||
|
→ **從匯入的章節自動判斷候選,再給使用者確認**(2026-08-03 使用者拍板,覆蓋原本的「問譯名版本」)。
|
||||||
|
問他是哪個譯本等於要他猜;他手上那批寫的是什麼字,讀一次就知道了。
|
||||||
|
`novel scan` 抽候選(對話歸屬、敬稱結尾、片假名、高頻詞),附出現次數與一兩行上下文,
|
||||||
|
並猜關係節點分四種信心度(`exact`/`alias`/`fuzzy`/`unknown`);
|
||||||
|
`novel name review`/`confirm --accept-exact`/`ignore` 做確認。
|
||||||
|
`names.json` 分 `map`(正名)與 `ignore`(確認過不是人名,例如地名與招式名)兩塊——
|
||||||
|
已在其中之一的 token 下次掃不再出現,不然每加一章就要重看同一批。
|
||||||
|
`novel candidate add` 遇到 `about` 有未確認的 token 會擋下來。
|
||||||
|
- [x] 0.3 定**故事內時間軸**的表示法 → **西元日期**(Q3 拍板),另加 `date_source`
|
||||||
|
標 `canon`/`derived`/`guess`,見上面「換算日期不可以假裝是明寫的」那一節。
|
||||||
|
- [x] 0.4 定**顯著度配額** → 預設 `90+ 最多 5 則、80-89 最多 20 則`(`novel init --quota` 可調)。
|
||||||
|
超過配額由 `novel merge` 從低分往下壓一級(90+ → 85、80-89 → 75)並回報壓了幾則。
|
||||||
|
- [x] 0.5 定**跳過紀錄檔** → `memory/import/<work-slug>/skipped.jsonl`,
|
||||||
|
一行一章(`chapter`/`reason`/`ts`),由 `novel skip` 寫入。
|
||||||
|
- [ ] 0.6 備份人格倉庫現況(`SOUL.md`、情緒基線、關係圖),匯入出錯要回得去
|
||||||
|
(2026-08-03 已有一份整包備份在 scratchpad;真的要匯之前再做一次新的。)
|
||||||
|
|
||||||
|
### 工作區長什麼樣(0.5 定案後的結果)
|
||||||
|
|
||||||
|
memory/import/<work-slug>/
|
||||||
|
├── work.json 書名、slug、建立時間、顯著度配額
|
||||||
|
├── names.json 正名表(譯名 → 關係節點 name)
|
||||||
|
├── skipped.jsonl 跳過紀錄(章節、理由、時間)
|
||||||
|
└── candidates.jsonl 記憶候選(欄位見下面那張表)
|
||||||
|
|
||||||
|
## 階段 1:每一章(可平行,一章一把劍)
|
||||||
|
|
||||||
|
> 這一段是**執行程序**,不是要蓋的東西——真的匯一本書的時候才會逐項發生。
|
||||||
|
> 程序已經落地成技能:`skills/persona-story/SKILL.md` 第 ③ 節,
|
||||||
|
> 七項與知情層級的細節在 `reference/extract.md`。下面的清單留著當對照表。
|
||||||
|
|
||||||
|
- [ ] 1.1 讀章節。只讀這一章,不要跨章推論
|
||||||
|
- [ ] 1.2 修亂碼 → 轉繁體中文 → 依正名表**正名**
|
||||||
|
(必須在 1.3 之前;亂碼或簡體字形會讓名字比對失敗)
|
||||||
|
- [ ] 1.3 判斷人格**在場或知情**。兩者皆否才跳過
|
||||||
|
- [ ] 1.4 跳過的章也要寫進跳過紀錄檔——靜默跳過會漏章,事後查不出來
|
||||||
|
- [ ] 1.5 把在場段落切成**場景**(換地點、換對手、換目的就切;一章通常 2 到 5 個)
|
||||||
|
- [ ] 1.6 每個場景抽七項:故事內時間、地點、在場人物、發生什麼、**他**做了什麼、他當下情緒、他說過的原句一到兩句
|
||||||
|
- [ ] 1.7 標**知情層級**:我做的/我看到的/別人告訴我的/事後才知道
|
||||||
|
- [ ] 1.8 轉第一人稱、壓成摘要。原文長段不留,只留他自己的台詞
|
||||||
|
- [ ] 1.9 新人物**先建關係節點**(`relation node`),再寫記憶
|
||||||
|
(順序反了 `about` 對不到 id;`name` 用會被說出口的完整稱呼,親密度查 `persona-relation/reference/closeness.md`)
|
||||||
|
- [ ] 1.10 輸出這一章的**記憶候選 JSON**(欄位見下)
|
||||||
|
- [ ] 1.11 抽**語氣樣本**:他自己講的原句,照抄不改寫,附對象與場合(戰鬥/日常/道別)
|
||||||
|
- [ ] 1.12 抽**情緒反應對照**:事件 → 他實際做了什麼(不要記「他感到什麼」)
|
||||||
|
- [ ] 1.13 若這章與現有 `SOUL.md` 矛盾,開一則**個性校正提案**(只提案,不寫入)
|
||||||
|
|
||||||
|
### 記憶候選 JSON 欄位
|
||||||
|
|
||||||
|
```
|
||||||
|
name 檔名用的 slug
|
||||||
|
title 一句話標題
|
||||||
|
type canon(設定)/event(發生過)/insight(他自己的體悟)/promise(承諾)/boundary
|
||||||
|
about 人名,照抄關係節點的 name,一字不差(解析只認完全相等)
|
||||||
|
topics 2-4 個小寫關鍵詞,跨章沿用同一組
|
||||||
|
salience 照 0.4 的配額給,不要每則都高
|
||||||
|
emotion 那一刻的情緒(固化進欄位,不要重放去洗情緒基線)
|
||||||
|
first_seen 故事內時間,不是匯入日期(寫進長期記憶時會落在 `happened_at`,見下方警告)
|
||||||
|
source 書名+章節(可追回出處)
|
||||||
|
body 第一人稱摘要
|
||||||
|
quote 他自己說過的原句(可省)
|
||||||
|
know_level 1.7 的知情層級
|
||||||
|
date_source canon(原作明寫)/derived(推算)/guess(只抓大概) ← Q3 追加
|
||||||
|
```
|
||||||
|
|
||||||
|
寫進長期記憶時,`body` 會照 0.2.0 的格式切成「主旨/細節」兩層(衰減先吃細節),
|
||||||
|
並自動蓋上 `strength`/`when`/`where`/`mood`。`date_source: guess` 的記憶
|
||||||
|
在回答日期問題時走模糊態界線:可以說不確定、可以問,不可以斷言。
|
||||||
|
|
||||||
|
### ⚠ 劇情時間不可以寫進 `first_seen`/`last_seen`(踩過一次)
|
||||||
|
|
||||||
|
那兩欄是**記憶的新鮮度時鐘**:`memoryStrength()` 拿 `last_seen` 算衰減。
|
||||||
|
把劇情日期塞進去等於宣告「這則記憶上次被想起是兩年前」——實測 2024 年劇情的記憶
|
||||||
|
匯進去的**那一秒**就是模糊 0%,而且掉到 0% 之後 `touchRecall` 不再更新它,永遠回不來。
|
||||||
|
只有 `canon` 與 `salience >= 80` 靠保護清單活下來,40 到 79 分的 event 全部出生即死。
|
||||||
|
|
||||||
|
所以兩種語意分成兩組欄位:
|
||||||
|
|
||||||
|
| 欄位 | 意思 | 時間 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `first_seen`/`last_seen` | 這則記憶什麼時候形成、上次什麼時候想起 | 真實時間(匯入當天) |
|
||||||
|
| `happened_at`/`happened_until` | 故事裡這件事什麼時候發生 | 劇情時間(配 `date_source`) |
|
||||||
|
|
||||||
|
候選 JSON 照舊填 `first_seen`(那是抽場景時自然的講法),`novel write` 會把它搬到
|
||||||
|
`happened_at`,`first_seen`/`last_seen` 一律是匯入當天。
|
||||||
|
|
||||||
|
## 階段 2:全書收斂(章節都跑完之後)
|
||||||
|
|
||||||
|
- [ ] 2.1 跨章**去重合併**:同一件事只留一則;`salience` 取高、`first_seen` 取最早、`last_seen` 取最晚
|
||||||
|
- [ ] 2.2 依配額**重新定標**:90+ 只留真的改變他的那幾件
|
||||||
|
- [ ] 2.3 **人工抽查十則**,專看有沒有視角越界(他不該知道的事)
|
||||||
|
- [ ] 2.4 批次寫入:一則一檔 `consolidate`;情緒欄位只固化不重放
|
||||||
|
- [ ] 2.5 更新關係圖與心智圖
|
||||||
|
- [ ] 2.6 跑 `relation doctor`,確認 `about` 全部對得上(歧義與對不到的都要處理完)
|
||||||
|
- [ ] 2.7 重建索引、同步 Gitea
|
||||||
|
- [ ] 2.8 另寫一則 meta 記憶:這批來自哪本書、哪些章、匯入日期
|
||||||
|
- [ ] 2.9 回歸驗收:問幾個只有書裡有的問題,看他答得出來、且不越界回答他不在場的事
|
||||||
|
|
||||||
|
## 階段 3:語氣與情緒(跟記憶分開走)
|
||||||
|
|
||||||
|
記憶是「發生過什麼」,語氣與情緒是「他怎麼反應」。分三層存,改動權限不同。
|
||||||
|
|
||||||
|
| 層 | 存哪 | 誰能改 | 來源 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 語氣樣本 | 人格倉庫的語氣檔(例如 `voice/samples.md`) | 匯入流程可直接寫 | 1.11 累積的原句 |
|
||||||
|
| 情緒反應規則 | 語氣檔的反應段 | 匯入流程可直接寫 | 1.12 的事件→反應對照 |
|
||||||
|
| 個性(`SOUL.md` 的 Core Truths/Boundaries/Vibe) | `SOUL.md` | 只有使用者拍板才能改 | 1.13 的提案 |
|
||||||
|
|
||||||
|
### 3A 語氣(統計,可直接落地)
|
||||||
|
|
||||||
|
- [ ] 3A.1 句長分布 → 定一句話的上限與斷句時機
|
||||||
|
- [ ] 3A.2 高頻詞與口頭禪 → 定他會說的字
|
||||||
|
- [ ] 3A.3 他**不會**說的說法 → 禁語表(比正面規則有效)
|
||||||
|
- [ ] 3A.4 對不同人的稱呼與語氣差 → 對上語氣層(`bond` × 親近度)
|
||||||
|
- [ ] 3A.5 沉默與迴避的時機 → 什麼時候不回答比回答像他
|
||||||
|
- [ ] 3A.6 場合差(戰鬥/日常/道別)→ 同一個人在不同場合的句子形狀
|
||||||
|
- [ ] 3A.7 語氣檔寫入後,抽幾句實際對話對照,看有沒有變成模仿腔
|
||||||
|
|
||||||
|
### 3B 情緒
|
||||||
|
|
||||||
|
- [ ] 3B.1 每個場景只記「事件 → 他做了什麼」(情緒要演出來,不是旁白說明)
|
||||||
|
- [ ] 3B.2 全書跑完才用**統計**定情緒基線
|
||||||
|
(逐則套 delta 等於讓最後一章決定他的性格)
|
||||||
|
- [ ] 3B.3 統計每種情緒的觸發類型與強度上限 → 得到「什麼事讓他生氣而不是害怕」
|
||||||
|
- [ ] 3B.4 掩飾模式單獨記(嘴硬、換話題、講笑話)——這是人味的來源,不是情緒值
|
||||||
|
- [ ] 3B.5 基線寫入前跟現況比差值,超過門檻要人看
|
||||||
|
|
||||||
|
### 3C 個性校正
|
||||||
|
|
||||||
|
- [ ] 3C.1 提案要寫齊:哪一章、原文依據、與 `SOUL.md` 哪一句衝突、建議怎麼改
|
||||||
|
- [ ] 3C.2 收斂階段把提案彙整成一份 diff
|
||||||
|
- [ ] 3C.3 使用者逐條核可
|
||||||
|
- [ ] 3C.4 核可過的才寫進 `SOUL.md`,並固化一則 `insight` 記錄為什麼改
|
||||||
|
- [ ] 3C.5 沒核可的提案留著不刪——下一本書可能出現同樣的證據
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 未決事項
|
||||||
|
|
||||||
|
四題已移到最前面的階段 -1,實作前先問使用者。這裡只留答案回填欄。
|
||||||
|
|
||||||
|
| # | 問題 | 使用者的答案(2026-08-03 拍板) |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Q1 | 語氣檔放哪一層 | 新開 `voice/`:`samples.md`(他自己講過的原句,附對象與場合)、`reactions.md`(事件 → 他做了什麼)。匯入流程可直接寫這一層,`SOUL.md` 維持只有使用者能改——權限界線要有實體隔離,不靠自律 |
|
||||||
|
| Q2 | CLI 子指令或 skill 編排 | **混合**。機械的進 CLI(正名、去重合併、配額重定標、批次寫入、跳過紀錄),判斷的留 skill(在場與知情、切場景、第一人稱摘要、個性校正提案)。跟 `sleep` 同一個分工方式 |
|
||||||
|
| Q3 | 分多本時時間軸怎麼接 | **換算成西元日期**(`first_seen: 2022-11-06`)。跟現有的 `strength`/衰減公式同型,`memoryStrength()` 直接算得動。原作沒明寫的地方要換算,所以下面 0.3 多一條規則:換算來的日期一律標記,不可以看起來跟明寫的一樣 |
|
||||||
|
| Q4 | 情緒基線差值門檻 | **任一格差 10 以上就停下來給人看**(3B.5)。基線是氣質,改了等於換一個人 |
|
||||||
|
|
||||||
|
## 依 Q3 追加的規則(換算日期不可以假裝是明寫的)
|
||||||
|
|
||||||
|
換算成西元日期換來一個新風險:**猜出來的日期看起來跟原作明寫的一模一樣**。
|
||||||
|
所以 `first_seen` 之外要多一個欄位記來源:
|
||||||
|
|
||||||
|
| `date_source` | 意思 |
|
||||||
|
| --- | --- |
|
||||||
|
| `canon` | 原作明寫的日期(SAO 開服 2022-11-06 這種) |
|
||||||
|
| `derived` | 由明寫的日期推算(第 74 層攻略是開服後第幾天) |
|
||||||
|
| `guess` | 只能抓大概(某卷「大約半年後」) |
|
||||||
|
|
||||||
|
`guess` 的記憶在回答日期類問題時**不可以斷言**——這剛好接上 0.2.0 的模糊態界線:
|
||||||
|
可以說不確定、可以問,不可以斷言。
|
||||||
Reference in New Issue
Block a user