Core Insight: 只在被问到时才回应的 Agent 是聊天机器人;按时间表、按事件、主动行动的 Agent 才是生产力系统。
为什么需要定时任务?
大多数人把 Agent 当作对话界面——你输入,它回复。这种心智模型把价值上限定在了"更快的搜索引擎"。真正的解锁发生在 Agent 不被要求也能执行工作时。
对比一下:
- 被动式: "帮我总结未读邮件。" → Agent 回复。
- 定时式: 每天早上 8:00,Agent 读取收件箱,按紧急程度过滤,格式化日报,推送到你的 Slack 频道。你醒来时看到一份从未请求过的简报。
第二种模式会复利。一个定时任务每天省你五分钟。十个定时任务重塑你的工作方式。定时任务将 Agent 从一个你使用的工具变成一个为你工作的系统。
本章介绍在 Harness(托管 Agent 的 Tool、Context、Memory 和执行生命周期的 Runtime 环境)中实现定时 Agent 工作的原语。
定时 Agent 工作的类型
并非所有自动化都遵循相同的节奏。四种模式覆盖了全貌:
One-Shot Timer(一次性定时器)
单次延迟执行。用户说"20 分钟后提醒我"或"下午 3 点发那封跟进邮件"。Harness 创建一个定时器,触发一次,然后丢弃。
关键特性:
- 仅触发一次
- 通常在对话中创建("提醒我……")
- 短周期——分钟到小时,很少到天
- 不需要循环逻辑
One-Shot Timer 是最简单的调度原语。只需一个时间戳和一个载荷。
Recurring Cron(循环 Cron)
Cron(得名于 Unix cron 守护进程)是按 Cron 表达式定义的重复计划运行的任务——一种指定分钟、小时、日、月和星期几的紧凑语法。
示例:
0 8 * * *→ 每天 08:000 9 * * 1→ 每周一 09:00*/30 * * * *→ 每 30 分钟
Cron 是 Agent 自动化的骨干。日报、周报、周期性监控——都是 Cron 的领地。
Event-Triggered(事件触发)
并非所有调度都基于时间。有些工作应该响应外部事件触发:
- 新的 Pull Request 被打开 → 生成 Review Agent
- 部署完成 → 运行冒烟测试并报告
- 来自 VIP 发件人的新邮件 → 总结并告警
事件触发自动化需要事件源(Webhook、轮询或平台集成)和一个在事件触发时创建 Agent Turn 的分发机制。Harness 在这里不按时钟运行——它按信号运行。
Heartbeat-Based(心跳式)
Heartbeat 是一种周期性轮询,Harness 按固定间隔(通常每 15-60 分钟)向 Agent 的主 Session 注入一个 Prompt。Agent 读取 Prompt,决定检查什么,然后行动或保持沉默。
与创建隔离执行的 Cron 不同,Heartbeat 在进行中的对话内运行。Agent 可以访问最近的消息、用户 Context 和 Session 状态。这使 Heartbeat 非常适合将多个轻量检查批量合并到单轮中。
典型的 Heartbeat Prompt:
Read HEARTBEAT.md if it exists. Follow it strictly.
If nothing needs attention, reply HEARTBEAT_OK.
Agent 可能检查邮件、看看日历、查看通知——全在一轮中完成,全都有对话 Context。
Cron 实现模式
Cron 是最结构化的调度原语。正确实现需要关注四个维度:调度定义、Session 目标、载荷类型和交付。
调度定义
Cron 表达式 使用标准五字段格式:
┌───────── 分钟 (0–59)
│ ┌─────── 小时 (0–23)
│ │ ┌───── 日 (1–31)
│ │ │ ┌─── 月 (1–12)
│ │ │ │ ┌─ 星期几 (0–7, 0 和 7 = 周日)
│ │ │ │ │
* * * * *
时区处理 是 Cron Bug 最常见的来源。规则很简单:
存储 UTC。显示本地时间。
内部,Harness 按 UTC 评估所有 Cron 表达式。向用户展示计划时,转换为本地时区。当用户说"每天早上 8 点",Harness 必须知道哪个 8 点——如果不知道就询问时区,存储 UTC 等价值,用本地时间确认。
用户:"每天早上 8 点跑我的日报"
Agent:"好的——每日日报 8:00 AM Asia/Shanghai(UTC 0:00)。✓"
这避免了歧义,也能正确处理夏令时转换(对于实施夏令时的时区)。
Session 目标
当 Cron 触发时,Agent 在哪里运行?两种模型:
隔离 Session —— Cron 生成一个独立的 Agent Turn,拥有全新的 Context Window。没有对话历史。没有之前的消息。Agent 从干净状态开始,执行任务,然后终止。
优点:
- 无历史污染——主 Session 保持干净
- 可预测的 Context——Agent 只看到 Cron 提供的内容
- 可并行化——多个 Cron 任务可以并发运行互不干扰
- 可配置——每个任务可以使用不同的 Model 或 Thinking 级别
隔离 Session 适用于独立任务:日报、报告、监控检查、数据采集。
主 Session —— Cron 将内容注入用户当前活跃的 Session。Agent 看到完整的对话历史,可以引用最近的消息。
优点:
- 对话 Context——Agent 知道你一直在讨论什么
- 连续性——可以跟进之前的话题
- 更低开销——不需要创建新 Session
谨慎使用主 Session 注入。每次注入都会增加 Context Window,过多会膨胀(见下方反模式)。
载荷类型
Cron 触发时究竟交付什么?
agentTurn —— 触发完整的 Agent 执行周期。Agent 收到 Prompt,可以访问所有 Tool 和 Skill,能做决策、调用 API、读文件、产出输出。这是最强大的载荷类型。
例如:日报 Cron 用 agentTurn 载荷触发。Agent 通过 IMAP 读邮件,检查日历,获取天气,格式化为简报,推送到频道。完全自主。
systemEvent —— 向 Session 注入一条文本消息,但不触发完整的 Agent Turn。可以理解为往对话里丢一张便条。Agent 会在下一轮(或 Heartbeat)时看到它,但不会立即行动。
例如:Webhook 收到部署通知,注入"Deploy v2.3.1 部署成功"作为 systemEvent。Agent 不需要行动——但如果用户问起,信息是可用的。
交付
结果去哪里?
- Announce to channel —— Agent 的输出被推送到特定消息频道(Slack、Discord、飞书群等)。这是日报和告警最常见的交付方式。
- Webhook —— 结果被 POST 到 HTTP 端点,用于与外部系统集成。
- None(静默) —— Cron 运行但不产出外部输出。适用于后台维护任务如 Memory 清理或数据预取。
交付配置应在 Cron 创建时设置,并绑定到发起 Session。如果用户在飞书群创建 Cron,结果应交付到那个群——而不是追随用户到他们最近聊天的地方。
实际案例
LangSmith Deployments Cron
LangChain 的 LangSmith 平台为其 Deployments 功能引入了 Cron 任务(参见 LangSmith Cron Jobs 文档)。模型:
- 创建一个 Deployment(托管的 LangGraph Agent)
- 定义 Cron 计划
- 每次触发时,系统创建一个新 Thread 并发送固定输入
这种方法干净且可预测。每次执行获得相同输入、全新 Thread,并在 LangSmith 的监控 UI 中产出可追踪的输出。
优势:
- 简单的心智模型——相同输入,全新 Thread,每次如此
- 通过 LangSmith Trace 的完整可观测性
- 与 LangGraph 的状态管理集成
局限:
- 每个 Cron 固定输入——无法根据 Context 动态调整 Agent 行为
- 每次执行一个 Thread 意味着运行之间没有连续性
- 绑定 LangSmith 的 Deployment 基础设施
Harness 原生 Cron
Harness 模式提供更丰富的模型:
- 用计划、Session 目标、载荷和交付定义 Cron
- 每次触发时,Harness 生成一个隔离 Session(或注入主 Session)
- Agent 拥有完整的 Tool 访问——可以读文件、调用 API、搜索网页、使用任何已安装的 Skill
- 结果交付到配置的频道
# 概念性 Cron 定义
schedule: "0 8 * * *" # 8:00 AM UTC
timezone: "Asia/Shanghai" # 显示参考
session: isolated # 每次运行全新 Context
payload: agentTurn # 完整 Agent 执行
model: claude-sonnet # 可不同于默认
delivery:
type: announce
channel: feishu-group-abc # 绑定到发起 Session
prompt: |
生成今天的早间简报:
1. 检查未读邮件中的紧急事项
2. 列出今天的日历事件
3. 总结过夜的 GitHub 通知
格式化为简洁日报。
与 LangSmith 的关键区别:
- 动态 Prompt——Agent 决定做什么,而非仅处理固定输入
- 完整 Skill 访问——可使用 Harness 提供的任何 Tool
- 按任务选择 Model——简单检查用便宜 Model,分析用强 Model
- 灵活交付——频道、Webhook 或静默
日报模式
最常见的 Cron 用例。流程:
Cron 触发(本地 8:00 AM)
→ Agent 在隔离 Session 中生成
→ 读邮件(IMAP Tool)
→ 读日历(Calendar Tool)
→ 查天气(Weather Skill)
→ 查 GitHub 通知(GitHub Skill)
→ 格式化日报,标注优先级和要点
→ 推送到用户首选频道
→ Session 终止
价值乘数:这每天都运行,不管用户记不记得去问。信息到达时已预处理和格式化。
监控模式
一个检查指标并仅在阈值被突破时告警的 Cron:
Cron 触发(每 15 分钟)
→ Agent 检查 API 响应时间
→ 与阈值对比(p99 < 500ms)
→ 如果健康:静默(不交付)
→ 如果降级:向运维频道发告警并附详情
→ Session 终止
关键设计选择:异常告警,而非每次检查都推送。 每 15 分钟推送"一切正常"的监控 Cron 是噪音。保持沉默直到出问题的才是信号。
Heartbeat vs Cron:何时使用哪个
Heartbeat 和 Cron 都能实现周期性 Agent 工作。它们服务不同目的。
| 维度 | Heartbeat | Cron |
|---|---|---|
| 时间精度 | 近似(允许漂移) | 精确(按计划触发) |
| Context | 主 Session(完整历史) | 隔离(全新 Context) |
| 每轮检查数 | 多个(批量) | 单任务聚焦 |
| Session 影响 | 增加主 Context Window | 不影响主 Session |
| 配置方式 | 编辑 HEARTBEAT.md | 显式 Cron 定义 |
| Model | 使用 Session 的 Model | 可按任务指定 |
使用 Heartbeat 当:
- 你想把 3-5 个轻量检查(邮件 + 日历 + 通知)批量合并到一轮
- Agent 需要对话 Context 来判断什么重要
- 时间精度不重要(大约每 30 分钟就行)
- 你想通过合并周期检查来减少总 API 调用
使用 Cron 当:
- 精确时间很重要("每周一早上 9:00 准时")
- 任务应在隔离环境中运行,不污染主 Session
- 你想为任务使用不同的 Model 或 Thinking 预算
- 输出应交付到特定频道,不碰主 Session
- 一次性提醒("20 分钟后提醒我")
经验法则: 如果你有五件事要周期检查且都不要求精确时间,把它们放在 HEARTBEAT.md 里,而不是创建五个 Cron 任务。如果你有一个任务必须在精确的早上 9 点用特定 Model 运行并交付到特定频道,那就是 Cron。
反模式
轮询循环
# ❌ 不要这样做
while True:
result = check_something()
if result.changed:
notify()
sleep(60)
这会占用持久进程,浪费计算资源,并绕过 Harness 的调度基础设施。改用 1 分钟间隔的 Cron。Harness 管理生命周期、重试和资源清理。
主 Session 污染
向主 Session 注入过多 systemEvent 会膨胀 Context Window。每次注入都增加 Token。经过一天的频繁注入,Agent 的 Context 被系统噪音主导,而非有用的对话。
症状: Agent 响应变慢,变得不连贯,或丢失对话主题。
修复: 高频工作使用隔离 Session。将主 Session 注入保留给罕见的、高信号的、用户需要在 Context 中看到的事件。
无超时
可以无限运行的 Cron 任务是资源泄漏。如果 Agent 卡住了(等待 API、陷入推理循环),任务会永远挂起。
修复: 每个 Cron 任务都应有超时。合理默认值:简单任务 2-5 分钟,复杂任务 10-15 分钟。如果任务无法在超时窗口内完成,应该大声失败——而非静默挂起。
重复交付
# ❌ Cron announce 到频道,同时 Agent 也手动发消息
delivery:
type: announce
channel: slack-general
prompt: |
检查指标并把结果发到 #general # Agent 也发了!
如果 Cron 配置为 Announce 结果到频道,而 Agent 的 Prompt 又指示它向同一频道发消息,用户会收到相同内容两次。
修复: 选择一种交付机制。要么让 Harness Announce,要么让 Agent 手动发送——绝不同时使用。
设计清单
在创建任何定时 Agent 工作之前:
- 时区 —— 你知道用户的时区吗?如果不知道,问。
- Session 类型 —— 需要对话 Context(主 Session)还是干净执行(隔离)?
- 交付 —— 结果去哪里?绑定到发起 Session。
- 超时 —— 最大可接受运行时间是多少?
- 失败模式 —— 任务失败怎么办?静默?告警?重试?
- 频率 —— 这个更适合做 Cron 还是 HEARTBEAT.md 条目?
- 去重 —— 你确定结果不会重复交付吗?
做对这七点,你的定时 Agent 工作将是可靠的、可预测的、真正有用的。
总结
定时任务是把对话新奇感和生产力系统区分开来的关键。Harness 提供四种原语——One-Shot Timer、Recurring Cron、Event Trigger 和 Heartbeat——各适合不同的自动化形态。
架构选择很重要:存储 UTC,显示本地时间。默认隔离 Session。设置超时。将交付绑定到发起频道。将轻量检查批量合并到 Heartbeat 而非生成多个 Cron。
一个按计划、按自己的主动性行动、不需要被要求的 Agent——那不再是聊天机器人。那是基础设施。