200字
Elion 技术札记(一):从聊天机器人到长期陪伴的虚拟个体
2026-07-29
2026-08-02

本文记录 Elion 第一阶段的产品思考、架构选择与文本聊天 MVP 实现。文章对应项目截至 2026 年 7 月 29 日的状态。

为什么要做 Elion

大多数聊天应用擅长完成一次问答,却很难成为一个长期存在的“个体”。

当对话跨越多天、多个会话甚至多个用户后,真正影响体验的往往不再只是模型单次回答得是否聪明,而是一些更基础的问题:

  • 它是否记得我们共同经历过什么?

  • 它的人格、表达方式和行为边界是否稳定?

  • 它能否延续对不同用户的情绪、关系和承诺?

  • 它是否知道哪些信息可以公开谈论,哪些只能留在私人关系中?

  • 当用户打断一段正在生成的回答时,系统状态是否仍然可信?

Elion 正是从这些问题出发。它不是一个一次性问答助手,而是一个支持多用户、强调长期关系连续性、稳定人格、情绪连续性、隐私感知记忆与行为一致性的虚拟个体系统。

第一阶段没有急着加入语音、Live2D 或复杂工具,而是先完成一个文本聊天 MVP。目标是验证最核心的闭环:身份隔离、连续对话、流式响应、可中断、长期状态和记忆投递。

当前已经实现了什么

目前 Elion 已经跑通端到端文本聊天:

  • React + Vite Web App,提供登录、流式聊天、中断、状态面板和公开用户目录。

  • Go + Gin API,提供本地账号鉴权、WebSocket Gateway 和管理 REST API。

  • ConversationService,统一编排 Session、Turn、Prompt、模型调用、中断和状态提交。

  • OpenAI-compatible Model Adapter,可连接真实模型,也可使用确定性的本地回退。

  • MySQL 权威数据层,保存用户、认证会话、原始事件、Session、Turn 和长期状态。

  • MemoryService + outbox worker,将对话异步投递到 Honcho v3;未配置 Honcho 时使用进程内 MemoryEngine。

  • 生产 Docker Compose,由 nginx 提供同源 Web、REST 与 WebSocket 入口。

这意味着,即使没有配置外部模型和 Honcho,系统仍可使用本地回退完成主要流程。只有 MySQL 是完整业务能力的必需依赖;未配置 ELION_MYSQL_DSN 时,后端只提供健康检查和版本接口。

架构:让“通道”与“个体”分开演进

Elion 的核心架构可以概括为:Gateway 单入口、ConversationService 统一编排、Session/Turn 保证一致性、Adapter 隔离外部能力。

flowchart LR U[用户] --> W[React Web App] W -->|登录与状态管理 REST| API[Management APIs] W -->|聊天事件 WebSocket| G[Gateway] G --> C[ConversationService] C --> P[PromptBuilder] C --> M[Model Adapter] C --> MS[MemoryService] C --> DB[(Elion MySQL)] API --> DB API --> MS MS --> O[Outbox Worker] O --> ME[MemoryEngine] ME --> H[Honcho v3 / Local Engine] M --> L[OpenAI-compatible Model / Local Adapter]

Gateway 只处理连接边界:校验 session cookie、绑定当前用户、补齐追踪字段、转发事件,并丢弃过期事件。它不做记忆选择、人格判断或模型调用。

ConversationService 才是业务编排中心。Session 与 Turn 的创建、状态迁移、PromptBuilder、模型流式生成、中断以及 outbox 创建都从这里归口。未来接入 TTS、ASR、Avatar 或工具时,它们应当以 Adapter 或独立服务的形式接入,而不是把核心架构改造成某种特定的“语音助手”。

这种拆分的目的不是增加层级,而是让交互通道和虚拟个体的长期状态可以独立演进。

一条消息如何穿过系统

一次普通文本输入会经历以下过程:

