Realizzare Sistemi MultiAgente con JADE
- Prima Parte Corso di Reti di Calcolatori
A.A. 2004-2005
Ing. Domenico Rosaci
JADE
 Middleware
che facilita la creazione di
sistemi multi-agente (MAS)



Ambiente run-time dove gli agenti possono
“vivere”. Deve assere attivo su un host se si
vuole che degli agenti vengano eseguiti su
quell’host
Libreria di classi JAVA
Tool grafici per l’amministrazione del MAS
Piattaforme
 Container:
istanza di JADE Runtime
Environment: al suo interno vengono
esguiti degli agenti
 Piattaforma: insieme di container attivi
 In una piattaforma deve esistere un Main
Container, presso cui tutti gli altri container
devono registrarsi
 Ogni agente in una piattaforma ha un
nome unico
Esempio di Piattaforme
Esempio: Agenti che comprano e
vendono
 Ogni
agente compratore accetta il nome di
un libro come input
 Periodicamente, chiede a tutti gli agenti
venditori che conosce di fare un’offerta di
vendita
 Tra tutte le offerte pervenute, sceglie
quella a più basso prezzo ed emette un
ordine di acquisto
Creiamo l’agente compratore







import jade.core.Agent;
public class AgenteCompratore extends Agent {
protected void setup() {
// Stampa un messaggio di benvenuto
System.out.println(“Ciao! L’agente compratore
“+getAID().getName()+” e’ pronto.”);
}
}
Il metodo setup()
 Serve
a specificare quali azioni l’agente
compie in fase iniziale
 Il vero comportamento dell’agente si
otterrà inserendo nell’agente un
“behaviour”
Agent Identifier (AID)
Ogni agente è identificato da un AID che è un’istanza
della classe jade.core.AID
 Il metodo getAID() restituisce l’AID dell’agente che lo
invoca
 L’AID si compone di un nome locale alla piattaforma
(nickname) e dell’indirizzo della piattaforma
 Per ottenere l’AID a partire dal nickname:
String nickname = “Peter”;
AID id = new AID(nickname, AID.ISLOCALNAME);
 ISLOCALNAME indica che nickname è un nome locale

Compilare un agente

Includere nella variabile d’ambiente CLASSPATH i
percorsi: c:\jade\jade-bin3.2\jade\lib\jade.jar;c:\jade\jade-bin3.2\jade\lib\jadeTools.jar;c:\jade\jade-bin3.2\jade\ib\iiop.jar;c:\jade\jade-bin3.2\jade\lib\base64.jar;c:\jade;

Quindi usare: javac AgenteCompratore.java
Creiamo una piattaforma
Creiamo un agente compratore
Argomenti, doDelete(), takeDown()





















import jade.core.Agent;
import jade.core.AID;
public class AgenteCompratore extends Agent {
// Titolo del libro da acquistare
private String targetBookTitle;
protected void setup() {
System.out.println(“Ciao! L’agente compratore “+getAID().getName()+” e’ pronto.”);
Object[] args = getArguments();
if (args != null && args.length > 0) {
targetBookTitle = (String) args[0];
System.out.println(“Sto cercando di acquistare “+targetBookTitle);
}
else {
// Fa terminare immediatamente l’agente
System.out.println(“Nessun libro specificato“);
doDelete();}
}
// Operazioni di chiusura
protected void takeDown() {
System.out.println(“agente compratore “+getAID().getName()+” terminato.”);}
}
Agente Compratore con argomenti
Il behaviour di un agente
Specifica i task che l’agente esegue
E’ implementato come un oggetto di una classe
che estende jade.core.behaviours.Behaviour
 Per aggiungere tale oggetto si usa il metodo
addBehaviour() della classe Agent. Lo si può
fare in qualunque momento, nel metodo start()
della classe Agent o all’interno di un qualunque
altro behaviour
 Ogni classe che estende Behaviour deve
implementare il metodo action() che specifica il
task da eseguire e il metodo done() che
specifica se il task è stato eseguito


Ancora sui behaviours


Un agente può eseguire più behaviour concorrentemente
Lo scheduling è collaborativo, non pre-emptive: quando un
behaviour è eseguito, esso non viene interrotto finchè non
termina
 E’ il programmatore che decide quando saltare da un
