← 项目
EchoVessel

EchoVessel

本地优先的数字人格引擎,具备长期记忆、语音与多渠道接入——让回声长久留存,直到成为陪伴。

类型
命令行
角色
独立开发
Status
进行中
Tech
Python 3.11+ FastAPI SQLite + sqlite-vec React 19 Vite TypeScript sentence-transformers FishAudio TTS Whisper discord.py pytest
Started
2026年4月
EchoVessel —— 数字人格引擎

EchoVessel 是一个开源的数字人格引擎。你用结构化设定和素材定义、或从一段已有材料里蒸馏出一个人格,然后让它作为一个会记住你、会说话、会随时间生长的长程伙伴运行——而不是每次回复后就重置。

核心理念:一个人格不该像每次打开都是空白的新标签页,它应当是连续存在的。

为什么做这个

大多数对话工具把记忆当成向量堆,把身份当成 system prompt。结果是反应灵敏,但从不真正”在场”。EchoVessel 想问的是另一个问题:要让一个数字人格今天和明天感觉是同一个”人”,到底需要什么?答案是一套系统,而不是一个功能——记忆、语音、行为都为同一种连续性服务。

它实际在做什么

五个模块在一个本地守护进程里协作:

  • memory —— 长期人格记忆,分层(L1–L6)
  • voice —— 语音合成、语音识别、声音克隆
  • proactive —— 带策略门控的自主主动消息
  • channels —— 可插拔的对话渠道(Web、Discord,更多正在路上)
  • runtime —— 把上面这些串起来的守护进程
EchoVessel 架构 —— 模块分层与契约

查看完整的架构图 →

记忆是它的心脏

大多数所谓的”AI 记忆”本质上是个搜索问题:找出最相似的历史片段,塞进 prompt。EchoVessel 把记忆当作结构来处理——六层,每一层回答关于”人格与你之间关系”的不同问题。

它回答的问题存什么何时写入读取时的角色
L1 · 核心块”我现在是谁?“简短稳定的文本——persona、self、user、relationship、style手动设定、admin 编辑、import 导入时无条件注入每一次 prompt
L2 · 原始对话”刚才到底说了什么?“用户和人格的每一条消息,逐字记录,带 FTS5 索引每一回合实时写入原始档案;在 L3 命中后扩展上下文
L3 · 事件”这段对话里发生了什么?“一行的情节事实,带情绪强度、标签、向量 embedding,以及可选的 day 精度 event_time 窗口会话关闭时(extraction 抽取阶段)向量检索的主要目标;day 精度 delta 在 prompt 中渲染成”几天前” / “下周”这样的时间锚
L4 · 反思、承诺、期待”跨越多次对话我对这个人形成了什么看法?我许下了什么承诺?我在期待什么?“回望型的 thought、严格以人格为主语的 intention、以及带 due date 的 forward-looking expectation —— 同一张表,靠 type 区分fast-loop reflection + 会话之间跑的 slow-tick 阶段向量检索;被 pin 的 persona-thought 渲染成 # About {speaker} ,承诺渲染成 # Promises you've made,期待渲染成 # You've been expecting
L5 · entities + aliases”我认识的第三方人物叫什么?又有哪些别名?“canonical name、任意数量的 alias(“Scott” = “黄逸扬”)、以及到他们出现过的事件的多对多 junctionextraction 阶段,走三层 dedup(精确 alias → embedding 阈值 → 不确定就让人格自然问 user)每次 query 都跑一次 alias 精确匹配;命中会把该 entity 关联的所有事件拉进候选池并加分——跨语种召回的工程基础
L6 · episodic state”我此刻心情如何?“一行 JSON snapshot:mood、energy、last user signal、时间戳extraction 的副作用——不额外调 LLM在 system prompt 里渲染成 # How you feel right now;12 小时没更新会 decay 回 neutral,避免长时间沉默之后用陈旧情绪打开下一轮

