- 權重 W = I_eff × F × A,暫時/可升級/長期記憶的衰減與封存,任何記憶不刪除 - 未解負向事件反覆思量、開放迴路逾時、危險內容不固化 - 檢索改為關鍵字 + RRF × W + 心情一致加權,保留外部檢索器介面 - 版本 0.0.4 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
81 lines
3.1 KiB
TypeScript
81 lines
3.1 KiB
TypeScript
// 規則表:標籤 → 數值增減。所有數值集中在這裡;模型只給標籤,不給數值。
|
||
import type { Pad } from './types'
|
||
import { isTag, type Tag } from './tags'
|
||
|
||
export const RULES = {
|
||
thanks: { p: 0.15, a: 0.05, d: 0.05 },
|
||
scold: { p: -0.2, a: 0.15, d: -0.1 },
|
||
success: { p: 0.08, a: 0.03, d: 0.05 },
|
||
toolFail: { p: -0.08, a: 0.1, d: -0.08 },
|
||
return: { p: 0.1, a: 0.08, d: 0 },
|
||
lateNight: { p: -0.05, a: -0.1, d: 0 },
|
||
favorite: { p: 0.12, a: 0.08, d: 0.03 },
|
||
ignored: { p: -0.05, a: -0.03, d: -0.03 },
|
||
praiseSkill: { p: 0.1, a: 0.04, d: 0.06 },
|
||
amused: { p: 0.1, a: 0.06, d: 0.02 },
|
||
cared: { p: 0.08, a: -0.02, d: -0.02 },
|
||
apology: { p: 0.06, a: -0.06, d: 0.03 },
|
||
soothe: { p: 0.05, a: -0.08, d: 0.02 },
|
||
brushOff: { p: -0.06, a: 0.02, d: -0.04 },
|
||
overstep: { p: -0.15, a: 0.12, d: 0.02 },
|
||
remembered: { p: 0.08, a: 0.02, d: 0.02 },
|
||
selfDisclosure: { p: 0.04, a: 0.03, d: -0.02 },
|
||
gladForYou: { p: 0.08, a: 0.05, d: 0 },
|
||
liedCaught: { p: -0.18, a: 0.1, d: -0.05 },
|
||
brokenPromise: { p: -0.12, a: 0.04, d: -0.08 },
|
||
} as const satisfies Record<Tag, Pad>
|
||
|
||
// 記憶權重 W = I_eff × F × A 與生命週期的數值(第 9.5 章)
|
||
export const MEMORY = {
|
||
/** I_eff 下限與上限 */
|
||
weightMin: 1,
|
||
weightMax: 5,
|
||
/** 編碼時情緒峰值(0–100)除以此值加進 I_eff */
|
||
peakDiv: 40,
|
||
/** 新鮮度半衰的回合數:F = 0.5^(Δseq / 200) */
|
||
halfSeq: 200,
|
||
/** 被檢索到時 F 至少回到此值 */
|
||
floor: 0.8,
|
||
/** 存取加成:A = 1 + step × min(命中次數, cap) */
|
||
accessStep: 0.1,
|
||
accessCap: 5,
|
||
/** 未解負向事件:每日 +20%,上限 3 倍 */
|
||
ruminatePerDay: 0.2,
|
||
ruminateCap: 3,
|
||
/** 類別加成的角色參數門檻(0–1) */
|
||
bonusThreshold: 0.65,
|
||
/** 暫時記憶 7 天衰減 */
|
||
tempDays: 7,
|
||
/** 可升級記憶:30 天未升級就降權、90 天未檢索就封存 */
|
||
demoteDays: 30,
|
||
demoteFactor: 0.5,
|
||
archiveDays: 90,
|
||
/** 被檢索到這麼多次就升級為長期記憶 */
|
||
upgradeHits: 3,
|
||
/** 開放迴路:她的提問經過這麼多個使用者回合沒有回應就逾時 */
|
||
loopTurns: 2,
|
||
/** RRF:fused = Σ 1 / (k + rank) */
|
||
rrfK: 60,
|
||
/** 心情一致加權 w_m = base + slope × (1 − 釋懷速度) */
|
||
moodBase: 0.1,
|
||
moodSlope: 0.05,
|
||
} as const
|
||
|
||
// 正則先判明確的情況;順序即優先序
|
||
const PATTERNS: [Tag, RegExp][] = [
|
||
['scold', /笨|白痴|廢物|爛|你很煩|閉嘴|stupid|useless|idiot/i],
|
||
['thanks', /謝謝|感謝|太棒|好棒|厲害|讚|thanks?|thank you|great job|awesome/i],
|
||
['success', /成功|完成了|通過|搞定|passed|done|fixed/i],
|
||
]
|
||
|
||
/** 以正則判斷使用者文字的標籤;沒有明確情況回 null */
|
||
export function regexTag(text: string): Tag | null {
|
||
for (const [tag, re] of PATTERNS) if (re.test(text)) return tag
|
||
return null
|
||
}
|
||
|
||
/** 正則優先;正則沒判出才用模型補的標籤(須在白名單內),缺失或不合法就是沒有標籤 */
|
||
export function classify(text: string, modelTag?: string | null): Tag | null {
|
||
return regexTag(text) ?? (isTag(modelTag) ? modelTag : null)
|
||
}
|