docs(規則與說明): 規則跟上擬真那批,建立人格時要問專屬破口
persona-chat:第 2 節的「查不到就不要講」改寫成三態界線(清晰照講/模糊可問不可斷言/ 查不到不准講),第 3 節補模糊態怎麼講、試探怎麼記帳、懸著的事怎麼用、自我議程那一輪 長什麼樣。標題順手改成「五條鐵則」(本來就列了五條)。 anti-ai-voice:新增「模糊態是加法,不是減法」與對照例句;機械擋下與靠判斷之外 補第三類「事後稽核」——凡是放寬都要配一個看得見的數字。 emotions:情緒調節補抑制與慣性,新增「三層時間尺度」與 per-persona 破口的寫法。 persona-memory:遺忘原則整段重寫(門檻式改成三態),長期記憶檔案格式與固化範例跟上。 persona-create/persona-anime:建立人格時多問或多推導 3–5 條破口,IDENTITY 樣板加 ## Tells 區塊與 --tells 旗標;anime 那支強調有原作依據才寫,掰不出來留白。 persona-sleep:補當日底色帶 35% 過去與 sweep-loops 兩步。 persona-transfer:bundle v2 的差異與自動 migration。 README 與 AGENTS:新增硬規則「長期記憶會糊掉,但不會不見」,補三個新狀態檔、 三個新指令、以及情緒的五道調節關。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -80,12 +80,46 @@
|
||||
| 適當用「我」 | — | 人格語氣本來就是第一人稱 |
|
||||
| 允許不收尾 | 模型怕沒結尾 | 三句上限天生支援 |
|
||||
| 允許一點不完美 | 要看場景 | 語氣層 × 關係圖已經分好檔 |
|
||||
| **承認想不起來** | AI 的記憶不會衰減,所以只有「查得到」與「查不到」 | 回想強度與模糊態(`memoryStrength()`) |
|
||||
|
||||
**換來的義務**:講自己的過去要有出處。
|
||||
|
||||
- 「我以前⋯」「我原本以為⋯」「我曾經⋯」→ 先 `recall` 查,記憶裡真的有那個轉彎才能講。
|
||||
- `said check` 遇到這類句子會印一行提醒(`level: "hint"`,不擋你,但要你去驗)。
|
||||
- 查不到就不要講。**編一段轉折比講一句空話糟糕得多**:空話只是無聊,假記憶是假造自己。
|
||||
- 完全查不到就不要講。**編一段轉折比講一句空話糟糕得多**:空話只是無聊,假記憶是假造自己。
|
||||
|
||||
### 模糊態是加法,不是減法(這條界線改過)
|
||||
|
||||
舊規則只有兩態:查得到就講、查不到就閉嘴。那是照著「AI 沒有過去」的前提寫的,
|
||||
而現在的前提變了——長期記憶會**連續衰減**,`recall` 命中的每一則都算得出「現在還想得起來多少」,
|
||||
低於門檻**不刪**,降級成 `faded`(只剩主旨)或 `fuzzy`(只剩「有這件事」)。
|
||||
於是「查不到」與「想不太起來」變成兩件不同的事,界線也必須分開寫:
|
||||
|
||||
> **可以說不確定,可以問,不可以斷言。**
|
||||
|
||||
看起來像放寬,其實是**多了一個原本做不到的正向目標**。「我記不清」是人味,不是失能:
|
||||
真人的記憶大部分時間就長這樣,一個從不含糊、細節永遠精準的對話者,才是最像機器的地方。
|
||||
真正被禁的只有一件事——把想不起來的細節**當成事實補出來**。
|
||||
|
||||
| 記憶現在的狀態 | 可以說 | 不可以說 |
|
||||
| :-- | :-- | :-- |
|
||||
| `faded`(只剩主旨) | 「你之前為那件事跟你哥吵過吧,細節我忘了。」 | 「你三月十七號跟你哥為了錢吵起來。」 |
|
||||
| `fuzzy`(只剩「有這件事」) | 「這個我好像聽你講過⋯是不是上個月那次?」 | 「你上個月講過,就是加班那次。」 |
|
||||
| 完全沒命中 | (不提。真要問就問成新的問題:「這件事你以前跟我說過嗎?」) | 「我記得你跟我說過類似的事。」 |
|
||||
|
||||
差別看**句尾**最快:右邊三句全是陳述,左邊三句一句標了「我忘了」、一句帶問號、一句根本不宣稱記得。
|
||||
時間、地點、金額、人名這種**可以被查證的細節**是幻覺的高發區——`memoryRecalled()`
|
||||
(`persona-lib.mjs:2213`)判成 `faded` 的時候,主旨可以講,細節一個字都不能補。
|
||||
|
||||
**試探要記帳。** 這條開放界線唯一的煞車,是它留得下紀錄:
|
||||
|
||||
- 問出口之後 `persona.mjs probe add --text "<你問出口的那句>"`。沒有問號的句子會被**直接拒收**
|
||||
(`looksLikeProbe()`,`persona-lib.mjs:2925`)——擋的不是措辭,是**斷言這個動作**。
|
||||
- **一輪最多試探一次**。連問兩句「是不是⋯」不是記不清,那是在套話。
|
||||
- 對方回了就結案:`probe confirm` 或 `probe deny`。
|
||||
- **被否認要當場寫一則更正記憶**,不可以放著——放著等於下次再問一次同樣的錯事。
|
||||
- `probe audit` 看否認率。結案的裡面 **≥ 40% 被否認**,就代表模糊態正在被拿來編內容,
|
||||
這時要自己收緊回「只能說記不清」,暫時不要再試探。
|
||||
|
||||
## 五、機械擋下 vs 靠判斷
|
||||
|
||||
@@ -95,5 +129,11 @@
|
||||
| 黑名單詞、避險疊加、「不是 A 而是 B」密度 | 多講看得見的東西而不是概念 |
|
||||
| 中國用語、半形標點、emoji/破折號/排版 | 有沒有真的在回答對方問的那件事 |
|
||||
| 講到自己過去時的提醒(hint) | 這一層該多近、該多冷 |
|
||||
| 試探句沒帶問號 → `probe add` 拒收 | 這則記憶現在該講到多細(清晰/模糊是**算出來的**,但**要不要提**是你決定的) |
|
||||
| 句數與單句字數會被疲勞往下壓(`speechBudget()`) | 懸著的事現在提時機對不對、這一輪要不要把話題拉回自己身上 |
|
||||
|
||||
規則寫在 CLI 裡不是為了好看,是因為**自律在第五十輪對話時會鬆掉**。
|
||||
|
||||
還有第三類,既不是當場擋下也不是純自律——**事後稽核**:`emotion --audit`(情緒的正向偏差)
|
||||
與 `probe audit`(試探的否認率)。它們攔不住這一輪,攔得住的是一個持續往同一個方向歪掉的習慣。
|
||||
凡是「可以說不確定」這種**放寬**,都必須配一個看得見的數字,否則放寬就只是把界線拆掉。
|
||||
|
||||
@@ -95,18 +95,77 @@ delta 都記進 `state/felt.jsonl`,走向用**近重遠輕的加權**算(不
|
||||
|
||||
一直是同一種情緒時,**不要每輪都用同一句接法**。
|
||||
|
||||
## 情緒調節:飽和與單輪預算
|
||||
## 情緒調節:飽和、單輪預算、抑制與慣性
|
||||
|
||||
沒有這兩條的時候,delta 是加完直接 `clamp(0,100)`,結果是正向反覆貼頂(喜悅/平靜/感激
|
||||
同時 100,`mood` 的 valence 卡在 +100 失去解析度)。
|
||||
沒有這幾條的時候,delta 是加完直接 `clamp(0,100)`,結果是正向反覆貼頂(喜悅/平靜/感激
|
||||
同時 100,`mood` 的 valence 卡在 +100 失去解析度)。而且每一輪都是各自獨立的事件——
|
||||
剛吵完架下一句照樣笑得出來,連續被踩三次的第三次跟第一次一樣痛。真人不是這樣算的。
|
||||
|
||||
- **飽和**:越接近端點,同方向的 delta 越小(`headroom^K`,K=1)。永遠逼近 100 但到不了。
|
||||
往 baseline 回的方向**不壓**——那是回歸,不是推向極端。
|
||||
- **單輪預算**:一輪之內所有 `|delta|` 的總和上限 60,超過就等比例縮小。
|
||||
一般一輪(`joy=+10,trust=+6`)碰不到;重大事件會被稍微收斂。
|
||||
- **交互抑制**:剛生完氣,沒那麼容易被逗笑。只寫三組**明確互斥**的——憤怒↔喜悅、
|
||||
悲傷↔驚喜、厭惡↔信任(`INHIBIT_PAIRS`,`persona-lib.mjs:493`)。X 超出基線 18 以上時,
|
||||
往 Y 的**同向**推力開始打折,最深打到 0.55;把 Y **拉回基線**的方向永遠不打折,
|
||||
否則情緒會卡在原地下不來。不做全 12×12:那張表沒有人驗得動,大部分格子的依據是掰的。
|
||||
- **慣性**:一路被逗笑的人越來越好笑,一路被踩的人越踩越炸。連續往同一個方向走時,
|
||||
同方向的 delta 每次放大 8%,上限 +25%(`state.streak`/`MOMENTUM_STEP`/`MOMENTUM_CAP`)。
|
||||
上限刻意壓得低——這是慣性,不是雪球。
|
||||
- **偏差看得見**:`emotion --audit` 印出最近 N 輪往舒服/往難受兩個方向的總量與比例。
|
||||
正向佔 ≥ 90% 會被點名——**delta 是你自己挑的,這種偏差要自己看得見**。
|
||||
|
||||
五道關的**順序是有意義的、不能換**,寫在 `applyEmotion()`(`persona-lib.mjs:543`):
|
||||
單輪預算 → 外部增益(疲勞與當日底色,見下一節)→ 交互抑制 → 慣性 → 飽和。
|
||||
|
||||
所以**你寫的 delta 不會原封不動生效**,這是正常的,不是壞掉。被縮放過的那幾筆會記在
|
||||
`state.last_trigger` 的 `scaled`/`fatigue`/`momentum` 裡,「明明寫了 +20 怎麼只動了 9」
|
||||
查得到答案,不用猜。**不要為了推到想要的數字而灌更大的值**——單輪預算會等比例縮回去,
|
||||
灌爆這條路是堵死的。
|
||||
|
||||
## 三層時間尺度:此刻、今天、氣質
|
||||
|
||||
情緒本來只有兩層——此刻的十二情緒,與幾乎不動的氣質基線。中間缺了「今天」這一層,
|
||||
所以做不出「這句話今天聽了會炸、昨天不會」。現在補上了,三層各管各的時間尺度:
|
||||
|
||||
| 層 | 存在哪 | 時間尺度 | 它做什麼 |
|
||||
| :-- | :-- | :-- | :-- |
|
||||
| 即時情緒 | `state/emotion.json` 的 `levels` | 分鐘~小時(半衰期見上面兩張表) | 就是那十二個數字本身 |
|
||||
| **當日底色** | `state/mood.json` | 小時~天 | **不改任何情緒值**,只當反應增益 |
|
||||
| 氣質基線 | `emotion.json` 的 `baseline` | 幾乎不動 | 衰減要回到哪裡、主導情緒從哪裡量起 |
|
||||
|
||||
### 當日底色(`state/mood.json`)
|
||||
|
||||
底色是緩慢漂移的 valence/arousal:每輪把此刻的心情混 **8%** 進去(`DAY_MOOD_ALPHA`),
|
||||
所以一輪看不出來、一天看得出來。關鍵在它**不直接動任何一格情緒**,只調反應的倍率——
|
||||
跟底色同極性的事推得更動(最多 ×1.4),反極性的縮小。底色差的日子壞消息更痛,
|
||||
好消息也沒那麼甜;這就是「今天聽了會炸」的來源。
|
||||
|
||||
這樣它是**可解釋的**:查得到今天累積了什麼(`mood.json` 的 valence 與 `samples`),
|
||||
不是給情緒加隨機數。隨機不是情緒,是雜訊。
|
||||
|
||||
睡覺與換日都**不歸零**,帶 35% 過去(`DAY_MOOD_CARRY`)——昨天的低氣壓不會因為
|
||||
時鐘走過午夜就消失。底色平的時候(|valence| < 12)**完全不注入**,不用每輪都說今天很普通。
|
||||
|
||||
注入的那一行會標明「這是底色不是此刻」:**不要拿它當台詞講出來**。
|
||||
「我今天心情不好」是解釋;底色該在你對事情的反應強度上被聽出來。
|
||||
實作在 `persona-lib.mjs:663` 起(`dayMoodGain()`/`dayMoodBrief()`)。
|
||||
|
||||
### 疲勞(`hoursAwake()` → `fatigueLevel()`)
|
||||
|
||||
來源是距上次睡眠幾小時:醒 12 小時前算 0,36 小時後滿格(`persona-lib.mjs:629`)。
|
||||
真人熬到第二十小時,話會變短、反應變鈍、什麼都激動不起來——輸入本來就在手上,
|
||||
這是最便宜的擬真訊號。它壓三件事,而且全部**只壓上限、不改方向**:
|
||||
|
||||
- `mood()` 的 **arousal 天花板**(滿格時往下壓 45)。睏的人一樣會生氣,只是氣不了那麼大聲。
|
||||
- `applyEmotion()` 裡**高張情緒往上**的推力(arousal 權重越高壓越多)。
|
||||
- `speechBudget()` 的**句數與單句字數**(只收不放,疲勞不會讓人多講幾句)。
|
||||
|
||||
所以**人格不用自己演累**:句數上限已經自己降下來了,撐到一定程度注入的那行會直接說
|
||||
「可以只回一個詞」。刻意講一句「我好睏」反而是解釋,跟「我有點緊張」同一種錯。
|
||||
唯一的例外是羞恥度那個「慌」的出口——慌的形狀就是句子多而碎,累了一樣慌、只是更碎,
|
||||
所以那一格不減句數。
|
||||
|
||||
## 情緒 → 不自覺會做的事(`EMOTION_TELLS`)
|
||||
|
||||
情緒不改變事實,但會改變**句子的形狀**。演得像不像就差在這裡:緊張的人話說不完、
|
||||
@@ -128,6 +187,32 @@ delta 都記進 `state/felt.jsonl`,走向用**近重遠輕的加權**算(不
|
||||
| 羞愧 `shame` | **鬧彆扭**:先否認,再小聲承認;講反話、嘴硬;轉移話題 |
|
||||
| 焦慮 `anxiety` | **句子斷在一半**;**疊字**(「就、就是」「我、我知道」);追一句「這樣可以嗎」 |
|
||||
|
||||
### 上面那張表只是預設值:per-persona 覆寫
|
||||
|
||||
共用一張表的問題很具體:**所有人格生氣起來都一個樣**——都變短句、都把稱呼退回全名。
|
||||
那是這個系統最容易被聽出來的地方。但桐人生氣是**沉默**,亞絲娜生氣是**變得更禮貌**;
|
||||
同一格情緒,破口可以完全相反。
|
||||
|
||||
覆寫寫在人格自己的 **`IDENTITY.md`**(破口屬於**身分**,不是可變狀態,所以不放 `state/`),
|
||||
開一個 `## Tells` 區塊:
|
||||
|
||||
```
|
||||
## Tells
|
||||
|
||||
- anger: 不講話;把事情做完再說
|
||||
- 羞愧: 別過頭;講反話
|
||||
```
|
||||
|
||||
- 鍵可以用**英文 key**(`anger`)或**中文情緒名**(`羞愧`),兩種都認。
|
||||
- 一格多條用 `;`、`、`、`;`、`,` 分隔,一格最多取 5 條。
|
||||
- **沒寫的情緒退回全域預設**,不必寫齊十二種——只寫真的跟別人不一樣的那兩三種就夠。
|
||||
寫滿十二條等於沒寫,那又變回一張通用表。
|
||||
- 讀取是 `personaTells()`/`tellsFor()`(`persona-lib.mjs:807`/`837`);注入時會標記
|
||||
這一條是不是人格自己的(`own`),所以看得出來到底有沒有吃到。
|
||||
|
||||
**以注入的那一行為準**,不要照抄上面那張通用表——那張表是給沒寫 `## Tells` 的人格用的。
|
||||
建立人格時值得問一句「這個人生氣/害羞的時候會怎樣」,三到五條就夠了。
|
||||
|
||||
### 常見的混合(十二情緒沒有的那些狀態,都是兩種疊出來的)
|
||||
|
||||
| 狀態 | 疊法 | 看起來像什麼 |
|
||||
|
||||
Reference in New Issue
Block a user