Agent Engineering 课程阅读
首页/课程十 · 常驻主动式 Agent/时段预算与常驻可观测:睡觉时的钱和心跳

在 GitHub 查看原文

本页目录

Lesson 07 — 时段预算与常驻可观测:睡觉时的钱和心跳

本课目标:管住常驻的最后两个风险——成本累积(每班都正常,一天 N 班加起来烧穿)和静默失败(进程死了,「没消息」被误读成「没变化」)。四件套:时段钱包、自适应扫描、心跳缺勤、日报。

学完你能回答面试官那句:「你的 Agent 半夜自己跑,怎么保证不烧穿账单?它死了你怎么知道?」


0. 起点:agent-ops 管不到的两件事

agent-ops L02 的钱包管一条轨迹——单次运行超预算会刹车。但常驻 Agent 一天自主跑 N 次,每次都在预算内,总量照样失控;agent-ops L07 的 run summary 是跑了才有——进程死了连 summary 都不出,没人问就没人发现。这两个风险都活在「轨迹之间」,是 L00 风险地图里成本累积与静默失败的最后收口。


1. 时段钱包:第三层预算

请求级(ops-L04 限流)      单次调用   —— 管 QPS
轨迹级(agent-ops L02 钱包)单次运行   —— 管这次别跑飞
时段级(本课)              一天 N 次  —— 管今天别烧穿

check_budget() 三态:ok(<80%)→ degrade(软线,该省着花)→ pause(硬线,今天到此为止)。关键的分层纪律:pause 挡的是下一班要不要开跑,不打断进行中的班次——进行中的自有轨迹钱包管,两层各自执法不越权。code.py Part 1 实录:

第3班花 2000 → 累计 10500/10000(105%)🛑 pause
第4班到点  → budget_paused(挡在门口,连 job 都不开)
次日到班   → researched(时段钱包按日翻篇)

每班结束,daemon 把轨迹钱包的 token_usage 记进当日总账(add_usage)——轨迹层的计量成为时段层的记账凭证,三层预算是串起来的,不是三套平行系统。


2. 自适应扫描:安静的信源不配每天扫

L02 证明了大多数日子「确认无变化」——那为什么还每天扫?note_scan_result 把每班的结局反馈给调度表:

  • 连续无变化streak+1,有效间隔 = 基础间隔 × min(2^streak, cap),下一班 = 本班 + 有效间隔;
  • 有变化:streak 归零,立即回到基础网格(mark_fired 已排好的班点);
  • 信源故障:streak 不动——「没能看到」既不证明世界安静(不该退避)也不证明有变化(不该回冲)。L02 的纪律在退避决策里再次生效。

🎯 核心认知:退避倍数取 2 的幂 → 班点仍落在 L01 的基础网格上(网格没被破坏,只是跳过一些格子);cap=8 保证最长 8 个基础周期必有一扫(退避不能退到「实际上不再盯了」)。取舍:退避省的是扫描成本(本来就便宜)+ 无变化研究判断成本,代价是变化发现延迟最坏拉长到 cap 倍——盯得越松,醒得越晚。cap 的紧松就是这两者的汇率。


3. 心跳与缺勤:安静和死了必须可区分

L04 教会 Agent 沉默——但沉默的系统和死掉的系统,从外面看一模一样。心跳把两者分开:

  • beat():daemon 每 tick 一笔(「我还活着」的最便宜证明——沉默是判断,心跳是证明);
  • check_absence():启动体检问「上次心跳距今多久」——超过 absence_alert_hours = 缺勤,alert 落箱:「缺勤期的世界变化没人看」。首次启动无心跳历史不算缺勤(没上过班谈不上旷工)。

这是 L02 纪律的服务级重演:内容层「没能看到 ≠ 没有变化」,服务层「没有通知 ≠ 一切正常」。局限的诚实标注:自己给自己测缺勤只能在「复活后」发现(死着的时候没人报警)——实时发现需要外部 watchdog(进程管理器健康检查 / 另一个进程盯心跳表),本课给了数据结构,外部盯梢留练习。


4. 日报:一天一行服务体检

📊 日报 2026-07-17 | 班次: 4成/0败/0待批 | 花费: 14000/200000 token(7%,4 班)
   | 打扰: 0立即+4摘要(配额尽降级 0)| 告警: 0 | 心跳: 4 tick | ✅