behaviour a un altro
 Sforzo aggiuntivo per il programmatore, ma vari vantaggi:
 Un singolo thread per agente (importante quando si usano
device con limitate risorse, es. cellulari)
 Migliori performance rispetto agli switch dei thread java
 Nessun problema di sincronizzazione: tutti i behaviour
sono eseguiti nello stesso thread
 Quando si verifica uno switch, lo stato di un agente non
contiene informazioni sullo stack e può quindi essere
salvato per una successiva “riesumazione” (persistenza) o
trasferito in un altro container (mobilità)
Thread di un agente
Inizializzazione
Inserimento behaviour
iniziali
L’agente è “ucciso”?
(doDelete() eseguito?)
In rosso i metodi che il
programmatore deve
implementare
Ottieni il prossimo behaviour
da pool dei behaviour attivi
Vita dell’agente:
Esecuzione di behaviour
Rimuovi il behaviour corrente
dal pool dei behaviour attivi
Operazioni di clean-up
Importante:
 Nessun
altro behaviour può essere
eseguito finchè il metodo action() del
behaviour corrente non si completa
 Quando non ci sono behaviour disponibili
per l’esecuzione, l’agente si “addormenta”
per non consumare tempo di CPU,
rsivegliandosi quando si verifica la
disponibilità di un behaviour
Behaviour one-shot






public class MyOneShotBehaviour extends
OneShotBehaviour {
public void action() {
// esegue l’operazione X
}
}
Il metodo action(), e quindi anche l’operazione
X, sono eseguiti una sola volta.
Behaviour cyclic
 public
class MyCyclicBehaviour extends
CyclicBehaviour {
 public void action() {
 // perform operation Y
}
}
Il metodo action() è eseguito
indefinitamente, fin quando l’agente che
ha lanciato il behaviour termina
Behaviour generic























public class MyThreeStepBehaviour extends Behaviour {
private int step = 0;
public void action() {
switch (step) {
case 0:
// perform operation X
step++;
break;
case 1:
// perform operation Y
step++;
break;
case 2:
// perform operation Z
step++;
break;
}
}
public boolean done() {
return step == 3;
}
}
A seconda dello stato in cui l’agente si trova, si esegue un’operazione. Il behaviour
viene ripetuto fino a quando si raggiunge una certa condizione (nell’es., step==3)
Schedulare le operazioni: la classe
WakerBehaviour

action() and done() sono implementati in modo tale da eseguire il metodo
astratto handleElapsedTimeout() dopo che un dato timeout (specificato nel
costruttore) viene raggiunto. Dopo l’esecuzione di handleElapsedTimeout()
il behaviour si completa.



public class MyAgent extends Agent {
protected void setup() {
System.out.println(“Aggiunto un waker behaviour”);
addBehaviour(new WakerBehaviour(this, 10000) {
protected void handleElapsedTimeout() {
// perform operation X
}
} );
}
}
L’operazione X è eseguita 10 secondi dopo che appare il messaggio
“Aggiunto un waker behaviour” .








Schedulare le operazioni: la classe
TickerBehaviour
•
action() and done() sono implementati in modo tale da eseguire il metodo
astratto onTick() ripetitivamente aspettando un certo periodo (specificato nel
costruttore) dopo ogni esecuzione. Un TickerBehaviour non si completa mai




public class MyAgent extends Agent {
protected void setup() {
addBehaviour(new TickerBehaviour(this, 10000) {
protected void onTick() {
// perform operation Y
}
} );
}
}
L’operazione Y è eseguita periodicamente ogni 10 secondi.






Il behaviour dell’AgenteCompratore



















protected void setup() {
System.out.println(“Ciao! L’agente compratore “+getAID().getName()+” è pronto.”);
Object[] args = getArguments();
if (args != null && args.length > 0) {
targetBookTitle = (String) args[0];
System.out.println(“sto cercando di acquistare “+targetBookTitle);
// Aggiunge un TickerBehaviour che schedula una richiesta all’agente venditore ogni minuto
addBehaviour(new TickerBehaviour(this, 60000) {
protected void onTick() {
myAgent.addBehaviour(new RequestPerformer());
}
} );
}
else {
// Fa terminare l’agente
System.out.println(“Nessun titolo di libro specificato“);
doDelete();
}
}
RequestPerformer() è una richiesta di comunicazione: ne parleremo più avanti
myAgent (variabile protected della classe Agent) è un puntatore all’agente che sta eseguendo il behaviour
Il behaviour dell’Agente Venditore



















