feat(modesty): 羞恥度動態化+三種出口(縮/炸/坦白),心裡話進得了記憶(v0.0.8 同批)
一、羞恥度高不等於話變少——三個出口(他指出來的,我上一版只做對一半)
縮 shrink :預設。一句嘴硬,說出口的那句在**迴避**心裡那句
炸 spill :慌了(焦慮 ≥55)/惱羞(憤怒 ≥45)/對方在生氣或逼你澄清
→ **4 句,但單句只有 22 字**:掩飾、急著否認、硬轉話題,碎而急
坦白 confess:羞恥高+信任 ≥75+只有兩個人 → 3 句完整句,憋很久一次講完,
而且**先寫完心裡話再開口**
關鍵:句數與單句字數要**一起動**,只調句數分不出「碎念」與「演講」。
`room post` 本來就同時擋這兩個,參數一改就生效。
二、羞恥度動態化(模擬跑過才實作)
`modestyState()` = trait + 情緒推力 + 語氣層 + 上一輪餘溫,存進 `felt.jsonl`。
護欄四道:`MODESTY_GAIN`=0.35(<1 才收斂,0.9 三輪就貼 100)、一輪最多動 15、
推力上限 25、只算超出基線的部分(比較不開心不代表比較害羞)。
慢的情緒推力打折(信任半衰期 720 分是底色,不是此刻的事)——
沒有這條,桐人會因為長期信任高而永遠低於自己的 trait 二十分。
斷路器是惱羞成怒:anger 權重是負的,被逗到極限翻臉,羞恥自己掉下來。
三、心裡話進得了記憶(但永遠不回顯)
在這之前心裡話只進 `inner.jsonl`、只被注入最近三句,**永遠不會變成記憶**。
對害羞的人格來說那是致命的——重要的東西幾乎都在心裡那句。
現在:`recallInner()` 讓 `recall` 找得到(標「不要講給他聽」),
`innerCandidates()` 把「24 小時內想過 ≥2 次的同一件事」列成固化候選。
要不要固化仍由人格自己決定。`think` 的輸出還是只有「💭 心想 N 句」。
四、修掉一個踩到的坑
`Number(null) === 0` —— 沒有上一輪時 `prev` 退回了 0 而不是 trait,
害每個人格的羞恥度都從 0 起算。已加測試守著。
測試:328 項全過(新增 14 項)。切詞從貪婪的 {2,4} 改成兩字滑動視窗——
貪婪比對會把「那台舊鐘的齒輪」切成固定區塊,「齒輪」永遠不會單獨出現。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -82,6 +82,7 @@ flowchart TB
|
||||
│ ├── emotion.json # 十二情緒 levels / baseline / 半衰期
|
||||
│ ├── inner.jsonl # 心裡話(推導過程;只回報「心想 N 句」,不說出口)
|
||||
│ ├── said.jsonl # 說過的話(用來擋短時間內的重複發言)
|
||||
│ ├── felt.jsonl # 每輪讀到的對方情緒、自己套用的 delta、當下的羞恥度
|
||||
│ ├── sync.json # Gitea 同步狀態(最後 push / pull)
|
||||
│ └── config.json # 含人格編號 code
|
||||
├── memory/
|
||||
@@ -127,6 +128,14 @@ flowchart TB
|
||||
用近重遠輕的加權算最近幾輪的趨勢(不用多數決——會被離群值主導又丟掉強度),
|
||||
注入成「他最近 3 輪的走向:悲傷 ↘ 在退」。一直是同一種情緒就不要每輪用同一句接法。
|
||||
|
||||
**羞恥度會被情緒推,而且有回饋**:`modestyState()` 在 trait 之上加當下的情緒推力
|
||||
(羞愧 +0.45/焦慮 +0.25 往上,**憤怒 −0.35**/驚喜 −0.30/喜悅・信任 −0.20 往下)、
|
||||
對象的語氣層、以及上一輪的餘溫(`MODESTY_GAIN`=0.35)。三道護欄讓它不會失控:
|
||||
**增益 < 1**(級數才收斂,0.9 三輪就貼 100)、**一輪最多動 15**、**只算超出基線的部分**
|
||||
(比較不開心不代表比較害羞)。慢的情緒(信任半衰期 720 分)推力自動打折——
|
||||
那是底色不是此刻的事。天然的斷路器是**惱羞成怒**:被逗到極限翻臉,`anger` 是負權重,
|
||||
羞恥自己就掉下來,而且會掉到比原本更低。
|
||||
|
||||
**情緒調節**:delta 不再是加完直接 `clamp`。**飽和**——越接近端點同方向漲得越慢
|
||||
(`headroom^K`,永遠逼近 100 但到不了;往 baseline 回的方向不壓);**單輪預算**——
|
||||
所有 `|delta|` 總和上限 60,超過等比例縮小。**偏差看得見**——`emotion --audit`
|
||||
@@ -181,7 +190,7 @@ AI 最容易露餡的六件事:把推理過程講出來、一次講一大段
|
||||
| 機制 | 怎麼運作 |
|
||||
| --- | --- |
|
||||
| **心裡話** `think` | 語意分析、推論、盤算全寫進 `state/inner.jsonl`;這個指令**只印「💭 心想 N 句」**,內容永不回顯。下一輪 `<persona-context>` 會帶回最近三句,推論因此有連續性,但使用者只看得到狀態 |
|
||||
| **一到三句** | `<persona-context>` 每輪注入上限;`room post` 對超過上限的發言直接拒收(`--force` 例外)。**上限跟著羞恥度走**:越害羞的人話越少(羞恥度 ≥ 75 → 2 句),`speechBudget()` 同時把心裡話的**下限**拉高——越害羞的人,心裡話比說出口的話重要,而且**說出口的那句常常正好在迴避心裡那句**,落差才是那個角色 |
|
||||
| **一到三句** | `<persona-context>` 每輪注入上限;`room post` 對超過上限的發言直接拒收(`--force` 例外)。**上限跟著羞恥度走**(`speechBudget()`),而且羞恥度高**不等於話一定變少**——有三個出口:**縮**(一句嘴硬,說出口的那句在迴避心裡那句)、**炸**(慌了/惱羞/被逼著澄清 → 4 句但每句只有 22 字,碎、急、重複)、**坦白**(信任高又只有兩個人 → 3 句完整句,憋很久一次講完)。心裡話的**下限**同時拉高:越害羞的人,心裡話比說出口的話重要,落差才是那個角色 |
|
||||
| **不重複** | 說出口的話由 `Stop` hook 自動記進 `state/said.jsonl`;`said check` 可事前確認,`room post` 事中攔截。相似度=字元 bigram Jaccard(0.4)+字集合 Jaccard(0.6),≥ 0.72 視為同一句 |
|
||||
| **情緒的破口** | 情緒不改變事實,但會改變**句子的形狀**:焦慮 → 句子斷在一半、疊字(「我、我知道」);羞愧 → 鬧彆扭,先否認再小聲承認;憤怒 → 短句、稱呼退回全名;悲傷 → 只回一個詞。十二情緒各自的破口寫在 `EMOTION_TELLS`,`emotionTells()` 每輪挑主導情緒裡強度 ≥ 40 的前兩種注入。三條界線:**演出來不要講出來**(「我有點緊張」是解釋,斷句才是緊張)、**一輪最多露一個破口**、**強度不到就不演**。混合狀態(緊張=焦慮+期待、害羞=喜悅+羞愧、賭氣=憤怒+悲傷…)的對照表在 `skills/persona-chat/reference/emotions.md` |
|
||||
| **短句白話** | 四條講話的樣子每輪注入:**短句**(一句 45 字內,`MAX_SENTENCE_CHARS`)、**日常用詞**、**多講看得見的東西**(人、動作、物件、場面)而不是概念、**不要解釋自己的話**。句長與「我的意思是/換句話說/也就是說」這類開頭由 `speechLint()` 機械攔截(`room post` 擋下、`said check` 事前警告,`--force` 例外);用詞與具體度沒辦法用規則抓,靠注入的規則自律 |
|
||||
|
||||
Reference in New Issue
Block a user