Skip to content

介绍 ​

古人认为万物年深日久皆可成精,故称“精”;其能迷惑人心,故称“魅”。

精魅是住在 Discord 和 Telegram 群里的 AI 群宠。一份配置可以同时养几个性格不同的角色:平时按概率接话,被点名一定回应;看得懂图片和视频,会发语音、上网查资料、算数,记得群友的生日。两个平台共用同一个对话核心,每个角色在每个频道按“对话段”使用 Pi 会话:只有被触发的角色才写自己的会话,连续对话接续同一段,间隔久了或积累多了就开新段,更早的聊天靠检索。

能做什么 ​

  • 懂内容再接话,被点名必路由:@ 提及、回复角色、叫名字/别名的路由优先级不变;普通人类消息在有决策客户端且开启接话判断时先识别是否在对某个角色说话,否则仅让 routingP 确定性抽样候选在冷却、发言占比与启用时的内容分数都合格后接话。bot 消息不触发角色;发送前还会检查最终文字,拦住内部标记或不自然的回复。
  • 失败不堵群:模型与工具轮次最多等 180 秒,超时中止并释放频道;失败只记日志,不在群里发送错误提示。Telegram 的成功文字/图片/语音回复也写入历史,回复 bot 时能继承原话题;Discord 仍通过平台回声记录。
  • 崩溃恢复,过期不插话:消息与待处理记录在同一事务入库,重启后补处理最近 3 分钟内的未完成消息;失败轮次不重试。收到或轮到处理时已超过 3 分钟的消息(包括长时间离线后补收的积压)只入库并写入向量索引:不回复(即使被 @、回复或叫名字)、不请求接话判断、不点秒回表情、不记入成员记忆和话题,Telegram 也不下载其中的图片和视频,只留 [图片]、[视频] 等占位。之后角色被触发时,它们仍作为积累的消息进入对话。恢复消息保留文字,图片以不可用说明代替。
  • 持续显示“正在输入…”:被路由的角色生成回复期间,Telegram 每 4 秒、Discord 每 8 秒刷新一次输入状态,回复发出、被扣留或失败时停止,最长显示 60 秒。
  • 能查“为什么没回”:每条人类消息记一行不含正文的 route 日志,写明最终路由、HMAC 候选、是否被冷却/占比挡住、接话判断结果与分数;暂停期间记 paused。字段见 docs/architecture.md。
  • Jev 秒回表情(可选):用 Jev 决策接口(或进程内 LLM 包装器)给消息点一个表情。点名的消息只要选中表情就会点,普通消息只有情绪强烈或确实好笑时才会,并且每个频道限频。不占用主模型,也不拖慢正式回复。详见 Jev。
  • 并行话题(可选):events 把同一频道的消息归入不同话题,用 §E 编号、标题、描述和主要参与者告诉角色当前在回应哪个事件,避免把同时发生的讨论混在一起;还能召回之前暂时结束的话题。
  • 对话段,按需接续:群消息一律入库并建索引,但只有被路由触发的角色才写自己的会话,没被触发的消息不会进入任何会话。角色被触发时,若距它上次成功回复不超过 5 分钟、之后积累的消息不超过 30 条、会话不超过 40,000 tokens,就接续原会话:把积累的消息作为一条上下文追加,再写触发消息;否则开新段,以触发前最近 30 条消息为种子。每行形如 [时间] #消息号 ↪ 被回复号 §E话题 作者: 内容 (相关 N 条),N 是更早历史里的相关消息数(超过 20 显示 20+),写入时固化、之后不变,因此前缀稳定、缓存命中。轮次超时、发送失败或最终出错后下一次一定开新段,重启后同样成立。
  • 历史检索:角色看到“(相关 N 条)”时,可以调用 related_messages 按某条消息查更早的相关聊天,或用 search_history 按关键词与语义检索(可按 ISO 时间或 YYYY-MM-DD 日期限定范围);每轮合计最多 3 次,每次最多 20 行,命中带前后各 2 行上下文,只查当前群/频道,已 /forget 的成员不会出现。关键词用 SQLite FTS5 trigram,语义用 sqlite-vec 向量(由 features.history 控制,默认开启,使用默认 embedding 模型;events 复用同一个模型)。升级前入库的旧消息要运行回填脚本才能被检索。
  • 看图与视频抽帧:每条消息最多 4 张图片,缩放到 1024×1024、200 KB 以内交给模型;视频用 ffmpeg 抽 1–3 帧。主模型不支持图片输入时,Pi 会把图片替换成一条省略说明;也可以配置 visionModel,先把图片描述成一两句文字。语音、文件、贴纸以 [语音]、[文件]、[贴纸 😀] 这样的文字占位。
  • 语音(可选):接入 Fish Audio 后,角色可以用中文、日语或英语发送带文字稿的 MP3。群友明确要求“用语音回复”时,最终回答也会转成语音。
  • 画图(可选):登录 Antigravity provider 后,角色可以在 send_reply 里放一个 image 部分,按群友的描述生成一张图发出(默认 Nano Banana 2 / gemini-3.1-flash-image,约十几秒)。登录方式见画图。注意:Google Antigravity 条款明确禁止用第三方工具调用 Antigravity OAuth,已有账号因此被封,建议使用小号。
  • 长文转图(可选):开启 textImage 后,文字回复超过 300 字(可配置)就不会发出,角色会被告知改用 send_reply 的 text_image 部分,把完整内容写成 Markdown 渲染成一张图发出:支持标题、列表、表格、代码块、LaTeX 公式($…$、$$…$$)、公网图片、函数图(函数、隐函数、参数方程、散点、3D 曲面),以及开启画图时由 AI 新画的插图。纯库实现,不需要浏览器。详见长文转图。
  • K 线图(可选):开启 kline 后,角色可以在 send_reply 里放一个 kline_image 部分,发出 Binance 现货交易对(如 BTCUSDT)的实时 K 线图(蜡烛图 + 成交量)。行情由 bot 从 Binance 公共接口取,模型只选交易对与周期,不写数字;纯库实现(手写 SVG + resvg),不需要浏览器。详见K 线图。
  • 联网搜索:配置 DEEPSEEK_API_KEY 后启用 DeepSeek 服务端联网搜索。消息里明确说“查一下”“搜索”时先搜再答,回答附来源链接;其他需要外部事实的问题,模型也可以自己调用搜索。
  • 计算:run_js 在短时子进程的 node:vm 隔离环境里运行小段纯计算 JavaScript,用于精确计算、日期运算和单位换算。必须在 Linux 上运行,并有可用的 bubblewrap(隔离文件系统、网络与 PID);启动时试运行一次,不可用就直接报错退出,没有回退。无新增配置;Ubuntu 启用见 docs/deploy.md,残余风险见 docs/architecture.md。
  • 成员记忆与 soul:按群记录名字、生日、本人明确说过的稳定信息,以及提及/回复形成的关系。成员记忆不会自动附在输入里,接话角色需要时调用 recall_member_memory 按聊天显示名回想(排除 bot 和已 /forget 的成员),这样历史更短、缓存更稳。角色会保存作者本人明确陈述的兴趣、角色、项目、时区、语言、目标与偏好,不会在群里复述完整档案或生日。每个角色在每个频道还有私人 soul,学到自身格式、语气、长度等稳定教训后先暂存,开新对话段或压缩成功后才转为正式内容。成员可随时 /forget。 何时保存、何时回想写在 system prompt 里:作者自述长期信息时先保存再回复(玩笑、一时状态、他人信息、敏感信息不存);被问到成员情况时先回想;查不到就说不记得,不编造。
  • 节日与生日祝福(可选):在指定频道、当地时间 09:00 之后发送生日祝福和中国/澳洲节日祝福;发送记录存在数据库里,重启不会重发。
  • 表情图:角色可以从内置的 4 张 PNG(hello、laugh、think、hug)或自己的本地 PNG/JPEG 图库里挑一张发出去(send_reply 的 reaction_image 部分),默认使用图库说明作配文;可按角色关闭。
  • 一次发几条:角色调用 send_reply 可以在一轮里按顺序发最多 4 条消息:文字、语音、新画的图、表情图、长文图(后四种每种最多 1 条),比如先发一张图再用文字或语音解释,或把回答分成几段。只有当前角色能用的种类才会出现在工具里。画图、渲染、合成语音等慢的部分并行准备,全部准备好才严格按顺序发出,只有第一条回复原消息;任一部分准备失败就一条都不发,角色改用文字;发到一半失败时已发出的留着、不重发,后面的不再发。文字与语音稿和普通文字回复一样经过内部标记检查、自然度审查和长度闸门。一句话说得完时角色仍直接写文字回复。
  • 默认不思考,省 token:reasoningEffort 默认 off;即使打开,已完成轮次的 thinking 也不会再发给模型。system prompt 和工具定义保持稳定,便于 provider 前缀缓存。
  • 固定身份与摘要边界:角色明确知道自己的名字、别名和已验证平台账号,接受路由交给它的回复轮次;媒体说明区分直接图片输入、可选辅助描述和占位,不编造处理流程。历史压缩摘要要求保留固定身份、只记确认事实并归因成员说法,不把助手猜测或过去拒绝固化为规则;风格教训仅在成员明确要求时保留。

架构一览 ​

一个监护进程、一个 bot 工作进程;工作进程内是一个对话核心、两个薄平台适配器。平台差异(格式、长度上限、表情集合)全部留在适配器里,核心只认 InboundMessage(进)和 PlatformTransport(出)。

设计原则体现
Pi 原生优先会话、窗口上限兜底压缩、模型目录与认证、图片降级都直接用 Pi
确定性优先于 LLM概率候选用可重放的 HMAC 抽样,冷却与占比用历史计算;内容判断只用有界决策请求,去重靠数据库主键
成本有界system prompt 与工具定义稳定以命中前缀缓存;动态内容只进消息;对话段按上限换新,种子只取最近 30 条,更早的靠检索;reasoning 默认关闭
隐私默认密钥只在 .env;日志自动脱敏,不记正文;成员可随时 /forget

完整数据流、表结构与 run_js 威胁模型见 docs/architecture.md。

BSD 2-Clause 许可