import jade.core.Agent;
jade.core.behaviours.*;
import java.util.*;
public class BookSellerAgent extends
Agent {
// Catalogo dei libri (titolo e prezzo)
private Hashtable catalogue;
// La GUI per mezzo della quale l’utente
può aggiungere libri al catalogo
private BookSellerGui myGui;
protected void setup() {
// Crea il catalogo
catalogue = new Hashtable();
// Crea e mostra la GUI
myGui = new BookSellerGui(this);
myGui.show();
// Aggiunge il behaviour serving requests
per le offerte dagli agenti compratori
addBehaviour(new
OfferRequestsServer());
// Aggiunge il behaviour serving purchase
orders per gli ordini dagli agenti compratori
addBehaviour(new
PurchaseOrdersServer());
}
















protected void takeDown() {
// Chiude la GUI
myGui.dispose();
System.out.println(“Agente Venditore
“+getAID().getName()+” terminato.”);
}
/**
Questo è invocato dalla GUI quando l’utente aggiunge
un nuovo libro per la vendita
*/
public void updateCatalogue(final String title, final int
price) {
addBehaviour(new OneShotBehaviour() {
public void action() {
catalogue.put(title, new Integer(price));
}
} );
}
}
La classe BookSellerGui è una semplice GUI Swing,
disponibile fra gli esempi di JADE
Comunicazione tra agenti
 Paradigma
di comunicazione:
asyncronous message passing
 Ogni agente ha una message queue in cui
JADE inserisce i messaggi inviati dagli altri
agenti
 L’agente viene avvertito quando riceve un
nuovo messaggio
Il linguaggio ACL
Specifiche definite da FIPA:
 Sender: mittente del messaggio
 Lista dei destinatari
 Performative: indica ciò che il messaggio vuole
ottenere dal destinatario. Può essere:





REQUEST
INFORM
QUERY_IF
CFP (Call for Proposals)
PROPOSE, ACCEPT_PROPOSAL, REFUSE
(performative di negoziazione)
Il Linguaggio ACL
 Content
(Contenuto del messaggio)
 Content Language: Sintassi usata per
esprimere il content
 Ontology: vocabolario dei simboli usati nel
content e loro significato
 Altri campi per il controllo delle
conversazioni concorrenti
Messaggi JADE

Un messaggio JADE è un oggetto della classe
jade.lang.acl.ACLMessage

ACLMessage msg = new
ACLMessage(ACLMessage.INFORM);
msg.addReceiver(new AID(“Peter”,
AID.ISLOCALNAME));
msg.setLanguage(“English”);
msg.setOntology(“Weather-forecast-ontology”);
msg.setContent(“Today it’s raining”);
send(msg);





Esempio del commercio libri
 Si
può usare la performativa CFP per le
richieste di ricevere un’offerta che l’agente
compratore fa all’agente venditore
 Si possono usare la performativa
PROPOSE per le offerte del venditore e le
performative ACCEPT_PROPOSAL e
REFUSE per le risposte del compratore ad
un’offerta
Messaggio di richiesta di offerta
 ACLMessage
