Guideline: Modular Agent Design
This guideline gives hints on the correct design of self-contained agents that work within a message-based multi-agent system.
Relationships
Parent Practices
Related Elements
Main Description

The design of modular agents that work well within a complex environment requires observing a number of issues that are specific to multi-agent designs. This document serves as a guideline to deal with them and provides suggestions for their solution.

Dependency Breaking

In object-oriented design, it is common to denote information flows between two classes structurally by connecting the two classes by an association and adding a public getter-method. In the example below, a class Robot can access information about new work units from a class Storage by simply calling the method storage.getNewWorkUnit().


Such a dependency between classes can not be readily used in multi-agent system design. This is due to the fact that agents run in different execution environments and interaction is message-based. Internally, a statement such as storage.getNewWorkUnit() dereferences the association to storage and calls the getNewWorkUnit(), returning a reference to an object of type WorkUnit. In a message-based system with agents running in different exection environments, this inferred semantics is not valid. Instead, a message would have to be sent to the storage agent, requesting the information. The storage would have to serialise this information and return it to the requesting agent. The requesting agent could then deserialise the information and work with it. Any changes to the deserialised object would, however, not affect the original object. Thus, instead of a call-by-reference (or call-by-sharing) evaluation, a true call-by-value is performed. A corresponding code snippet looks like this:

Message m = sendMessage(storage.agentIdentifier, "getNewWorkUnit");
WorkUnitModel wum = m.waitForReply();

Note the use of WorkUnitModel instead of WorkUnit. This is due to the fact that in many cases, not the actual object is serialised but rather a stripped down version that only contains some of the attributes of the original class to limit the required communication bandwidth. This is especially useful if the class contains many internal state variables that do not necessarily have to be restored after the transfer. The class diagram corresponding to the design just described looks like this:

Note that the robot does no longer have a direct association with the storage, but has access to its agent identifier through a model. The getNewWorkUnit() method is marked as external, indicating that the method is part of the external interface of the storage. The stereotypes used here are part of the PosoMAS Auxiliary UML Profile.

The designer has to make a conscious decision whether this level of detail is required in the design models. If a common understanding of the problem and of the solution approach exists within the development team, it might be easier to design a regular class diagram that does not take these peculiarities into account. Instead, they could be dealt with by a model-to-model transformation or similar means. However, if the dependencies can not always be broken by the same mechanism, it might be worthwhile to have a more detailed design model in which these problems have already been resolved.

More Information