Foundations of Multi-Agent Systems: From Single Agents to Agent Societies
Foundations of Multi-Agent Systems: From Single Agents to Agent Societies
What changes when a software component stops waiting to be called and starts deciding for itself what to do next? That single question is the entry point to multi-agent systems, and it is the question this opening chapter sets out to answer. For most of the history of mainstream software engineering, programs have been built out of *passive* components: objects that expose methods, libraries that wait for function calls, services that respond to requests. The runtime topology of these systems is determined entirely by the developer at design time, and at execution time the components do exactly what the call stack tells them to do. A multi-agent system inverts this arrangement. The components are *active*: they have their own threads of control, their own beliefs about the world, and their own goals, and they decide, moment by moment, what to do, what to communicate, and with whom to cooperate. The shift from passive object to active agent is not merely an implementation detail; it is a change in the fundamental unit of abstraction, and that change is what makes multi-agent systems the right tool for a class of problems that classical software engineering handles poorly. This chapter builds the conceptual ground floor for the rest of the book: the properties that define an agent, the loop that connects an agent to its environment, the trade-offs that distinguish a single-agent architecture from a multi-agent architecture, the taxonomy that classifies agents by their internal sophistication, and a small worked example that puts the vocabulary to work in pseudocode before we preview the disaster-response scenario that will run through the remaining fourteen chapters.
From Objects to Agents: What the Paradigm Shift Really Buys You
The cleanest way to see why the agent abstraction is needed is to start with the abstraction it replaces. In object-oriented design, a `Robot` class might expose methods like `moveTo(x, y)`, `pickUp(item)`, and `reportStatus()`. The methods are public, the fields are private, and the lifecycle of a `Robot` instance is managed by whatever code created it. When nobody calls `moveTo`, the robot does not move. When `pickUp` returns, the robot has done what it was told and is now waiting, passively, for the next call. This is not a flaw; it is the entire point of the object metaphor. A well-designed object is a deterministic responder to messages, easy to test, easy to reason about, and easy to compose. A program built from such objects is a closed system: the developer has enumerated every reachable state, and the runtime will hit only those states.
An agent built from the same physical sensors and actuators, but designed with the agent metaphor, behaves differently. The same `Robot` class, recast as an agent, would not wait for someone to call `moveTo`. It would run its own *control loop*, repeatedly observing the environment through its sensors, updating its internal beliefs, choosing an action, and acting. The decision of *whether* to move, and *where*, would be made inside the agent, on the basis of its own goals and its model of the world. From the outside, the difference looks small: in both cases the robot's wheels turn. From the inside, it is enormous. In the object case, the intelligence lives in the caller; in the agent case, the intelligence lives in the robot.
The shift becomes decisive in three situations. The first is when there is no natural central controller. Consider a fleet of warehouse robots, each with a partial view of the floor, each capable of picking and dropping pallets. There is no single piece of code that knows where every robot is, where every pallet is, and which robot should pick which pallet next. The "caller" simply does not exist. The second is when the environment is dynamic enough that the policy of what to do cannot be baked in at compile time. A disaster-response drone entering a partially collapsed building encounters layouts, hazards, and survivor signals that no developer could have enumerated. The third is when the components must negotiate, compete, or cooperate in ways that are themselves part of the system's behavior. Two logistics agents bidding for the same delivery slot are not a function call and a return value; they are two autonomous decision-makers trying to reach agreement, and the path they take matters as much as the result.
These three situations share a common property: the system's behavior is *emergent*. It is the result of many local decisions interacting, and it cannot be predicted by reading any single component. Object-oriented design is at its weakest exactly here, because it assumes a single thread of control that calls methods in a known order. Agent-oriented design is at its strongest exactly here, because it assumes nothing about a single thread of control, and instead builds the system out of components that each carry their own decision-making.
This is not a claim that objects are obsolete, or that agents are "better." It is a claim about the mapping between problem and abstraction. For a payroll system, a compiler, or a web server handling stateless requests, objects are the right tool and agents would be a wasteful complication. For a warehouse fleet, a disaster-response team, a smart grid, or a market simulation, agents are the right tool and objects would force the developer to reimplement, by hand, the very autonomy and social coordination that the agent abstraction provides natively. The remainder of this chapter is a precise account of what that abstraction provides.
The ARPS Properties: What Makes an Agent an Agent
The most widely cited definition of an agent, due to Wooldridge and Jennings, characterizes an agent by four properties, conventionally abbreviated as ARPS: Autonomy, Reactivity, Proactivity, and Social ability. Every property is necessary, and together they carve out a region of design space that excludes both passive objects and bare reactive controllers. The properties are best understood not as a checklist to memorize but as answers to four specific design questions: *who decides what the component does, who reacts to the environment, who initiates action, and who coordinates with whom*.
Autonomy is the property that an agent operates without direct external intervention and has some form of control over its own actions and internal state. The word "autonomy" is doing real work here: it is not the same as "independence" in the human sense, and it is not the same as "automation." A thermostat that turns the heater on at 7 a.m. and off at 9 p.m. is automated, but it is not autonomous; its schedule is fixed by the developer. An autonomous agent, by contrast, decides for itself, on the basis of its current beliefs and goals, what to do next. The classic concrete example is a Mars rover. Nobody on Earth is calling its methods in real time; the round-trip light delay is twenty minutes. The rover must decide on its own when to move, when to stop and analyze a rock, when to conserve power, and when to phone home. The fact that its decision policy was designed by humans does not make it less autonomous; what matters is that *at runtime* no external controller is in the loop.
In practical terms, autonomy means three things for the engineer. First, the agent must maintain some internal state — a belief base, a goal stack, a policy — that is not directly writable from outside. Second, the agent must have a *decision function* that maps its current state to a chosen action. Third, the agent's action must be a function of its own decision, not of an external command. The thermostat fails the third test; the Mars rover passes it.
Reactivity is the property that an agent perceives its environment and responds in a timely fashion to changes that occur in it. This sounds trivial, but it rules out a class of systems that is often confused