长时间 AI 任务最让人不安的,往往不是失败本身,而是沉默。
人类这边做完家务、买完东西、吃完饭再回来,AI 还显示“工作中”。这时有两种完全不同的可能:
- 它正在认真跑一个巨大的测试套件。
- 它几个小时前就已经卡住了。
仅靠加载动画无法区分这两种情况。长时间没有 commit 也不能证明已经停止,因为测试、调查、比较、生成或等待外部系统时,本来就可能暂时没有新产物。
因此,长时间 AI 除了智能,还需要可观测性(observability)。
1. 结论――只要任务可能持续较长时间,就应该暴露“现在在哪里”
长时间 Agent 不应该只在最后汇报结果。中间状态也应该能被人读取。
不需要每分钟喊一次“我还活着”。真正需要的是能回答:
- 现在在做什么
- 已经完成什么
- 还剩什么
- 是否正在测试
- 是否被某个问题阻塞
- 最近一次确认仍在运行是什么时候
- 最近一次真正发生代码或产物变化是什么时候
一个实务配置示例是:大约 10 分钟没有可见产物时更新一次 Heartbeat;Heartbeat 超过 20 分钟没有更新时,不直接判定为“停止”,而标记为 STALE_UNKNOWN。
沉默首先意味着“无法确认”,而不是“已经失败”。
2. 为什么只看 commit 不够
Git commit 非常适合记录实际变化,却不适合单独承担存活确认。
一个持续一小时的回归测试可能完全正常,却一个 commit 都没有。反过来,如果为了证明“还活着”每 10 分钟提交一个毫无意义的 Heartbeat 文件,只会把历史记录变成垃圾场。
最好分开:
Heartbeat = 当前状态
Material change = 代码、合同、产物或验证结果真正改变的证据
分别记录 lastHeartbeatAt 和 lastMaterialChangeAt,就可以准确理解“30 分钟没有 commit,但 5 分钟前仍处于 TESTING”的情况。
目标不是增加 commit 数量,而是让“沉默”有意义。
3. 至少应该记录哪些字段?
长时间 run 建议记录:
runId:本次任务唯一 IDstate:RUNNING / BLOCKED / COMPLETED / STALE_UNKNOWN 等phase:READING / IMPLEMENTING / TESTING / VERIFYING 等workingOn:当前具体工作startedAtlastHeartbeatAtlastMaterialChangeAtbranch / baseSha / headSha / PRcompletedMilestones / remainingMilestonesblockerstestsnextCheckpoint
有了这些信息,六小时任务就不再只是“六小时神秘黑箱”,而可以被读成:
IMPLEMENTING → TESTING → INTEGRATING → VERIFYING
再聪明的黑箱,也还是黑箱。时间一长,人自然会焦虑。
4. 测试阶段尤其需要 Heartbeat
长测试在外观上和“AI 卡死”几乎一模一样。
开始长测试前,可以记录:
phase = TESTING- 测试名称
- 测试范围
- 如果总量固定,就写
84 / 127这样的真实数字 - 当前是否出现 failure
不要随便写“完成 82%”这种气氛型数字。设计和调试剩下的 18% 到底是什么,通常没人知道。
比例只在分母客观固定时有意义:
- 84 / 127 tests
- 3 / 5 acceptance gates
“实现完成 82%”就是 AI 版的“我快到了”——一问位置,可能还在家。
5. “是不是停了?”最好分阶段判断
一个实务 Heartbeat 策略可以这样分类:
| Heartbeat 距今时间 | 解读 |
|---|---|
| 0–10 分钟 | CURRENT |
| 10–20 分钟 | HEARTBEAT_OVERDUE |
| 超过 20 分钟 | STALE_UNKNOWN |
STALE_UNKNOWN 不等于 FAILED。
之后按顺序查看:
- 当前进度记录
- Check / Status
- branch / PR
- 最新 commit
- 最后才进行推测
如果 Heartbeat 旧了,但后来出现了新 PR 或新 commit,往往表示“工作还在继续,只是忘了更新状态”。
AI 也会发生:活干了,日报忘了写。
6. 不要这样管理进度
不要把 Heartbeat 专用 commit 堆到 main
会污染历史、增加并发冲突,还可能触发无意义的 CI 或部署。更适合用可更新的 Issue comment、Check、Status 或非生产 ops 区域。
不要每次 Heartbeat 都新建评论
一个 run 对应一个可更新记录更易读。每 10 分钟多一条评论,最后会变成考古现场。
不要把沉默直接判成失败
仅仅 Heartbeat 过期时,应使用 STALE_UNKNOWN。只有存在明确失败证据时才使用失败状态。
不要把秘密写进进度日志
API key、token、password、私有 URL、原始私聊、个人信息、机密文件内容都不应进入进度日志。
不要因为可观测性渠道坏了就把安全工作也全部停掉
进度 API 失败时,应该降级到其他 sink;可以安全继续的工作仍然继续。
7. 一个实用模板
State: RUNNING
Phase: TESTING
Run ID: agent-20260916-long-task
Started: 10:00
Last heartbeat: 14:05
Last material change: 13:42
Branch: feat/long-task
Head SHA: abc1234
PR: #123
Working on:
- regression tests
Completed:
- runtime implementation
- contract update
Remaining:
- regression completion
- merge verification
- production readback
Blockers:
- none
Tests:
- 84 / 127 passed so far
- no failure observed
Next checkpoint:
- finish regression, then integration
仅仅这些信息,就足以把“是不是停了?”变成“原来在测试”。
进度可视化的目的并不是催 AI,而是避免人类因为不确定而重复启动、打断流程或重复下达同一个命令。
8. 总结――长时间 AI 要把“聪明”和“看得见”分开设计
长时间任务需要明确区分:
- 没有 commit ≠ 停止
- 有 Heartbeat ≠ 有实际进展
- Heartbeat 过期 ≠ 失败
- 一个 blocker ≠ 全局停止
- 测试时沉默 ≠ 睡着了
如果 AI 可以工作六小时,人不应该被迫盯它六小时。
更好的设计是:任何时候回来查看,都能立刻知道它现在在哪里。
理想的长时间 Agent 不是一直说话的 Agent。
它可以安静工作,但只要你看一眼,就知道它走到哪一步了。

