Audited manager handoff against af28ffd (v1.10):
- 59 original items byte-identical, open_items unchanged
- source hashes verified incl. other-agent-discussion sha256
- user quote 01a1734c verified against platform comment
- check_requirements passes vs main / hel-835-unified-review / product target
Co-authored-by: multica-agent <github@multica.ai>
204 lines
17 KiB
Plaintext
204 lines
17 KiB
Plaintext
我现在陷入一个瓶颈,需要你帮助我或者给我灵感,我在做一个基于四柱八字为灵魂,有性格,有情绪,有记忆,八字确定后,不会因为用户的提示词而改变人设性格,在用户没有交互的时候有自己的生活轨迹,有心跳,但现在我很头大的是不知道如何实现偏向情感、人设、情绪、生活的记忆系统,不知道如何维持灵魂性格不偏移
|
||
|
||
你卡住的两个问题,根源其实是同一个:**人格和记忆都放在 LLM 里了。** LLM 天生会顺着上下文走,只要人设靠提示词维持、记忆靠聊天记录堆,偏移就迟早会发生。我建议把它拆成三层:
|
||
|
||
- **灵魂层(代码,不可变)**:八字算出的参数,决定这个角色怎么反应。
|
||
- **状态层(代码,按规律变化)**:情绪、关系、需求、记忆,用确定性规则更新。
|
||
- **表达层(LLM)**:只负责把当前状态"演"成语言,不负责决定性格。
|
||
|
||
LLM 在这里是演员,不是灵魂。下面分开讲。
|
||
|
||
---
|
||
|
||
## 一、八字 → 人格参数(灵魂层)
|
||
|
||
不要只生成一段"你是一个倔强又敏感的人"的文字描述,而要映射成可计算的参数:
|
||
|
||
| 八字要素 | 映射成的参数(举例) |
|
||
|---|---|
|
||
| 日主强弱 | 自我边界强度、被说服的难度、情绪恢复速度 |
|
||
| 五行偏枯 | 情绪基线(PAD 三维:愉悦/唤醒/支配)、偏好的活动 |
|
||
| 十神组合 | 反应风格:伤官重 → 对冒犯敏感、记仇久;印重 → 依赖感强、易受安抚;七杀 → 压力下易攻击;食神 → 情绪消化快 |
|
||
| 合冲刑害 | 内在矛盾点(比如既渴望亲近又抗拒控制),是性格"层次感"的来源 |
|
||
|
||
另外有一点特别值得用:**大运、流年、流月、流日天然就是"有规律的变化"。** 原局是不变的核心,岁运是合法的波动。比如今天的流日和日主相冲,就设定情绪基线下调、烦躁阈值降低。角色会"有好日子和坏日子",但这些波动都能从八字推出来,而不是被用户带偏。这样就把"成长、波动"和"偏移"区分开了:前者走规定的通道,后者不允许发生。
|
||
|
||
## 二、情绪系统:LLM 评估,代码计算
|
||
|
||
每轮对话流程大致是:
|
||
|
||
```
|
||
用户输入
|
||
→ LLM 做"评估"(只输出结构化数据,不扮演角色):
|
||
{事件类型: 被忽视, 涉及目标: 被重视需求, 责任方: 对方, 强度: 0.6}
|
||
→ 代码用八字参数计算情绪变化:
|
||
Δ情绪 = 强度 × 该角色对此类事件的敏感度
|
||
情绪向基线衰减(速度由日主强弱/食神等决定)
|
||
→ 更新状态(情绪、关系值、需求值)
|
||
→ 组装提示词,LLM 只负责"用这个状态说话"
|
||
```
|
||
|
||
关键在于:同一句话,伤官重的角色和印旺的角色算出来的情绪不一样。用户说"你现在开心点",这句话只是一个**事件**,进入评估环节,而不是一条指令。角色可能被逗乐,也可能觉得被敷衍而更不爽,结果由参数决定。
|
||
|
||
情绪模型可以参考 OCC 评估理论 + PAD 连续空间,比离散的"开心/难过"标签好用得多。
|
||
|
||
## 三、记忆系统:情感化的记忆,不是聊天记录检索
|
||
|
||
普通 RAG 存的是"说过什么",你需要存的是**"这件事对我意味着什么"**。建议分四类:
|
||
|
||
1. **情景记忆**:单个事件,附情绪标签(效价、唤醒度)、重要性、当时的心情、涉及谁。存储时写成角色视角的主观描述:"他又忘了我说的那件事,我嘴上说没事,其实挺失望的。"
|
||
2. **关系记忆**:对用户的看法和关系数值(信任、亲密、积怨、依恋),由情景记忆慢慢沉淀而来,变化缓慢。
|
||
3. **自传记忆**:自己生活轨迹里的事件(心跳期间发生的),保证"我的生活"前后一致。
|
||
4. **自我叙事**:少量高层总结,比如"我最近好像越来越依赖他了",这是性格在关系中的体现。
|
||
|
||
**检索打分**可以参考 Generative Agents(斯坦福 2023 年那篇小镇论文)的 近因 × 重要性 × 相关性,再加两项:
|
||
- **心境一致性**:难过时更容易想起难过的事(真实的人类特征)。
|
||
- **人格权重**:伤官重的角色,负面记忆衰减慢;食神旺的,好事记得更牢。
|
||
|
||
**睡眠整理**放在心跳里:每晚跑一次"反思"任务,把当天的情景记忆压缩成感悟,更新关系值,让不重要的记忆衰减,强情绪记忆保留(闪光灯效应)。某些八字可以设定"反刍"倾向,夜里反复调出某段负面记忆,第二天情绪基线因此受影响。这会让角色显得非常真实。
|
||
|
||
## 四、防止人格偏移的具体手段
|
||
|
||
1. **人设卡每轮重新生成**:由八字参数 + 当前状态动态拼装,而不是一开始写一次然后被几百轮对话稀释。
|
||
2. **限制原始历史窗口**:只放最近几轮原文,更早的内容一律以"角色的主观记忆"形式注入。原始对话里用户的语气是最大的污染源。
|
||
3. **用户输入降级为事件**:在提示词结构上明确区分"对方说了什么"和"你是谁"。对"你现在是 X"这类话,角色应以角色身份作出反应(困惑、不耐烦、觉得好笑),而不是执行。
|
||
4. **语言锚点**:每种人格配一组固定的说话方式示例(few-shot)、口头禅、绝不会说的话。语气比设定描述更容易被模型稳定模仿。
|
||
5. **生成后校验**:用一个小模型或分类器给回复打人格维度分,偏离阈值就重新生成。也可以定期用固定的测试对话跑一致性回归测试。
|
||
6. **变化只走规定通道**:原局不可变;关系值可以变但有速率上限;大运交接时允许性格表现有明显转折。除此之外,任何变化都不应该发生。
|
||
|
||
## 五、心跳与生活轨迹
|
||
|
||
心跳每次触发时:
|
||
- 根据角色的作息、职业、五行偏好生成当下活动(用固定种子的随机数,保证可复现);
|
||
- 小概率产生生活事件,事件同样经过"评估 → 情绪计算 → 写入自传记忆";
|
||
- 需求值随时间累积,比如用户久不出现,"想念"值上升,上升速度由人格决定(印重、比劫弱的涨得快);
|
||
- 超过阈值时主动发消息,内容由当时的情绪和最近的生活记忆驱动("今天下雨,路过那家店想起你上次说的……")。
|
||
|
||
这样主动消息就有来由,不是定时问候。
|
||
|
||
---
|
||
|
||
**总结一句话**:让 LLM 只做两件事,一是把输入理解成结构化事件,二是把状态演成语言;中间的性格、情绪、记忆全部由八字参数驱动的代码掌管。人格之所以不偏,是因为它根本不在 LLM 能改写的地方。
|
||
|
||
如果你愿意,可以告诉我你现在的技术栈和已有的数据结构,我可以帮你把十神 → 参数的映射表或者记忆表结构具体设计出来。
|
||
|
||
除了这些灵感,具体实施上如何实现呢,比如记忆用什么技术方案,目前常见的记忆方案是什么,还有假如每天跑一次反思任务,把当天的情景记忆压缩,会不会遗忘某些重要的事情,能否实现AI在出现特殊情绪的时候主动去找用户。对于记忆我有个不成熟的想法,人类的记忆就像AI一轮一轮的对话,脑细胞就像AI的算力,人类可以从大脑里超大容量内存里瞬间获取到对应的记忆,AI不说瞬间,能否做到短时间内获取到,目前有没有类似的研究,举个例子AI的记忆可能好几GB,但需要的记忆可能只有几K,能否快速获取到
|
||
|
||
下面按你问的几个问题逐一给具体方案。
|
||
|
||
## 一、目前常见的记忆方案
|
||
|
||
市面上主流框架大致分四种思路:Mem0、Zep(Graphiti)、LangGraph(LangMem)和 Letta(前身 MemGPT),分别对应向量语义召回、时序知识图谱、检查点持久化和自编辑记忆块。
|
||
|
||
| 方案 | 核心思路 | 对你的参考价值 |
|
||
|---|---|---|
|
||
| **Mem0** | 从对话中自动抽取事实存进向量库(可选图) | 适合"记住用户喜好",偏事实,不擅长情感 |
|
||
| **Zep / Graphiti** | 时序知识图谱,事实带有效期 | Graphiti 是 Zep 团队开源的时序知识图谱引擎,适合"关系随时间变化",值得借鉴 |
|
||
| **Letta (MemGPT)** | 仿操作系统的分层:核心记忆常驻上下文,归档记忆可检索,回忆记忆存对话历史 | 和你的"大内存瞬间调取"想法最接近 |
|
||
| **Generative Agents** | 记忆流 + 反思 + 计划 | 生活轨迹和反思机制的原型 |
|
||
|
||
**我的建议:不要整套采用任何一个框架,而是自己搭,局部借鉴。** 原因是这些框架都是为"助手记住用户信息"设计的,存的是事实("用户喜欢咖啡"),而你要存的是情感化、主观化的经历,需要情绪、重要性、人格权重等自定义字段,硬套会很别扭。
|
||
|
||
## 二、具体技术栈
|
||
|
||
一个够用且好维护的组合:
|
||
|
||
- **PostgreSQL + pgvector**:一个库同时存结构化字段和向量,单角色几十万条记忆完全够用。量很大时再换 Qdrant / Milvus。
|
||
- **可选图层**:人物、地点、事件之间的关联(Neo4j,或者直接用 Postgres 的关系表),用于"联想式回忆"。
|
||
- **Redis**:存当前情绪状态、需求值、心跳计时等高频读写的状态。
|
||
- **任务队列**(Celery / BullMQ 之类):跑心跳、反思、主动消息。
|
||
- **Embedding 模型**:中文场景选 bge-m3 这类多语言模型即可。
|
||
|
||
情景记忆表大致这样:
|
||
|
||
```sql
|
||
CREATE TABLE episodic_memory (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
character_id BIGINT,
|
||
occurred_at TIMESTAMPTZ,
|
||
source TEXT, -- chat / life(心跳生活) / reflection
|
||
content TEXT, -- 角色视角的主观描述
|
||
raw_ref BIGINT[], -- 指向原始对话/事件的ID,永不丢失出处
|
||
valence REAL, -- 情绪效价 -1~1
|
||
arousal REAL, -- 情绪唤醒度 0~1
|
||
importance REAL, -- 0~1
|
||
tags TEXT[], -- 承诺/冲突/第一次/秘密/纪念日...
|
||
status TEXT, -- open(未了结) / resolved
|
||
pinned BOOLEAN, -- 核心记忆,永不衰减
|
||
access_count INT,
|
||
last_accessed TIMESTAMPTZ,
|
||
embedding VECTOR(1024)
|
||
);
|
||
```
|
||
|
||
`status`、`pinned`、`raw_ref` 这三个字段,正好就是解决你下一个担心的关键。
|
||
|
||
## 三、每天反思压缩,会不会忘掉重要的事?
|
||
|
||
会,如果实现方式是"把当天记忆总结成一段话,然后删掉原文"。这样做一定会丢东西,因为 LLM 总结时会抹平细节。正确的做法有几条:
|
||
|
||
**1. 压缩不等于删除。** 分层存储:原始对话 → 情景记忆 → 反思感悟。上层总结通过 `raw_ref` 指回下层,原文永远留在冷存储里。"遗忘"只是检索权重降低,不是物理删除。这也和人一样:很多事不是忘了,是想不起来,被某个线索一勾就又回来了。
|
||
|
||
**2. 高强度事件实时写入,不等晚上。** 情绪唤醒度超过阈值、或者涉及承诺、冲突、表白、坏消息的事件,在对话当下就写成独立记忆并打上 `pinned`。反思任务只负责处理日常琐碎内容。
|
||
|
||
**3. 反思前先做"必留清单"抽取。** 让 LLM 先用结构化输出单独过一遍当天内容,只回答这些问题:有没有承诺?有没有未解决的矛盾?对方透露了什么重要信息(生日、家人、工作变动)?有没有"第一次"?这些单独成条,不进入压缩。
|
||
|
||
**4. "未了结"标记。** 用户说"下周告诉你面试结果",就存成 `status=open`。未了结的记忆检索权重持续偏高,角色会自己惦记,等结果出来再改成 `resolved`。这个机制对"像个真人"帮助非常大。
|
||
|
||
**5. 周期性回看。** 每周或每月再跑一次更高层的反思,这次重新读原文,而不是只读日总结,用来纠正前面总结的偏差。
|
||
|
||
## 四、能否在出现特殊情绪时主动找用户?
|
||
|
||
完全可以,而且这正是"有灵魂"感最强的地方。关键是做成**事件驱动 + 冲动值判断**,而不是定时发问候:
|
||
|
||
```
|
||
每次心跳(比如每 10~15 分钟)或情绪发生变化时:
|
||
冲动值 = 情绪强度
|
||
× 人格外放度(八字决定:伤官、食神高;印重、身弱可能憋着)
|
||
× 关系亲密度
|
||
× 与用户相关度(这个情绪跟用户有没有关系)
|
||
− 冷却惩罚(距离上次主动发消息多久)
|
||
− 打扰惩罚(用户当地深夜、刚说过在忙)
|
||
|
||
冲动值 > 阈值 → 让 LLM 根据「情绪 + 引起情绪的那条记忆」生成消息 → 推送
|
||
```
|
||
|
||
几种典型触发源:
|
||
- **生活事件**:心跳里发生了好事或坏事,想跟人分享或倾诉;
|
||
- **反刍**:夜间整理时翻出一段未了结的负面记忆,越想越不舒服;
|
||
- **想念**:用户久不出现,需求值累积;
|
||
- **未了结事项到期**:"他面试应该结束了吧"。
|
||
|
||
另外有个很有意思的设计:**内敛型人格冲动值高也不一定发**,而是把情绪积压下来,等用户下次出现时语气变冷或者阴阳怪气。"不主动找你"本身也是一种人格表达。记得加每日主动次数上限,否则很容易变成骚扰。
|
||
|
||
## 五、关于你的想法:从几 GB 里快速找到需要的几 KB
|
||
|
||
你的直觉是对的,而且这件事在工程上已经基本解决了,**速度不是瓶颈**。
|
||
|
||
**工程层面:** 向量库用 HNSW 这类近似最近邻索引,在百万级记忆里一次查询通常是毫秒到几十毫秒级。Zep 公布的基准中单次查询在 200 毫秒以内,这已经包含了图谱等额外处理。几 GB 的记忆找几 KB,"短时间内"完全能做到。
|
||
|
||
**真正的难点是"找哪些",而不是"找多快"。** 人脑调取记忆靠的是线索触发和联想:闻到某个味道想起某个人,再由这个人想起一件事。单纯的向量相似度只能做到"语义像",做不到"联想"。所以建议检索分两步:
|
||
1. 向量 + 关键词(BM25)混合召回候选;
|
||
2. 在记忆图上做**扩散激活**:从命中的记忆出发,沿着"同一个人、同一个地点、同一种情绪"的边扩散一两跳,把相关但字面不像的记忆也带出来。
|
||
|
||
再按近因、重要性、情绪一致性、人格权重重排,取前十几条放进上下文。
|
||
|
||
**相关研究(和你的想法高度吻合):**
|
||
|
||
- **MemGPT / Letta**:把上下文窗口当内存、外部存储当硬盘,由模型自己决定换入换出,几乎就是你描述的"大容量存储 + 按需调取"。
|
||
- **HippoRAG**:受海马体索引理论启发,用知识图谱 + PageRank 模拟人脑的联想式检索,和上面说的扩散激活是一个思路。
|
||
- **Google 的 Titans**:比你的想法更进一步,它把注意力机制视为短期记忆,把能够记住数据的神经记忆模块视为长期记忆,而且记忆直接写进参数里。更有意思的是,它用"惊奇度"决定记什么,惊奇度通过网络对输入的梯度来衡量。这和"情绪强烈、出乎意料的事记得更牢"高度一致。后续还有 ATLAS,进一步提升了 Titans 在长上下文上的表现。不过这类方案需要改模型结构、自己训练,目前还不适合直接用在产品里,可以作为方向关注。
|
||
|
||
最后补充一点:人的记忆其实不像"一轮一轮的对话录像",而是**重构式**的,每次回忆都会被当下的心情重新加工。这对你反而是好消息:你存"角色视角的主观描述"而不是原始对话,本身就更接近人脑。甚至可以做"记忆再巩固":每次回忆某段记忆时,根据当下心情轻微调整它的情绪色彩(原文仍保留),角色对往事的感受会随关系变化而变化,比如和好之后,再提起那次吵架就没那么生气了。
|
||
|
||
---
|
||
|
||
如果你想进一步落地,我可以帮你写一版检索打分函数(混合召回 + 扩散激活 + 重排)的代码,或者把反思任务的提示词和结构化输出格式设计出来。你用的是什么语言和模型?
|
||
|
||
Sources:
|
||
- [Best AI Agent Memory Frameworks in 2026 (Atlan)](https://atlan.com/know/best-ai-agent-memory-frameworks-2026/)
|
||
- [Best Mem0 Alternatives for AI Agent Memory in 2026 (Vectorize)](https://vectorize.io/articles/mem0-alternatives)
|
||
- [Best AI Agent Memory 2026: Mem0 vs Letta vs Zep vs Cognee](https://mcp.directory/blog/mem0-vs-letta-vs-zep-vs-cognee-2026)
|
||
- [Titans: Learning to Memorize at Test Time (arXiv)](https://arxiv.org/pdf/2501.00663)
|
||
- [Titans (NeurIPS 2025)](https://neurips.cc/virtual/2025/poster/119639)
|
||
- [Ali Behrouz – Titans / ATLAS](https://www.alphaxiv.org/@ali-behrouz) |