news 2026/9/10 3:19:55

Heartbeat Tasks

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Heartbeat Tasks

Heartbeat Tasks

【免费下载链接】OpenVikingSelf-evolving Context Database for AI Agents. Unify Agent Memory, Knowledge RAG and Skills.项目地址: https://gitcode.com/GitHub_Trending/op/OpenViking

Active Tasks

Completed

三个区块各司其职: - **`# Heartbeat Tasks`**:文件主标题,同时是空内容判定时被跳过的标题行(见下文 `_is_heartbeat_empty` 的过滤逻辑); - **`## Active Tasks`**:待执行的周期性任务列表,用户在此行下方添加任务条目; - **`## Completed`**:已完成任务归档区。模板注释明确给出两种维护方式——把已完成任务移动到该区,或直接删除。 ## 二、心跳服务的运行原理 ### 2.1 一次完整的心跳周期 HeartbeatService 的核心逻辑在 [bot/vikingbot/heartbeat/service.py](https://link.gitcode.com/i/ed0292dadc72c74d5a92e8a26285cc54) 中。服务启动后进入异步循环 `_run_loop`:每经过 `interval_s` 秒休眠,调用一次 `_tick()` 执行单轮巡检: ```python async def _run_loop(self) -> None: while self._running: try: await asyncio.sleep(self.interval_s) if self._running: await self._tick() except asyncio.CancelledError: break except Exception as e: logger.exception(f"Heartbeat error: {e}")

_tick()是单轮巡检的核心,其流程可以概括为"收集工作区 → 读取任务清单 → 唤醒 Agent → 判定结果"四步:

  1. 通过_get_all_workspaces()枚举所有可巡检的会话工作区;
  2. 对每个工作区调用_read_heartbeat_file()读取其中的HEARTBEAT.md
  3. _is_heartbeat_empty()判定清单是否"无可执行内容",为空则跳过该工作区;
  4. 对非空清单调用on_heartbeat回调,把预置提示词与heartbeat元数据交给 Agent,最后用is_heartbeat_noop_response()判定返回值是否代表"无操作"。

2.2 预置提示词与 HEARTBEAT_OK 协议

每次唤醒 Agent 时,服务注入的固定提示词定义在源码常量HEARTBEAT_PROMPT中:

Read HEARTBEAT.md in your workspace (if it exists). Follow any instructions or tasks listed there. IMPORTANT: Use the 'message' tool to send any results or updates to the user. If nothing needs attention, reply with just: HEARTBEAT_OK

这条协议规定了心跳轮次中 Agent 的两个行为出口:

  • 有可汇报的更新:使用message工具主动把结果发送给用户;
  • 无事可做:原样回复令牌HEARTBEAT_OK

服务端对回复做宽松匹配。normalize_heartbeat_response()会把响应内容去掉首尾空白、转大写、并剥离下划线与空格:

def normalize_heartbeat_response(content: str | None) -> str: if not content: return "" return content.strip().upper().replace("_", "").replace(" ", "")

随后is_heartbeat_noop_response()将其与规范化后的HEARTBEAT_OKHEARTBEATOK)比对。因此HEARTBEAT_OKheartbeat_okHEARTBEAT OK等变体都会被识别为无操作响应,容错性较好。Agent 循环在 bot/vikingbot/agent/loop.py 中结合消息元数据里的heartbeat标记,跳过对这类无操作响应的常规记录,避免心跳轮次污染会话历史。

2.3 空文件判定逻辑

_is_heartbeat_empty()实现了对"无任务"的保守判定。它逐行扫描内容,跳过以下几类行后若仍无有效内容,即判定为空:

  • 空行;
  • #开头的标题行;
  • <!--开头的 HTML 注释行;
  • 空复选框条目:- [ ]* [ ]- [x]* [x]

这意味着默认模板(只有标题、注释和空复选框)被视为"空清单",心跳会直接跳过该工作区,不会白白消耗一次模型调用。反过来,只要清单中出现任何一行实质任务文本,Agent 就会被唤醒。

三、配置文件与运行参数

3.1 HeartbeatConfig 配置项

心跳的启停与间隔由 bot/vikingbot/config/schema.py 中的HeartbeatConfig定义:

class HeartbeatConfig(BaseModel): """Heartbeat service configuration.""" enabled: bool = True interval_seconds: int = 10 * 60 # Default: 5 minutes

对应到配置文件即bot.heartbeat.*前缀。根据 README_CN.md 的配置总表:

配置默认值说明
bot.heartbeat.enabledtrue是否周期检查HEARTBEAT.md
bot.heartbeat.interval_seconds600心跳间隔

需要说明的是,配置 schema 层的默认值是 600 秒(10 分钟);而 heartbeat/service.py 中作为服务构造参数兜底的DEFAULT_HEARTBEAT_INTERVAL_S = 30 * 60(30 分钟)。实际生效值取决于装配时传入的配置——CLI 装配逻辑(见下)总是显式传入config.heartbeat.interval_seconds,因此线上行为以配置值为准,默认即 600 秒。

3.2 CLI 装配链路