聚合四本账:班次(jobs)、花费(时段钱包)、打扰(inbox,含 quota_exhausted 审计)、心跳。与 agent-ops L07 的分层:run summary 是一次运行一行(轨迹体检),日报是一天 N 次运行一行(服务体检)。日报本身走 digest 通道投递——它是「今晚看」的内容,不配打扰。

⚠️ 诚实标注:jobs 的时间戳走真实时钟(agent-ops 资产不为本课改),日报按真实日期聚合;code.py Part 4 因此把 FakeClock 对齐到真实 now。


5. 流派对比:常驻的成本怎么管?

流派 做法 取舍
不管,月底看账单 云账单做事后审计 ✅ 零开发;🚫 发现即既成事实(L00 风险地图的原样)
压低单次预算 把轨迹钱包调小 ✅ 复用现有机制;🚫 量纲错了——单次 5k×一天 40 班照样 200k;且挤压正常班次质量
时段钱包 + 降频(本课) 日预算三态 + 无变化退避 ✅ 量纲正确(管总量)、退避从源头省(少跑班)、pause 有底线;🚫 多一张表多一层判断;变化发现延迟被拉长(cap 控制)
平台配额(API 供应商月限额) 供应商侧硬顶 ✅ 最后保险丝,必设;🚫 粒度太粗(全应用共享)、触发即全停——它该是兜底不是日常闸门

选 ③ + ④ 兜底:与 agent-ops L01 的「步数预算 + recursion_limit」同构——业务限位(可配、能收尾)在前,保险丝(粗暴、崩溃式)在后,永远不该靠保险丝过日子。


6. 跑起来

cd ambient-agent-lessons/07_period_budget
python code.py        # 零 API、零联网、零等待

7. 落地清单

文件 改动 如何验证
src/research_assistant/period_budget.py 新增:时段钱包(add_usage/check_budget 三态)+ 自适应扫描(note_scan_result)+ 心跳(beat/check_absence)+ 日报(build_daily_report) 见下
src/research_assistant/daemon.py 四处开关内接线:cycle 前预算门(pause→budget_paused);cycle 后记账;step 后心跳+退避反馈;startup 缺勤体检 pytest tests/test_daemon.py -q(17 个不回归)
src/research_assistant/config.py 新增enable_period_budget/period_budget_tokens/period_soft_ratio/enable_adaptive_scan/adaptive_backoff_cap/enable_heartbeat/absence_alert_hours(默认全关)
tests/test_period_budget.py 新增:17 个测试(累计与跨日/三态/退避封顶与回网格/failed 不动 streak/心跳/首启≠缺勤/日报聚合/daemon 四处接线) pytest tests/test_period_budget.py -q

验收

cd portfolio-projects/research-assistant
python -m pytest -q          # 306 + 17 = 323 passed
python -m pytest tests/test_period_budget.py -q   # 17 passed

8. 本课在两条主线上的位置

  • 倒置主线:第⑥环(谁守着它)收口——守夜从「人守着进程」变成「预算守钱、心跳守命、日报守账」。至此六个环节全部倒置完毕,L08 开始对着 L00 基线算总账。
  • 注意力经济主线:本课管的是这条主线的钱的一半:时段钱包给「睡觉时的钱」设硬顶,退避让安静的信源少花钱;日报把两种预算的消耗(钱 + 注意力配额)合并成一行可审计的账。

🎯 面试话术

「常驻 Agent 的成本我管三层:请求级限流管 QPS、轨迹级钱包管单次运行、时段级钱包管一天总量——单次都正常、总量烧穿的洞就是第三层补的。时段钱包三态:80% 软线提醒省着花,100% 硬线只挡下一班、不打断进行中的班次,两层预算各自执法不越权。再配自适应退避:连续无变化间隔翻倍封顶 8 倍,安静的信源从源头少跑班,一有变化立即回基础网格;信源故障不动退避——没能看到既不证明安静也不证明有变化。

它死没死怎么知道?daemon 每 tick 写心跳——沉默是判断,心跳是证明;重启体检时心跳缺口超阈值就发缺勤告警,『这两天的世界变化没人看』是显式信息。每天一行日报聚合班次、花费、打扰、心跳四本账,走摘要通道不打扰人。」