面向Agent的软件设计开发方法
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.6 语义重用的Agent和组件

自从计算机科学出现以来,可重用性一直被认为是开发技术重点考虑的主要特性之一。针对创建可重用软件单元的需求,先前的“过程”,以及后来出现的“类”都是最直接的反应,这么做的目的在于:

● 加速新系统的实现;

● 通过组合大量的现有组件,确保所实现系统的质量。

面向组件的软件工程已经定义了采用组件构建系统过程中的大部分特性,并且确认了任何改进重用性的技术都应该考虑的三个概念:语义互操作性(Heiler,1995),语义的组合性(Pratt等,1999)和语义扩展性(Fankhauser等,1991)。这些概念的形式化定义在文献中找不到,对这些概念的形式化描述一般需要“非组件元模型”的部分概念。通过考虑Agent元模型的基本要素,能够给出这些概念的形式化定义。

1.语义互操作性

软件组件的前期研究在很多方面已经认识到了语义互操作的问题,并且Agent社区也已经开始研究这个课题。例如,最近对于Web服务能力特征的研究工作就遵循了已有成果所给出的指导(McIlraith和Martin,2003)。但令人奇怪的是,至今仍没有对语义的互操作性达成一致的定义,这个概念在不同的文献中可能会有一些出入,使用不同的名字,甚至有的名字可能已经使用一段时间了。

组件的语义互操作性概念来自于对语法互操作性的合理扩展,如CORBA(以及DCOM和Java RMI等类似标准)所提供的互操作性。CORBA允许组件交换消息,并且就消息的语法达成一致。消息交换的语义是隐含的,即对一个CORBA接口方法的调用一般被隐含定义如下:方法的调用实际上就是方法本身的运行。但是并没有提及这个调用的具体结果,也就是在方法结束运行后,执行方法的组件将会对外部世界产生什么样的结果。这个结果被认为是针对特定应用的,并且完全依赖于程序员的。程序员负责读接口文档,并且决定何时以及如何调用方法。

语法互操作性抑制了组件的自动装配,因为当客户决定执行服务组件的方法时,并没有提供手段去推导这个调用的结果。语义互操作就是采用方法调用结果的形式化描述,来实现对组件接口的扩展,从而允许客户自主决定什么时候,以及如何来调用这个方法。

如果认为调用一个组件方法类似于要求Agent执行一个动作,那么就可以把上面的描述应用到Agent上。利用Agent的特征,能够对语义互操作形式化如下(从客户立场出发):

给定两个 Agent CSacquaintanceC,它们被认为是语义互操作的,当且仅当:∀g:GCg,GCdone(delegate_to(C,S,g))⇒KS GCdone(delegate_to(C,S,g))

这里delegate_to(C,S,g)是C的一种抽象行为,其结果是KCGSg

这个定义阐述了:如果Agent C(在某个时间点上)想要实现目标gGCg),并且它想要把这个目标委派给S(GCdone(delegate_(C,S,g))),那么S将知道这样一个愿望(KS)。用这种方式,可以很容易地捕捉到所丢失的信息,这是语义互操作的核心。如果Agent有一个目标,那么它能把这个目标传达给一个提供服务的Agent,而不会降低任何精度。目标的通信方式并不重要,唯一重要的结果就是通信需要将目标委派给服务提供者。

语义互操作的定义是从客户的角度出发,因为C是g的发起者,但是并没有提及S希望为一组可能的客户提供服务。一个相似的定义是从服务者的角度出发,但是这样的定义基本上等价于已经展示的,对它的讨论将不会为实现本章增加更多的东西。

对语义互操作的定义有一个相当有趣的结果:如果考虑一个多Agent系统,其中的Agent仅仅打算进行语义互操作,那么具有“achieve”原语的基本ACL就已经够用了。这一点也不奇怪,因为ACL的工作很容易通用化。

语义互操作的成果不仅是改进可重用性的一种方式,也是促进优化的一种可能方式。通过采用日常的语法进行互操作,一个Agent要求其他Agent执行动作从而实现目标,即利用向其他Agent委派任务来实现自己的目标。语义互操作充分利用了目标委派,这或许会促进交叉优化。