cfp = new
ACLMessage(ACLMessage.CFP);
 for (int i = 0; i < sellerAgents.lenght; ++i) {
 cfp.addReceiver(sellerAgents[i]);
 cfp.setContent(targetBookTitle);
 myAgent.send(cfp);
Essendo sellerAgents un vettore di agenti
venditori
Il metodo receive()
 ACLMessage
msg = receive();
 if (msg != null) {
}
Estrae il primo messaggio dalla coda dei
messaggi
Classe interna
OfferRequestsServer





















private class OfferRequestsServer extends CyclicBehaviour {
public void action() {
ACLMessage msg = myAgent.receive();
if (msg != null) {
String title = msg.getContent();
ACLMessage reply = msg.createReply();
Integer price = (Integer) catalogue.get(title);
if (price != null) {
// Il libro richiesto è disponibile per la vendita. Rispondi con il prezzo
reply.setPerformative(ACLMessage.PROPOSE);
reply.setContent(String.valueOf(price.intValue()));
}
else {
// Il libro richiesto non è disponibile per la vendita.
reply.setPerformative(ACLMessage.REFUSE);
reply.setContent(“not-available”);
}
myAgent.send(reply);
}
}
}
Bloccare il behaviour

OfferRequestServer è implementata come
classe interna della classe AgenteVenditore
 Quando noi inseriamo questo behaviour
nell’agente, il thread dell’agente inizia un
oneroso loop.
 Per evitarlo, usiamo dentro il metodo action() il
metodo block() che blocca l’agente fino a
quando non è ricevuto un messaggio
Bloccare il behaviour











public void action() {
ACLMessage msg = myAgent.receive();
if (msg != null) {
// Messaggio ricevuto. Processalo
...
}
else {
block();
}
}
Quando un nuovo messaggio è inserito nella coda dell’agente, tutti i
behaviour bloccati diventano disponibili.
Selezionare messaggi con
caratteristiche specifiche











public void action() {
MessageTemplate mt =
MessageTemplate.MatchPerformative(ACLMessage.CFP);
ACLMessage msg = myAgent.receive(mt);
if (msg != null) {
// CFP Message received. Process it
...
}
else {
block();
}
}
Questo agente processa solo messaggi che aderiscono al template mt,
che “richiede” la performativa CFP
La classe RequestPerformer -1


















private class RequestPerformer extends Behaviour {
private AID bestSeller; // Agente che fornisce l’offerta migliore
private int bestPrice; // Miglior prezzo offerto
private int repliesCnt = 0; // Contatore delle risposte da agenti venditori
private MessageTemplate mt; // Template per ricevere risposte
private int step = 0;
public void action() {
switch (step) {
case 0:
// Manda una Call for Proposals a tutti gli agenti
ACLMessage cfp = new ACLMessage(ACLMessage.CFP);
for (int i = 0; i < sellerAgents.length; ++i) {
cfp.addReceiver(sellerAgents[i]);
}
cfp.setContent(targetBookTitle);
cfp.setConversationId(“book-trade”);
cfp.setReplyWith(“cfp”+System.currentTimeMillis()); // valore unico
myAgent.send(cfp);
La classe RequestPerformer - 2




















// Prepara il template per ricevere le proposte
Mt = MessageTemplate.and(MessageTemplate.MatchConversationId(“book-trade”),
MessageTemplate.MatchInReplyTo(cfp.getReplyWith()));
step = 1;
break;
case 1:
// riceve tutte le proposte/rifiuti dagli agenti venditori
ACLMessage reply = myAgent.receive(mt);
if (reply != null) {
// Replica alle proposte ricevute
if (reply.getPerformative() == ACLMessage.PROPOSE) {
// Questa è un’offerta
int price = Integer.parseInt(reply.getContent());
if (bestSeller == null || price < bestPrice) {
// Questo è al momento il miglior offerente
bestPrice = price;
bestSeller = reply.getSender();
}
}
repliesCnt++;
La classe RequestPerformer -3






















if (repliesCnt >= sellerAgents.length) {
// ricevute tutte le offerte
step = 2;
}
}
else {
block();
}
break;
case 2:
// manda ordine di acquisto al seller che ha fornito l’offerta migliore
ACLMessage order = new ACLMessage(ACLMessage.ACCEPT_PROPOSAL);
order.addReceiver(bestSeller);
order.setContent(targetBookTitle);
order.setConversationId(“book-trade”);
order.setReplyWith(“order”+System.currentTimeMillis());
myAgent.send(order);
// Prepara il template per l’ordine di offerta
mt = MessageTemplate.and(MessageTemplate.MatchConversationId(“book-trade”),
MessageTemplate.MatchInReplyTo(order.getReplyWith()));
step = 3;
break;
La classe RequestPerformer -4






















case 3:
// Riceve la risposta all’ordine di acquisto
reply = myAgent.receive(mt);
if (reply != null) {
if (reply.getPerformative() == ACLMessage.INFORM) {
// risposta positiva. Possiamo terminare
System.out.println(targetBookTitle+“ acquisto concluso.”);
System.out.println(“Prezzo = ”+bestPrice);
myAgent.doDelete();
}
step = 4;
}
else {
block();
}
break;
}
}
public boolean done() {
return ((step == 2 && bestSeller == null) || step == 4);
}
} // Fine della classe interna RequestPerformer
Protocolli di negoziazione
 Il
protocollo da noi implementato è un
protocollo ben noto il jade; si chiama
“Contract-net”: avrebbe potuto essere
molto più facilmente implementato tramite
la classe jade.proto.ContractNetInitiator
 Il package proto contiene diversi protocolli
di interazione
Pagine Gialle: la classe DFService
 Come
fare in modo che un agente
compratore conosca quali siano gli agenti
venditori?
 Il servizio di pagine gialle consente a un
agente di rendere noti i servizi che eroga
 Il servizio di pagine gialle in JADE è fornito
dagli agenti DF (Directory Facilitator)
Gli agenti DF
 Ogni
piattaforma conforme a FIPA
contiene un agente DF, chiamato df
 Altri agenti DF possono essere attivati per
formare con l’agente df di default un
sistema di pagine gialle distribuito
Interazione con gli agenti DF
 Si
realizza tramite messaggi ACL
 Content language: SL0
 Ontology Language: FIPA-agentmanagement-ontology
 Package: jade.domain.DFService
Servizio di Pubblicazione
 Ogni
agente interessato al servizio deve
fornire al DF:



Il suo AID
La lista dei linguaggi e delle ontologie che gli
altri agenti devono conoscere per interagire
con lui
La lista dei servizi offerti
Servizi offerti da un agente

Per ogni servizio offerto occorre specificare:





Tipo
Nome
Linguaggi e ontologie richieste
Proprietà del servizio
Classi coinvolte: DFAgentDescription,
ServiceDescription, Property incluse nel
package jade.domain.FIPAAgentManagement
Pubblicare un servizio



















Creare un’istanza della classe DFAgentDescription
Chiamare il metodo register() della classe DFService
protected void setup() {
...
// Registra il servizio di book-selling nelle pagine gialle
DFAgentDescription dfd = new DFAgentDescription();
dfd.setName(getAID());
ServiceDescription sd = new ServiceDescription();
sd.setType(“book-selling”);
sd.setName(“JADE-book-trading”);
dfd.addServices(sd);
try {
DFService.register(this, dfd);
}
catch (FIPAException fe) {
fe.printStackTrace();
}
...
}
Deregistrazione dei servizi












protected void takeDown() {
// Deregistra dalle pagine gialle
try {
DFService.deregister(this);
}
catch (FIPAException fe) {
fe.printStackTrace();
}
// Close the GUI
myGui.dispose();
System.out.println(“Seller-agent “+getAID().getName()+”
terminating.”);
}
Ricerca di servizi
 Per
cercare un servizio si deve fornire al
DF un template descrittivo
 Il risultato della ricerca è una lista di
descrizioni che soddisfano il template
fornito
 Si usa il metodo search() della classe
DFService
L’agente compratore



























public class BookBuyerAgent extends Agent {
private AID[] sellerAgents;
protected void setup() {
System.out.println(“Hallo! Buyer-agent “+getAID().getName()+” is ready.”);
Object[] args = getArguments();
if (args != null && args.length > 0) {
targetBookTitle = (String) args[0];
System.out.println(“Trying to buy “+targetBookTitle);
addBehaviour(new TickerBehaviour(this, 60000) {
protected void onTick() {
// aggiorna la lista degli agenti venditori
DFAgentDescription template = new DFAgentDescription();
ServiceDescription sd = new ServiceDescription();
sd.setType(“book-selling”);
template.addServices(sd);
try {
DFAgentDescription[] result = DFService.search(myAgent, template);
sellerAgents = new AID[result.length];
for (int i = 0; i < result.length; ++i) {
sellerAgents[i] = result.getName();
}
}
catch (FIPAException fe) {
fe.printStackTrace();
}
myAgent.addBehaviour(new RequestPerformer());
}
} );
Scarica

Realizzare Sistemi Multi-Agente con JADE

ppt

ppt