主题
高频面试题
Agent 死循环问题有遇到过吗?如何解决?
这题的高分点不是承认“加过 max_steps”,而是能像处理线上事故一样复盘:先看 trace,判断是哪类循环,再分别修工具、状态、终止条件、预算和降级。
面试官角度分析,想考什么
怎么判断是死循环而不是合理多步?
考进展:同一动作重复、错误不变、state 不推进,而不是 step 多就叫死循环。除了 max_steps 还有哪些止损手段?
考 action 去重、no-progress、错误分类、预算和 stop reason。怎么排查和防止复发?
考先看 trace 再改 prompt;badcase 进离线 eval 和线上指标。
可直接抄走的 30 秒参考答案
text
遇到 Agent 死循环我会先看 trace,而不是先改 prompt。判断它是不是连续调用同一工具同一参数、拿到同样错误、检索没有新增证据、state 没有变化,或者在计划和 handoff 之间空转。处理上先用 max_steps、timeout、token 和 tool call limit 止损;再加 action signature 去重、state progress 检测、错误分类和 stop reason;最后按原因恢复,比如参数错让模型改,权限错停止或授权,证据不足就说明不确定,缺信息就问用户。修完后把这个 case 放进离线 eval 和线上指标监控。面试回答详解,知其所以然
这道题最好用“我会怎么排查和修复”来回答。即使没有真实公司案例,也可以讲一套可信的工程 SOP:先识别现象,再分层定位,再补 runtime 防线,最后把 case 进回归集。
1. 什么情况算 Agent 死循环
Agent 是多步系统,多跑几轮不一定是死循环。真正的死循环是:系统消耗了更多模型调用、工具调用或时间,但目标状态没有实质推进。
常见判断信号有:
- 动作重复:同一个工具、同一组参数连续出现。
- 错误重复:同一错误码或失败原因被反复触发。
- 证据重复:搜索、检索、网页读取返回高度相同内容。
- 状态不变:关键字段、任务 checklist、产物、计划状态没有变化。
- 计划空转:一直“重新规划”,但没有执行动作或验证结果。
- 结论摇摆:没有新增证据,却在两个方案之间来回切换。
- handoff 空转:多个 Agent 互相转交,但没有新增信息。
可以用一句话区别合理多步和死循环:
text
合理多步 = 每轮都让任务状态更接近完成
死循环 = 每轮都消耗预算,但 state diff 基本为空2. 第一反应:先止损,再定位
线上遇到死循环,第一步不是改 prompt,而是止损:
- 暂停或取消当前 run。
- 限制该用户、该工具或该任务类型的最大调用预算。
- 对有副作用的工具立即切到人工确认。
- 保留完整 trace,避免日志被后续重试覆盖。
- 对用户返回可理解状态:已停止、已尝试路径、当前缺什么。
止损后再定位。否则 Agent 一边循环一边烧 token、打外部 API、甚至重复执行副作用操作。
3. 排查要按 trace 分层看
一次 Agent step 至少要能看到这些字段:
text
step_id
state_before
model_input_summary
model_output / tool_call
tool_name
tool_args
tool_result / error_type
state_after
state_diff
stop_reason
token / latency / cost排查顺序可以这样走:
- 看 action signature:
tool_name + normalized_args + target_resource是否重复。 - 看 observation:工具是报错、空结果、重复结果,还是结果被模型误读。
- 看 state diff:工具返回后 reducer 有没有把关键事实写入状态。
- 看 prompt 和 memory:上下文里是否有冲突指令、旧错误、重复计划或污染内容。
- 看 stop checker:是否缺少
need_user、permission_denied、no_progress、insufficient_evidence等出口。 - 看预算指标:是否过晚才触发 max_steps,是否应该更早触发成本阈值。
这套排查能避免一句“模型不行”盖过真正问题。
4. 常见死循环类型和修法
- 工具重试循环:同一工具同一参数反复失败。
修法:错误分类,确定性错误不重试;记录失败签名;连续命中后换工具、追问用户或停止。 - 检索循环:不断改写相似 query,但证据没有新增。
修法:记录 query embedding 或结果 ID;无新增证据后停止,返回已有证据和不确定性。 - 规划循环:反复生成新计划,不执行也不验证。
修法:要求计划步骤必须落到可执行 action;限制连续 replan 次数;每次 replan 必须说明新增信息。 - 状态写回失败循环:工具明明返回成功,但 Agent 下一轮像没见过一样。
修法:检查 reducer,把关键事实写入结构化 state,而不是只 append 到 messages。 - 权限循环:403、401、审批未通过还一直尝试。
修法:权限失败设为不可重试,直接进入need_auth、permission_denied或requires_approval。 - 分页循环:反复拉同一页或 cursor 不变。
修法:记录 cursor、page token、seen ids;cursor 不变或has_more=false立即停止分页。 - 修复循环:代码 Agent 反复改同一类错误,测试失败类型没变化。
修法:记录失败类别和 diff;连续同类失败后要求总结假设、缩小改动或请求人工。 - 多 Agent handoff 循环:A 转给 B,B 又转回 A。
修法:orchestrator 记录 handoff 路径,限制连续转交,并要求每次转交携带新增证据或明确阻塞原因。
5. 解决策略要分三层
第一层是硬保护,防止无限损失:
max_stepstimeout- token / cost budget
- max total tool calls
- max calls per tool
- 高风险工具执行次数上限
第二层是进展检测,让系统更早识别空转:
- action signature 去重
- normalized args 比较
- state diff 检查
- evidence id / seen ids 去重
- error_type 连续计数
- replan 次数限制
- handoff path 检测
第三层是恢复策略,让 Agent 知道停下来后该怎么办:
- 可重试错误:指数退避、换参数、换工具。
- 不可重试错误:明确停止并解释原因。
- 缺少信息:向用户追问,不继续猜。
- 无权限:走授权、审批或拒绝。
- 证据不足:返回当前结论和不确定性。
- 无进展:总结已尝试路径,转人工或交付部分结果。
6. 修复后要进评估和监控
死循环不是修一次 prompt 就结束。要把这次 badcase 变成可回归的测试:
- 保存原始用户输入、工具 mock、关键 observation 和期望 stop reason。
- 离线 eval 检查是否在 N 步内停止。
- 指标监控
max_steps_reached、repeated_action_blocked、平均 step、P95 step、重复工具率、无进展停止率。 - 对高风险工具单独监控重复调用和失败后重试。
- 每次修改工具描述、prompt、模型或路由策略后跑回归。
一个成熟回答要强调:死循环修复的目标不是“让它永远多跑几步”,而是让它在该继续时继续、该停时带着原因停。
面试官追问3个问题
追问一:怎么区分死循环和复杂任务本来就需要很多步?
- 考察点:是否用“进展”而不是“轮数”判断。
- 回答方向:看每轮是否产生新的目标相关状态:新增证据、新文件、新测试结果、新决策、待办减少、风险降低。如果 step 多但 state 一直推进,是合理多步;如果 step 少但重复同一动作且 state 不变,也是循环。
追问二:工具返回 200 但 Agent 还在循环,怎么排查?
- 考察点:是否区分技术成功和业务成功。
- 回答方向:检查返回内容是否为空、重复、业务失败或缺关键字段;检查 reducer 是否把结果写入 state;检查模型是否能看到关键 observation。HTTP 200 只是调用成功,不代表任务推进。
追问三:重复调用检测会不会误杀正常重试?
- 考察点:是否理解重试和重复的差异。
- 回答方向:会,所以要结合错误类型、参数变化、退避策略和状态变化。瞬时 5xx 可以有限重试;参数错误、权限错误和业务规则拒绝不应重试。重复检测触发后也可以先让模型换策略,而不是一律失败。
扩展知识
max_steps 为什么不是完整答案
max_steps 只回答“最多跑几轮”,不回答“为什么还在跑”。它像保险丝,能避免无限损失,但不能证明任务正常完成,也不能定位根因。
更完整的停止检查应该是:
text
每轮结束后检查:
success checklist 是否满足
是否缺少用户输入
是否权限或审批阻断
action signature 是否重复
state diff 是否为空
evidence 是否新增
错误类型是否连续重复
预算是否接近上限action signature 怎么设计
不要直接比较原始 JSON 字符串,因为字段顺序、空格和同义参数可能不同。更稳的是做归一化:
text
signature = hash(
tool_name
+ normalized_required_args
+ target_resource_id
+ operation_type
)比如分页工具要把 cursor、page token 和 seen ids 放进签名;文件编辑工具要把文件路径和 patch 摘要放进签名;搜索工具可以把 query 归一化后再结合 top result ids。
stop reason 要能服务用户和工程
推荐不要只返回 failed。更好的 stop reason 包括:
successneed_userpermission_deniedrequires_approvalinsufficient_evidencetool_unavailablerepeated_action_blockedno_progressmax_steps_reachedtimeoutbudget_exhaustedhandoff_loop_blocked
这些状态既能告诉用户发生了什么,也能进入监控和离线评估。