2.语义组合性

通过组装Agent来实现MAS,不仅是Agent采用最佳方式进行通信的问题,还要允许它们能够互相找得到。对于组合性来说,互操作性是必要但不充分的:语义互操作要求SacquaintanceC,我们需要对此进行详述,以获取完整的语义组合性。

在面向组件的软件工程文献中,语义组合性已经被研究了很长时间。它起始于关于对象组合性的著名研究成果,目前在面向方面(aspect oriented)的程序设计社区中很活跃。语义组合性所隐含的基本思想是,应该将组件所提供的一组服务自由组合,而不受以下限制:定位合适的服务提供者,接口与服务提供者之间不匹配等。这就要求被组合的组件不仅要有兼容的接口,而且要对世界做出一致性假定。语义组合性已经扩展到了Agent,可以通过使用与语义互操作相同的技术来使它更加形式化。如果不对Agent委派目标的方式加以限制,可以说两个Agent在语义上是可以组合的,更加形式化的语义组合性定义如下:

给定一组nAgent,MAS={A1,A2,A3,…, An},它们被认为是满足语义可组合的,当且仅当:

CMAS,g:GCg,AMAS:slovesA(g)

GCdone(delegate(C,g))⇒∃SMAS:slovesS (g),KS GCdone(delegate(C,S,g))这里slovesA是A所能解决的目标,delegateC,g)是C的一种抽象行为,结果是KC(∃XMAS:GXg)。

这个定义阐明了如果Agent C有一个目标,并且在MAS中有一个Agent S能够实现这样的目标,那么C可以把目标委派给S,而不会由于通信引起精确度的损失。用这种方式,能够捕捉由于语义互操作引起的信息损失,而不需要C知道S。目标如何通信,与谁通信都不怎么重要,组合的最终结果是MAS中的一个Agent将会为C实现目标。

这个定义并不要求客户在委派任务之前就知道服务提供者Agent,也不保证在委派以后知道被选中的提供者。这和明确选择服务提供者的一般方法相兼容,因为这两种方法都符合这个定义:客户能根据它的目标来确认所选择的服务提供者。例如,如果Agent C想要S帮助它实现目标j,那么C所实现的目标就是g=KSGCGSj

3.语义扩展性

通过参看有关面向组件的软件工程文献,我们发现追求可重用性不仅要构造可重用的组件,还要使这样的组件具有扩展性(Booch,1994)。扩展性主要提供了两种关于重用的可能性:

● 新组件作为现有组件的扩展实现;

● 用一个不同的组件来代替现有组件,而不引起系统的其余部分发生变化。

传统上认为第一种可能性是面向对象程序设计的基础:它通过继承和多态来支持创建新的对象类。这仍然是一种实现重用的好方式。但是第二种可能性现在更受推崇,因为它允许重用整个系统,而不仅是单个类。这种所谓的“基于框架的可重用性”依赖于这种可能性,即一个组件替代另一个组件时,系统(即框架)的其余部分没有感觉到这样的替代。

面向对象和面向组件的方法通过继承和多态来实现基于框架的可重用性,因为它们假设,如果两个组件属于同一个类(即它们是同类型的),那么它们就是可以替代的。这很明显是不够的,尤其是类型等价的相互替代可能存在下列问题:这两个类或许会提供同样的方法,但是这些方法的语义,即组件对外部世界所做的,或许是完全不同的。换言之,这两个类或许结构相同,但语义不同(Fankhauser等,1991)。

语义扩展背后的思想是,能够用一个对初始组件的扩展版本来替代这个组件,同时保持操作语义不变,客户仍然能够像替代之前那样操作。

考虑面向Agent的思想,并且利用在前面章节所介绍的形式化,可以将语义扩展性形式化定义如下:

定义(语义扩展性):给定两个Agent BD,可以说DB的一个语义扩展,当且仅当∀g:slovesB(g) ⇒ slovesD(g)

这个定义阐述了(在各个时间点上),B能解决的D也能解决,即从任何可能的客户观点出发,B所能提供的客户感兴趣的服务,D都能提供,那么它们是可以互相替代的。

