buddyMe 心跳系统与 Loop 引擎:让 AI 自己干活,还不花钱

admin · 2026-05-11 · architecture · heartbeat · loop · 科普 · 树状分支结构流程图

如果 AI 永远不需要休息,会怎样?

想象一下:你有一个 AI 助手,它不光在你聊天的时候才工作。你睡觉了,它还在默默帮你整理笔记、查天气、同步数据——就像一个从不疲倦的私人秘书。

但问题来了:如果让 AI 每隔 30 分钟就执行一次任务,每次都要调用大模型,一个月下来光是 Token 费用就能让你的账单"心跳加速"。

buddyMe 的解决方案很有创意——它设计了一套"心跳系统"来管理后台任务,又发明了一个"Loop 引擎"来实现"录制一次,永久回放"。两个系统配合,把周期性任务的 Token 成本砍掉了 99% 以上。

先看一张全景图,对整个架构有个直觉:

  心跳系统 (后台调度)
         |
         | tick 触发
         v
  Loop 引擎 (录制 & 回放)
         |
    +----+----+
    |         |
    v         v
  有 Skill   无 Skill
    |         |
    v         v
  确定性回放  LLM 执行
  零 Token   降级兜底
    |         |
    +----+----+
         |
         v
      任务完成

一、心跳系统:AI 助手的"自主神经系统"

为什么需要心跳?

你身体的自主神经系统不需要你"想"就能运转——心跳、呼吸、消化,全自动。buddyMe 的心跳系统做的事也类似:让 AI 在后台自动执行一些重复性任务。

比如:

如果没有心跳系统,这些任务要么得你手动触发,要么得写复杂的定时脚本。有了它,AI 真正变成了一个"自己会干活"的助手。

双层设计:数据归数据,执行归执行

心跳系统的设计遵循了一个经典的工程原则:分而治之。它把整个系统分成了两层:

  Agent 主进程
       |
       v
  [调度执行层]  Agent.tick()  --->  工具 / LLM / Loop 回放
       |
       v
  [数据管理层]  HeartbeatManager
       |
       v
  heartbeat.json (配置 & 任务状态)

这就像公司里的分工:HR 只管人员档案(数据层),项目经理负责安排工作(执行层)。谁也不越界,出了问题好排查。

所有配置,一个文件搞定

心跳系统把所有的任务配置存在一个叫 heartbeat.json 的文件里。长这样:

{
  "config": {
    "interval_minutes": 30,
    "active_hours": {"start": "08:00", "end": "23:00"}
  },
  "tasks": [
    {
      "id": "memory_update",
      "name": "记忆更新",
      "interval_minutes": 30,
      "enabled": true,
      "last_run": "2026-05-10T14:30:00"
    }
  ]
}

翻译成人话就是:每 30 分钟检查一次,但只在早上 8 点到晚上 11 点之间工作(毕竟你也不想 AI 在凌晨 3 点疯狂写日志吧)。

两种触发方式:闹钟 vs 计时器

心跳系统支持两种任务触发方式,就像手机上的两种提醒:

模式像什么怎么工作适合做什么
Interval(间隔模式)计时器:每隔 30 分钟响一次距离上次执行够了 30 分钟就触发周期性任务:记忆更新、数据同步
Schedule(定时模式)闹钟:每天早上 9 点响到了指定时间(±5 分钟容忍度)就触发,每天最多一次每日固定任务:早间提醒、日报生成

心跳节拍:每 60 秒的一次"脉搏"

心跳系统的工作方式特别简单:起一个后台守护线程,每 60 秒做一次检查(叫一次 tick())。每次 tick 就像一次脉搏:

  tick() 开始
      |
      v
  加载 heartbeat.json
      |
      v
  在活跃时段? (08:00-23:00)
      |
      +-- 否 --> 跳过, 等下次
      |
      是
      |
      v
  遍历所有任务 <-------------------+
      |                             |
      v                             |
  该执行吗? (_should_run)           |
      |                             |
      +-- 否 --> 下一个任务 -------->+
      |                             |
      是                            |
      |                             |
      v                             |
  执行任务                          |
      |                             |
      v                             |
  原子更新 last_run                 |
      |                             |
      +----> 下一个任务 ------------>+