心跳服务在 CLI 启动流程中被组装,见 bot/vikingbot/cli/commands.py 的prepare_heartbeat()

async def on_heartbeat( prompt: str, session_key: SessionKey | None = None, metadata: dict | None = None, ) -> str: return await agent_loop.process_direct( prompt, session_key=session_key, metadata=metadata, ) heartbeat = HeartbeatService( workspace=config.workspace_path, on_heartbeat=on_heartbeat, interval_s=config.heartbeat.interval_seconds, enabled=config.heartbeat.enabled, sandbox_mode=config.sandbox.mode, session_manager=session_manager, )

关键点是on_heartbeat回调直接复用了 Agent 主循环的process_direct,因此心跳唤醒的本质上就是一次"定向注入提示词的 Agent 执行",与普通对话共用同一套工具与安全边界。启动时控制台会打印✓ Heartbeat: every {interval}s或禁用提示(commands.py)。

四、工作区枚举与跳过规则

4.1 会话与工作区的映射

_get_all_workspaces()通过session_manager.list_sessions()枚举会话,再根据沙箱模式解析每个会话对应的工作区路径:

  • shared模式:所有会话共享workspace / "shared"目录下的同一个 HEARTBEAT.md;
  • 其他模式:调用resolve_workspace_path()(位于 bot/vikingbot/utils/session_paths.py)按会话维度解析独立工作区。

4.2 三类被跳过的会话

_get_all_workspaces()_is_session_stale()的实现可以归纳出三类不会触发心跳的会话:

  1. 显式禁用:会话元数据中带skip_heartbeat: true则跳过。设置入口在 bot/vikingbot/session/manager.py 的get_or_create(key, skip_heartbeat=False);Agent 主循环在创建会话时对 CLI/直连会话默认开启跳过(loop.py 中session_key.type == "cli");
  2. 长期不活跃:会话的updated_at/created_at距当前超过STALE_SESSION_THRESHOLD = timedelta(days=2)即视为失活(service.py);
  3. 空任务清单:HEARTBEAT.md 不存在或_is_heartbeat_empty()判定为空。

这类"三级跳过"保证了心跳只在确有任务、确有活跃用户的工作区上消耗模型预算。

五、Heartbeat 与 Cron 的边界

心跳机制常与定时任务混淆,TOOLS.md 与 02-agent-capabilities.md 均明确了两者的分工:

维度CronHeartbeat
触发方式at(一次性)、every_seconds(固定间隔)、cron_expr(日历表达式)周期读取HEARTBEAT.md
精度精确时间点/间隔尽力而为(best-effort),不适合精确到秒的提醒
适用场景一次性提醒、固定时刻任务持续巡检一组可能变化的任务
内容来源调度时指定任务工作区中的HEARTBEAT.md文件

同一份文档还给出了使用边界:只有用户明确要求"持续周期检查"时才应修改 HEARTBEAT.md;任务指令应当具体、安全、幂等,过时任务要及时移除而非永久悬挂。这正呼应了模板中"Move completed tasks here or delete them"的维护约定。

六、实战:编写你的心跳任务清单

在活动 Workspace(首次使用时从 bot/workspace 模板复制)中编辑 HEARTBEAT.md,把周期任务写入## Active Tasks区块。一个可直接套用的示例:

# Heartbeat Tasks ## Active Tasks - [ ] 检查工作区临时目录,删除超过 7 天的构建产物 - [ ] 汇总最近 24 小时来自各渠道的待办消息,通过 message 工具汇报 - [ ] 巡检 OpenViking 资源索引,标记失效资源 ## Completed <!-- Move completed tasks here or delete them --> - [x] 清理上周的过期日志(已完成,2026-09-01)

【免费下载链接】OpenVikingSelf-evolving Context Database for AI Agents. Unify Agent Memory, Knowledge RAG and Skills.项目地址: https://gitcode.com/GitHub_Trending/op/OpenViking

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 3:19:50

2026随身WiFi选购指南:格行/波导/中兴信号调校与稳定性横评

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/10 3:18:50

lib60870-2.2.0源码深度解析:IEC 60870-104协议栈分层实现与故障调试

简介&#xff1a;本资源是lib60870-2.2.0开源C库的完整源代码分发包&#xff0c;面向电力自动化、工业通信领域的嵌入式开发工程师与协议栈学习者&#xff0c;用于快速构建符合IEC 60870-5-101/104标准的SCADA系统通信模块。包内共120个文件&#xff0c;涵盖41个C实现文件&…

作者头像 李华
网站建设 2026/9/10 3:17:36

从硬件到备份:自组四盘位家庭NAS完整实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/10 3:17:29

算子融合与计算图优化:突破AI芯片内存墙的关键技术

开头先从一次硬件迁移的经历切入。当时我负责把一个视觉模型从GPU服务器搬到某款端侧NPU上&#xff0c;GPU上用TensorRT推理&#xff0c;算子执行时间分布相对均匀&#xff0c;瓶颈基本就在Conv大算子身上。换到NPU上以后&#xff0c;同样的网络&#xff0c;BatchNorm、ReLU、A…

作者头像 李华