额度快用完时,最容易出现一种误会:只要当前 Agent 知道自己快停了,事情就算有准备了。可真正参与协作的人,往往不是当前这个 Agent,而是稍后被叫来的另一个 Agent。它不知道刚才发生过什么,也不知道应该去哪里找未完成的任务。
这次我遇到的就是这个问题。一个 Agent 发现自己的额度即将耗尽,我想知道,豆包、Codex、WorkBuddy 或未来接入的其他 Agent,能不能在秒级发现哪些会话被挡停,哪些任务还没有完成,以及这些任务是否可以交给别人继续。表面上,这是一个“怎么检测额度”的问题;后来我发现,真正要处理的是“检测结果能不能被发现、理解和交接”。
额度挡停不是最难的部分
一开始我以为,第一步应该去扫描所有会话转录,从大量文字里找“额度用完”“任务没做完”之类的句子。这个想法听起来保险,因为转录最完整。但它也意味着每个外部 Agent 都要重新理解目录结构、文件格式和上下文,速度慢只是次要问题,更大的问题是不同 Agent 会得到不同结论。
后来我沿着已有的续跑流程核对,发现额度挡停的信息早就写在本地的小型元数据里。客户端遇到用量限制时,会把错误写进一个固定格式的本地记录。检测程序只需要读取这些记录的错误字段,不必扫描完整的项目转录。一次扫描数百份文件,实际只用了数十毫秒,检测本身已经达到秒级。
额度信号的第一原则,是读取离事件最近、语义最明确的元数据,而不是把所有历史材料都翻一遍。
这个判断很重要。转录适合回答“任务做到哪里、为什么这样决定”,不适合承担每次额度探测的第一入口。把这两层混在一起,既浪费读取成本,也让状态判断依赖语言猜测。一个错误字段已经明确表达了“被用量限制挡停”,就不应该再用全文搜索去推断同一件事。
表面上有信号,实际上没人知道去哪里找
检测做快之后,我本来以为问题已经解决了一半。可当我站在外部 Agent 的角度再问一次,答案并不乐观:它知道这个 Agent 可能有额度限制,却不知道信号放在哪里,也不知道信号长什么样。即使本地已经生成了一份报告,如果报告藏在某个只有原 Agent 熟悉的位置,外部协作者仍然等于看不见。
这件事让我重新意识到,“已经生成”不等于“可以发现”。跨平台协作需要一个不依赖私下记忆的固定入口。于是我沿用了已有的未完成会话契约:每个 Agent 在约定的位置提供一个最新的机器可读快照,同时提供一份方便人阅读的文本说明。外部 Agent 不需要了解内部实现,只要知道去读这个 well-known 快照,就能先判断有没有被挡停的会话。
快照里最关键的不是一大段描述,而是稳定的字段。顶层保留用量限制造成的阻塞数量;下面列出对应会话,并给出会话标识、标题、工作目录、挡停时间、是否已经到可恢复时间,以及后续动作线索。字段名一旦稳定,调用方就可以用同一套逻辑接入不同 Agent,而不必为每个平台写一套猜测规则。
跨平台契约的价值,不是让所有 Agent 内部实现一样,而是让它们在边界上说同一种话。
我还保留了一份 Markdown 版本。它不是机器判断的真相源,却很适合直接贴进派工消息或让人快速浏览。机器需要固定字段,人需要能读懂的上下文,两种输出共享同一份扫描结果,才不会出现“JSON 说有任务,说明却没有对应内容”的漂移。
交接必须带着任务线索走
发现“有一个会话被挡停”之后,下一问自然是:接手者怎么知道该做什么?只给一个标题不够。标题可能很短,甚至只是临时命名;只给工作目录也不够,因为目录里可能有多个计划、多个草稿和多轮尝试。
所以我把交接拆成了几类线索。第一类是原始转录的定位,让接手者能够回到真实对话,而不是依赖二手摘要。第二类是工作目录,让它知道相关文件在哪个范围内。第三类是任务规格的线索,例如目录中的计划文件,让接手者先读原始要求,再判断哪些已经完成、哪些仍然欠着。
这里最容易误判的是,交接信息越多越好。把整个会话目录、所有历史文件都塞进快照,确实看起来完整,但接手者反而要重新筛选。真正有用的交接,不是复制全部材料,而是指出最短的上下文入口:先读哪份任务规格,需要时再读哪条原始转录,最后到哪里验证结果。
好的交接信号不是替接手者完成判断,而是把判断所需的第一批证据放到手边。
如果不处理这一层,外部 Agent 即使准确发现了额度挡停,也只能得到一个模糊警报。它可能重复派发同一个任务,可能从错误的文件开始,也可能因为找不到原始上下文而放弃接手。信号存在,却没有把任务带到可行动的位置,这种“可发现”仍然是不完整的。
能发现,不代表能恢复
接下来我专门核对了权限边界。最容易犯的错误捷径,是把“外部 Agent 能读到信号”直接等同于“外部 Agent 能替原会话继续运行”。这两个能力完全不同。
原会话的恢复动作依赖它所在的桌面会话和专用的消息入口。其他 Agent 即使能读取快照,也没有权限直接向那个原会话发送续跑指令。它们能做的是发现、判断和派发:知道某个会话被额度挡停,知道任务线索在哪里,再决定是否唤起合适的恢复入口,或者由自己的 Agent 按计划接手。
我选择把这条边界明确写进交接说明,是因为模糊承诺比明确限制更容易造成任务丢失。如果系统声称“可以恢复”,使用者自然会期待一次调用就能继续;实际却只能读到状态,最后就会把权限问题误判成信号失效。把发现、派发、恢复分开,反而让每个参与方知道自己真正能做什么。
这也回答了“自己能不能恢复”。当前会话还活着时,可以在自己的权限范围内处理其他会话;但如果当前会话本身已经彻底耗尽额度,它不能靠自己发出下一条消息。此时真正有价值的不是期待它自救,而是在尚有能力时留下信号,让下一次启动或另一个 Agent 能够接上。
用刷新和门禁让信号不靠记忆
有了固定快照,还要解决新鲜度问题。只在额度出问题时手动生成一次,仍然容易忘记;只在任务结束时更新,又可能错过中途挡停。我的做法是把信号生成挂到 Agent 的启动门禁上:每次新会话开始时顺手刷新一次,刷新失败也不阻塞正常开工。
另外,我把“能不能派活给这个 Agent”单独做成了一个轻量的预检查。它只返回两类结果:GO 表示当前没有发现用量阻塞,可以继续派发;HOLD 表示应该暂停派发,改走接手或恢复路径。这样,派发方不必先解析完整快照,就能在真正派活的地方做一次保守判断。
这个决策背后有一个取舍。共享索引解决的是“信号在哪”,预检查解决的是“现在能不能派”,两者不能互相替代。只有索引,没有触发点,能力会安静地躺在磁盘上;只有预检查,没有稳定索引,发现问题后仍然不知道该去哪里取上下文。
一个成熟的交接机制,至少要同时解决发现入口、状态判断和后续权限这3件事。
一套可以复用的交接规则
回头看,这次形成的方法并不依赖某一个 Agent。它可以被整理成一套更小的规则。
第一,为每种 Agent 提供固定位置的最新快照,并统一阻塞状态的字段命名。第二,检测优先读轻量元数据,完整转录只在需要补上下文时读取。第三,快照同时提供机器格式和人类可读格式,但两者必须由同一次扫描生成。第四,每条未完成记录至少带上原始转录、工作范围和任务规格线索。第五,在派发动作前增加 GO/HOLD 预检查,避免把新任务派给已经被用量挡停的会话。第六,把发现、接手和原会话恢复写成不同权限,不用一个模糊的“可恢复”覆盖全部情况。
这套规则的核心不是多建几个文件,而是把交接从临时说明变成稳定契约。未来增加新的 Agent 时,它不需要理解所有旧系统,只要遵守同一套快照、退出结果和线索字段,就能被发现层收录。外部调用方也不需要猜每个平台的目录,只读统一索引,再按条目决定下一步。
这件事让我重新意识到,额度耗尽并不只是一个运行时错误。它还暴露了一个协作系统是否成熟:失败发生后,系统能不能留下足够清晰的痕迹,让别人不用依赖原作者的记忆继续工作。真正难的不是把“我停了”写出来,而是把“我停在哪里、为什么停、谁能接、谁不能直接恢复”说完整。
下次我会怎么做
下次再为一个 Agent 设计跨平台信号,我会先问4个问题:外部调用方去哪里找?它能否在秒级得到机器可读结果?发现后是否有最短的任务上下文?它拥有的是观察、派发还是恢复权限?这4个问题任何一个没有答案,我都不会把功能称为完成。
我也会把检查顺序固定下来:先读轻量状态源,再核对统一快照;发现阻塞后,补齐原始转录、工作范围和任务规格线索;派发前跑一次 GO/HOLD;最后明确接手方式和恢复边界。这样做的好处,不是把流程变得复杂,而是避免每个新 Agent 都从零猜一遍。
一个流程成熟的标志,不是它在额度充足时能顺利跑完,而是它在被挡停时仍然能把下一步交给别人。我真正想留下的不是一条“额度用完了”的通知,而是一份可发现、可判断、可接手,同时诚实说明权限边界的交接信号。