sequenceDiagram participant Web as React Web App participant Gateway participant Conversation as ConversationService participant DB as MySQL participant Memory as MemoryService participant Prompt as PromptBuilder participant Model as Model Adapter Web->>Gateway: user.input.text Gateway->>Gateway: 校验 cookie,绑定 current_user_id Gateway->>Conversation: 转发标准事件 Conversation->>DB: 创建或恢复 Session,创建 Turn Conversation->>DB: 先保存原始输入事件 Conversation->>Memory: 查询当前用户记忆上下文 Memory-->>Conversation: 上下文或降级为空 Conversation->>Prompt: 组装人格、情绪、承诺、关系与记忆 Prompt-->>Conversation: 模型消息 Conversation->>Model: StreamGenerate Model-->>Web: assistant.output.text.delta Conversation->>DB: 保存完成事件并提交 Turn Conversation->>DB: 创建用户与助手消息 outbox 任务 DB-->>Memory: worker 异步投递

这里有两个刻意设计的先后关系。

第一,原始事件先写 MySQL,再进行异步记忆投递。Elion 不在聊天主链路里同时写 MySQL 和 Honcho,因为任何一次双写失败都会制造难以解释的数据分叉。MySQL 保存权威事实,outbox 负责最终投递;MemoryEngine 不可用时,对话仍可以继续。

第二,用户可见文本优先流式返回。记忆、情绪和承诺等结构化信息属于异步层,不应该拖慢当前回答。当前版本已经实现结构化模型接口和相关数据边界,但自动结构化抽取尚未接入 ConversationService 的任务编排,现阶段 outbox 主要负责把原始对话投递到 MemoryEngine。

Session/Turn:可中断系统的一致性骨架

流式输出最容易被忽略的问题,是“用户看到了什么”和“系统生成了什么”可能不同。

Elion 使用 Session 表示一次连续交互窗口,用 Turn 表示一次用户输入到系统输出的完整一致性单元。Turn 会经历如下状态迁移:

stateDiagram-v2 [*] --> CREATED CREATED --> PROCESSING PROCESSING --> STREAMING PROCESSING --> FAILED PROCESSING --> INTERRUPTED STREAMING --> COMPLETED STREAMING --> INTERRUPTED STREAMING --> FAILED COMPLETED --> [*] INTERRUPTED --> [*] FAILED --> [*]

每次状态更新都带有 state_version,用于阻止旧任务覆盖新状态。用户发起中断时,ConversationService 会取消当前模型 context,将 Turn 标记为 INTERRUPTED,并记录用户已经看到的输出范围。之后即使供应商仍返回迟到的数据,也不能再把它提交为有效结果。

这个约束也为后续 REPLAN_TURN 留出了空间:新的 Turn 可以关联被打断的 Turn,但只能使用中断元数据、用户已看到的内容和新的修正输入,不能偷偷使用从未展示给用户的过期输出。

为什么 MySQL 和 Honcho 都需要

长期记忆系统通常会产生两类数据:

  1. 原始、可审计、必须准确归属的数据;

  2. 为检索和推理生成的摘要、表征、结论与向量索引。

Elion 将两者明确分开:

  • Elion MySQL 保存用户、认证会话、原始事件、Session、Turn、Persona、Emotion、Relationship、Commitment、CorrectionEvent、OutboxTask 和 ContextSnapshot,是权威数据源。

  • Honcho 是首个 MemoryEngine 实现,负责 peer、session message、上下文摘要和记忆推理,但不拥有 Elion 的权威业务状态。

flowchart LR subgraph Authority[权威数据层] DB[(Elion MySQL)] O[Outbox] end subgraph Derived[可替换记忆推理层] MS[MemoryService] H[(Honcho v3)] end C[ConversationService] -->|先写原始事件与状态| DB DB -->|创建任务| O O -->|异步消费| MS MS -->|统一接口| H H -->|摘要与上下文| MS MS -->|按需查询结果| C DB -. 原始事件可重放 .-> MS

MemoryService 位于二者之间,ConversationService 不直接依赖 Honcho API。当前对接的是 Honcho v3 workspace API,每个用户映射为独立 peer,Elion 自身使用另一个 peer。查询失败时系统降级为 MySQL 状态加空记忆上下文;投递失败时 outbox 使用指数退避,最多尝试 5 次,之后进入 DEAD_LETTER,等待显式 retry 或 discard。

这个边界保证未来即使更换 MemoryEngine,也能从 MySQL 原始事件重放,而不必把整个产品的数据主权交给某个记忆供应商。

