本文主要阐述行为树的概念和语法,以及学习过程中常常会遇到各种概念和专有名词。
0x00 有限状态机(FSM,Finite-state Machine)
有限状态机是一种用来进行对象行为建模的工具,其作用主要是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件。在计算机科学中,有限状态机被广泛用于建模应用行为、硬件电路系统设计、软件工程,编译器、网络协议、和计算与语言的研究。比如下图非常有名的TCP协议状态机。
TCP协议状态机
我们可以通过一个小案例来理解FSM:比如士兵的行为有“巡逻”,“追击敌人”,“攻击敌人”,“逃跑”等行为,响应的事件就有“发现敌人”,“追到敌人”,“敌人逃跑”,“敌人死亡”,“自己血量不足”等。那么可以写成这样一个状态机:
1.士兵 “”,如果 “”,那么,“”
2.士兵 “”, 如果 “”, 那么,“”
3.士兵 “”, 如果 “”, 那么,继续 “”
4.士兵 “”, 如果 “”, 那么,继续 “”
5.士兵 “”, 如果 “”, 那么,“”
其中,士兵就是这个FSM的执行者,红色的就是状态,蓝色的就是事件,整个状态机的行为可以总结为:
当前状态=>是否满足条件1,如果是,则跳转到对应状态
否则=>是否满足条件2,如果是,则跳转到对应状态
由此可看出,状态机是一种“事件触发型”AI,就是只有事件的触发才会发生引起状态的变化。
0x01 层次化状态机(HFSM,Hierarchy Finite-state Machine)
简单来说,就是FSM当状态太多的时候,不好维护,于是将状态分类,抽离出来,将同类型的状态做为一个状态机,然后再做一个大的状态机,来维护这些子状态机。
举个决策小狗行为的例子:
我们对小狗定义了有很多行为,比如跑,吃饭,睡觉,咆哮,撒娇,摇尾巴等等,如果每个行为都是一个状态,用常规状态机的话,我们就需要在这些状态间定义跳转,比如在“跑”的状态下,如果累了,那就跳转到“睡觉”状态,再如,在“撒娇”的状态下,如果感到有威胁,那就跳转到“咆哮”的状态等等,我们会考量每一个状态间的关系,定义所有的跳转链接,建立这样一个状态机。如果用层次化的状态机的话,我们就先会把这些行为“分类”,把几个小状态归并到一个状态里,然后再定义高层状态和高层状态中内部小状态的跳转链接。
其实层次化状态机从某种程度上,就是限制了状态机的跳转,而且状态内的状态是不需要关心外部状态的跳转的,这样也做到了无关状态间的隔离,比如对于小狗来说,我们可以把小狗的状态先定义为疲劳,开心,愤怒,然后这些状态里再定义小状态,比如在开心的状态中,有撒桥,摇尾巴等小状态,这样我们在外部只需要关心三个状态的跳转(疲劳,开心,愤怒),在每个状态的内部只需要关心自己的小状态的跳转就可以了。这样就大大的降低了状态机的复杂度,另外,如果觉得两层的状态机还是状态太多的话,可以定义更多的状态层次以降低跳转链接数。
0x02 决策树(DT,Decision Tree)
在介绍决策树之前,先说一下分类算法,它是机器学习领域里的基本算法之一,常见的分类算法有贝叶斯分类算法、KNN算法、逻辑回归算法、神经网络算法等,当然,还有各种深度学习算法。决策树是一种简单但广 泛使用的分类器,因此,。
See:《决策树(Decision Tree):通俗易懂之介绍》。
0x03 行为树(BT,Behavior Tree)
行为树的概念最早来源Halo这款游戏里的AI控制结构,它通过类似于决策树的树形决策结构来选择当前环境下应该做出的具体行为。
先借用网上的一张图来诠释下行为树到底是怎么样的:
行为树
可以参考:《行为树概念与结构》。
0x04 决策树 vs 行为树
从名称上来看,决策树就是为了制定决策,行为树是为了控制行为。两者最主要的区别在于遍历的方式,而且布局方式和节点“类型”也不一样。
决策树每次都从根到叶子分析。为了让决策树正确工作,每个父节点的子节点都要能表达出父节点所有可能的决策。如果一个节点可以应答“是,否,可能”,那么那必须有三个子节点:“是”节点、“否”节点和“可能”节点。这就意味着,在到达结束节点前,总是可以遍历到某个底层节点。这种遍历总是向下的。如图所示:
我们从根节点开始,基于某种分析来选择节点1、2、3。首先选择3,然后再执行另外一种分析,并选择B或B...好吧,这里我重用了下层的图形,抱歉。就当左边的B是个假B吧。
行为树有不一样的分析方法。第一次分析(或重置后),它们从根节点开始(这里所有的父节点作为选择器),并且从左到右分析每个子节点。这些子节点按优先级排列。如果一个子节点所有的条件都满足,就开始它的行为。当一个节点开始一个行为,这个节点被设置为“运行中”,并返回这个行为。下一次分析这棵树的时候,重新检查最高优先级的节点,当走到“运行中”节点时,它便知道从它暂停的地方继续执行它。在到达结束状态之前,这个节点可以包含一系列的行动和条件。任意条件失败,遍历器便会返回到父节点。父选择器接着移动到下一个优先级的子节点上。我尝试用下图表达:
行为树遍历
遍历从根节点开始,走到1号子节点,检查子节点的条件(例如“周围是否有敌人?”)。这个条件失败了,遍历器返回树(根节点)并移动到2号节点。2号节点执行了一个行动(例如寻路)和一个行为(例如沿路线走)。“沿路线走”的行为被设置为“运行中”,并且行为树返回状态“运行中”。失败和完成的节点会返回“待命”。接着下一次我们检查这个树,我们再次从最高优先级的节点开始。它又失败了,所以我们执行到2号节点。在2号节点,我们发现有一个“运行中”的行为。当我们发现这个行为完成了,那么我们把它标记成“完成”并返回。然后这颗行为树就被重置了,并准备好再次开始。
你会发现行为树(比决策树)更复杂。行为树(比决策树)更牛逼并且允许更复杂的行为。决策树易于理解和实现。所以,如果你需要更复杂的行为和更多对行为的控制,那么你可以使用行为树。决策树可以被作为行为树的一部分,或者单独使用来实现简单的AI。
0x05 规则引擎、工作流及其他
在定制业务规则的时候,我们还会经常遇到规则引擎和工作流的概念,其中行为树和规则引擎的概念有一定的相似性,容易混淆,在此一并讲解。
我们先来探讨下规则引擎和工作流的概念,以及两者的区别。
什么是工作流引擎?
工作流引擎是一个软件应用程序或工具,旨在帮助用户执行一系列构成“业务流程”或“工作流”的重复任务。工作流引擎从工作流的设计中获取提示,并指导流程完成其各个步骤。这是通过工作流自动化来完成的。
许多人认为工作流引擎和业务规则引擎是相同的。有些甚至认为可以互换地使用工作流引擎和业务规则引擎的术语,但实际上它们是完全不同的概念。
工作流程示意图
让我们看一下这两个术语在实际使用中的一些差异,来消除对这两个术语的误会。
工作流是将数据处理成完成状态的一系列任务。这是一个有时间限制的编排,任务具有重复性和预测性。例如,当你从你最喜欢的网上商店买一条牛仔裤时,它启动了一个涉及付款处理、订单履行和发货等多个步骤的工作流。
并且在数量众多的企业中大多数工作流程都是手动完成的,通过电子邮件或书面文件进行审批。但近年来,现代化企业已经使用工作流软件实现他们的工作流自动化,以此提高速度、准确性和成本效率。
大多数这些工具都是用流程设计器编码完成的,该特性允许软件用户在不需要编码的情况下运行工作流实例。工作流设计器允许管理员以线性顺序派发任务,根据表单中的数据动态分配任务,并添加条件、异常、并行分支等设定来丰富工作流的种类。
那么工作流引擎是从哪里来的呢?在这种情况下,工作流引擎是一个预先编码的脚本,它考虑了工作流设计,即任务应该如何从一个阶段流向另一个阶段,并执行该步骤。工作流引擎是嵌入在软件中的代码,用于将任务从一个阶段推送到另一个阶段。
什么是业务规则引擎?
业务规则引擎可以理解为程序中的一组条件,如果满足所有条件,则执行相应的程序代码。它是关于设置一个软件在特定参数内的行为准则。规则引擎的优点是,它允许非技术性软件用户根据其业务需求更改软件行为,而无需更改底层代码。业务规则引擎根据大量的信息数据做出快速可靠的决策,通常这些数据对于人类大脑来说太大了,无法处理。
业务规则引擎是一个更广泛的概念中的一部分,它的范围甚至超出了工作流管理。规则引擎无法控制编排任务,但它们根据特定条件为推断决策指南。同时,它还可用于在给定条件下模拟工作流的过程。
例如下面这个电子商务网站如何将以下规则引擎之一应用于其支付网关的示例:如果买家年龄在18到29岁之间,可享受15%的青年折扣;如果买家选择年龄大于59岁,则对该商品给予20%的折扣;如果买家选择年龄在30到59岁之间,则不对该商品进行折扣。
组合在一起的一组业务规则引擎称为规则集;它们通常以表格形式或决策树表示。企业软件主要使用业务规则引擎来确保操作的一致性。
规则引擎的最大优点是,它使业务规则所有者可以实现业务规则,而不是让程序员承担责任。即使您有一个敏捷的过程,不断获得利益相关者的反馈并进行快速迭代,它仍然无法达到让制定业务规则的人员也执行它们所能达到的效率水平。
但是凡事有利即有弊,规则引擎有一定的学习成本,如果你的业务并不复杂,就不应该引入这个复杂的概念。
工作流引擎与业务规则引擎的区别
工作流引擎和业务规则引擎都允许非技术性的最终用户在运行时更改流程行为,而无需更改代码。但它们的不同之处多于相似之处。如上所述,它们的工作模式和目的有着根本的不同。下面列出了工作流引擎和业务规则引擎之间的一些其他区别:
规则引擎与工作流的比较
了解完规则引擎和工作流的概念和区别,我们再回过头来看看行为树与规则引擎,就会发现其实两者有完全不同的应用场景:前者更适合游戏或者仿真领域中实体AI,后者适合作为业务流程管理(BPM)。
1x01 行为树语法
行为树4大类型的Node:
- Composite Node 组合节点
- Decorator Node 修饰节点
- Condition Node 条件节点(叶节点)
- Action Node 动作节点(叶节点)
任何Node被执行后,必须向其Parent Node报告执行结果:成功/失败。
这简单的成功/失败汇报原则被很巧妙地用于控制整棵树的决策方向。
先看Composite Node,其实它按复合性质还可以细分为3种:
-
Selector Node
当执行本类型Node时,它将从begin到end迭代执行自己的Child Node:
如遇到一个Child Node执行后返回True,那停止迭代,
本Node向自己的Parent Node也返回True;否则所有Child Node都返回False,
那本Node向自己的Parent Node返回False。 -
Sequence Node
当执行本类型Node时,它将从begin到end迭代执行自己的Child Node:
如遇到一个Child Node执行后返回False,那停止迭代,
本Node向自己的Parent Node也返回False;否则所有Child Node都返回True,
那本Node向自己的Parent Node返回True。 -
Parallel Node
并发执行它的所有Child Node。
而向Parent Node返回的值和Parallel Node所采取的具体策略相关:
Parallel Selector Node: 一False则返回False,全True才返回True。
Parallel Sequence Node: 一True则返回True,全False才返回False。
Parallel Hybird Node: 指定数量的Child Node返回True或False后才决定结果。
Parallel Node提供了并发,提高性能。
不需要像Selector/Sequence那样预判哪个Child Node应摆前,哪个应摆后,
常见情况是:
(1)用于并行多棵Action子树。
(2)在Parallel Node下挂一棵子树,并挂上多个Condition Node,
以提供实时性和性能。
Parallel Node增加性能和方便性的同时,也增加实现和维护复杂度。
PS:上面的Selector/Sequence准确来说是Liner Selector/Liner Sequence。
AI术语中称为strictly-order:按既定先后顺序迭代。
Selector和Sequence可以进一步提供非线性迭代的加权随机变种。
Weight Random Selector提供每次执行不同的First True Child Node的可能。
Weight Random Sequence则提供每次不同的迭代顺序。
AI术语中称为partial-order,能使AI避免总出现可预期的结果。
再看Decorator Node,它的功能正如它的字面意思:它将它的Child Node执行
后返回的结果值做额外处理后,再返回给它的Parent Node。很有些AOP的味道。
比如Decorator Not/Decorator FailUtil/Decorator Counter/Decorator Time…
更geek的有Decorator Log/Decorator Ani/Decorator Nothing…
然后是很直白的Condition Node,它仅当满足Condition时返回True。
最后看Action Node,它完成具体的一次(或一个step)的行为,视需求返回值。
而当行为需要分step/Node间进行时,可引入Blackboard进行简单数据交互。
整棵行为树中,只有Condition Node和Action Node才能成为Leaf Node,而也
只有Leaf Node才是需要特别定制的Node;Composite Node和Decorator Node均
用于控制行为树中的决策走向。(所以有些资料中也统称Condition Node和Action
Node为Behavior Node,而Composite Node和Decorator Node为Decider Node。
通过上述的各种Nodes几乎可以实现所有的决策控制:if, while, and, or,
not, counter, time, random, weight random, util…
总的来说,行为树具有如下几种优点,确实是实现AI框架的利器,甚至是一种
通用的可维护的复杂流程管理利器:
静态性
越复杂的功能越需要简单的基础,否则最后连自己都玩不过来。
静态是使用行为树需要非常着重的一个要点:即使系统需要某些”动态”性。
静态性直接带来的好处就是整棵树的规划无需再运行时动态调整,为很多优化和预编辑都带来方便。
直观性
行为树可以方便地把复杂的AI知识条目组织得非常直观。
默认的Composite Node的从begin往end的Child Node迭代方式就像是处理一个
预设优先策略队列,也非常符合人类的正常思考模式:先最优再次优。
复用性
各种Node,包括Leaf Node,可复用性都极高。
扩展性
虽然上述Node之间的组合和搭配使用几乎覆盖所有AI需求。
但也可以容易地为项目量身定做新的Composite Node或Decorator Node。
还可以积累一个项目相关的Node Lib,长远来说非常有价值。
1x01 更多的学习资料
强烈安利这个博客,比如这篇文章:《从有限状态机(FSM)到行为树(Behavior Tree)》
网友评论