Aeria
GitHub
改 · 3.20

定时跑的那些事

最后核对 2026-10-08对应提交 4dc8009依据 bot.py · maintenance_heartbeat.py · config.py

消息进来时跑的是对话那一条路;没人说话的时候,作息、主动找人、补看、学习、清理这些事由每个人格一条「维护循环」按顺序跑。这一篇讲它跑哪几步、各自多久一次、卡住了怎么知道、加一步要注意什么。

本页 5 节
  1. 一轮
  2. 卡住、死掉
  3. 加一步
  4. 对应的代码
  5. 没做到的

一轮

每个人格一条维护循环(bot.py 里 ticks 那一段)。一轮按顺序走完下面十三步,到了时间再做一次重清理,然后睡一会儿再来:间隔是 min(60, max(5, [conversation].state_retention_seconds / 4)) 秒,默认 60 秒。

每一步自己决定这一轮要不要真的干活:大部分步骤在实例上记着上次跑的时刻,不到点就直接返回。

步骤 做什么 自己的节奏
生命周期 认知内核的作息和活动往前走一步:困了没有、该不该睡、活动开始、结束(3.17) 每轮
时间线 生活引擎手上的活动、睡眠、梦、发呆同步进人生时间线,只写变了的(3.16) 每轮
承诺和里程碑 过期三天的承诺记成没做到;最近两天聊过的人,算有没有新的关系里程碑 10 分钟
记忆隐私检查 群的空间里混进了私聊来源的记忆,收紧成只在私聊里想得起来 6 小时(启动后第一轮就查)
群聊门槛 按每个服务器最近 14 天插话的下场,重算群聊过滤的偏置 10 分钟
补回 醒着、网好了:不在时没看到的话挨个回头看一眼 每轮(有要补的才干活)
学习补课 私聊里攒下没学过的消息,每轮最多开一个学习任务,走后台额度 每轮
外联扫描 主动找了人、等够了还没回的,结掉,变成心情和印象 10 分钟
冲动 有没有突然想起谁、想起了要不要说;整步不调用模型(3.18) 5 分钟
社交自检 便宜的一道检查;过了才为一个人调一次模型 默认 20 分钟
跟进 认领一个到时间的联系计划,照常过回复的几道关发出去 每轮,一次最多一个
环境主动 认知内核在状态允许时开一次口 每轮,一次最多一个
记忆核心 重试没写成的、补向量、第一次启动时迁旧记忆、睡着时巩固(3.15);重的活放到后台任务里 补写 5 分钟;巩固睡着时 6 小时、醒着最多 24 小时一次

重清理,六小时一次(每次启动的第一轮也跑):按保留期清聊天记录([conversation].message_retention_days = 30、每个频道最多 messages_per_channel = 5000 条,人生时间线里和人有关的跟着走)、记忆的生命周期、中期记忆、运营事件、外联、念头、语义审议的记录。每一项各自兜底,一项失败不拖累后面几项。

卡住、死掉

维护循环有两种坏法,日志里都是一片安静:某一步抛了异常没人接,循环就此结束;某一步 await 了一个永远不回来的东西,循环停在那一行。src/aeria/maintenance_heartbeat.py 管这两件事:

加一步

  1. 写一个 async def _<名字>_tick(self, monotonic_now: float):先看离上次跑够不够久,不够就返回;把上次跑的时刻记在实例上(参照 _commitment_milestone_tick)。
  2. 在 ticks 里加一行:中文名(心跳和看门狗打的就是它)、调用、失败时的日志。顺序有讲究:要读生活引擎最新状态的,排在「生命周期」后面。
  3. 重的活(迁移、建索引、跑模型)放进 asyncio.create_task,在实例上记着任务,下一轮看它跑完没有(参照 _hmc_tick)。不要让一步一跑就是几十秒:后面的步骤都在等它。
  4. 一步里最多调一次模型,而且要有自己的额度和间隔:维护循环每分钟一轮,不设间隔的模型调用一天就是一千多次。

对应的代码

没做到的