多用户不是共享所有记忆

多用户支持带来了一个比登录更重要的问题:Elion 可以知道其他用户存在,但不能泄露他们的私人关系。

当前规则是:

  • 每个请求都由后端 session cookie 绑定到 current_user_id,客户端传入的 user_id 不可信。

  • 每个用户拥有独立的私密记忆、情绪、承诺和私人对话边界。

  • 跨用户认知只允许读取基础身份字段和 public_profile

  • PromptBuilder 在谈及其他用户时,只注入公开投影。

  • 对明显索取他人私密信息的请求,系统会直接拒绝。

flowchart LR A[当前用户 A] --> PA[用户 A 的私密状态] PA --> P[PromptBuilder] B[被提及用户 B] --> PB[public_profile] PB --> P B --> SB[私密记忆 / 对话 / 情绪 / 承诺] SB --> X[隐私边界:禁止读取] P --> M[Model Adapter]

这是一种“默认认识、默认不共享隐私”的模型。MVP 暂不支持群聊、社交关系图或 ShareGrant 定向授权,先把最小隐私边界做清楚。

Model Adapter:屏蔽模型供应商差异

主模型通过 OpenAI-compatible /chat/completions 接口接入,并支持 SSE 流式输出与 context 取消。模型未配置时,系统切换到确定性的本地 Adapter,方便开发和自动化测试。

真实供应商并不总是严格返回同一种数据。例如当前适配过的流中同时存在用户可见 content 和内部 reasoning_content。Elion 只转发、持久化和投递 content,内部推理不会进入 WebSocket、Turn 事件、Prompt 或 MemoryEngine。如果流结束时完全没有用户可见内容,Adapter 会把它视为错误,而不是完成一个空回复。

这类细节说明 Adapter 不只是“换一个 URL”,它也是外部协议与系统语义之间的防火墙。

当前边界与下一步

文本聊天 MVP 已经验证了核心架构,但它还不是最终形态:

  • 当前没有用户注册 API 或 UI,测试用户仍需通过初始化数据创建。

  • 自动记忆、情绪和承诺的结构化抽取尚未接入异步编排。

  • 状态面板后端已有读取与修正接口,前端当前主要用于展示,并提供基础情绪覆盖操作。

  • Honcho conclusion 级修正尚未设计;目前 CorrectionEvent 以 MySQL 记录为准。

  • REPLAN_TURN 已有数据和协议边界,但执行流程仍是后续能力。

  • WebSocket 会复用数据库中的活跃 Session,但连接握手尚未实现客户端会话恢复协商。

  • 跨用户提及目前通过 username 或 display name 子串匹配,后续需要更可靠的实体解析。

  • TTS、ASR、Avatar、动作与工具 Adapter 尚未实现。

  • 原始数据删除、导出和 MemoryEngine 重建流程尚未提供。

  • 当前 Gateway 的 WebSocket origin 策略偏向本地开发,公开部署前仍需结合域名策略进一步收紧。

下一阶段的重点不是简单叠加更多 UI,而是继续沿着现有边界补齐异步结构化状态、可审计修正和新的输出通道。按照当前路线,文本 MVP 之后会优先接入 TTS,再考虑 ASR,最终让 Avatar 和动作消费同一套语义事件。

结语

Elion 第一阶段最重要的成果,并不是“又做了一个聊天页面”,而是建立了一套能够承载长期关系的系统骨架:

  • 用 Session/Turn 管住流式与中断的一致性;

  • 用 MySQL 保留权威事实和审计链路;

  • 用 outbox 隔离对话主链路与记忆推理;

  • 用 Adapter 隔离模型、记忆引擎和未来交互通道;

  • 用明确的用户边界阻止长期记忆演变成隐私泄露。

一个虚拟个体是否可信,最终不只取决于模型有多强,也取决于系统能否记住正确的事、忘掉不该使用的输出,并始终知道自己正在和谁说话。

这正是 Elion 接下来要继续验证的方向。

Elion 技术札记(一):从聊天机器人到长期陪伴的虚拟个体
作者
Luawig
发表于
2026-07-29
License
CC BY-NC-SA 4.0