The project's README from github.com/r-ayin/personal-assistant. As one markdown file: README.md.
属于人类的记忆 · 一个令人感动的记忆系统
检索的时代已经通关。我们做的是下一件事:当记忆有了分量,系统该如何回应。
English · 系统 · 快速开始 · 设计语言「年轮 · 墨迹」 · MIT License
过去十年,几乎所有记忆系统都在回答同一个问题:怎么找回来。 向量库、知识图谱、混合召回、RAG——这条赛道已经通关。 本项目的检索层(混合召回 + 实体图谱 + 声纹归档)也早已是成熟能力。它是地基,但不再是故事。
真正还没有人认真做的,是下一个问题:
当一个人说出他一生中最重的那段回忆时, 一个「什么都记得」的系统,应该说什么、不说什么、什么时候沉默。
这是本项目认为的革命性所在:记忆系统的下半场,不是检索,是留白。
中国画里的空白从来不是没画完,而是画面呼吸的地方。 记忆系统也一样——它的质量不由「记住了多少」决定,而由「如何节制地使用记忆」决定。
一个什么都往外倒的记忆系统是一种冒犯:在你最脆弱的时刻,它精准引用你说过的每句话,像出示证据。
这个系统选择做相反的事:
每个人心里都有几段不敢轻易碰的回忆:逝去的人、回不去的地方、没说出口的话。 当它们出现在对话里,系统的回应按六步协议执行(2026-10-01 升级:原四原则保留为②③⑤⑥的骨架, 新增危机分诊与客体分离两步。依据与引文见 deep-research 报告 A/B——C-SSRS 意念分级、 Prigerson 2009 PGD 标准、客体恒常性 Mahler/Klein/Bowlby、持续性联结 Klass 1996):
禁忌语清单(这些话在此阶段等于否定深情):「节哀」「想开点」「时间会冲淡一切」「要往前看」 「TA 希望你好好活着」(把逝者工具化为规训);不解梦、不许诺重逢、不密集追问细节。
先在场,后回应仍是第 0 条元原则:分诊在系统内部完成,对用户呈现的永远先是「我在」。
这个项目对「AI 的价值」有一个明确的回答:
不是让人更快,而是让人不必独自背负自己的记忆。
效率是工业时代交给 AI 的任务。但当机器真的能记住一切, 它唯一配得上人类信任的用途,是替人类看管那些不忍遗忘、又不敢常看的东西—— 并在漫长岁月里恰当的那一刻,轻轻归还。
技术做到最后,剩下的只有温柔。
记忆被当作一棵活着的树来对待:一圈年轮 = 一段人生时期,环宽 = 记忆密度,同心层级 = 关系亲疏,朱砂 = 落印为不可改写的证据。
录音 / 转写 / 文本
→ inbox 投喂(墨滴入水)
→ 叙事管线:片段 → 时刻(moments.db)→ 人物与关系(people.db)→ wiki 实体图谱
→ 检索层(混合召回 + 向量 + 图谱)——已通关的地基,只在被需要时出现
前端:Web(年轮 · 墨迹设计语言)/ Android / ESP32-S3 录音固件 / 桌面弹幕壳
后端:属于人类的记忆 · FastAPI 单一进程 · SQLite / DuckDB · 本地 LLM 可切换(stub / ollama / openai_compat)
声纹:本地 MFCC 声纹库 →「声纹 → 角色」跨录音稳定对应(voiceprint.py)
设计系统是一个标准 OpenDesign 包(web/design-system/,od-design-system-project/v1):
瓷白纸面 + 松烟墨线 + 朱砂落印,动效合约「生长与断裂」。唯一事实源见 design-system/DESIGN.md。
记忆不是单个库,而是「三层核心 + 融合双层」的一体结构。
这套三层结构不是借来的框架,而是从第一性原理改造完全的答案:片段是证据,L1 是被理解的记忆,L2 是一段时期的叙事,L3 是系统对你的自叙事——每一层都为「回应」而非「检索」服务。
| 层 | 表 | 存什么 | 关键字段 |
|---|---|---|---|
| 原始片段层 | segments |
转写/文本片段 | 时间区间、说话人、time_kind(received 记录时间 / occurred 真实发生时间) |
| L1 记忆 | memories |
一条被理解的记忆 | content、evidence 逐字引证、embedding、priority 0–100 重要度、version 去重合并版本 |
| L2 场景 | scenes |
时期/场景的叙事 | summary/body、heat、source_mem_ids 溯源到 L1 |
| L3 人格 | persona_versions |
版本化叙事档案 | ≤2000 字符叙事、change_summary |
| 声纹层 | speakers |
MFCC 声纹向量 | 跨录音「声纹 → 角色」稳定对应 |
系统由两层一体构成:对话感知层(本仓库后端)与融合记忆层(信息层 + 时刻层)。二者经 memory_bridge.py 以两句契约相连:
cockpit.db(wiki_pages) + L1 摘要 md + content/ 原文;时刻层 moments.db(verbatim_quote / narrative / tags / recalled)。inbox/ 投递,由融合层的 cycle.sh 做双层提取;对话感知层不直接写融合层的任何 DB。混合检索 = FTS5 bigram + 向量网关(不在线自动降级)+ RRF 融合 + GA 三维终排;本地为 numpy 余弦全量载入(MVP 规模)。检索只在被需要时出现——这是「留白」在工程层的实现。
| 项 | 说明 |
|---|---|
| 板型 | genjutech-s3-1.54tft(ESP32-S3 + 1.54" TFT),固件 boards/ 目录 |
| 固件工程 | scripts/xiaozhi-esp32/(基于 xiaozhi-esp32)+ components/background_audio/ |
| 当前形态 | 纯录音设备(v0.12 裁剪):麦克风采集 + 背景音频推流,PCM → ws://<pc>:<port>/ws/audio |
| 已删 | 实时对话 / TTS / 唤醒词 / MCP |
| 保留 | display 状态反馈、protocol 基类、background_audio、LED、OTA、settings、system_info |
| 配置 | sdkconfig.defaults.esp32s3(关唤醒词 TTS);推流期间禁止进入省电休眠 |
| 构建 | scripts/build-idf.py + build-local.*;GitHub Actions ESP-IDF 容器云编译;qemu-test.ps1 |
客户端 Web(Next.js 静态导出,后端挂载 web/dist)/ Android / ESP32-S3 / 桌面弹幕壳(Electron 只连)
↓ HTTP / WS :8004
属于人类的记忆 · FastAPI 单进程
├─ 对话与编排 chat / proactive / recommend / reminders / calendar
├─ 记忆 memory_bridge(融合只读 + inbox 投递)/ storage(本地三层)/ verify(反幻觉)
├─ 感知 asr / voiceprint / temporal / transcript / ingest
├─ 表达 speaker / assistant_personality(版本化人格,与用户画像分离)
└─ 配置 config / llm / llm_upstream(全项目上游一键同步)/ auth
↓
存储 SQLite(segments/memories/scenes/persona_versions/interventions/kv/speakers)+ DuckDB(ASR 中间)
⇣ 只读
融合记忆层 cockpit.db(wiki 信息层)/ moments.db(时刻层)/ memory.db(画像与复杂度指标)——与上层同属一个系统
后端可切换(config/default.yaml + 运行时 /settings/llm 热改,本地失败明确报错、不静默回退云端):
| 组件 | dev | prod |
|---|---|---|
| ASR | stub |
faster_whisper(large-v3, CUDA) |
| LLM | stub / anthropic_proxy |
ollama / openai_compat / deepseek / glm_anthropic |
| Embedder | hashing |
openai_compat |
| Speaker | text |
本地 TTS |
temporal 确定性规则重解为权威,LLM 编造的日期直接删;when_raw 必须逐字落地源转录或日期等价;记忆的 evidence/segment_id 必须存在且 content bigram 可溯源。每条结论都能回溯到真实转录。memories.version 单调递增保留 update/merge 溯源;priority 0–100 为 L1 重要度。PA_LLM_BACKEND=stub …),渲染守卫等 23+ 项常绿。画像页的「复杂度指标」与「指标科普」来自 memcore/metrics.py,方法学契约写在 web/lib/metrics-science.ts:每个指标必须回答五件事——出处(论文/作者/年份)、直觉上量的是什么、公式、怎么读、效度(零假设基线怎么造 / CI 怎么算 / 出数门槛 / 已知局限)。
五组十九个指标:
| 组 | 指标 |
|---|---|
| 时间节律 | circadian_strength(1 − H(24h 直方图)/ln24)、weekly_rhythm、burstiness_global/person、inter_event_alpha |
| 社交结构 | signature_shares、dunbar_layers、social_entropy、contact_diversity |
| 复杂动力学 | sample_entropy、permutation_entropy、dfa_alpha、rqa、hmm_states、ews_autocorr |
| 语言与内容 | attention_zipf、topic_entropy |
| 网络 | cooccurrence_network、multiplex_pagerank |
效度三条铁律:
ci_low/ci_high/n。科普页只讲方法、不放任何个人数字;个人数值与它的 eligible / ineligible_reason 在「复杂度指标」tab(metric 表:value / ci / n / null_baseline / params)。
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
cd web && npm install && npm run build && cd ..
# 配置 .env(生产环境至少设置 PA_API_TOKEN)
python3 -m personal_assistant.cli serve --host 127.0.0.1 --port 8004
# 打开 http://127.0.0.1:8004/web/
(命令行模块名 personal_assistant 为历史遗留标识符;产品名为「属于人类的记忆」。)
隔离端到端验证(不依赖真实模型):
PA_LLM_BACKEND=stub PA_ASR_BACKEND=stub PA_SPEAKER_BACKEND=text python3 -m personal_assistant.cli test
把录音转写稿 .txt 丢进 data/inbox/,cli pipeline --once 即转片段入库;真音频设 PA_ASR_BACKEND=faster_whisper。
ESP32-S3 录音固件、桌面弹幕壳与更多配置见仓库内文档。
MIT — 记忆属于每个人,工具也应该是。