21|生产可观测性与可靠运行:Trace、队列、取消和恢复
目标:从一次完整任务轨迹找到真正瓶颈,并定义可运行的故障策略。不是要求每个本地脚本都建设分布式观测平台。
本章目录
沿着对象与状态理解本章
排队、执行、重试、取消以及恢复共同构成等待时间,Trace应显示这些因果关系。
下方图解的固定输入在“输入与适用条件”中声明。它用于解释本章机制,不与本章其他独立例子的数值暗中接续。
Trace要告诉你因果,不只是时间戳
为何优化一个最显眼的步骤,整体却没变快?
执行轨迹像工程里的时间账,但更重要的是依赖关系。串行阶段会相加,并行阶段往往取关键路径;只有知道下一步在等谁,才能知道哪里值得优化。还要把排队、推理、工具、验证和重试分开,不能全算成模型慢。
输入与适用条件:固定教学秒数,无真实产品耗时数据。第4帧只改变工具A时长,其他条件保持不变。
1 / 5 · 先看一条完整任务
窄屏可左右滑动图形,或点击“放大图形”。文字解释紧随图后。
构造的任务从0到16秒:排队2秒、第一次模型3秒、并行工具A3秒/B8秒、第二次模型2秒、核验1秒。
基准墙钟16秒;工具工作量11秒默认静止。用“下一步”看完解释再继续;播放到最后一步自动停止。键盘聚焦播放器后,可用左右键逐步查看、空格播放/暂停。图中颜色辅助区分,含义同时用文字注明。
为什么需要
把优化投入到确实支配成本或完成时间的环节。
怎样实现
按依赖关系画时间线,再用同负载实测对照。
可能的代价与误解
只看平均值会隐藏长尾;把并行跨度相加会错误夸大总耗时。
如何判断是否做对
按时间戳与依赖重算16秒,检查是否把等待和重试遗漏。
1. Trace要表达因果,而不只是时间戳
顶层span代表用户任务,下层区分检索、模型请求、工具、压缩、委派、验证。并行子任务应记录因果关系与父任务,不能简单把耗时加总当墙钟时间。模型输出到工具执行之间的等待可能来自审批、队列或解析,不都属于“模型慢”。
OpenTelemetry提供生成式AI相关语义约定,且规范位置与字段会演进。本书采用任务/调用/工具/验证这些稳定概念,不把某个未稳定字段硬编码为永恒标准。接入生产时应固定SDK与约定版本。[N82]
日志负责离散事件,指标负责聚合健康,Trace负责关联单次路径。只保留指标无法复盘一个错写文件;保存全部原文又可能泄密。应明确最小必要证据及访问控制。
2. 记录什么才能解释失败
模型调用记录模型标识、提示/工具版本、Token用量、响应状态和耗时;检索记录索引版本、过滤条件、结果ID和截断;工具记录动作ID、目标范围、前置版本、结果与错误类型;验证记录命令/验收器版本和工件版本。
不要求日志暴露完整Prompt或内部推理。可以把敏感原文存到受控位置,在Trace中保留引用。不要在脱敏时删掉所有能解释错误的元数据,例如把不同调用ID统一替换成同一个字符串,导致因果链断裂。
任务成功指标必须来自验收,不来自模型自述。一个响应HTTP 200但内容为拒绝或未完成,服务请求成功与用户任务成功应分别计数。
3. 排队与限流是系统问题
API常有请求数、Token或并发限制,具体参数随服务与账号变化,不能在教材硬编码当前额度。客户端应限制在途请求、输出预算与重试,并避免多个子Agent各自以为拥有全部总额度。
指数退避加抖动能减少集中重试,但应只用于适合重试的错误。权限拒绝、Schema错误、确定性业务失败不应盲目退避;外部副作用未知需对账。重试总次数、时间和成本应有上界。
队列还需要背压:下游工具拥塞时,不能不断产生更多计划和候选动作。对长任务可保存可恢复状态,释放昂贵运行资源;对交互任务应优先保证可接受延迟。调度策略应基于业务优先级,而不是谁生成更多Token谁占更多资源。
4. 取消与超时如何传播
用户取消后,主任务应向子Agent、模型请求和可取消工具传播信号。已经提交的外部动作不一定能撤销,需要继续跟踪其终态。取消的结果应区分“未开始”“已停止”“已完成但不再继续”“状态未知”。
超时也应分层:连接超时、闲置流超时、单工具超时、整任务预算。若整任务只剩少量预算,不应再启动一个不可取消的大型操作。剩余时间不是硬性保证,但必须影响调度。
进程重启后恢复需要读取持久化工件,而不是重新询问模型“之前做到了哪里”。模型可帮助解释记录,但不能创造不存在的执行事实。第08章动作日志提供了最小本地例子。
5. 熔断、降级与人工接管
外部服务持续失败时,可以暂时熔断,避免耗尽预算;但要区分全局故障与单资源权限问题。降级可以减少可选检索、改为只读报告或转人工确认,不应悄悄降低质量还保持“已验证完成”的标签。
若主模型不可用,切到备用模型也需检查工具/上下文/结构输出兼容性。不可读压缩状态不一定可跨模型或跨供应商迁移;需要保留可解释的任务状态和证据入口,而不是假设任意二进制状态通用。
人工接管要提供当前目标、已执行动作、未决副作用、当前版本和下一步,而不是一整段未经整理的聊天历史。接管者首先需要知道哪里不能重复执行。
6. SLO与错误预算
SLO应该围绕用户价值,例如在规定资源与时间内完成合法任务的比例,或高风险动作零未授权执行。可用性、正确性、延迟和安全是不同维度,不一定能合成一个数字。Google SRE关于SLO的实践提供了定义用户可感知指标与错误预算的方法。[N51]
平均延迟容易掩盖少数非常慢的任务,需看尾部;平均成功率可能掩盖某语言或高风险场景退化,需分层。告警应可行动:持续工具权限错误需要查配置,不应笼统报警“模型不够聪明”。
7. 事故复盘要回到系统边界
一次“Agent重复修改文件”可能由超时重试、崩溃窗口、状态未持久化、操作ID不稳定或前置版本缺失引起。复盘应找到最小可重现序列,补相应故障测试,再决定修复哪个层。不要用“加强Prompt要求谨慎”代替执行语义修复。
验收题:四个子任务各耗时30秒,父任务耗时40秒,能否报告120秒执行时间?120秒可以表示子任务资源时间总和,但用户墙钟时间是40秒。两者都可有用,必须命名清楚,不能混用来证明加速。
重试风暴怎样把暂时故障放大
输入与条件。100个请求同时收到限流。如果全部马上重试,下一秒仍有100个请求;每个再启动一个新重试分支则会更多。
| 步骤与对象 | 内部动作 | 中间结果 / 新状态 |
|---|---|---|
| 1无界重试 | 失败立刻再次发送 | 请求没有减少,可能加重限流。 |
| 2指数退避 | 第1次等1秒、第2次2秒、第3次4秒 | 限制单请求重试频率。 |
| 3加抖动 | 在允许区间随机错开 | 避免100个请求始终同一时刻醒来。 |
| 4总预算 | 最多重试次数、截止时间和取消信号 | 不为了“保证成功”无限延长任务。 |
| 5副作用检查 | 写操作仍要幂等或核查 | 退避不能消除重复执行风险。 |
把过程连起来。可靠性不只是多试几次;重试必须受负载、幂等性和用户等待边界约束。
边界与反例。1/2/4秒为教学参数,真实应尊重服务返回的重试提示和业务时限。
依据与适用范围:[DERIVE]。示例输入和场景由本书明确设定。