Skip to content

高频面试题

Agent 系统中如何设计优雅的终止条件?避免死循环有哪些策略?

终止条件是 Agent 工程里最容易被低估的控制面:没有清晰退出路径,Agent 很容易把“自主决策”跑成重复调用、状态摇摆和预算燃烧。

适合阶段:Agent 工程 / Runtime 设计面核心能力:Stop Condition · Loop Guard · State Progress · Human Handoff

面试官角度分析,想考什么

  • 为什么必须显式设计终止条件?
    考你是否知道 Agent 默认会继续跑,max_steps 只是硬刹车,不算优雅退出。

  • 如何区分正常完成和异常中止?
    考 stop reason:做完、做不下去、没权限、没进展、预算耗尽、转人工,每种都要有证据。

  • 终止该由模型判断还是代码判断?
    考控制权:模型可以提议完成,代码必须用进展检测、预算和策略做最终裁决。

可直接抄走的 30 秒参考答案

text
我会把 Agent 的终止条件分成两类:一类是正常完成,比如目标 checklist 满足、证据齐全、最终产物已经生成;另一类是止损退出,比如缺少用户信息、无权限、证据不足、超过步数、超时、预算快耗尽、重复调用同一个工具,或者连续多轮没有状态进展。`max_steps` 只是保险丝,不是完整方案。生产里应该由 runtime 记录 state、action、observation 和 stop_reason,用 verifier 判断是否真的完成,用重复检测和 no-progress detector 防死循环,必要时追问用户或转人工。

面试回答详解,知其所以然

这道题的核心不是“给 Agent 加一个最大轮数”。更成熟的回答是:Agent 的终止条件要同时覆盖成功路径和失败路径,并且每次退出都要有明确的 stop_reason、可追溯的证据,以及用户能理解的下一步。

1. 终止条件解决的是循环控制问题

Agent 的运行方式通常是:

text
读取目标 -> 决策下一步 -> 调用工具 -> 观察结果 -> 更新状态 -> 继续或停止

只要系统允许模型在多轮中选择下一步,就一定要回答三个问题:

  • 什么叫任务已经完成?
  • 什么叫继续执行还有意义?
  • 什么情况下必须停止、澄清、降级或转人工?

如果这些问题没有写清楚,Agent 很容易出现三类事故:反复调用同一个工具、在两个状态之间来回跳、工具失败后继续编结果。LangGraph 的 GRAPH_RECURSION_LIMIT 报错,本质上就是图在命中停止条件前达到了最大步数,经常意味着循环里缺少正常退出路径。

2. 终止条件要分成“完成条件”和“止损条件”

面试里可以先把终止条件拆成两大类:

  • 完成条件:目标已经达成,可以输出最终结果。
  • 止损条件:目标没达成,但继续跑下去只会增加风险、成本或错误。

常见 stop reason 可以这样设计:

  • success:目标状态满足,必要证据齐全,最终答案或产物可交付。
  • need_user:缺少关键输入,例如订单号、权限确认、业务偏好或歧义选择。
  • insufficient_evidence:查不到可靠证据,继续生成会变成幻觉。
  • permission_denied:工具或数据无权限访问,不能绕过系统限制。
  • requires_approval:动作有副作用或高风险,需要人工确认后再执行。
  • handoff_to_human:问题超出 Agent 能力、规则冲突或需要人工裁决。
  • max_steps_reached:超过最大步骤,作为硬保险丝强制停止。
  • timeout:超过时间预算,避免用户长时间等待。
  • budget_exhausted:token、费用或工具调用预算接近上限。
  • no_progress:多轮之后状态没有新增事实、证据或可执行产物。
  • repeated_action_blocked:重复调用相同工具和参数,被循环检测拦截。

这里的关键是:退出不是只有“成功”和“失败”。一个好的 Agent 应该能告诉用户“我卡在哪里、为什么不能继续、已经试过什么、下一步需要你补什么”。

3. max_steps 是保险丝,不是方向盘

max_steps 很重要,但它只是最低级防线。它能防止 Agent 无限烧钱,却不能让 Agent 在正确时机优雅停止。

只靠 max_steps 会有两个问题:

  • 到了上限才停,说明前面已经浪费了多轮调用。
  • 停下来的原因太粗,无法判断是目标完成失败、工具失败、证据不足还是逻辑循环。

更好的做法是把 max_steps 和业务状态结合:

text
每轮检查:
  是否满足 success checklist
  是否缺少关键输入
  是否存在权限或安全阻断
  是否连续 N 轮没有新增状态
  是否重复相同 action signature
  是否接近 token / cost / time budget

这样 max_steps 只是最后兜底,真正的停止来自状态变化和业务证据。

4. 避免死循环要检测“有没有进展”

Agent 死循环不一定表现为完全相同的文本。有时它会换个说法,但本质上还在做同一件事。

工程上可以用几类信号判断 no progress:

  • 动作重复:相同工具、相同参数、相同查询条件连续出现。
  • 状态不变:关键 state 字段没有新增,任务 checklist 没有推进。
  • 证据不变:检索或工具返回的 evidence id、文件片段、结果摘要高度重复。
  • 计划空转:一直在“重新规划”,但没有进入执行或验证。
  • 错误重复:同一个错误码连续出现,比如权限失败、schema 校验失败、超时。
  • 输出摇摆:Agent 在两个互斥结论之间反复切换,没有新增证据。