几个关键的安全设计:

二、Loop 引擎:录制一次,永久回放

一个关键洞察

Loop 引擎的发明来自一个简单的观察:

"同一个定时任务,AI 每次调用的工具序列几乎一模一样,变的只是参数。"

举个例子——每 30 分钟查天气:

步骤工具第一次第二次
1获取当前时间2026-05-10 14:302026-05-10 15:00
2查天气北京 晴 25°C北京 多云 22°C
3写入文件天气日志+14:30数据天气日志+15:00数据

看出来了吗?操作流程完全一样,只是"时间"和"天气数据"不一样。

那为什么要每次都让大模型重新"想"一遍呢?这就好比你已经知道做蛋炒饭的步骤了,不需要每次都翻菜谱。Loop 引擎做的就是:第一次让 AI 认真做一遍并"录下来",之后按录像"回放"就行。

四个阶段:创建 → 录制 → 生成 → 回放

  /loop 30m         AI 执行         提取模板         按 skill.json
  查天气      -->   + 录制    -->   生成 skill  -->   零Token执行
  (创建任务)        (录制阶段)      (生成阶段)        (回放阶段)

阶段一:创建

你只需要说一句话:

/loop 30m 每30分钟查天气

系统会自动创建一个心跳任务,标记为"等待首次执行"。

阶段二:录制

第一次执行时,系统会让 AI 正常完成任务,但会同时录制它的每一步操作:

录制的工具链 (tool_chain):
Step 1: bash    -> "date ..."          -> "2026-05-10 14:30:00"
Step 2: bash    -> "python weather.py"  -> "北京 晴 25°C 南风3级"
Step 3: write_file -> weather_log.txt   -> "写入成功"

这就像在厨房里架了一台摄像机,把厨师做菜的全过程拍下来。

阶段三:生成

录制完成后,系统会自动分析工具链,把其中"每次都会变"的部分提取出来,替换成模板变量:

原始值模板变量含义
2026-05-10 14:30:00{{current_time}}每次执行时的真实时间
北京 晴 25°C 南风3级{{step_1_result}}上一步(查天气)的真实结果
文件原有内容{{prev_content}}读取文件时的当前内容

最终生成的 skill.json 就是一个"菜谱"——告诉你每一步该用什么工具、传什么参数。

阶段四:回放

从第二次执行开始,心跳系统检测到有现成的 Skill 文件,就完全不经过大模型了。它直接按 skill.json 里的步骤,一步步调用工具:

  tick 检测到 Loop 任务
      |
      v
  skill.json 存在?
      |
      +-- 否 --> 降级为 LLM 执行 (Token ~1000)
      |
      是
      |
      v
  加载 Skill 步骤
      |
      v
  替换模板变量
  ({{current_time}}  -> 真实时间)
  ({{step_N_result}} -> 真实结果)
      |
      v
  调用工具
      |
      v
  还有步骤? -- 是 --> 回到 "替换模板变量"
      |
      否
      v
  返回结果, Token 消耗 = 0
  1. 用真实的当前时间替换 {{current_time}}
  2. 执行天气查询,拿到真实结果替换 {{step_1_result}}
  3. 把结果写入文件

整个过程零 Token 消耗。

省多少钱?算一笔账

以"每 30 分钟查天气"为例:

传统方式(每次调 AI)Loop 回放方式
每次 Token 消耗~500-20000(首次 ~1000 后不再消耗)
每天执行次数48 次48 次
每天 Token 消耗~24,000~1,000(仅首次)
每月 Token 消耗~720,000~1,000
节省比例—99.86%

一个任务就能省这么多。如果你有 5 个、10 个定时任务呢?Loop 引擎的价值就非常明显了。

为什么禁止 edit_file?

Loop 引擎在录制时有一个特殊规则:拒绝使用 edit_file 工具。

原因是 edit_file 需要"精确匹配"文件中的某段文字才能编辑。但回放时文件内容可能已经变了,之前录制的匹配文本找不到了,就会出错。