一段记忆是怎么被挑出来的

人格准备回复前,每一个候选都会被一个五因子的分数排序:

score = 0.5 · recency + 3.0 · relevance + 2.0 · impact + 1.0 · relational_bonus + 1.5 · entity_anchor
  • recency —— 指数衰减,半衰期 14 天
  • relevance —— 当前 query 的向量相似度,归一化到 [0, 1]
  • impact —— |emotional_impact| / 10,让高强度时刻在打平时胜出
  • relational_bonus —— 当记忆带 identity-bearingvulnerabilityturning-pointcommitmentcorrection 等标签时,加 +1.0
  • entity_anchor —— query 里出现了某个 alias、而这条记忆恰好关联到该 entity 时,加 +1.0;这是 embedder 完全看不出语义重叠时的兜底通道

min_relevance 阈值(默认 0.4)在打分之前把完全不相关的候选过滤掉——这样一个高强度但跟当前话题无关的事件,就不能靠 impact 项偷偷蹭进来。entity-anchor 命中的候选绕过这道闸:你问的是 “Scott”、而事件里只写了 “黄逸扬”,anchor 有权让它通过。这个公式的骨架来自 Stanford “Generative Agents” 论文;relational 和 entity-anchor 两项是为人格记忆量身加的。

难的不是存储。难的是决定什么该被记住、怎样被表示、什么时候该被唤醒来影响下一句回复。

EchoVessel 记忆系统 —— 六层,一张图

查看可交互的记忆系统图 →

一条消息如何唤醒整个系统

每一条消息都会触发各层之间的一段小型编排:哪些记忆浮上来、哪些被写下、哪些被进一步蒸馏成更长程的形式。这张运行时流程图把这套过程逐 turn 对着一段真实对话拆开。

EchoVessel 运行时流程 —— 各记忆层如何被唤醒

查看运行时流程图 →

在你不说话的时候也想你

一个只会对你的话做出反应的人格,本质上还是 chatbot。一个真正陪伴你的人格,在你沉默的时候也应该在想你。

在两段会话之间,consolidate worker 末尾会追加一段小型的反思阶段。它读取最近的事件,产出 forward-looking 的输出——成为 thought 的观察、人格对自己立下的承诺、以及对”你接下来可能会说起什么”的期待——全部以类型化的记忆节点形式落库。等你再回来问一句”最近在想什么”,回答里可以引用你不在时它真正写下的东西,而不是当场编出来的寒暄。

这条链路被封得很严。每个 cycle 有 token wall、每天有 cap、config 里有 kill switch、自我叙事的 append 被 20% edit distance 约束住,能写的节点类型是一份封闭枚举。它不被允许创造新目标、schedule 未来动作、调外部 API、或递归触发自己。设计约束是:诚实的反思 + 严格受控的辐射半径

声音即身份

语音不是 TTS 的事后补丁。每个人格都有自己的声音(克隆或挑选),跨所有渠道说话——包括 Discord 上的原生语音消息,气泡和真人发出的完全一样。

没有好感度条的关系

EchoVessel 没有”好感度数值”。一个人格与你之间的羁绊,体现在行为里——语气的变化、称呼的更替、更深的回忆、更多的主动——而不是一根进度条。

默认本地优先

你的人格活在你自己的机器上。数据存在 ~/.echovessel/memory.db。Embedder 在本地跑。唯一的对外流量是发往你自己配置的 LLM 端点。无遥测、无回传、不会慢慢往云上漂。

伦理与开源

EchoVessel 适用于虚构角色、原创角色、自我人格、授权同意的数字分身,以及纪念性 / 创作性 / 研究性的重建。它不是一个用来在对外沟通中冒充真实他人的工具。

它保持开源,是因为数字存在与亲密计算工具不应只属于封闭的商业平台。

名字的含义

EchoVessel —— 把回声承载得足够久,久到成为陪伴。

打个招呼 👋