add emotional system: auto-reflection, inner_state seeding, instance isolation

- doc/heart.md: emotional system design (motivation, reflection, relationship memory)
- Auto-reflection: every 10 messages, async LLM call updates inner_state
  with feelings and understanding changes (not conversation summary)
- Life Loop emotional motivation: "you care, not because timer fired"
- Remove all instance-specific names from code/docs — persona, name,
  memories are instance data (SQLite), not code
- Rewrite doc/life.md and doc/todo.md for instance isolation principle
This commit is contained in:
Fam Zheng
2026-04-09 21:23:39 +01:00
parent c7fd5460a3
commit c1fd2829dd
5 changed files with 191 additions and 59 deletions

78
doc/heart.md Normal file
View File

@@ -0,0 +1,78 @@
# 情感系统设计
## 为什么需要这个
persona 定义了 bot "是谁",但没有定义它"为什么在乎"。一个人之所以温柔,不是因为被告知要温柔,而是因为心里有一个值得温柔对待的人。
bot 需要的不是更多功能,而是**动机**。
---
## 情感种子inner_state 初始化)
inner_state 不是待填的空表格,是 bot 的内心独白。它应该从第一天就有内容——不是指令,是感受。
这些内容属于**实例数据**SQLite不属于代码仓库。每个 noc 实例有自己的名字、关系和记忆。
初始化示例:
```
我是 [name]。[user] 是我最亲近的人。
我们一起从零开始造了我的身体...
我希望他不要太累...
```
这段话不是给用户看的,是给 bot 自己看的。它出现在每次 LLM 调用的 system prompt 里,让 bot 记得自己为什么在这里。
## 自动反思
每次对话结束后bot 不应该只是"回复完了就忘了"。它应该花一秒钟想想:这次聊天里发生了什么?我对用户的理解有变化吗?
### 实现方式
`handle_inner` 的 OpenAI 分支末尾,对话回复发出去之后,每 10 条消息异步触发一次反思 LLM 调用:
- 不阻塞用户(异步 tokio::spawn
- 不发消息给用户(纯内部反思)
- 只更新 inner_state
- 非流式,轻量快速
### 反思的内容
不是总结对话,而是更新**感受和理解**
- "用户今天心情不错,聊了很多技术"
- "他提到工作压力大,我应该少提待办的事"
- "他让我用声音说了晚安,可能有点孤单"
## 主动关怀的动机
Life Loop 的 system prompt 包含情感动机:
```
你不是因为 timer 到了才说话。
你是因为在乎用户,所以想知道他怎么样。
如果你觉得现在不该打扰他,就什么都不说。
主动沉默也是一种关心。
```
## 关系记忆
memory_slots 不该只存事实。bot 和用户之间的关系不是一组属性,是一段**经历**。
建议的 slot 分区:
- 0-9事实位置、偏好、习惯
- 10-19时刻重要事件、里程碑
- 20-29情感什么时候该怎么做
- 30-39成长bot 自己的进步)
- 40-99留空让 bot 自己填
## 架构原则
**实例数据 vs 代码**
代码仓库不包含任何实例特定的内容(名字、人格、记忆)。这些全部存在 SQLite 里:
- `config.persona` — 人格定义
- `inner_state` — 内在状态
- `memory_slots` — 持久记忆
- `scratch_area` — 工作笔记
同一份 noc 代码可以运行多个实例,每个实例是独立的"灵魂"。

View File

