Files
persona/TODO_故事匯入.md
T
jiantw83andClaude Opus 5 c0e1c4828f docs(故事匯入): 小說匯入的 TODO 進版控
前一批留在工作區沒進版控的那份。內容是 persona-story 的階段清單
與四題拍板結果(語氣檔放 voice/、機械進 CLI、時間軸換算西元日期、
情緒基線差 10 以上要人看),還有踩過一次的坑:劇情時間不可以寫進
first_seen/last_seen,那兩欄是記憶的新鮮度時鐘。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 06:56:43 +00:00

12 KiB
Raw Blame History

TODO:故事匯入(小說 → 人格記憶/語氣/情緒)

把小說變成一個人格的記憶,同時讓它從原作學語氣與情緒表達。

技能:/jsc-persona:persona-storyskills/persona-story/)。 開場的五題問答在 reference/interview.md,場景要抽什麼在 reference/extract.md。 機械那半是 persona.mjsnovelvoice 子指令。

三條界線先立,後面所有步驟都受它們約束:

  1. 視角:人格不在場、也沒人告訴他的事,最多進 canon 或別人的關係欄,不能變成他的 event
  2. 原文:整本不入倉庫。只留摘要、他自己的台詞、以及可追回出處的章節標記。
  3. 個性SOUL.md 不由流程自動改寫。匯入只出提案,使用者逐條核可才寫入。

階段 -1:實作前一定要先問使用者(四題,沒答案不要開工)

這四題會決定檔案放哪、介面長什麼樣,答錯要重做。問完拿到答案再進階段 0。

  • Q1 語氣檔放在人格倉庫的哪一層?→ 新開 voice/samples.md 原句、reactions.md 事件對反應)
  • Q2 匯入要做成 CLI 子指令,還是全部由 skill 編排?→ 混合:機械的進 CLI,判斷的留 skill
  • Q3 同一部作品分多本匯入時,first_seen 的時間軸怎麼接續?→ 換算成西元日期
  • Q4 情緒基線差值超過多少才要人看?→ 差 10 以上

階段 0:前置(做一次)

  • 0.1 確認目標人格編號、作品名、章節檔清單、原文編碼 → 不預先問,由 skill 在匯入的當下問2026-08-03 使用者拍板)。 問法與順序寫在 skills/persona-story/reference/interview.md
  • 0.2 建正名表:角色的各種譯名/簡稱/原文名 → 關係節點的 name從匯入的章節自動判斷候選,再給使用者確認2026-08-03 使用者拍板,覆蓋原本的「問譯名版本」)。 問他是哪個譯本等於要他猜;他手上那批寫的是什麼字,讀一次就知道了。 novel scan 抽候選(對話歸屬、敬稱結尾、片假名、高頻詞),附出現次數與一兩行上下文, 並猜關係節點分四種信心度(exactaliasfuzzyunknown); novel name reviewconfirm --accept-exactignore 做確認。 names.jsonmap(正名)與 ignore(確認過不是人名,例如地名與招式名)兩塊—— 已在其中之一的 token 下次掃不再出現,不然每加一章就要重看同一批。 novel candidate add 遇到 about 有未確認的 token 會擋下來。
  • 0.3 定故事內時間軸的表示法 → 西元日期Q3 拍板),另加 date_sourcecanonderivedguess,見上面「換算日期不可以假裝是明寫的」那一節。
  • 0.4 定顯著度配額 → 預設 90+ 最多 5 則、80-89 最多 20 則novel init --quota 可調)。 超過配額由 novel merge 從低分往下壓一級(90+ → 85、80-89 → 75)並回報壓了幾則。
  • 0.5 定跳過紀錄檔memory/import/<work-slug>/skipped.jsonl 一行一章(chapterreasonts),由 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 對不到 idname 用會被說出口的完整稱呼,親密度查 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 的格式切成「主旨/細節」兩層(衰減先吃細節), 並自動蓋上 strengthwhenwheremooddate_source: guess 的記憶 在回答日期問題時走模糊態界線:可以說不確定、可以問,不可以斷言。

⚠ 劇情時間不可以寫進 first_seenlast_seen(踩過一次)

那兩欄是記憶的新鮮度時鐘memoryStrength()last_seen 算衰減。 把劇情日期塞進去等於宣告「這則記憶上次被想起是兩年前」——實測 2024 年劇情的記憶 匯進去的那一秒就是模糊 0%,而且掉到 0% 之後 touchRecall 不再更新它,永遠回不來。 只有 canonsalience >= 80 靠保護清單活下來,40 到 79 分的 event 全部出生即死。

所以兩種語意分成兩組欄位:

欄位 意思 時間
first_seenlast_seen 這則記憶什麼時候形成、上次什麼時候想起 真實時間(匯入當天)
happened_athappened_until 故事裡這件事什麼時候發生 劇情時間(配 date_source

候選 JSON 照舊填 first_seen(那是抽場景時自然的講法),novel write 會把它搬到 happened_atfirst_seenlast_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 TruthsBoundariesVibe 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 的模糊態界線: 可以說不確定、可以問,不可以斷言。