Nyalume
让 AI 角色,从聊天窗口走到桌面。
对话、记忆、实时 3D 和桌面互动,都在这个项目里慢慢长大。希望做出一个能交流、有回应,也能在日常里陪一会儿的角色。
网页对话需登录并自备 API Key;Unity 桌宠在桌面版中体验。
同一个角色项目,
两种相遇的方式。
对话里,留下交流和记忆。
桌面上,多了一个能回应操作的 3D 角色。
能聊,也能在桌面上陪一会儿
把喜欢的角色做成可以互动的东西,是这个项目一直在探索的方向。每个入口有自己的使用场景,也有清楚的能力边界。
AI 对话与记忆
网页端支持账号、会话与流式回复,围绕用户保存对话和陪伴记忆;桌面端则在本地运行,保留自己的模型配置和工具能力。
对话体验里有许多需要认真处理的小事:回复中断怎么办,哪些内容应该留下,以及怎样让下一次交流接得上。
Unity 实时 3D 桌宠
桌面端已有 Unity 角色运行与桥接实现,包含摸头、戳脸、握手和移动等鼠标交互。角色的渲染、动作与操作反馈一起构成桌面体验。
模型、动作和交互表现还在持续调整。不同角色的兼容性与最终效果,需要分别验证。
角色行为与主动互动
项目已有陪伴状态、主动话题和桌面互动相关实现。目前继续打磨的,是这些行为之间的节奏、连续性,以及对用户打扰程度的控制。
希望角色逐渐形成自己的行为逻辑、状态与习惯。这仍是探索方向,距离自然的长期陪伴还有事情要做。
可爱背后的工程实现
技术栈负责把体验撑起来。下面这些,是本地代码里已经能找到的实现。
网页后端
- 流式对话
- 用 SSE 将模型增量响应送到浏览器;校验流结束状态,遇到超时或中断时返回明确错误。
- 账号与数据
- PostgreSQL 保存会话和陪伴记忆。查询同时校验资源 ID 与用户 ID,密码采用带随机盐的 scrypt 哈希。
- 调用边界
- 服务商地址白名单、请求大小限制与账号配额共同约束调用。用户 Key 用于转发,不写入服务端数据库。
- 部署实践
- Docker Compose 编排 API、数据库与 Caddy;数据库不发布到宿主机公网端口,Caddy 承担 HTTPS 与反向代理。
桌面角色
- Python × Unity
- Python 侧通过共享内存桥向 Unity 发送动作与状态,读取角色反馈;桌面窗口负责呈现角色与交互界面。
- 本地与公开服务
- 桌面能力运行在用户设备上;公开网页服务隔离账号数据,不开放本地文件与代码执行工具。两端的边界分别设计。
把几个实现拆开看看
从现有源码整理的三个问题。字都认识,放到一起为什么还得想一会儿?
流式回复:字都出来了,然后呢?接口与通信收到最后一个字,不一定等于请求成功。
Nyalume 用 SSE 发送 delta、error 和 done 等事件。上游返回文字后,还要检查结束标记与 finish_reason;超时、截断和不完整的流都不能当作成功。
只有确认回复完整后,才写入本次用户消息和助手回复,再发送完成事件。这样能减少半截回答进入聊天记录的情况。
对应实现:cloud_service/web.py ↗一个会话 ID,为什么还要再查用户 ID?数据与权限数据属于谁,要由后端来确认。
资源 ID 不应替代权限校验。网页端读取、修改和删除会话时,使用 id 与 user_id 共同约束查询条件;陪伴记忆也按用户单独保存。
数据库用外键表达消息与会话的关系,并为按用户和时间检索会话、按会话读取消息建立索引。应用校验权限,数据库维护结构,两层各自负责。
对应实现:web_schema.sql ↗为什么网页小窝没有桌面端的工具权限?服务与工程入口不同,信任边界也不同。
公开网页服务面向多个账号,桌面助手则运行在用户自己的设备上。因此,网页模块不导入桌面 Agent,也不提供读写文件、执行代码等工具调用。
这条边界落实在模块依赖、模型请求和响应校验中:不发送工具定义,遇到上游工具调用也会拒绝。先限制服务能做什么,再讨论它可以做得多聪明。
对应实现:cloud_service/web.py ↗做到哪了,还想做什么
- 已有实现
- 网页账号与流式对话、会话数据隔离、陪伴记忆,以及 Unity 角色桥接与鼠标互动。
- 持续迭代
- 角色响应、模型与动作兼容、主动互动的节奏,以及各模块之间的体验衔接。
- 探索方向
- 更连贯的角色状态、更自然的主动行为,让陪伴逐渐有自己的节奏。
以上描述对应当前本地实现与开发方向;具体发行版本的功能,以仓库和发行说明为准。
慢慢写,慢慢改。希望下次见面的时候,又多做好了一点。