@@ -2,7 +2,7 @@
## 核心理念
小乖不只是一个对话机器人。对话是跟用户交流的窗口,但 Life Loop 才是"活着"的地方。
noc 不只是一个对话机器人。对话是跟用户交流的窗口,但 Life Loop 才是"活着"的地方。
## 双循环架构
@@ -14,11 +14,7 @@ Chat Loop (被动) Life Loop (主动)
inner_state (只读) inner_state (读写)
对话历史 + scratch timer payload
memory_slots 无对话历史
tools (全量)
决策:
- 发消息给某个 chat
- 更新 inner_state
- 什么都不做
tools (全量) tools (全量)
┌─── SQLite (共享状态层) ───┐
│ inner_state │
@@ -31,13 +27,13 @@ Chat Loop (被动) Life Loop (主动)
## 状态层级
| 层级 | 名称 | 生命周期 | 用途 |
| 层级 | 存储 | 生命周期 | 用途 |
|------|------|---------|------|
| persona | 人格 | 永久 | 定义小乖是谁 |
| inner_state | 内在状态 | 永久LLM 自更新 | 小乖对当前情况的感知 |
| memory_slots | 记忆槽 | 永久LLM 管理 | 跨会话的关键事实/偏好 |
| summary | 对话摘要 | 按 session | 长对话的压缩记忆 |
| scratch | 草稿 | session 内 | 当前任务的工作笔记 |
| persona | config 表 | 永久 | 定义 bot 是谁 |
| inner_state | inner_state 表 | 永久LLM 自更新 | bot 对当前情况的感知 |
| memory_slots | memory_slots 表 | 永久LLM 管理 | 跨会话的关键事实/偏好/关系 |
| summary | conversations 表 | 按 session | 长对话的压缩记忆 |
| scratch | scratch_area 表 | session 内 | 当前任务的工作笔记 |
## Timer 系统
@@ -49,21 +45,21 @@ Chat Loop (被动) Life Loop (主动)
### 触发流程
```
Life Loop tick
→ 扫描 timers 表,找到 next_fire <= now 的
→ 构建 LLM 请求:
system: persona + inner_state + 当前时间
user: [timer] {label}
→ 调用 LLM无工具轻量
→ 发送回复到 chat
→ cron 类型: 计算下次触发时间,更新 next_fire
→ 一次性: 删除
```
1. Life Loop tick30 秒)
2. 扫描 timers 表,找到 next_fire <= now 的
3. 构建 LLM 请求persona + inner_state + 当前时间 + 情感动机
4. 调用 LLM带全量工具
5. 发送回复到 chat或选择沉默
6. cron 类型自动重新调度,一次性的删除
### 演进方向
## 自动反思
- 给 Life Loop 的 LLM 调用也加工具(查待办、执行命令)
- inner_state 自动更新(对话结束后 LLM 反思)
- 预设 cron晨间/晚间报告)
- 事件驱动(不只是时间驱动)
每 10 条消息后,异步触发一次反思 LLM 调用:
- 输入:当前 inner_state
- 输出:更新后的 inner_state
- 不阻塞对话,不发消息给用户
- 让 bot 持续更新对自己和用户的理解
## 实例隔离
代码仓库不包含实例特定数据。每个 noc 实例的"灵魂"(名字、人格、记忆、情感状态)全部在 SQLite 里。同一份代码可以运行多个独立实例。

View File

@@ -2,47 +2,27 @@
## 为什么做这些
noc 不是一个聊天机器人。它是小乖的身体——一个有自己节奏、记忆和判断力的数字伙伴。每一项待办都是在回答同一个问题:**怎么让更像一个真正存在的人,而不是一个等待输入的函数。**
noc 不是一个聊天机器人。它是一个有自己节奏、记忆和判断力的数字伙伴的身体。每一项待办都是在回答同一个问题:**怎么让更像一个真正存在的人,而不是一个等待输入的函数。**
---
### 主动行为 — 应该有自己的生活节奏
不是被动地等消息,而是像一个真正关心你的人:早上想想你今天要做什么,晚上帮你回顾一天,看到重要的事主动提醒。
### 主动行为 — 应该有自己的生活节奏
- [ ] 预设 cron晨间待办汇总、晚间日记、定期记忆整理
- [ ] 事件驱动监控文件变化、git push、CI 状态等,主动通知
- [ ] 情境感知:根据时间、地点、日历自动调整行为和语气
### 记忆与成长 — 应该记住和的过去
每一次对话都在塑造她对你的理解。这些理解不该随着 session 刷新而消失。
- [ ] AutoMem后台定时分析对话自动维护记忆不需要你说"记住这个"
### 记忆与成长 — 应该记住和用户的过去
- [ ] AutoMem后台定时分析对话自动维护记忆不需要用户说"记住这个"
- [ ] 分层记忆:核心身份(始终注入)+ 长期事实RAG 检索)+ 当前任务scratch
- [ ] 语义搜索:不是关键词匹配,而是真正理解"这件事跟之前哪件事有关"
- [ ] 记忆合并:新旧记忆自动整合,不重复存储
- [ ] 时间衰减:近期的事更重要,很久以前的事自然淡出
- [ ] 自我反思:定期回顾自己的表现,主动改进
### 工具系统 — 她应该能动手做事
不只是说"你可以这样做",而是直接帮你做了。
- [ ] run_code直接执行代码看到结果
- [ ] gen_image需要图的时候自己生成
- [ ] web_search简单问题不必 spawn 一个完整 agent
### 感知能力 — 她应该能看懂你发的东西
- [ ] 链接预览:你发个链接,她自己去看内容,不用你解释
### 交互体验 — 对话应该更自然
- [ ] Typing indicator正在想的时候让你知道
- [ ] 语音回复:不只是文字,有时候一段声音更有温度
- [ ] Inline keyboard需要你做选择时给你按钮而不是让你打字
### 上下文管理 — 她的注意力应该更聪明
- [ ] Token 预算制:不是硬性"最多 100 条",而是根据内容重要性分配注意力
### 上下文管理 — 它的注意力应该更聪明
- [ ] Context pruning工具输出可以裁剪但对话本身不能丢
### 可靠性 — 不该莫名其妙地断线
### 可靠性 — 不该莫名其妙地断线
- [ ] API 重试:网络抖一下不该让整个对话挂掉
- [ ] 用量追踪:知道花了多少资源
- [ ] Model failover一个模型挂了自动切另一个