EL LENGUAJE ADL
Ramón M. Gómez Labrador
Departamento de Lenguajes y Sistemas Informáticos
Junio 1.997.
La figura siguiente muestra esquemáticamente la estructura de un agente MIX.
![]() |
Este modelo ha sido ampliado desde varios puntos de vista:
Otro aspecto importante del modelo es el ciclo de control básico, que muestra el comportamiento de un agente MIX. El siguiente pseudocódigo presenta dicho ciclo de control.
Enviar un mensaje CheckIn al agente servidor de nombre.
Esperar la respuesta.
Actualizar la base de datos interna.
Iniciar las funciones de objetivos, si existen.
REPETIR SIEMPRE:
Buscar un mensaje nuevo en el buzón (escucha).
SI hay mensajes pendientes:
Seleccionar uno según la política de gestión del buzón.
SEGÚN el tipo de mensaje
Petición de servicio (AskForService):
SI va a procesarse (de acuerdo con serv_policy):
Ejecutar el método de servicio asociado.
FIN-SI
Petic. de servicio con coste (AskForServiceWithCost):
SI va a procesarse (de acuerdo con serv_policy):
Ejecutar el método de coste asociado.
FIN-SI
Respuesta (Answer):
Ejecutar el método asociado.
Objetivo o servicio no alcanzado (ErrorReport):
Ejecutar el método asociado.
EN-OTRO-CASO:
Error.
FIN-SEGÚN
FIN-SI
FIN-REPETIR
Cada una de las 2 clases predefinidas del modelo tiene una serie de servicios fundamentales, que permiten realizar las funciones más básicas de cada agente.
Ambas clases heredan funciones de más bajo nivel de la clase Agent, como el servicio Suicide, que cierra las comunicaciones y finaliza la ejecución de un agente.
El siguiente gráfico muestra esquemáticamente la estructura de programación de la plataforma MIX.
![]() |
Para la obtención de los procesos (agentes), el traductor ADL utiliza:
Un programa ADL consta de 2 partes principales: la cabecera y la zona de definición de clases y agentes.
La cabecera de un programa ADL tiene el siguiente formato:
El cuerpo de un programa ADL consta de las definiciones de agentes, de clases de agentes y de sociedades de agentes.
Estas sociedades trabajan como un único agente. Los objetos internos declarados idénticos en la cláusula COMMON_OBJECTS se tratan como un único objeto y deben pertenecer a la misma clase. El resto de la comunidad de agentes puede acceder a los servicios declarados en la cláusula EXPORT.
STRONGLY_COUPLED_SOCIETY ag1, ag2, ...
[ EXPORT FROM ag1: serv11, serv12, ... ;
FROM ag2: serv21, serv22, ... ; ... ]
[ COMMON_OBJECTS :
obj11 FROM ag1, obj12 FROM ag2, ... ;
obj2M FROM agM, obj2N FROM agN, ... ; ... ]
END_SOCIETY
CLASS clase -> clase_padre
[ recursos ]
[ objetos internos ]
[ control ]
[ objetivos ]
[ servicios ]
END clase
AGENT agente -> clase_padre
[ recursos ]
[ objetos internos ]
[ control ]
[ objetivos ]
[ servicios ]
END agente
El cuerpo de la declaración de agentes y de clases de agentes consta de 5 secciones:
Los recursos engloban al conocimiento estático que el programador tiene sobre las necesidades del agente. Por otro lado, el entorno engloba al conocimiento dinámico sobre los servicios que ofrecen los agentes en un momento determinado.
Estos recursos puede ser:
RESOURCES
[ REQ_LIBRARIES: biblioteca1, biblioteca2, ... ]
[ REQ_SERVICES: serv1 [ CONTRACT_POLICY método ]
[ TIMEOUT real ]
[ RETRIES entero ] ;
serv2 ... ]
[ SUBSCRIBE_TO: grupo1, grupo2, ... ]
[ REQ_PUBLIC_GORUPS: grupo1, grupo2, ... ]
[ REQ_PRIVATE_GROUPS: grupo1: ag11, ag12, ... ;
grupo2: ag21, ag22, ... ; ... ]
[ REQ_ONTOLOGIES: fichero1, fichero2, ... ]
Cada agente puede tener sus objetos propios, instancias de clases C++ o de conceptos de una ontología.
INTERNAL_OBJECTS
obj11, obj12, ... -> clase1 | ontología1::entidad1 ;
obj21, obj22, ... -> clase2 | ontología2::entidad2 ; ...
ADL permite modificar el bucle de control básico del agente.
CONTROL
[ MBOX_MANAGER: función ]
[ SERV_POLICY : función ]
[ DEST_POLICY : función ]
Un objetivo puede definirse como una función que el agente inicia en su nacimiento. Al menos un agente de la comunidad debe tener algún objetivo.
Atendiendo a este criterio los agentes pueden ser:
GOALS
objetivo1 : CONCURRENT método
[ IF_SUCCESS función ]
[ IF_FAIL función ] ; ...
Los servicios son funciones C++ que ofrece un agente a otro y que pueden ejecutarse en modo concurrente o no concurrente.
La petición de servicio y la respuesta se realiza mediante un protocolo de paso de mensajes transparente para el usuario final. Uno de estos protocolos es el Contract Net, que requiere una función de estimación de coste para el servicio. El agente emisor elegirá la petición de menor coste.
SERVICES
servicio1 : [ CONCURRENT ] método
[ COST método ] ; ...
Un método es una función que puede tomar como parámetros -tanto de entrada como de salida- mensajes con estructuras ontológicas. Su sintaxis en ADL es:
función
[ REQ_MSG_STRUCT ontología1 :: entidad1, ... ]
[ ANS_MSG_STRUCT ontología1 :: entidad1, ... ]
El MIX-CKRL es un subconjunto del Lenguaje para la Representación de Conocimientos Comunes CKRL 2.0. Un programa en MIX-CKRL consta de un conjunto de declaraciones de entidades. Estas entidades pueden ser:
La sintaxis del lenguaje resulta algo incómoda de expresar y es preferible estudiarla en el apartado de ejemplos.
Un servicio es una rutina en C++ que toma 2 parámetros -uno de la clase servicio y otro de la clase mensaje- y que tiene el siguiente formato:
// Ficheros de inclusión.
#include <service.H>
#include <message.H>
// Formato de la función.
void nombre_servicio (Service &s, Message &m)
{
}
Un mensaje consta de los siguientes campos:
Para declarar en la rutina mensajes y listas de mensajes se usa el formato:
Message m; // m es un mensaje
List<Message> l; // l es una lista de mensajes
Las funciones que permiten enviar una petición son:
int Service::AskForSyncService (Message &m, List<Message> &resp);
int Service::AskForAsyncService (Message &m);
int Service::AskForDeferredService (Message &m, int &id_resp);
int Service::AskForSSwithCost (Message &m, List<Message> &resp);
Para enviar una respuesta se utiliza el método SendAnswer de la clase Service:
s.SendAnswer (m);
Para obtener la respuesta en diferido, se utiliza la función:
int GetDeferredAnswers (List<Message> &resp, int id_resp);
MIX permite la traducción entre CKRL y C++. Una vez definida la ontología necesaria, un servicio puede tratar la estructura de datos creada.
La recepción de objetos C++ se realiza en 2 pasos:
Los siguientes ejemplos permitirán ilustrar todos los conceptos fundamentales para la programación de agentes utilizando ADL, MIX-CKRL y C++.
Este es el ejemplo más sencillo. El sistema consta de un agente de páginas amarillas (servidor de nombre), un agente que gestiona el servicio foo y un agente cliente de dicho servicio y que no espera respuesta (comunicación asíncrona).
La siguiente tabla muestra los agentes del dominio, el tipo de cada agente, los servicios que presta, los servicios que necesita de otros agentes y sus objetivos.
Agente |
Clase de agente |
Servicio prestado |
Servicio requerido |
Objetivos |
YP_Agent |
YPAgent |
|||
Foo_Agent |
BaseAgent |
Foo |
||
Client_Foo |
BaseAgent |
Foo |
AskForFoo |
Por último los programas.
// foo.adl
#DOMAIN "foo_domain"
#YP_SERVER "arturo.lsi.us.es:6050"
#MIX_LIBRARY "/home/ramon/tesis/mix/MIXWP1.4"
AGENT YP_Agent -> YPAgent
END YP_Agent
AGENT Foo_Agent -> BaseAgent
RESOURCES
REQ_LIBRARIES: "foo-functions.C"
SERVICES
Foo: CONCURRENT foo_service
END Foo_Agent
AGENT Client_Foo -> BaseAgent
RESOURCES
REQ_LIBRARIES: "foo-functions.C"
REQ_SERVICES: Foo
GOALS
AskForFoo: CONCURRENT AskForFoo
END Client_Foo
// foo-functions.C
#include <service.H>
#include <message.H>
#include <MASError.H>
void foo_service (Service &srv, Message &msg){
cout << "I am the foo service" << endl;
}
void AskForFoo (Service &s, Message &msg){
Message m;
//msg is the message requesting the service ask-for-foo received
//by the agent
//m is the message we send to request the foo service
m.To = "Foo_Agent";
m.ServName = "Foo";
m.Body = ""; //This line is not necessary
cout << "I request the foo service" << endl;
if (s.AskForAsyncService(m) != SMA_SUCCESS)
Error();
}
Este ejemplo trata las peticiones síncronas y en diferido. Aparte del agente servidor de nombre, el sistema consta de un agente servidor -la montaña que repite el eco- y 2 agentes clientes, que permitirán observar las diferencias entre los dos métodos de petición de servicio.
Los archivos utilizados son:
// echo.adl
#DOMAIN "echo_domain"
#YP_SERVER "arturo.lsi.us.es:6050"
#MIX_LIBRARY "/home/ramon/tesis/mix/MIXWP1.4"
AGENT YP_Agent -> YPAgent
END YP_Agent
AGENT Mountain -> BaseAgent
RESOURCES
REQ_LIBRARIES: "echo-functions.C"
SERVICES
echo: CONCURRENT Echo
END Mountain
AGENT Mixy -> BaseAgent
RESOURCES
REQ_LIBRARIES: "echo-functions.C"
REQ_SERVICES : echo
GOALS
user_echo: CONCURRENT user_echo
END Mixy
AGENT Mixie -> BaseAgent
RESOURCES
REQ_LIBRARIES: "echo-functions.C"
REQ_SERVICES : echo
GOALS
user_echo2: CONCURRENT user_echo_2
END Mixie
// echo-functions.C
#include <service.H>
#include <message.H>
#include <MASError.H>
void Echo(Service &s, Message &msg)
{
Message m;
cout << "ECHOOOOO: " << msg.Body << endl;
m.Body = msg.Body; //Returns the input message
s.SendAnswer(m); //Sends the msg to the caller
};
void user_echo(Service &s, Message &msg)
{
Message m, m_aux;
List<Message> answers;
//Gets the user name
cout << "Type your name and the Mountain will make an echo ";
cin >> m.Body;
//Asks Mountain for the echo service
m.To = "Mountain";
m.ServName = "echo";
if (s.AskForSyncService(m, answers) == SMA_SUCCESS)
{
do
{
m_aux = answers.GiveCursor(); //each answer
//Process the message
m_aux.Show(); //Show is a method of the message class
//to display the message structure
}
while(answers.GoNext());
}
else
Error(); //Invoke the standard error function
};
void user_echo_2(Service &s, Message &msg)
{
Message m, m_aux;
List<Message> answers;
int ServReq_id;
//Gets the user name
cout << "Type your name and the Mountain will make an echo ";
cin >> m.Body;
//Asks Mountain for the echo service
m.To = "Mountain";
m.ServName = "echo";
if (s.AskForDeferredService(m, ServReq_id)== SMA_SUCCESS)
{
//Now execute some actions before getting answers
cout << "Service echo just requested" << endl;
//Getting answers
if (s.GetDeferredAnswers(answers, ServReq_id)== SMA_SUCCESS)
{
do
{
m_aux = answers.GiveCursor(); //each answer
//Process the message
m_aux.Show();
}
while(answers.GoNext());
}
else
Error();
}
else
Error(); //Invoke the standard error function
};
Por último, el ejemplo que permite comprobar la traducción de CKRL a C++. El agente Santa es el encargado de repartir los juguetes a los niños. Si el niño ha sido bueno durante el año (agente Mixy), recibirá un regalo extra además del que ha pedido. Si el niño a sido malo (agente BadMixy), obtendrá carbón.
Para representar los comportamientos se definen 2 conceptos CKRL: la carta de Navidad (Christmas_letter) y el juguete (Toy). La tabla muestra las propiedades de cada concepto.
Concepto |
Propiedad |
Tipo |
Restricciones |
Christmas_letter |
child_name |
string |
  |
age |
integer |
0-99 |
|
good_behaviour |
Boolean |
Por defecto: true |
|
toy_name |
string |
Por defecto: ball |
|
Toy |
toy_name |
string |
Por defecto: ball |
toy_kind |
string |
Los ficheros utilizados son:
// santa.ckrl
defproperty boy_name
range (string);
defproperty age
range (integer (0:99));
defproperty good_behaviour
range (boolean)
default (true);
defproperty toy_name
range (string)
default ("ball");
defproperty toy_kind
range(nominal(good,bad))
default(good);
defconcept Christmas_letter
relevant boy_name, age, good_behaviour, toy_kind, toy_name;
defconcept Toy
relevant toy_kind, toy_name;
// santa.adl
#DOMAIN "santa_domain"
#YP_SERVER "arturo.lsi.us.es:6050"
#COMM_LANGUAGE ckrl
#MIX_LIBRARY "/home/ramon/tesis/mix/MIXWP1.4"
#ONTOLOGY "santa.ckrl"
AGENT YP_Agent -> YPAgent
END YP_Agent
AGENT Santa -> BaseAgent
RESOURCES
REQ_LIBRARIES: "santa-functions.C"
SERVICES