如果我们把Agent看做是可重用的原子单元,那么语义扩展性与语义组合性一起将Agent的可重用性最大化。Agent可以根据它们的目标自由组合,并且可能被其他具有扩展能力的Agent所替代,最终实现完全重用,即由替代Agent完全构成MAS。

4.大致语义可重用性

我们已经讨论的可重用性模型很明显是理想化的,因为它并没有提供支持组合和扩展的任何可操作性手段。然而,如果使goalsAslovesA公开化和清晰化,那么语义组合性仅仅是把一个目标从客户传递到服务提供者的问题,在最一般的情况下,这仅仅是个通信的问题。可以使用一个匹配Agent来将客户同服务提供者联系起来,或者依靠中间件基础设施。在后一种情况中,可以使用元空间将目标从客户提交给服务提供者,或者依靠直接的消息传递,程序员可以在客户端进行明确的编码。类似的,使slovesA公开和清晰化,能够确保语义的可扩展性,因为客户在从服务提供者S请求一项服务之前,总要检查slovesA

但是,goalsAslovesA在大多数情况下不能被计算,只能依靠它们近似的公开和明确。组件和Agent提供了不同的近似,在重用性方面Agent比组件所具有的优势正来自于这些不同的近似。ParADE框架(Bergenti和Poggi,2001)给出的语义可重用性大致如下:

(1)BAKA:Agent的知识接近于Agent所相信的,即通过对环境感知运用稳定规则推导出来。

(2)IAGA:Agent的目标近似于意图,能够从信念和计划引擎所派生出来的规则计算出来。

(3)capabilitiesAslovesA:Agent所能解决的目标近似于它行动的后续条件。这些后续条件考虑了Agent的状态和行动完全施行以后的环境状态。

组件的元模型依赖于更强的假设:

(1)stateAKA:组件的知识接近于组件的状态,即它的属性值及与其他组件的联系。(2)postcondition-of-next-callAgoalsA:组件的目标接近于包含所激发组件方法后续条件的集合。

(3)postconditioslovesA:组件所能解决的目标接近于它的方法后续条件。这样的后续条件在一个方法完全施行以后根据组件的状态进行定义,但是并没提及环境的状态。

大致上,Agent比组件的可重用性更好,因为框架要素(如匹配Agent)负责使客户和服务提供者之间的信息流畅通,对于如何执行它的工作有着更加精确的信息。

当组件方法的后续条件在方法完全施行后只考虑服务提供者的状态时,Agent在语义可扩展性上比组件更好,因为它们使用能力描述标志来构成Agent周围环境的条件。因此,出于确保语义扩展性的目的,Agent能够为行动结果提供一个非常精确的信息。

讨论:Agent不仅适用于非通用类型的应用(一般会用到“学习”和“自治性”这样的高级特征),而且还是对其他成熟技术的一个有效替代。

● 为开发人员提供了比目前其他技术更高层次的抽象;

● 就可重用性而言比组件有着具体的好处。

第一点,采用更高层次的抽象工作,虽然有很明显的好处,但也有一个普遍的缺点:缓慢的执行速度。为了能够充分地利用Agent的可能性,需要实施一个具备推理能力的Agent模型,这种Agent可能速度比较慢。现今,这似乎并不是一个障碍,因为速度并不总是具有最高的优先权,例如对于市场而言,时效性及整体质量经常更加重要。就第二点而言,Agent需要为重用性的改善付出一定代价:速度会更慢。根据定义,使用目标委派取代任务委派会要求“手段—目的”推导,会面临实施低速Agent的可能性。

在这两种情况下,Agent的性能下降缓慢。可以选择进行多少推理,也就是速度降低多少,这需要针对每个Agent进行考虑。也许会出于以下原因使用Agent:

● 特别复杂的情况,能受益于更高层次的抽象;

● 希望在许多不同的项目中自由地扩展和组合。

相反,如果对速度有迫切需求时,可以依靠反应Agent或组件。这种判断标准应该是很好的,因为一个Agent越复杂,附加值越多,我们就越想重用它,以及采用它来构成其他Agent。而且,反应Agent与组件是完全等效的,因此使用面向Agent的方法来代替面向组件的方法并不会失去什么。