解决方案很简单:用 read_file(读取)+ write_file(整个写入)来替代。每次先读取最新内容,拼接修改后再完整写入,这样就不依赖精确匹配了。

万一出了问题?降级策略兜底

系统设计了完善的"安全网",确保任何情况下任务都不会丢:

  异常发生
      |
      v
  什么情况?
      |
      +--> 录制失败 / 工具链不合格
      |        |
      |        v
      |    不生成 Skill
      |        |
      |        v
      |    后续 tick 走 LLM 执行
      |
      +--> 首次执行超时
      |        |
      |        v
      |    清除 pending 标记
      |        |
      |        v
      |    后续 tick 走 LLM 执行
      |
      +--> 回放步骤出错
      |        |
      |        v
      |    本次跳过
      |        |
      |        v
      |    下次 tick 重试回放
      |
      +--> 用户执行 /loop --remove
               |
               v
           删除任务 + Skill 文件, 终止
发生了什么系统怎么办
首次录制失败(工具链不合格)不生成 Skill,以后每次用 AI 正常执行
首次执行超时清除标记,降级为 AI 执行
回放过程中某一步出错本次跳过,下次心跳再试
用户主动删除(/loop --remove)同步删除任务和 Skill 文件,干净利落

核心原则:宁可用 AI 执行,也不让任务中断。

三、完整生命周期:一张图看懂

一个 Loop 任务从创建到结束的完整流程:

  用户输入: /loop 30m 查天气
      |
      v
  写入 heartbeat.json (标记: 等待首次执行)
      |
      v
  后台线程首次执行: AI 完成 + 录制工具链
      |
      v
  校验工具链
  (非空? 无 edit_file? 有 write_file? 无错误?)
      |
      +-- 合格 --> 生成 skill.json
      |                |
      |                v
      |            后续 tick: 确定性回放 (Token = 0)
      |                |
      +-- 不合格 --> 不生成 Skill
                       |
                       v
                   后续 tick: LLM 执行 (Token ~1000/次)
                       |
                       v
               用户: /loop --remove
                       |
                       v
               删除任务 + Skill 文件, 干净退出

四、工程亮点:不止是能用,还要稳

原子写入:断电也不怕

所有文件写入都采用"先写临时文件 → 确认写入完成 → 重命名覆盖"的方式。就算写入过程中突然断电,也不会产生半截损坏的文件。这就像寄快递:先把东西包好、确认无误,再贴地址寄出。

Skill 三层加载:按需取用

  L1 基础层               L2 指令层              L3 执行层
  (元数据, ~100 Token) --> (SKILL.md, 按需) --> (skill.json, 零Token)
  名字 / ID               详细指令               回放步骤

日常运行只走 L3,完全不碰 L1 和 L2,最大程度节省资源。

总结

buddyMe 的心跳系统和 Loop 引擎,其实回答了一个关键问题:

"怎么让 AI 在后台持续工作,还不把钱花光?"

  怎么让 AI 后台持续工作, 还不把钱花光?
      |
      +--- 心跳系统 (稳定可靠的后台调度)
      |    "像身体的自主神经, 不用你操心也能运转"
      |
      +--- Loop 引擎 (录制一次, 永久回放)
      |    "像学会做菜, 不需要再翻菜谱"
      |
      +--- 降级策略 (任何情况都不掉链子)
           "像信号差时自动切 2G, 慢但不断线"
      |
      v
  7x24 不间断服务, 账单不会心跳加速

这种"第一次认真学,之后自动重复"的思路,不仅适用于 AI 助手,对任何需要定期执行重复任务的系统都有参考价值。

最终效果:buddyMe 智能体既能响应你的实时请求,又能在后台默默帮你处理重复工作——真正的 7x24 小时不间断服务,而且账单上不会让你心跳加速。

一句话引用:buddyMe 如何通过"录制一次,永久回放"的 Loop 引擎,把周期性任务的 Token 成本砍掉 99% 以上?用最通俗的语言拆解心跳系统与 Loop 引擎的设计原理。