想象一位总厨接到一个棘手的委托:三天后要为三十位客人办一场晚宴。他没有立刻冲到灶台前手忙脚乱,而是先铺开一张纸,把“晚宴”这个巨大的目标拆成骨架——定菜单、备食材、烹饪、摆桌;随后把“烹饪”再拆成“炖汤、煎主菜、蒸甜品”;一层层拆下去,直到变成“切葱、焯水、关小火”这种厨房里任何人看一眼就能照做的动作。这种“从大目标到小动作、按图索骥”的规划方式,正是本章的主角——层次化任务网络,简称 HTN(Hierarchical Task Network)。它不靠盲目试错,而是靠一张张沉淀了老师傅经验的“菜谱”,把复杂任务稳稳当当拆到底。
学会 HTN,你就掌握了把“目标”翻译成“可执行动作序列”的结构化方法,这是让 AI Agent 拥有“靠谱执行力”的必修课,也是自主规划方向面试与实战的硬通货。
可视化演示
展示HTN任务递归分解树(根任务→复合任务→原子操作)、方法库匹配过程(前置条件检查与子任务生成)、以及HTN与状态空间规划搜索空间对比。
本节配有交互动效(进入视口后自动加载,约 3KB)。
HTN任务递归分解树 根任务(root)递归分解为3个复合任务(cmp),再分解为6个原子操作(atm) 分解路径由方法库约束,每层展开遵循预定义的分解规则 plan=decompose(root,methods) 三层分解将高层任务展开为可执行操作序列
HTN核心思想
总厨拿到宴席订单后,第一件事不是拿起炒勺,而是铺开纸,把“晚宴”一笔一划拆成“前菜、主菜、汤品、甜品”;再往下一层,“主菜”拆成“备料、烹饪、装盘”。每拆一层,问题就具体一层。脑中若没有整本菜谱,面对“晚宴”二字只会愣在原地;老主厨的厉害之处,在于他拥有一套成熟的拆解习惯,把宏大的承诺变成一道道可执行的工序。
计算机里的 Agent 也一样。面对“举办晚宴”这种高层目标,如果直接去状态空间里盲目搜索,就像没有菜谱的学徒面对满灶台食材一样无从下手。HTN 的出发点恰恰是:不直接搜状态,而把目标当作“任务”,用一个可复用的方法库(也就是菜谱集)把复合任务递归地拆成越来越小的子任务,直到变成能直接执行的原子动作。规划的质量,取决于方法库是否靠谱。
数学上,这等价于一条不断应用方法(method)的分解链。规划器从初始任务出发,每应用一个方法,就把当前复合任务替换成一组子任务;子任务若仍为复合任务,就继续匹配方法,直到所有叶节点都是原子任务。最终得到的不是一条“碰运气”碰出来的路径,而是由领域知识约束出的合理流程。
就像总厨把“晚宴”一层层拆到“关小火”才放心交给帮厨,HTN 把“高层目标”一路还原到“可执行的小动作”。拆得够细,执行才不慌——这是整个 HTN 思想的灵魂。
- 起点复合任务$t_0$ 表示最顶层的复合任务,比如“做晚宴”,它是规划的唯一入口。
- 方法驱动拆分$m_1$ 是方法库中适用于 $t_0$ 的方法,它把 $t_0$ 替换成 $t_1, t_2$ 两个子任务。
- 递归推进$m_2, m_3$ 继续作用在子任务上,$\cdots$ 表示“匹配方法→替换任务”的循环反复进行。
- 原子收束最终叶子全部变成 $a_1, a_2, \ldots, a_n$,即能直接交给执行器的动作序列。
基本概念模型
菜谱要发挥作用,得先约定“菜”和“动作”的区别。“醋溜土豆丝”是一道菜——它还能继续拆成“刮皮、切丝、爆炒”;而“切丝”是不可再拆的基本动作。同一样东西,在总厨眼里有时是“菜”,有时只是“手部动作”,区分不清,后厨就会乱套。
HTN 把它形式化成四个概念:复合任务(compound task)需要被方法继续分解;原子任务(primitive task)直接对应领域动作;方法(method)描述“复合任务如何拆成子任务网络”;操作符(operator)描述原子任务执行后对世界状态产生什么效果。前两者回答“要拆什么”,后两者回答“怎么拆、怎么执行”。
形式化地说,一个方法由三部分组成:方法头(要处理的复合任务)、子任务网络(产出的子任务及其约束)、约束集合(前置条件、变量绑定等)。操作符则类似经典规划中的动作,定义前提和效果,负责真正改写世界状态。这样,规划器的每一步都有了明确依据:该谁分解、该谁执行,各司其职。
有了“菜”和“动作”的区分,总厨的菜谱才能编写、执行;有了复合任务与原子任务的区分,HTN 的规划器才知道哪些任务要继续拆、哪些可以直接上手做。概念模型,就是整套规划的“行业术语表”。
- 方法头$\text{head}(t)$ 注明该方法服务于哪个复合任务,相当于菜谱封面写着的菜名。
- 子任务网络$T_{\text{sub}}$ 是分解后得到的子任务集合,含它们之间的先后与并行关系。
- 约束集合$C$ 记录前置条件、变量绑定等规定,例如“必须要有砂锅”“所有子任务必须串行”。
方法库设计
一家餐馆的菜谱库不会只有一道菜。糖醋排骨、红烧排骨都是“做排骨”,但步骤、火候、配料天差地别;同样是“处理食材”,荤菜要解冻、素菜要浸泡。菜谱库要想好用,每本菜谱都得写清楚:适用什么菜、需要什么前提、拆成哪几步,否则帮厨一翻就头晕。
HTN 的方法库(method library)正是这种“结构化菜谱库”。每条方法由方法头声明它对付哪个复合任务,由前置条件声明什么状态下才能使用,由子任务网络声明拆解结果。规划时,规划器遍历方法库,寻找“方法头匹配 + 前置条件成立”的方法来分解当前任务;若多个方法同时可用,就产生多个分解分支,形成一棵搜索树。方法库设计得好不好,直接决定这棵树大不大、歪不歪。
子任务之间的顺序约束也在方法里定义,通常用偏序关系表示“谁必须先于谁”。比如“炖汤”方法要求“加水”先于“点火”,而“洗菜”“切菜”则可以并行。约束的分类主要包括顺序约束、变量绑定约束和前置条件,它们共同限定分解的合法性,也决定了最终计划的形态。
好的菜谱库是餐馆的底气,好的方法库是 HTN 规划器的底气。方法库越贴近真实领域,规划器拆出来的方案就越像老师傅的手笔;反之,菜谱写错了,再熟练的厨师也会端出黑暗料理。
- 子任务序列$t_1, t_2, \ldots, t_k$ 是该方法产出的 $k$ 个子任务,它们构成一个任务网络。
- 偏序运算符$t_i \prec t_j$ 表示 $t_i$ 必须先于 $t_j$ 执行,允许部分任务并行。
- 网络形态尖括号勾勒的是带约束的任务网络,而不是简单排队的串行清单。
规划执行流程
晚宴当天,总厨手里攥着一张待办清单。他先看清单顶部:“烹饪”是个大词,没法直接动手——翻开菜谱库,找到《宴会烹饪》方法,把“烹饪”划掉,替换成“炖汤、煎主菜、蒸甜品”;再看“炖汤”,还是大词,继续翻菜谱……直到清单上只剩下“开火”“倒水”“放盐”这类即刻能做的动作,他才放心交棒。
HTN 规划器的执行主体,就是这样一个不断改写“任务网络”的循环。它维护一个待处理任务集合,每次取出一个任务检查:如果是原子任务,就搜索匹配的操作符并预演执行、更新状态;如果是复合任务,就遍历方法库选择适用方法,用其子任务网络替换该任务。循环往复,直到待处理集合为空。若某个方法分支走入死胡同(子任务找不到任何可匹配的方法),规划器就回溯,尝试另一个方法分支。
从递归函数的角度看,规划过程只有三种情况:任务集合为空则返回空计划;遇到复合任务则选方法替换后继续递归;遇到原子任务则匹配操作符、记录动作后继续。三个分支循环嵌套,构成了 HTN 规划器的完整骨架。
总厨按着这套“翻菜谱→替换→再翻”的流程,最终能把整场晚宴变成一张精确到分钟的动作时刻表。HTN 规划器也是如此:它不靠枚举所有可能性碰运气,而是让方法库里的经验一步步牵引,直到任务清单清零。
- 递归终止$t_0 = \varnothing$ 表示待处理任务集合为空,规划完成,返回空计划。
- 分解分支遇到复合任务时,从方法库 $D$ 中选方法 $m$ 并替换为子任务网络,得到新任务集合 $t'_0$ 后继续递归。
- 执行分支遇到原子任务时,从操作符集合 $O$ 中匹配 $a_0$,把它记录进计划头部,再规划剩余任务。
优势与局限
为什么老主厨出菜又快又稳?因为他不用每次从零发明火候,直接照菜谱执行即可。HTN 最大的优势就是“把经验变成捷径”:方法库直接告诉规划器“这类任务通常怎么拆”,搜索空间被大幅压缩,规划速度快、结果稳定、可解释。客户问起为什么这么安排,总厨能一五一十讲出依据。
用复杂度语言来说,经典状态空间规划要在每一层尝试所有动作组合,搜索空间近似 $b^d$ 指数爆炸;而 HTN 每到一层只从适用方法里挑选,搜索空间约等于各任务可用方法数的乘积。方法库中的领域知识越充分,这个悬殊就越大——这正是“知识即算力”的直观体现。
但菜谱也有天花板:菜谱库里没有的菜,总厨做不出;食材超出菜谱假设,方法就无法落地。HTN 的局限同样来自对领域知识的依赖——方法库需要领域专家手工构建与维护,方法缺失时规划直接失败;面对完全未知的场景或剧烈动态变化,静态方法库显得僵硬,需要重规划或引入机器学习动态补充。理解这条边界,才能选对战场:HTN 不是万能规划器,而是“领域知识明确、流程可枚举”场景的利器。
- HTN 侧搜索空间$\prod_{t \in T}|M_t|$ 表示对每个任务 $t$,只考虑方法库中适用的 $|M_t|$ 个方法。
- 状态空间侧搜索空间$b^{d}$ 是经典规划中每个状态约 $b$ 个可选动作、深度 $d$ 的指数爆炸。
- 对比含义当方法库足够精准时 $|M_t|$ 远小于 $b$,HTN 搜索空间实现数量级缩小。
应用与融合
老师傅的经验不会只封存在一家厨房。教徒弟、开分店、写入中央厨房 SOP——同一套菜谱在不同灶台上重复发光。HTN 的方法库正是“把老师傅经验结构化”的载体:机器人用它规划“做早餐”的动作链,游戏 AI 用它编排 NPC 的行为流程,物流系统用它拆解配送工单,工作流引擎用它驱动审批与执行。
在具身智能中,“打开冰箱→取出鸡蛋→煎蛋→装盘”由 HTN 自上而下拆解,底层的机械臂控制器执行最后一个原子动作。在工业与物流中,“完成订单”被层层分解为“拣货、打包、调度、配送”,方法库浓缩了资深调度员的经验。这些场景的共同点是:领域规则清晰、流程可枚举,正好踩中 HTN 的能力区。
更进一步,HTN 正与 Agentic AI 深度握手。大语言模型擅长生成“如何做事”的常识,却不擅长保证每一步都不跳、不错;HTN 恰好提供结构化骨架。实践中常见的分工是:LLM 按需生成或修订方法库,HTN 规划器负责严格递归分解。多智能体团队还可各持一套方法库,围绕共享目标协同规划,形成“LLM 补常识、HTN 保结构”的混合范式。
从单模型到多智能体协作,从静态流程到动态环境,HTN 的方法库哲学始终成立:把领域知识沉淀成可复用的“菜谱”。而要把这套体系推向工业级,仍需跨学科的知识融合与产学研协同——就像一道名菜走向全国连锁,靠的从来不止一位厨师,而是一整套可复制的技艺体系。
- 方法库汇集$\mathcal{D}_i$ 是第 $i$ 个智能体的方法库,取并集得到团队方法库 $\mathcal{D}$。
- 全局目标$G$ 是团队共享的高层复合任务,例如“双机器人协作完成装配”。
- 联合规划$\pi_{\text{team}} = \text{HTN}(G, \mathcal{D}, s_0)$ 表示在初始状态 $s_0$ 上,用 $\mathcal{D}$ 对 $G$ 递归分解得到团队方案。
AI 应用场景
具身智能机器人:把“做早餐”拆成机械臂指令
阶段:任务规划与执行阶段
解决的问题:传统机器人把“做早餐”写死成 if-else 流程,场景一变化就崩溃。HTN 把复合任务按方法库递归分解为机械臂可执行的原子动作,并显式处理前置条件(食材、工具是否就绪),让规划更稳健、可解释。
具体案例:服务机器人接到“制作早餐”指令,HTN 规划器查方法库:“备餐 = 取食材 + 煎蛋 + 烘面包”,“煎蛋 = 开火 + 倒油 + 磕蛋 + 翻面”。当初始状态缺少“鸡蛋”时,规划器先安排“采购”子任务,再继续分解,最终形成一条完整可执行的动作链交给底层运动控制器。
游戏 AI:NPC 行为编排不再手忙脚乱
阶段:游戏 AI 行为决策阶段
解决的问题:传统行为树需要手写大量节点,行为一变整棵树重构。HTN 方法库让策划把“巡逻→警戒→战斗→撤离”写成方法,NPC 根据局势动态套用,行为既自然又可控。
具体案例:3A 游戏里的守卫 NPC 遭遇入侵时,“处理入侵”方法展开为“警戒搜索 + 呼叫支援 + 追击入侵者”,每个子任务再分解为寻路、播放动画、攻击等原子动作。当玩家躲入掩体,规划器重新选择方法分支,NPC 不再机械站桩,而是展现出“有经验”的应对。
Agentic AI 智能体:LLM 补常识,HTN 保结构
阶段:LLM Agent 的工具调用与多步任务编排阶段
解决的问题:纯 LLM 自由发挥调用工具,容易跳步、遗漏前置验证。HTN 提供结构化骨架,LLM 负责动态补齐方法库,两者结合保证复杂任务稳定、可审计地执行。
具体案例:销售智能体执行“跟进客户”:HTN 拆解为“检索客户记录→生成个性化邮件→发送→预约会议”,其中“检索客户记录”再分解为“查询 CRM + 读取最近互动摘要 + 校验权限”。LLM 为缺失环节动态生成方法,HTN 规划器保证顺序与约束不丢,杜绝 AI 乱序操作。
Python 演示
class HTNPlanner: """一个极简的层次化任务网络HTN规划器演示""" def __init__(self, methods, operators, state): self.methods = methods self.operators = operators self.state = list(state) self.plan = [] def applicable(self, preconditions): return all(p in self.state for p in preconditions) def apply(self, effects): for e in effects: if e not in self.state: self.state.append(e) def decompose(self, task, depth=0): if depth > 10: return False for op in self.operators: if op["name"] == task and self.applicable(op["pre"]): self.apply(op["eff"]) self.plan.append(task) return True for m in self.methods: if m["task"] == task and self.applicable(m["pre"]): for sub in m["subtasks"]: if not self.decompose(sub, depth + 1): return False return True return False def plan_for(self, root): ok = self.decompose(root, 0) return ok, list(self.plan) def main(): operators = [ {"name": "切菜", "pre": ["有菜刀", "有蔬菜"], "eff": ["菜已切好"]}, {"name": "热锅", "pre": ["有锅", "有炉灶"], "eff": ["锅已热"]}, {"name": "炒菜", "pre": ["菜已切好", "锅已热"], "eff": ["菜已炒好"]}, {"name": "上菜", "pre": ["菜已炒好", "有餐具"], "eff": ["晚宴备好"]}, ] methods = [ {"task": "做晚宴", "pre": [], "subtasks": ["备菜", "烹饪", "摆桌"]}, {"task": "备菜", "pre": ["有食材"], "subtasks": ["切菜"]}, {"task": "烹饪", "pre": [], "subtasks": ["热锅", "炒菜"]}, {"task": "摆桌", "pre": ["有餐具"], "subtasks": ["上菜"]}, ] planner = HTNPlanner( methods, operators, ["有菜刀", "有蔬菜", "有锅", "有炉灶", "有食材", "有餐具"], ) ok, plan = planner.plan_for("做晚宴") print("规划成功:", ok) print("执行序列:", " -> ".join(plan) if ok else "无可行计划") if __name__ == "__main__": main()
return all(p in self.state for p in preconditions)逐一检查前置条件是否都在当前状态里,相当于总厨确认“食材和工具都齐了”。self.apply(op["eff"])执行操作的“效果”,把新事实写进当前世界状态,模拟做完一道工序后厨房的变化。for m in self.methods:遍历方法库,寻找能分解当前复合任务的“菜谱”。if m["task"] == task and self.applicable(m["pre"])既要菜名匹配,又要前提条件成立,两条都满足才选用这个方法。for sub in m["subtasks"]:对方法展开出的每个子任务递归调用decompose,任一子任务失败就整体返回失败。ok, plan = planner.plan_for("做晚宴")从顶层复合任务“做晚宴”出发,最终得到可直接执行的原子动作序列。
常见误区
误区我理解的 HTN 就是把“做晚宴”直接展开成“买菜、切菜、炒菜、上菜”的一张写死清单,本质跟手写 if-else 流程没有区别。
正解HTN 的关键在于“任务网络”:复合任务与方法库分离,每个复合任务可能有多个候选方法,规划器要按前置条件和约束选择、递归展开、必要时回溯。同一目标在不同初始状态下会走出不同分支,这一点与写死的流程有本质区别。方法库让规划器“看情况出招”,而不是“一条道走到黑”。
为何常见:初学者容易只盯着最终输出的动作序列,而忽略了方法库、前置条件和偏序约束这些中间结构,于是把结果误当成全部。
误区方法覆盖得越全,能处理的情况就越多,所以方法库自然是多多益善,塞得越满越强。
正解多个方法同时适用时会产生分解分支,方法库膨胀会让搜索树急剧扩大,规划变慢甚至解的质量下降。方法库需要精心设计:条件尽量互斥、分解粒度均匀、可维护可测试。好的菜谱库讲究“每本都有用、互相不打架”,而不是堆满一墙废纸。
为何常见:人们容易把“信息多”和“能力强”划等号,忽略了搜索成本与条件冲突带来的风险。
误区规划器既然输出了完整动作序列,那执行时照着做就行,环境怎么变都不用管。
正解传统 HTN 是离线、确定性的,它假设分解时世界状态不再突变。动态环境中需要周期性重规划、失败触发修复,或引入“执行→监控→重规划”闭环;好在 HTN 的层次结构支持只重规划受影响的子分支,不必推倒重来。
为何常见:看到“规划器输出完整序列”就默认序列永远成立,忽略了世界是动态的、执行中会出现意外。
误区规划结果看起来是一串动作列表,所以执行时就应该从上到下逐个做完,没有任何并行空间。
正解HTN 输出的是带偏序约束的任务网络,允许并行任务存在。比如“洗菜”和“切菜”若没有先后依赖,就可以并行推进;实际调度系统会利用这些并行关系提升效率,而不是机械地串行执行所有动作。
为何常见:计划打印出来常呈现为线性列表,让人误以为内部不存在并行结构,忽略了偏序约束才是任务网络的真实形态。
面试题
Q1. HTN 规划中“复合任务”的典型特征是?
- A.不需要任何分解直接执行即可
- B.需要调用方法继续逐层分解← 正确答案
- C.等价于一个原子性基本动作
- D.一定与其他任务相互冲突矛盾
答案:B。复合任务无法直接执行,必须由方法库中的方法继续分解,直到变成原子任务。C 把复合任务和原子任务混为一谈;A、D 均不符合 HTN 中复合任务的语义。
Q2. 方法(method)在 HTN 规划中的核心作用?
- A.直接把当前世界状态进行改写
- B.描述复合任务如何拆分子任务← 正确答案
- C.只用于判断初始状态是否良好
- D.随机生成一组可执行的动作集
答案:B。方法定义了“复合任务→子任务网络”的映射,相当于菜谱。改写世界状态是操作符的职责,随机生成违背方法库的确定性,因此 B 正确。
Q3. 下列哪一项更符合“原子任务”的定义?
- A.将葱切成小段这类基本动作← 正确答案
- B.设计一份完整的宴会菜单方案
- C.协调多位服务员的分工与协作
- D.决定采用煎煮还是油炸的烹饪
答案:A。原子任务直接对应可执行操作,不可再拆。B 和 C 属于含复杂子结构的高层活动,D 本质是方法选择而非任务,所以 A 正确。
Q4. 以下哪些属于 HTN 规划的基本概念模型?
- A.复合任务与原子任务的清晰划分← 正确答案
- B.方法库与操作符的明确分工← 正确答案
- C.梯度下降与反向传播的神经网络
- D.状态转移与奖励函数的强化学习
答案:AB。HTN 的核心概念是复合任务、原子任务、方法库和操作符。C 属于深度学习训练机制,D 属于强化学习的建模语言,均不属于 HTN 的概念体系。
Q5. HTN 相比经典状态空间规划的主要优势是?
- A.借助方法库大幅缩小搜索空间← 正确答案
- B.完全不需要任何领域知识支撑
- C.可以生成长度无限的执行路径
- D.不需要定义任何前置条件即可
答案:A。方法库携带领域经验,让搜索沿着知识引导的路径走,空间显著缩小。B、D 恰恰相反,HTN 高度依赖领域建模与前置条件;C 不符合任务最终收敛到原子动作集的特性。
Q6. 一个完整的方法通常包含哪三要素?
- A.目标、奖励、值函数的组合
- B.状态、动作、策略的三元组
- C.方法头、子任务网络、约束← 正确答案
- D.感知、决策、执行的流程
答案:C。HTN 方法形如 $m=(\text{head}, T_{\text{sub}}, C)$,即方法头、子任务网络、约束集合。A 属于强化学习,B 属于马尔可夫决策过程,D 属于机器人控制架构,均非 HTN 的方法定义。
Q7. 关于 HTN 方法库设计,下列说法正确的有?
- A.每个复合任务至少提供一个方法← 正确答案
- B.方法数量越多则规划速度一定越快
- C.不同方法条件尽量互斥且语义清晰← 正确答案
- D.方法库可由领域经验结构化沉淀← 正确答案
答案:ACD。每个复合任务至少需要一个方法才能完成分解;方法条件互斥能减少分支冲突;方法库正是领域经验的结构化沉淀。B 错误——方法过多会带来分支爆炸,反而可能拖慢规划。
Q8. 规划器遇到一个复合任务时,正确的首要处理是?
- A.立即执行该任务对应的动作
- B.将该任务从任务网络中删除
- C.在方法库中匹配适用的方法← 正确答案
- D.随机挑一个子动作尝试执行
答案:C。复合任务必须“查方法库→匹配方法→替换成子任务网络”。A 只适用于原子任务;B 会丢失目标;D 违背方法库引导的确定性。因此 C 正确。
Q9. 在 HTN 与 Agentic AI 融合的实践中,最常见的分工方式是?
- A.大模型直接输出全部动作序列
- B.HTN 反向训练大模型网络参数
- C.用 HTN 替代全部感知决策组件
- D.LLM 辅助方法库且 HTN 保结构← 正确答案
答案:D。LLM 擅长常识与动态生成,HTN 擅长结构化约束分解,两者互补形成“LLM 补常识、HTN 保结构”的主流范式。A、B、C 都颠倒了二者的职责边界。
Q10. 关于 HTN 在动态开放环境与多智能体协作中的使用,说法正确的有?
- A.可以用大模型动态补充缺失的方法库← 正确答案
- B.环境变化时只能丢弃全部已生成计划
- C.层次结构支持局部重规划来适应变化← 正确答案
- D.多智能体可共享一套方法库的语义约定← 正确答案
答案:ACD。LLM 可动态补全方法库;HTN 的层次化分解天然支持只重规划受影响的子分支,不必全盘丢弃;多智能体可通过共享方法库约定实现协同。B 过于绝对,与 C 矛盾,故排除。