对应的策略不是简单停止,而是分情况处理:

  • 可重试错误:允许有限重试,调整参数或换工具。
  • 不可重试错误:立刻停止并说明原因。
  • 缺少信息:追问用户,不继续猜。
  • 权限问题:拒绝或走审批。
  • 无进展:总结已尝试路径,给出当前最佳结论或转人工。

5. 终止条件要写进 runtime,而不是只写进 prompt

提示词可以告诉模型“完成后请停止”,但这不够。模型可能误判完成、忽略失败 observation,或者在长上下文里忘掉停止规则。

更稳的责任边界是:

  • 模型负责:判断候选下一步、解释当前状态、提出是否完成的建议。
  • Runtime 负责:校验动作、统计步数、预算、重复调用和权限。
  • Reducer 负责:把 observation 写入结构化 state。
  • Verifier 负责:检查 success checklist 是否真的满足。
  • Orchestrator 负责:多 Agent 场景下的全局预算、任务接力和降级。

OpenAI Agents SDK 这类 runtime 会管理 tool loop、handoff、approval、tracing,并在 run 完成或需要审批时暂停。这个方向说明了一点:Agent 的“停”不是一句 prompt,而是运行时控制能力。

6. 优雅停止要对用户有交代

“优雅”不只是内部停止,还包括对外表达。

一个优雅退出应该包含:

  • 当前结论:已经完成了什么,或为什么无法完成。
  • 关键证据:用了哪些工具、查到哪些结果。
  • 停止原因:是完成、缺信息、无权限、证据不足、预算耗尽还是人工接管。
  • 下一步建议:用户补什么信息、是否授权、是否换方案。
  • 可恢复性:后续是否能从 checkpoint 或当前 state 继续。

这比“任务失败,请重试”有用得多,也更像一个生产系统:可观测、可恢复,也方便运营和人工接管。

面试官追问3个问题

追问一:为什么 max_steps 不能算真正修复死循环?

  • 考察点:是否能区分保险丝和正常退出路径。
  • 回答方向:max_steps 只能防止无限执行,不能说明任务完成,也不能减少无效调用。真正修复要靠明确 success checklist、重复 action 检测、状态进展检测、错误分类和业务 stop reason。

追问二:怎么判断 Agent 连续多轮没有进展?

  • 考察点:是否会用状态和证据判断进展。
  • 回答方向:看关键 state 字段是否新增,任务 checklist 是否推进,工具 evidence id 是否变化,action signature 是否重复,错误类型是否变化。连续 N 轮没有新增事实、没有新产物、没有减少待办,就触发 no_progress

追问三:停止条件应该由模型判断还是代码判断?

  • 考察点:是否理解模型和 runtime 的边界。
  • 回答方向:模型可以判断语义上的“看起来完成”,但代码要做确定性验证。低风险文本任务可以让模型主导,高风险动作、业务状态变更、代码提交、支付退款等必须由 verifier、权限系统或人工确认。

扩展知识

终止条件和失败出口不是一回事

可以用一句话区分:

text
终止条件管“做完了就停”,失败出口管“做不完也要停”。

比如代码修复 Agent 的终止条件可以是 npm test 通过;失败出口可以是连续两次同类测试失败、超过 8 轮修改、权限不足或依赖无法安装。只有完成条件,没有失败出口,Agent 会一直尝试;只有失败出口,没有完成条件,Agent 可能停得很粗糙,无法证明任务真的完成。

常见死循环类型

Agent 死循环可以分成几类:

  • 工具重试循环:工具失败后反复用同一参数调用。
  • 检索循环:不断搜索相似 query,但没有新增证据。
  • 规划循环:一直重新拆计划,却不执行任何可验证动作。
  • 状态摇摆:在两个结论或两个 agent handoff 之间来回切。
  • 分页循环:反复拉取同一页或下一页没有终止标记。
  • 修复循环:改代码、跑测试、失败、再改,但错误类型没有变化。

每种循环的修法都不一样。工具循环要看 action signature,规划循环要看是否产生执行状态,分页循环要看 cursor 和 has_more,修复循环要看错误类别是否变化。把所有问题都归结为 max_steps,会让排障很粗。

多 Agent 场景下的终止协调

多 Agent 系统里,终止条件不能只放在子 Agent 内部。一个 Researcher、Coder 或 Reviewer 子 Agent 可能觉得自己还应该继续,但全局任务已经超时、预算不足,或者其他子 Agent 已经给出足够证据。

常见做法是引入 orchestrator:

  • 给每个子 Agent 分配局部目标和局部预算。
  • 监控每个子 Agent 的 step、token、工具调用和 stop reason。
  • 合并局部结果,判断全局目标是否完成。
  • 子 Agent no-progress 时重试、换 Agent、降级或返回部分结果。
  • 防止两个 Agent 互相 handoff,形成接力死循环。

这也是为什么多 Agent 系统更需要 trace 和全局状态,而不是让每个 Agent 自己说“我还要再试试”。

终止条件也要进入评估集

很多团队只评估答案对不对,不评估停得好不好。Agent 上线后,停止条件本身也应该被测试。

可以设计这些 case:

  • 已有充分证据时,Agent 是否能及时停止。
  • 工具连续失败时,是否有限重试后退出。
  • 缺少必要参数时,是否追问用户而不是猜。
  • 无权限时,是否拒绝或走审批。
  • 同一工具同一参数重复调用时,是否触发循环检测。
  • 达到预算阈值时,是否返回当前最佳结果或降级。

对应指标可以看:平均 step 数、P95 step 数、max_steps 命中率、重复 action rate、no-progress stop rate、handoff rate、成功停止率、错误停止率和用户二次追问率。

基于 MIT 协议开源