指南

调整唤醒行为

三种触发来源、wait 条件声明,与 standard、willingness、jev 的配置

唤醒引擎决定 runtime 在什么时候开始一轮。输入提交与开启轮次是两条路径:消息到达只负责写入事实流,是否因此开启轮次由引擎判断;接口也允许引擎自己计时,在没有新输入时按计划运行。

profile 的 wakeup 段选择变体并给出参数,缺省为 standard。

醒来由谁触发

  1. 模型声明的等待条件。上一轮用 wait 声明「再等 N 条新入站事件」或「等 T 秒」,条件满足即开启轮次。
  2. 唤醒引擎。引擎在 attach(agent) 之后自行决定运行时机。内置变体都在消息提交后判定;自定义引擎可以按时钟、外部日程或其他信号开启轮次。
  3. 外部唤醒。扩展或持有 runtime 的宿主代码调用 runtime.wake(prompt?),例如一次性的提醒或主动消息。

三者各自计时、各自触发,任一满足就醒来。入站消息总会写入事实流(提交完成以 message.appended 为准),没有触发只表示没有开始新一轮;消息保存在事实日志中,等下一次醒来一并处理。

声明等待:wait 工具

wait 是常驻工具,由模型直调。它不进入 codemode 沙箱,也不受 direct 名单影响。模型在某一轮里用它声明下一次自动唤醒的窗口:

wait({ msgs: 3, secs: 60 })

Prop

Type

msgs 与 secs 可以同时给出,先到者生效。语义:

  • 一次性声明。触发一次即作废,没有周期,也不写事实流。runtime 重启后不会恢复未触发的声明。
  • 收尾动作。调用它的那一步结束后本轮不再继续,条件在轮末生效。一轮里多次调用以最后一次为准;secs 的计时从条件生效时开始。
  • 只在以 done 收尾的轮次生效。轮次以 failed 或 aborted 结束时,声明被丢弃。
  • 计数来自提交。轮内到达的消息已经进入本轮上下文,不会继续计入新窗口;如果声明时这批消息已经达到 msgs,条件会在轮末立即触发,使已达到条件的输入及时进入下一轮。
  • 不调用等同于不排定唤醒。之后能开启轮次的只有唤醒引擎与外部唤醒,没有 profile 默认值兜底。
  • 返回值回显真正生效的窗口。没有有效窗口(空调用或 {msgs: 0})时返回 none: true,明确告诉模型这一轮之后没有排定自动唤醒。

怎么选

默认的行为指引给了几条建议:先看上下文和未回应的输入;对方可能还在打字就稍等一拍;话题不属于自己就保持沉默;被点了名但没内容,也可以继续等。

落到 wait 上:

场景声明
一句话可能还没说完、@ 了但没内容{msgs: 1, secs: T},T 在群聊里取短些,私聊里长些
话题与自己无关不调用,让被点名这件事把自己带回来
正常对话,说完了{msgs: 1, secs: T} 等着对方接话,或不声明

输入保持待回应状态,每次醒来都会被重新考虑。没有排定唤醒时保持沉默,是合法结果。

唤醒引擎收到的输入

runtime 负责把入站事件写进事实流,引擎在提交之后观察它们。

  • runtime.deliver(event) 是纯摄取:捕获附件,然后 agent.send(event, { trigger: false, ifBusy: "join" }),成功投递后返回。有轮次正在运行时消息接入当前轮,在该步输出之后提交;空闲时持久化在后台进行。返回不代表已经落盘,提交完成以 message.appended 为准。
  • 提交后,core 在 message.appended 上通知订阅者。内置变体在 attach(agent) 里订阅这条通知,自行过滤:同一批通知里还混着工具目录、附件与模型输出。
  • 引擎认定该开启轮次时调用 agent.continue()。自动唤醒不传文本时,模型看到的是已有历史。
  • 订阅回调会被 core 等待。长耗时的判定要另起任务并捕获错误,不能堵在提交路径上。
  • 开启轮次前检查 agent.isIdle(),延迟或异步判定返回后再检查一次。忙碌时等待、重试还是跳过,由引擎自己的策略决定。

