Jev
Jev 是 TypeSafe 的“System One”决策模型:不生成文字,只对结构化问题返回校准过的概率。远程决策接口也可以换成 OpenAI Decisions API(jev.provider: "openai",模型 gpt-6-luna):问题完全相同,是非题以 predicate 发送、选择题以 choice 发送,是非题的判断标准并入说明文字,拒答按调用失败处理。精魅用同一个决策客户端做接话判断、最终文字审查、表情、记忆排序,以及可选的话题归属与参与度判断。
接话判断(replyDecision,默认 true)。明确 @、回复、名字/别名命中时直接路由,不请求接话判断。其他人类消息在启用且有客户端时各发一次请求:带上发言者,从当前空间的全部角色与 none 中判断是否在对某个角色说话。没有点名时只有明显在回应角色刚说的话才算(角色刚发过言不算),拿不准选 none;选中角色的概率 ≥ 0.5 时直接路由,不受抽样与门控限制,秒回表情也视它为被点名。
- 普通接话候选仍按累积
routingP的 HMAC 抽样产生。角色当前平台账号最近 30 秒发过任何消息则冷却;最近 10 分钟最多 30 条消息中,该账号至少 3 条、其他不同作者多于 1 人且该账号占比 ≥ 25% 时也不主动接话。 - 只有抽样且未被门控的候选才在同一次请求中附带
chat_in的 noul 评分问题,评分 ≥replyThreshold(默认0.7)才接话。即使没有候选或被门控,仍判断内容指向;调用失败记participation_failed和错误类别,不让任何角色接话。关闭或没有客户端时,只用 HMAC 抽样与门控。
最终文字审查。发送最终文字(或把它转换成明确要求的语音)前,先检查 §E 后跟数字、[当前事件 等内部标记,命中直接判为不通过,不请求审查。有客户端时再用 noul 评分自然度:分数 < 0.5 不通过;用户明确要求总结、梳理或列时间线时,应要求做的复述算自然正文。
- 重写一次:每轮第一次不通过不会直接沉默。自然度不过时再问一次决策模型原因(复述群聊、写作规划、列草稿、其他),按原因给角色一句具体的修改提示(标记泄漏则提示去掉标记),让它重写;记
reply_rewrite。最终文字通过隐藏的jingmei_audit_gate_v1消息告知并触发重写;send_reply则在工具结果里告知,本轮不结束,角色可以再调一次或改发文字。重写照常审查。 - 仍不通过:整条回复不发,改发固定的一句
(系统提示:说了不该说的东西被捂嘴了)(回复原消息、入库),记不含正文的reply_withheld;最终文字还会持久保存隐藏的jingmei_withheld_v1标记。下轮 provider 投影去掉被拒的草稿、重写提示与被扣留的回复,避免把未发送内容当历史。 - 审查调用失败:内容指向和概率接话不重写、静默扣留(
audit_failed,没有判断就不说“说了不该说的”),明确 @、回复、名字路由则放行。没有客户端时只做标记检查。
send_reply 在准备任何部分前做同样的审查:所有文字部分与语音稿合在一起审查自然度,配文与长文图 Markdown 也做内部标记检查。只有图片、表情图的纯媒体回复不请求自然度审查。
秒回表情(quickReactions)。每条有文字的人类消息发一次 Jev 请求,同时问三件事:从表情表里选一个(或 none)、这条消息情绪是否强烈、是否好笑。
- 点名的消息(@、回复、叫名字或内容判断选中 directed 角色):由对应角色点上选中的表情,Jev 选
none时不点。 - 普通消息:只有 max(情绪强烈, 好笑) ≥
threshold,并且该频道距上一次这样的表情已超过minIntervalMs才点;由该群配置顺序里第一个角色来点。处于限频期的消息连 Jev 都不调用。 - 与主回复并行,失败只记日志,不影响回复。开启后,主模型不再注册
react_to_message工具,表情完全交给 Jev。
记忆排序(memoryScoring)。角色按需调用 recall_member_memory 时,把候选事实和关系(每人最近 20 条事实、最强 16 条关系)一次性交给 Jev 与当前消息比对相关度,每人保留最相关的 5 条事实和 4 条关系。Jev 不可用时退回按时间和互动次数排序。
本地包装与回退。jev.apiKeyEnv 有值时先调用 jev.endpoint;配置了本地 LLM 时,远程调用任何失败都会回退一次到进程内 notjev 包装器。没有远程 key 时直接用包装器,不另起 HTTP 服务。“本地”指包装器在进程内运行,其 LLM 可以是远程 DeepSeek。省略 localJev、有 DEEPSEEK_API_KEY 且没有远程 key 时,默认连接 https://api.deepseek.com 的 deepseek-flash;配置了远程 key 时这个默认不生效,也就没有回退,要回退须显式写 localJev;显式 localJev 完全覆盖这个默认,省略其 apiKeyEnv 即不带鉴权。
包装器默认超时 30 秒,关闭 DeepSeek thinking(thinking.type=disabled);LLM 必须返回 logprobs,缺失会作为 invalid_response 调用失败处理。模型弃答时取概率最大的选项(argmax)。
秒回表情和记忆排序仍须显式配置 jev 段落;仅配置 events 或仅有 DeepSeek key 不会开启它们。接话判断默认开启,有共享决策客户端即可运行;最终文字审查也在有客户端时运行,不受 replyDecision 开关控制。jev 可省略 apiKeyEnv,这时使用本地包装器,但必须有可用的本地 LLM(localJev 段落或 DEEPSEEK_API_KEY),否则是配置错误。完全不写 jev 段落时退回确定性路由与标记检查。显式填写的 apiKeyEnv 若在 .env / 进程环境中缺失,仍是配置错误,不会悄悄回退。包装器调用按所选 LLM 的费用计费。
成本。远程 Jev 只按输入 token 计费,输出免费(撰写时 jev-1.13 为每百万 token $0.042,以官方价格为准)。一次表情请求只包含当前消息、最多 5 行近期聊天(每行截断到 200 字符)和三个问题,通常只有几百 token;远程请求超时 3 秒。它不消耗主模型的 token;本地包装器则消耗其配置的 LLM token。
接话判断启用且客户端可用时,每条未明确点名的人类消息额外 +1 次决策请求(内容指向与可选接话分数合并),每条最终文字回复额外 +1 次自然度审查(不通过时再 +1 次原因判断,重写后再 +1 次审查);明确点名省掉接话请求,内部标记命中省掉审查请求。这些调用不使用主回复模型,但本地包装器按其 LLM 计费;远程失败回退可能额外调用一次本地 LLM。
配置。在 .env 写 TYPESAFE_API_KEY: …,在 jingmei.config.json 加(用 OpenAI 时改为 "provider": "openai"、"apiKeyEnv": "OPENAI_API_KEY",并省略 endpoint 与 model 以使用其默认值):
"jev": {
"endpoint": "https://api.typesafe.ai/v1/systemone",
"apiKeyEnv": "TYPESAFE_API_KEY",
"model": "jev-latest",
"quickReactions": true,
"memoryScoring": true,
"replyDecision": true,
"replyThreshold": 0.7,
"threshold": 0.8,
"minIntervalMs": 60000
}| 字段 | 默认 | 说明 |
|---|---|---|
provider | typesafe | 远程接口格式:typesafe 或 openai |
endpoint | https://api.typesafe.ai/v1/systemone | 远程 Jev 的 http(s) URL;openai 默认 https://api.openai.com/v1/decisions |
apiKeyEnv | 无 | 远程 key 的环境变量名;省略则仅使用本地包装器 |
model | jev-latest | 也可固定版本,如 jev-1.13.0;openai 默认 gpt-6-luna |
quickReactions | true | 秒回表情 |
memoryScoring | true | 记忆排序 |
replyDecision | true | 内容感知接话判断;关闭仍保留确定性抽样门控与最终文字审查 |
replyThreshold | 0.7 | 取值 (0, 1],普通抽样候选接话所需的最低分 |
threshold | 0.8 | 取值 (0, 1],普通消息点表情所需的最低分 |
minIntervalMs | 60000 | 同一频道两次“普通消息表情”之间的最短间隔 |
emojis | 平台默认表 | 按平台覆盖表情表:{ "discord": { "👍": "赞同" }, "telegram": { … } };不能使用保留键 none |
默认表情表(表情 → 交给 Jev 的含义):
| 含义 | Discord | Telegram |
|---|---|---|
| 赞同、收到 | 👍 | 👍 |
| 好笑 | 😂 | 🤣 |
| 难过、破防 | 😭 | 😭 |
| 暖心、感谢 | ❤️ | ❤ |
| 疑问、不确定 | 🤔 | 🤔 |
Telegram 自定义表情表中不在 Bot API 允许集合里的表情会被丢弃并记一条警告。
话题配置
"events": {
"summaryModel": "deepseek/deepseek-flash",
"embeddingModel": "fast-bge-small-zh-v1.5"
}回复某条已有话题的消息时,直接沿用该话题,不调用决策模型(bot 消息同理,未回复的 bot 消息无话题)。去掉 [贴纸 …]、[视频 N帧]、[文件] 等裸媒体占位后不足 2 个字母/数字的人类消息,并入 10 分钟内最近活跃的话题。其余人类消息在有候选话题时由决策客户端选择归属:短回复、追问和情绪反应倾向延续正在进行的话题;决策选“新话题”但其概率低于 0.6 时,改归概率最高的现有话题。最近 2 小时有消息的话题视为活跃,每次最多提供 5 个活跃话题、2 个同频道向量召回的旧话题,以及“新话题”选项。累计消息数达到 3、6、12、24……时,后台生成/刷新标题描述、参与度与向量;同一事件只同时刷新一次,不阻塞频道处理。摘要使用独立的 summaryModel;话题说明只在触发回复的那一轮附在消息后面,下一轮起不再留在历史里,也不写入 system prompt。
话题摘要要求中性地描述正在讨论或玩的内容:接梗仍是接梗,不评价成员行为,不给角色安排管理任务,也不保留与话题无关的成员隐私。
