Loop Engineering 是什么?为什么说它是新瓶装旧酒?
Agent 的主循环看似简单——感知、规划、行动、观察、反思,转起来就行;真正的工程全在”何时停、错了怎么办、状态存哪里”。这篇拆解主循环五个环节的设计要点、终止条件与防失控手段、错误恢复策略,以及循环状态的持久化。
主循环的五个环节
- 感知(Perceive):组装本轮输入——用户目标、历史轨迹、刚返回的工具结果、相关记忆。感知质量约等于上下文工程质量:常驻规则放前面,已验证的过程压成结论,原始日志保留检索入口而非全文。
- 规划(Plan):模型决定下一步:直接回答、调用工具,还是继续思考。复杂任务可先产出显式计划再逐步执行。
- 行动(Act):执行工具调用。执行环境在此做参数校验、权限拦截与超时控制。
- 观察(Observe):把工具结果回写进上下文。关键动作是”消化”——截断、摘要、提取关键字段,而不是原文堆积。
- 反思(Reflect):对照目标评估进展:离完成更近了还是原地打转?可以内联在模型的思考里,也可以交给独立的评审节点——自我评价天然偏宽容,重要任务的反思最好与生成隔离。
主循环之外还存在一层”外层循环”:任务级的重试、换策略、转人工、跨会话接力。内层循环管”这一步怎么走”,外层循环管”这轮失败后整个任务怎么办”,两层的预算与计数器要分开。
骨架代码:
def agent_loop(goal, tools, max_steps=20, token_budget=100_000): |
终止条件与防失控
失控的循环烧的是真金白银。终止信号要分层,不能只靠模型自觉:
- 主动终止:模型判断任务完成,返回最终答案。这是最理想的出口,但不能是唯一出口。
- 最大步数:硬性上限,到点必须停。取值可参考同类任务的 P95 步数再上浮。
- 预算:Token、金额、墙钟时间,任一耗尽即停。注意重试预算要有唯一持有者——模型 SDK、框架、网关各自重试,会把一次故障放大成嵌套调用。
- 无进展检测:连续几轮工具结果雷同、重复以相同参数调同一工具、失败原因不变,判定兜圈子,强制退出或换策略。这是防”看起来在忙”的关键。
- 质量门槛:有评分器的场景,达标即收工,避免无意义打磨。
再加一层死循环告警:循环活着但长期无进展时主动上报,而不是等账单来提醒。
错误恢复策略
不同错误走不同路径,一刀切重试是最常见的错误设计:
| 错误类型 | 例子 | 策略 |
|---|---|---|
| 瞬时故障 | 接口超时、限流 | 有界重试,指数退避加抖动 |
| 可恢复错误 | 参数不合法、输出格式错 | 把错误原因回写上下文,让模型自我修正 |
| 缺输入 | 指令有歧义、关键信息缺失 | 挂起等待补充,而非瞎猜 |
| 权限不足 | 越权调用被拒 | 停止该路径,升级人工或申请授权 |
| 代码缺陷 | 状态迁移非法、解析失败 | 快速失败并告警,重试无意义 |
关键原则:恢复动作要落在正确的层级。工具调用失败由循环内部消化;阶段级失败由外层编排决定是否降级、换路或终止。还有一种常被忽略的恢复是”降级回答”:预算耗尽时,基于已收集证据给出标注了不确定性的部分结论,胜过悄无声息地空手而归。
循环中的状态持久化
循环状态分两类,别混存:
- 会话状态:对话历史、工具调用记录、当前迭代进度。崩溃后能从最近一步恢复。
- 任务状态:目标、已完成产物、失败记录、已消耗预算。跨会话、跨天恢复依赖它。
落盘时机选在”结果已确认、可独立校验”的节点:每次工具调用成功后、每个阶段完成后。需要人工审批的动作,暂停前先保存待执行参数。恢复不是从某行代码继续,而是从最近的有效状态重新出发——因此读取类工具可以有界重试,带副作用的操作必须幂等。
持久化的回报很直接:中断可恢复、失败可复盘、长任务可跨会话接力。只把聊天记录丢进缓存,撑不起这三件事——恢复时必须能重建目标、已确认产物与剩余预算,而不只是对话文本。
另外别忘了观测:循环的每一步(第几轮、调了什么工具、消耗多少 Token、因何继续)都要进 Trace,否则”为什么会跑 20 步”永远是悬案。
面试视角
怎么防止 Agent 死循环? 分层终止:主动退出 + 步数上限 + Token/时间预算 + 无进展检测,再拿真实流量压测退出的可靠性。
错误处理怎么设计? 先分类再施策:瞬时故障重试、可恢复错误回写、缺输入挂起、越权升级、代码缺陷快速失败;恢复动作落在正确层级,重试预算唯一持有。
小结
- 主循环五环:感知、规划、行动、观察、反思;工程重心在观察的消化与反思的真实性。
- 终止条件必须多层兜底:步数、预算、无进展检测缺一不可。
- 错误恢复先分类,重试只用于瞬时故障,其余各有归宿。
- 状态分会话与任务两层持久化,这是恢复、复盘与接力的地基。