wait 条件与 runtime.wake(prompt?) 是另外两条独立来路,它们直接调用 core 的 continue,不经过唤醒引擎,引擎的规则也无法拦下它们。

三种内置变体

以下三种变体在消息提交后判定,适合配置消息驱动的触发策略。

按固定规则判定,不额外调用模型

standard 引擎按四条规则判定:

wakeup:
  engine: standard
  standard:
    direct: true          # 私聊必醒
    atSelf: true          # 被 @ 必醒
    quoteSelf: true       # 引用回复 bot 的消息必醒
    keywords:             # 消息包含任一关键词必醒
      - neko
      - 喵酱

四条规则独立生效,命中任一即唤醒。三个开关都设为 false、keywords 留空后,引擎不再主动开启轮次,消息仍会进入事实流;此时能开启轮次的只剩 wait 条件与外部唤醒。

默认值:direct、atSelf、quoteSelf 均为 true,keywords 为空。

自主调度

需要按日程或固定间隔自主运行时,可以编写唤醒引擎:在 attach 里维护计时器或读取外部日程,到点检查 agent.isIdle() 后调用 agent.continue()。完整示例见引擎系统:写一个自主调度的唤醒引擎。

runtime 按需创建,计时器从引擎的 attach 开始。当前平台接入在首次输入路由到该频道时创建实例。扩展也可以在自己的定时器里调用 runtime.wake(),适合一次性的提醒或主动消息;未提供原因或原因只含空白时,运行时写入 Continue. 作为开场内容。作为 profile 的长期运行节奏时,写成唤醒引擎更容易替换与配置。

验证与排错

修改 profile 后重启插件生效。验证 standard:空闲时发一条私聊消息应立即唤醒。验证 jev 的兜底规则:空闲时,命中 rules 的私聊消息应直接开启轮次。验证 jev 的模型判定:关闭 rules.direct 与 rules.atSelf,发送一条完整、明确的请求,观察 debug 日志中的 wakeup jev 判定结果与模型调用。验证 willingness:连续普通消息后再 @ 一次,观察是否开口;willingness 不输出引擎日志,可以临时打开 atMentionForce,或调低 probabilityThreshold 观察触发情况。验证 wait:让模型声明 wait({ secs: 5 }),之后不再说话,5 秒后应看到它自己开了一轮;debug 日志会出现 wake: timer 5s expired。等待条件只活在内存里,重启后不会恢复。

常见问题:

  • jev 判定提示模型不存在或类型错误:检查 models.yaml 是否存在 wakeup.jev.model 指向的条目,并把模型声明为 type: decision。
  • jev 判定永远不醒:检查模型接口是否可达、threshold 与 addressedThreshold 是否过高;冷却期、连续回复预算与参与比例也会让引擎保持安静。模型调用固定使用 8 秒超时。
  • rules 写成 jev 的同级段不生效:兜底规则必须写在 jev: 段内部。
  • 消息进来却迟迟没有回应:可能还在 wait 声明的窗口里,也可能被引擎的冷却期或概率跳过。消息已在事实流中,下一次醒来会一并处理。
  • 它再也不自动醒来了:上一轮可能没有排定 wait,或轮次以失败结束导致声明被丢弃;引擎规则、冷却期与外部唤醒仍按各自条件生效。
  • 它几乎从不用 wait:行为指引没有讲清何时声明,或提示词要求等到「轮末」才声明。检查 persona 是否覆盖了默认指引;也可以让模型调用一次不带参数的 wait(),回显会直接说明这一轮之后没有排定唤醒。
  • 想让它按时间自主运行:内置变体不含定时调度,写一个自定义唤醒引擎,见上文「自主调度」。

On this page