最近我帮团队做技术面试,连着面了一批候选人,简历上清一色写着大模型应用开发、Agent 相关项目经验。但当我把"Agent 怎么做规划"这道题抛出去,十个人里有八个让现场气氛陷入沉默。有的人背了一串名词,把 ReAct、Plan-and-Execute、AutoGPT 说了一遍,再往下追问一句"那你的系统里重规划是怎么触发的",就接不上话了。这其实是一个非常典型的现象:大家看了很多 Agent 的科普文章,也调过几个大模型的接口,但真正把"规划"当成一个系统工程问题想清楚的人很少。
这道题之所以淘汰率高,是因为它表面问的是"你知不知道 Agent 会规划",实际考察的是"你有没有亲手设计过一个能稳定工作的规划模块"。面试官的潜台词是:给我讲讲,你如何在代码层面把 LLM 的一次次推理变成一条可靠的任务执行链路。这篇文章我就把这道题拆开讲清楚,包括规划的本质、两条主流技术路线、任务拆解的方法论、真实的模块设计细节,以及面试现场可以直接拿来用的回答框架。
1. 面试官问"Agent 怎么做规划",到底想听什么?
先别急着背概念。我作为面试官,看到候选人简历上写了 Agent 项目,又抛出一道规划题,我的真实目的只有一个:区分"调包工程师"和"系统设计师"。你是否有能力理解自己在做什么,而不只是知道在用什么。
1.1 表面在问名词,实际在问系统
这道题最常见的错误答法是:"Agent 的规划就是让大模型自己拆解任务,比如用户说要订机票,它就把任务拆成查航班、比价格、填订单、付款。"这种回答我只能给出一个礼貌的微笑。因为它描述的是规划的效果,不是规划的机制。
面试官想知道的是:拆解任务之后你打算怎么执行?步骤之间如果有依赖关系怎么办?某一步执行失败了,你的 Agent 是直接停下来,还是带着错误信息重新规划?你设计的规划模块是一次性生成一个完整计划,还是允许在执行过程中边做边调整?这些都不是名词解释能覆盖的问题,而是一个完整的系统设计问题。
我经常用一个比喻来提醒候选人:Agent 的规划模块就像现实中的项目经理。项目经理拿到一个模糊目标之后,要做的是把它拆成排期、分配资源、设定里程碑、处理风险。面试官想听的不是"项目经理很会拆任务",而是"你如何设计一套流程,让项目即便有人请假、需求变更、工期延误,也能把活干完"。
1.2 三个递进层次,大部分人只答到第一层
按照我的观察,面试回答的深度通常分成三层。第一层是概念层,能说出 ReAct 是推理加行动、Agent 会自主规划,这一层大概能拿到 30 分。第二层是系统层,能讲清楚规划器的状态流转、重试机制、工具调用的参数生成,这一层能拿到 60 到 70 分。第三层是工程层,能说出你实测中遇到的失败模式,以及你为什么在某个场景下没选某种方案,这一层才是区分度所在。
80% 的候选人倒在了系统层。原因很简单:他们只在 Demo 里见过 Agent 跑通一顿操作,没见过生产环境里 Agent 是怎么在二三十次工具调用后依然不失控的。所以这篇文章真正想帮你补的,是第二层和第三层。
1.3 隐藏考点:对 LLM 能力边界的理解
再往深处说,这道题其实在考察你对大模型能力边界的认知。如果一个人认为 LLM 是万能的,觉得把任务扔给它就能自己规划自己执行,那他一上来就输了。真实的 LLM 在规划上能力是很不稳定的:它可能把"订酒店"拆成"打开浏览器""输入网址""点击搜索",拆得过于琐碎;也可能把两个本应串行的任务设计成并行,完全忽略了现实约束。
所以一个成熟的规划模块设计,核心思路是"别让 LLM 自由发挥太多,要把它的不可靠性通过工程手段兜住"。比如限制规划输出的格式、对计划做规则校验、引入人工确认环节、对执行失败做重规划。你把这些边界设计讲清楚了,面试官就知道你是真的跟 Agent 打过交道,而不是只看过几篇热门文章。
2. Agent 规划的两条主流技术路线:先排期还是边干边想?
聊到具体方案,目前业界广泛使用的规划路线主要有两条:一条是管线式规划,业内叫 Plan-and-Execute;另一条是循环式规划,以 ReAct 为代表。面试的时候把这两条路讲透,比列十个名词有用得多。
2.1 管线式规划:像做项目排期表
管线式规划的思路非常直观:启动任务时,先让 LLM 生成一份完整的多步骤计划,然后按计划逐步执行。这份计划可以是一个列表,每一项包含步骤描述、输入输出、依赖的工具。执行器拿到这个列表后逐项推进,执行完当前步骤再进入下一步。
这种方式的好处是稳定。整个执行路径在开始阶段就清晰可见,你可以提前做步骤合法性校验,可以给用户展示完整规划让用户确认,也可以很方便地把每个步骤的输出记录下来用于审计。在那些任务边界清晰、步骤顺序基本固定的场景里,这种方法非常舒服。
但它也有明显的短板:一旦中间某一步的结果和预设不一致,后面整条计划都可能失效。我做过一个实际项目,任务是自动收集某个流程的数据并生成报告。前几步执行得都很顺利,但到第三步需要的某个接口突然换了返回格式,后续的所有步骤全部失去了意义。碰到这种情况,Plan-and-Execute 就非常僵硬,要么把这一步的结果喂给 LLM 重新编一份新计划,要么就得设计复杂的回溯机构。
2.2 循环式规划:像开车时随时调整方向
ReAct 走的是完全不同的路线,它不先预设完整计划,而是一次只走一步。整个循环是:Thought(当前状态分析)→ Action(调用工具或进行推理)→ Observation(观察工具返回结果)→ 再 Thought(基于新观察重新分析)→ …… 直到最终给出答案。
这个模式的本质是让"规划"和"执行"深度融合。你不需要提前预测后面十步会发生什么,只需要根据当前掌握的信息决定下一步怎么走。这在那些探索性极强、路径不固定的任务里优势巨大,比如让 Agent 从一个结构化网页里找出一条满足多个条件的信息,或者做一轮需要反复试错的数据清洗。
代价是稳定性和成本控制变差。Agent 可能绕半天圈子找不到出路,整个循环陷入死循环;也可能调用十几步工具却什么都分析不出来,Token 消耗和接口调用费用都非常可观。所以真实项目里一般会给 ReAct 循环加最大步数限制,超过上限强制退出,再让 LLM 基于已有信息重新规划。
2.3 两种路线怎么选:三个维度做决策
面试时如果能给出清晰的选型逻辑,会显得你非常有经验。根据我的实践,可以从三个维度来权衡。
| 维度 | Plan-and-Execute(管线式) | ReAct(循环式) |
|---|---|---|
| 任务路径确定性 | 高,路径可预先推演 | 低,需要边做边探索 |
| 环境变化频率 | 低,外部依赖相对稳定 | 高,中间结果不可预测 |
| Token 与费用控制 | 好,计划阶段消耗集中在一次 | 差,循环过程消耗难预估 |
| 可解释性 | 好,计划可提前展示给用户 | 中,过程需要逐步骤解释 |
| 失败恢复 | 僵硬,需要整段重规划 | 灵活,观察后即可调整下一步 |
我的经验是:如果一个任务你在拿到需求时就能写出大致的操作手册,哪怕写得不精确,优先用 Plan-and-Execute;如果一个任务你在开始前根本不知道要查几次才能查到结果,那就用 ReAct。很多成熟系统实际上是把两者混用:主路线用 Plan-and-Execute,单个复杂步骤内部再嵌套一个 ReAct 循环,这也算现在业内比较主流的设计。
3. 规划的真正难点:把目标拆成任务、动作和工具调用
明确路线之后,接下来就是具体的拆解设计了。很多候选人喜欢说"让 Agent 自己拆任务",但这句话等于没说。你要能讲清楚:目标是怎么变成任务列表的?任务列表里的每一项粒度多大?每一项对应哪个工具调用?如果工具参数生成出错了怎么办?
3.1 一个贯穿全文的例子:三天两夜旅行规划
为了把这些问题说透,我用一个在面试里经常出现的场景来举例:给 Agent 安排一个任务,帮用户规划一次三天两夜的旅行,预算五千块钱,重点是美食和轻松体验,不要赶景点。
如果让一个不做规划的裸 LLM 直接回答,它会给你一篇文章式的建议,完全没法执行。但 Agent 的规划模块需要把它变成类似下面的计划:
- 第一阶段(任务分解):根据用户偏好,将"规划旅行"拆解为目的地选择、交通规划、住宿预订、美食路线规划、日程安排五个子任务。
- 第二阶段(动作编排):为每个子任务绑定工具,比如"机票比价工具""酒店搜索工具""本地美食推荐接口""地图路线计算工具"。
- 第三阶段(依赖分析):明确先后关系,只有确定了目的地之后,交通和住宿才能并行搜索;只有确定了住宿位置之后,美食路线才方便规划。
- 第四阶段(边界确认):检查预算是否与行程冲突,如果酒店费用太高,送回重规划,触发预算调整。
这一步真正的价值在于把"规划"拆成了四个动作:任务分解、动作编排、依赖分析、边界确认。面试官想听的就是这四个动作在你脑海里要有一个清晰的顺序,而不是笼统的一句"拆成五步"。
3.2 任务拆解时最容易犯的三个错
我见过很多 Agent 项目在任务拆解环节栽跟头,犯错的方式几乎一样。第一个错是粒度不均:有些步骤拆到"点击按钮"这种原子操作,有些步骤却是一个需要十次工具调用的大任务。粒度不均会让执行器和后续的失败重试都很难设计,因为你没法为每种粒度分别定义成功率。
第二个错是忽略依赖关系。旅行规划中"根据住宿地点规划美食路线"和"先预订住宿"之间有严格的先后关系,但 LLM 在生成计划时经常把这种依赖当作并列关系。所以我一般在设计规划 Prompt 时会强制要求 LLM 输出每个任务的"依赖条件"字段,再用代码做一次校验:如果发现某个任务依赖的前置任务还没出现在计划里,直接让 LLM 重新生成。
第三个错是缺少可验证的完成标准。任务清单里只写"搜索酒店"是不够的,你还得定义什么叫"搜索完成"。是返回搜索结果给用户就算完成?还是完成比价后直接推荐一个最优选项?没有这个定义,执行器在循环里很容易卡在"生成结果"和"判断结果是好是坏"这两个环节之间打转。
3.3 工具层规划:LLM 如何把任务变成参数
任务拆解完之后,还需要有一个阶段把任务翻译成具体的工具调用。这里最核心的技术细节就是函数调用(Function Calling)机制。
比如"搜索符合预算的酒店"这个任务,LLM 在规划阶段就要把它转成类似这样的调用意图:调用 search_hotel 工具,参数是 city, date_range, budget_low, budget_high, preference_keywords。这里最容易出问题的是参数幻觉。LLM 可能会编造一个城市名,或者把预算单位算错,甚至把目的地写成一次旅行中的某家餐厅名。
我的常用做法是三层防护:第一层,在工具定义里写清楚每个参数的类型、范围和示例值,减少模型自由发挥空间;第二层,在调用前用 pydantic 这类库做 schema 校验,参数类型不对直接拦截;第三层,对调用结果做一个语义校验,比如判断返回结果是否真的与查询意图匹配。这三层用完,工具调用这一环才真正可靠。
4. 一个真实规划模块的设计:状态、重试与重规划
如果面试进行到这里,你已经把两条路线和拆解逻辑说清楚了,接下来的加分项就是讲一个真实模块的设计细节。我拿之前做过的一个跨平台智能助手项目来举例,这个项目的核心功能是帮用户完成多步骤事务办理,规划模块是整个系统最关键的组件,也是踩坑最多的地方。
4.1 规划器的核心状态:从 IDLE 到 DONE
我们一开始把规划器当成一个简单的"LLM 调用+循环"来实现,结果很快就发现了问题:执行次数一多,整个服务就没法控制了。后来我们重新设计,把规划器当成一个状态机来管理。核心状态大概有这么几个:
- IDLE:等待新任务,系统空闲
- PLANNING:LLM 正在生成整体计划
- WAITING_CONFIRM:计划已生成,等待用户确认或修改
- EXECUTING:正在按计划执行当前步骤
- WAITING_TOOL:等待外部工具返回结果
- REPLANNING:发生失败或计划偏差,LLM 正在重新生成计划
- FAILED:到达最大重试次数,任务终止
- DONE:所有步骤执行完成,产出最终结果
这个状态机的好处是,你可以在任何状态下对系统做干预。比如用户在中途说"取消"、"改预算"、"换目的地",你不会在一个深度的循环里手足无措,而是可以通过状态切换安全地回到 PLANNING 或 WAITING_CONFIRM。面试的时候能把这段讲出来,面试官就知道你处理过真实场景。
4.2 重规划机制:什么时候触发、怎么触发
重规划是这个模块的心脏。为了讲清楚它的必要性,我举一个特别典型的案例:有个任务需要调用某政务类查询接口,正常流程是查完 A 再查 B,B 依赖 A 返回的编号。有一次 A 返回的数据里没有编号字段,整个后续链条就断了。
当时我们设计的处理办法是这样的。第一,EXECUTING 阶段一旦捕获到工具报错或者关键字段缺失,不直接让整个任务失败,而是把错误信息原封不动地整理成文本,连同当前任务步骤的历史上下文一起送到 LLM 那里。提示词大概是:"当前计划第 3 步执行失败,失败原因是……目前已经做到第 3 步,已获得的信息有……请重新规划后续步骤。"
第二,给重规划加一个最大次数限制。我们当时设置的是两次。加上第一次原始规划,一个任务最多经历三次规划。超过这个次数说明这个问题可能真的超出了模型的规划能力,再让它尝试只会烧钱,不如直接进入 FAILED 状态并通知用户。
第三,重规划之后必须做计划差异校验。我见过太多次 LLM 重规划之后把已经执行完的步骤又重新来一遍,比如用户已经确认了预算,重规划之后又生成了一个超预算的方案。所以重规划之后要把新计划和旧计划做对比,检查是否违背了用户已经确认的关键条件。
4.3 状态持久化:中断恢复与用户修改
最后一个值得讲的细节是状态持久化。Agent 任务一般都比较长,中途可能遇到服务重启、用户关闭页面、切换设备。我们当时把所有状态序列化成了 JSON,每完成一个步骤就写入存储。
这样做有一个很实际的收益:用户可以在第二天重新打开应用,Agent 能接着昨天的进度继续执行,而不是把所有任务从头再来一遍。这个功能对真实用户非常友好。毕竟让用户看着 Agent 白白重复已经做过的操作,是很糟糕的体验。
持久化设计还有另一个作用,就是支持用户修改需求。比如用户看了一眼生成的计划,说"第二天的行程我不想安排太满"。你把当前计划的第 5、6 步标记为待重排,这两个步骤的内容和约束条件一并喂给 LLM,重新生成一小段计划插入原来的位置。这个操作比整体重规划省得多,也明显更可控。
5. 面试中三个翻车回答,以及怎么把它们变成加分项
说完了方案设计,我们回到面试现场本身。我在面试时收集了不少真实的翻车回答,这里拿出三个最常见的,讲讲为什么会翻车,以及怎么从一个被动回答变成加分项。
5.1 翻车一:"ReAct 就是让模型推理加行动"
这个回答没有错,但也没有信息量。如果候选人只答这一句,我一追问"你的循环终止条件是什么""如果工具一直返回空结果怎么办",他就答不出来了。
正确的答法要把它展开成一个完整的循环控制逻辑。你可以这样说:ReAct 本质上是一个 while 循环,循环体是"根据当前观察进行推理→选择动作→调用工具",终止条件一般是两个:要么模型自己输出了 Final Answer,要么执行步数到达了系统预设的上限。如果到达上限还没得出结论,我们会把已收集的信息作为上下文,让模型尝试生成一个尽量完整的答案,或者进入人工处理流程。这一套讲下来,同一个名词的含金量完全不同。
5.2 翻车二:"我们项目直接用开源框架的 Agent 就行"
很多候选人一听到规划问题就想到自己常用的那套开源 Agent 框架,然后开始背框架文档。面试官问的是你的设计思路,不是框架说明书。而且开源框架默认的规划行为在真实业务里几乎都需要大量定制,因为框架根本不知道你的工具会返回什么格式的数据。
如果你确实用了某个框架,正确的答法是讲清楚你做了什么定制。比如说:框架默认的 AgentExecutor 执行完一步就直接进入下一步,但我们的业务里某几个工具会返回临时性的失败码,需要重试三次。因此我改造了执行器,加入了针对特定工具错误码的重试逻辑;又比如说:框架默认的 Agent 不会提前给用户展示计划,我在外层套了一个 Plan 确认节点,把计划发给用户,用户确认后再进入执行循环。讲到这里,框架只是一个载体,你本人的设计能力才是核心。
5.3 翻车三:"规划就是让 LLM 输出一个 JSON 计划"
这个说法让我哭笑不得。它把规划的落地点说对了,但把规划的复杂度严重低估了。LLM 输出 JSON 只是整个规划流程里非常靠前的一小步,真正的挑战在于这个 JSON 生成之后。
我一般会继续追问:这个 JSON 里可能包含一个不存在的工具名,你怎么校验?某个步骤的依赖字段指向了一个后面才出现的步骤,你怎么处理?这些都要答出具体的解法。比方说:我们会拉一份工具清单做本地匹配;会校验依赖关系的拓扑排序是否合法;会把计划里的步骤数量和预计工具调用次数加起来做成本估算,超过预算就退回让人工确认。这一层补上之后,这个回答才配得上"规划"两个字。
6. 这道题的满分回答框架,拆开给你看
讲了这么多,最后我总结一个可以直接在面试里用的回答框架。只要准备时间允许,我会建议候选人用这个框架来组织思路,不管面试官从哪个角度切入,你都能稳稳地把话术落下来。
6.1 三层答题法:定义、选型、落地
第一层是定义问题,用一句话讲清楚你会把 Agent 规划理解成什么。这是为后面所有内容定的基调。我比较推荐的说法是:我认为 Agent 的规划本质上是把用户模糊的目标,转化为一组有依赖关系、可执行、可验证的子任务,并为每个子任务匹配相应的工具和退出条件。
第二层是选型逻辑,说明在你的场景里你会选哪条技术路线,以及为什么。这里最好带上对比权衡,突出"我没有无脑选择某个方案,而是基于我的任务特点做的判断"。
第三层是落地细节,这是区分度最高的部分,也是你前面讲的所有内容能否立住的关键。讲一两个你踩过的坑,配上你当时的解法,面试官就会由心底认可你。
6.2 一个两分钟的话术范本
假设面试官直接问"Agent 怎么做规划",你可以这样回答:
我一般把 Agent 的规划拆成三件事。第一件事是把用户目标结构化,也就是任务拆解。拿"规划一次旅行"举例,我会让它生成一个包含子任务、依赖关系、工具绑定、完成标准的计划结构。第二件事是设计执行控制,我会根据任务特性选择一次性生成完整计划还是边执行边规划。如果路径比较确定,我偏向 Plan-and-Execute;如果探索性强,我会用 ReAct 循环,但会严格控制最大步数。第三件事是安排失败恢复。我的系统里有一个重规划机制,某一步执行失败时会把错误信息连同历史上下文交给模型重新生成计划,同时限制最多重规划两次,防止无限循环烧钱。同时每一步状态都会持久化,方便用户中途修改需求或跨设备继续执行。
这个回答大概不到两分钟,却把定义、选型、落地三层全部覆盖了。面试官后续无论往哪个方向深挖,你都有内容可以接住。
6.3 面试前值得做的三个小演练
最后分享三个我在准备这类面试题时觉得特别有效的演练方式。
演练一,拿不同复杂度的任务考自己。从"帮我查明天的天气"到"帮我规划一次 7 天的出境自由行",逐一走一遍:这个任务适合哪种路线?需要哪些工具?哪些步骤可能失败?你怎么恢复?这样能把方法论真正内化成自己的思路。
演练二,手动模拟一遍 ReAct 循环。拿一张纸把自己当成模型,写下一步 Thought、下一步 Action、下一步 Observation,然后再写下一步 Thought。不要用代码,纯粹手动走三轮。你很快就能体会到模型在规划时的"纠结感",也更理解为什么循环要加终止条件。
演练三,读一个开源 Agent 项目的规划器源码,注意不是看文档,是看代码。重点找三个东西:它在循环内部是怎么处理异常的?它在哪里插入重规划逻辑?它的计划数据结构里有哪些字段?这三种细节,比任何面试题汇总都有价值。
我把这道题的回答逻辑完全拆给你了。最近面试下来,能把这些内容组织成一套连贯思路的候选人,一个巴掌数得过来。绝大多数人缺的其实不是技术,而是在项目里没有真正把规划当成一个系统问题去思考,也没有花时间去沉淀那些失败经验。面试官一眼就能看出你是背出来的,还是做出来的。希望你去刷这道题之前,先自己动手把一个规划模块从头到尾设计一遍,甚至实现一遍。到那时候,你会发现自己再也不会怕面试官问规划的问题了。