Entry Level Artificial Intelligence Markup Language (AIML)
Ciarán O'Leary
|
<aiml version=2.0> ... </aiml> |
Fig. 1. Sample AIML message, consisting of single root tag with version attribute.
|
aiml tag must be one of the following
requestresponsetype. This indicates the type of message being sent, e.g. newrun, endrun etc.
They may also carry an attribute called runid. This attribute is used by stateful servers in a manner analogous to the use of cookies in web applications. When a new run is started the server returns a runid as part of the response. This runid uniquely identifies this particular run in the server. Subsequent calls to the server from the client should include this runid in order to ensure that the server is making use of whatever data it has accumulated for this particular run. All responses should include this attribute as well. It is not a mandatory attribute, since some servers may not be stateful i.e. they may generate identical responses regardless of the particular run. These servers do not need to include the runid attribute.
The response message may also carry two optional attributes,
statusstatustext1000 indicates success, although this may be qualified as partial success, analogous to HTTP 2XX status values. Anything with a status of 1000 or over indicates an error, meaning that no meaningful data is being returned, and that no operation was completed.
| ||||||||||||||||||||||||||||||||||||||
| Fig. 2. Response status codes |
The type attribute indicates which of the set of six messages is being sent. The type should be surrounded by quotes and be in lower case (by convention). The type of a response will always be the same as the type of the request it was sent in response to. Fig. 3 and Fig. 4 below show a sample request and response (without some of the nested tags that will be discussed below.
<aiml version=2.0> <request type="newrun"> ... </request> </aiml> |
<aiml version=2.0> <response type="newrun" status="0001" statustext="New Run Started" runid="1234"> ... </response> </aiml> |
Fig. 3. Sample AIML request, including type attribute indicating which message is being sent.
|
Fig. 4. Sample AIML response, including type, status and statustext attributes indicating the level of success of the message.
|
Information carried as part of a message (for the purposes of the remainder of this document, a request or reponse is called a message) will be one of three types.
paramargumentdatadata tags until the next sub section.
Parameters (indicated using the <param> tag) carry a single piece of information (in a name, value pair) as part of the message. There are a set number of parameters for each message type, and these are included as part of the specification, as given in the next section. Consider and example. The specification indicates that the newrun request can carry a parameter called 'client' with a value indicating the process that is calling the server. The format for such a parameter is shown in fig. 5. Parameters can be passed as part of either a request or a response.
<aiml version=2.0> <request type="newrun"> <param name="client" value="http://host:port/process"/> </request> </aiml> |
| Fig. 5. An example of passing a parameter as part of a message. |
Arguments (indicated using the <argument> tag) are precisely the same as parameters, except that the types of arguments passed do not form part of the specification. A server decides upon which arguments it will accept, over and above those contained as part of the specification. For example, in order to start a new run in a mind server (which is a neural network) the client may need to pass a value indication the number of hidden layers to include in the neural network. There is no parameter included in the specification to permit this, so the server publishes the fact that it will accept this argument (using the discovery mechanism discussed below). Clients are then aware of the fact that this argument is permitted and can send the data required. This argument example is shown in fig. 6. Arguments can only be sent as part of a request
<aiml version=2.0> <request type="newrun"> <param name="client" value="http://host:port/process"/> <argument name="hiddenlayers" value="2"/> </request> </aiml> |
| Fig. 6. An example of passing an argument as part of a message. |
Data values represent the state or action to be passed between different servers. In sub-symbolic AI this data is typically a vector of weights, represented as real numbers. Our protocol makes absolutely no attempt to control the format of the data being passed, leaving it up to the servers themselves to correctly interpret the date. (See [O'Leary and Humphrys, 2002]] for further discussion of this.) What we do provide is a tag called <data> which will wrap up the values being passed. The client can ignore anything that is contained between the tags and just pass it on to the other server. We do provide an attribute called name which indicates what exactly the data represents, as listed here:
name="x"name="a"name="y"<data> tag are given in fig. 7 and fig. 8.
<aiml version=2.0> <request type="GetAction" runid="1234"> <data name="x"> (1,2,3,4) </data> </request> </aiml> |
<aiml version=2.0> <request type="TakeAction" runid="1234"> <data name="a"> (4, 6, 9) </data> </request> </aiml> |
Fig. 7. Sample AIML GetAction request. The state of the world is provided as the data in the request. The action will be returned from the server as the data part of a response.
|
Fig. 8. Sample AIML TakeAction request. The action, represented as a vector of numbers returned from the mind server in the response to the GetAction request, is passed to the world server, indicating to the body that it should take the action. It is assumed at layer 1 that it can interpret the data format.
|
The core of the AIML protocol consists the following six types of messages
newrunendrungetstategetactiontakeactiongetprofiletype attribute in the request and response. Message 1, 2, 3 and 5 must be supported by all world servers. Messages 1, 2, and 4 must be supported by all mind servers. This is required so that the client can handle a run (a continuous interaction between a world and mind server consisting of newrun (world), newrun (mind), getstate (world), getaction (mind), takeaction (world), getaction (mind), takeaction (world), getaction (mind), takeaction (world), etc., endrun (world), endrun (mind). Message 6 is part of the specification, in order to allow evolution of servers. This is discussed in the next section. Servers do not have to support message 6, but it aould be advisable to do so, even with dummy handling, in order to prevent errors.
We will discuss each of these messages in turn, outlining the parameters they require, and the minimum amout of information a server should provide in response to one of these requests.
newrun
A newrun request is required to start a run in a world or mind server. The request may contain the url of the client process as a parameter. It may also contain the url of the other server involed in the run (since a run consists of a world and a mind). The server may need this for discovery. It should not be given the runid in the other server, however, since it would be undesirable for a server to be getting requests for the same run from two different sources. The two parameters used for this are client and otherparticipant. The response should indicate which runid was chosen for this particular run (if the server is stateful, its absence indicates a stateless server). Example requests and responses are shown in fig. 9 and fig. 10.
<aiml version=2.0> <request type="newrun"> <param name="client" value="http://host:port/process"/> <param name="otherparticipant" value="http://host:port/process"/> </request> </aiml> |
<aiml version=2.0> <response type="newrun" status="0001" statustext="New Run Started" runid="1234"> </response> </aiml> |
Fig. 9. newrun request.
|
Fig. 10. newrun response.
|
runid.
endrun
An endrun request is required to end a run in a world or mind server. No parameters are expected for the request, and the response should simply be an indication that the request was processed successfully. Example requests and responses are shown in fig. 11 and fig. 12.
<aiml version=2.0> <request type="endrun" runid="1234"> </request> </aiml> |
<aiml version=2.0> <response type="endrun" status="0001" statustext="Run Ended" runid="1234"> </response> </aiml> |
Fig. 11. endrun request.
|
Fig. 12. endrun response.
|
runid if it exists. At the very least the response must return some indication that the request was processed, and if the server is stateful the response should give a runid.
getstate
A getstate request is required to get the current state of a world server. No parameters are expected for the request. The response should contain the data that represents the state of the world. Example requests and responses are shown in fig. 13 and fig. 14.
<aiml version=2.0> <request type="getstate" runid="1234"> </request> </aiml> |
<aiml version=2.0> <response type="getstate" status="0001" statustext="State Provided" runid="1234"> <data name="x"> (1,2,3,4) </data> </response> </aiml> |
Fig. 13. getstate request.
|
Fig. 14. getstate response.
|
runid if it exists. At the very least the response must contain the data representing the state, so that this can be passed to the mind server. If the server is stateful the response should give the runid.
getaction
A getaction instructs a mind server to analyse a given state and choose an action based on it. The request must contain the data representing the state of the world. The response must contain the data that represents the action chosen by the mind. Example requests and responses are shown in fig. 15 and fig. 16.
<aiml version=2.0> <request type="getaction" runid="1234"> <data name="x"> (1,2,3,4) </data> </request> </aiml> |
<aiml version=2.0> <response type="getaction" status="0001" statustext="Action Provided" runid="1234"> <data name="à"> (4, 6, 9) </data> </response> </aiml> |
Fig. 15. getaction request.
|
Fig. 16. getaction response.
|
runid if it exists as well as the data representing the state. At the very least the response must contain the data representing the action. If the server is stateful the response should give the runid.
takeaction
A takeaction instructs a body in a world server to take an action and return the new updated state of the world. The request must contain the data representing the action to be taken. The response must contain the data that represents the new state of the world. Example requests and responses are shown in fig. 17 and fig. 18.
<aiml version=2.0> <request type="takeaction" runid="1234"> <data name="a"> (4, 6, 9) </data> </request> </aiml> |
<aiml version=2.0> <response type="getaction" status="0001" statustext="Action Taken" runid="1234"> <data name="y"> (1,2,3,5) </data> </response> </aiml> |
Fig. 17. takeaction request.
|
Fig. 18. takeaction response.
|
runid if it exists as well as the data representing the action. At the very least the response must contain the data representing the new state. If the server is stateful the response should give the runid.
Discovery is the process of finding out the profile of a server i.e. the messages that is supports. The last section showed the five messages that must be supported by servers in order to facilitate a run by a client application. It indicated the bare minimum that was required for each of these messages. It will be the case that some servers will require more data than in indicated above in order to process some requests, I repeat here the example of the neural network mind server which needs the client to choose a number of hidden layers before a run can be started. If this is the case then that server supports an extension on the standard newrun request. While the extension to the request itself is not supported by the core protocol, there should be means by which the client can find out the extra parameters (arguments really, as discussed above) that the server needs. The server may also return extra arguments in the response. This should also be shown in the profile, although they will not be handled by the client in this version of AIML. It will also be the case that servers wish to extend the set of messages. In the example given here, the server may support a message called restarttraining in order to re-initialise all the weights in the neural network. There should be a way the client can find out the extra requests the server supports. In order to allow this discovery we provide a message called getprofile as part of the protocol.
When a run has started, it may be the case that the mind and world server are aware of eachother (if the url was passed as part of the newrun request). They will not, however, be aware of the runid appropriate for the run it is involved in, in the other server. If, say, a mind server is aware that it is choosing actions for a particular world server, then it may want to find out, for example, its current score in the world. There is no mechanism for this in the core protocol. However, it the mind server was able to see the profile of the world server, and see that there was a request called getcurrentscore it should be able to request this data from the world. In order to allow this we provide a mechanism called tunnelling which allows a server send a request to a client. Obviously the client will not understand this message, since it only receives responses, so it just passes it on to the other server. When the client gets the response it passes it back to the original server.
getprofile
The getprofile message should be supported by all servers, even those that only use the five core messages (it could provide an empty response rather than an error). It should not require a run to have started, as it is only an informational request. Therefore, it makes no use of the runid. When a server gets a getprofile request it should return a list of the following:
newrun request. For each of these messages it should list the arguments it requires, the types of these arguments (int, string etc.), possible values and the default value.restarttraining for the neural network (described above) or the message getscore indicating the current score attributed to the actions chosen for a certain run in a world.
getprofile request is shown in fig. 19 below. This is always the same and will never carry any parameters or arguments.
<aiml version=2.0> <request type="getprofile"> </request> </aiml> |
Fig. 19. The getprofile request.
|
boolean<argspec name=synchronous type=boolean default=true>
string<argspec name=clientauthor type=string default='anonomous'>
integer<argspec name=hiddenlayers type=integer default=2>
real<argspec name=weight type=real default=1.5>
url<argspec name=subserver type=url>
listvalue attribute as part of its specification. This lists all the components of the list in a comma separated list surrounded by double quotes. <argspec name=algorithm type=list value="alg1,alg2,alg3,alg4" default=alg4>
datadata as discussed above. No default is specified as part of the protocol. When the message is being constructed by the client to sent to the server, this is the only argument that will not use the <argument> tag. It will instead use the <data> tag.
<argspec name=goalstate type=data>
The profile of a message is given using a <messagespec> tag which includes a set of <argspec> tags. One <messagespec> tag is given for each non-standard message, and within this one <argspec> tag is given for each non-standard argument for that message. An example <argspec> is given for each of the different types above. The <argspec> tag has the following attributes:
directionin or an output argument, sent as a result, in which case it's value will be out
nametypedefaultvaluelist type. Gives the values that the client chooses from.<messagespec> tag has a single attribute.
<description> which is a description in HTML of the message and its arguments. An example <messagespec> for a newrun request that expects an argument providing the number of hidden layers for a neural network is given below in fig. 20.
<messagespec type="newrun"> <description> In order to start a run the client is required to indicate how many layers should be in the neural network </description> <argspec direction=in name="hiddenlayers" type=integer default=2/> </messagespec> |
Fig. 20. The messagespec for a newrun request that expects an argument giving the number of hidden layers in a neural network.
|
<messagespec> for every non-standard core message, as well as every additional non-standard message that the server defines. This should list an <messagespec> for all the non-standard input and output values that the server will provide for this message, as well as an (optional) description of the message in HTML. nameauthordisplayurldatecreateddatelastmodifiedgetprofile request (in other words, the complete profile) for a server with the following (non-standard) characteristics is given in fig. 21.
Server Characteristics
newrun request to indicate the number of hidden layers in the neural network it uses.restarttraining which lets the client tell the server to re-initialise all weights using the seed providedgetscore which returns the score it has calculated for its own performance so far in this run
<aiml version=2.0> <response type="getprofile" status="0001" statustext="Profile Provided"> <param name=author value="Ciaran O'Leary"/> <param name=name value="Back Prop II"/> <param name=displayurl value="http://comp.dit.ie/coleary/mind"/> <param name=datecreated value="27/02/2001"/> <param name=datelastmodified value="18/02/2002"/> <messagespec type="newrun"> <description> In order to start a run the client is required to indicate how many layers should be in the neural network </description> <argspec direction=in name="hiddenlayers" type=integer default=2/> </messagespec> <messagespec type="restarttraining"> <description> Server will re-initialise all weights using random numbers generated using the seed provided by the client </description> <argspec direction=in name="seed" type=real default=2/> </messagespec> <messagespec type="getscore"> <description> Gives the current score as calculated by the mind based on its perception of its effectiveness </description> <argspec direction=out name="score" type=real/> </messagespec> </aiml> |
Fig. 21. The response to a getprofile request.
|
Tunnelling
Fig. 22 shows the following situation:
A client has started a run using a world server and a mind server. The world server has published its profile and has stated that it supports a request to get the current score in the world. The mind is using a learning algorithm and wants to know what score it is achieving in the world, in order to adjust its algorithm accordingly.The protocol as outlined so far does not support any mechanism for two servers to communicate with eachother in order to be able to send requests and get responses. The servers may know what other server is involved in the run with them (if the client provided this information at the
newrun stage) but they do not know what runid is associated with their run in the other server. Therefore, they may send requests to the other server once those requests to not require a runid. In the example described here the mind server needs to make use of two requests. Firstly it needs to find out the profile of the world server it is involved in the run with. This is can do quite easily, since the getprofile request does not require a runid. Then it needs to call the getscore request on the world server. The score will obviously differ across runs, so the mind server will need the runid in order to send this request.
|
| Fig. 22. A message being tunnelled from one server to another through the client. |
We support this with the idea of tunnelling. Basically, a server can tunnell a message to another server by sending it to the client. If the client gets a request it hands it straight on to the other server in the run (after it changes it to the appropriate runid). This works because a client is never expecting to get a request, it only ever expects responses. The client can also filter these requests so that it doesn't pass on requests that servers should not be sending to eachother (e.g. they should not send newrun requests through a client, they should send this directly to the server in question if they wish to begin a run).
Layer 2 of the WWM will handle a more sophisticated mechanism for representing the profile of a server. It will allow for the specification of an XML Schema for a specific domain. Uisng XML schema it can take full advantage of the advanced data typing mechanism that forms a part of the standard. Alternatively, server authors can describe their server using a pre-existing schema such as WSDL, a language designed specifically for the purpose of describing data. XML Schema can also be used for representing the data. A schema will define how certain classes of server, for example neural network minds, represent data in a standard way. The data can then be formatted using XML to ensure full compliance with other servers. If discrepencies arise, the two formats can be aligned with the assistance of the user, and the power of XSL-T [w3.org/tr/xslt], and possible inclusion of substitution groups in schema.
We define an XML Schema for the definition of services on the WWM. This schema outlines the following:
substitution groups which can aid with alignment.
Making use of a Schema, and forcing profiles to be valid and well-formed XML, does not change the philosophy of AIML. AIML remains the same. All that changes is the format of the profile, which was essentially just one part of AIML. The AIML requests and responses will remain the same, with the exception that at layer 2, the service can return it's profile as an XML document that conforms to a particular schema.
WSDL (Web Services Description Language) provides a mechanism whereby web services (and indeed our web servers expose a web service) can be described as a set of operations. An operation is composed of an input message, an output message and an optional fault message. Requests and responses are described at an abstract level, as a set of input and output parts. All the operations are grouped together into a portType. The portType is not ties to any particular implementation of a transport protocol, or any specific location. This happens when the service tag is defined. A child tag of service, called port binds the set of operations to a particular location. A separate binding tag defines the binding of the operations to a particular protocol (SOAP, HTTP GET, HTTP POST). All interaction with WWM services takes place over HTTP POST, but the binding for this protocol is unsuitable for our needs. It defines the parameters in HTTP POST as the set of different name=value pairs carried in the optional data field of the HTTP packet. The parameters in our case are the param, argument and datatags in the AIML messages. We require a binding to AIML, but for the moment we're satisfied to omit the binding for our examples, meaning that the WSDL code in Fig. 23 below is not actually valid WSDL.
<definitions name ='neuralnetservice' xmlns='http://schemas.xmlsoap.org/wsdl/'> <service name='NeuralNetService' > <port name='NeuralNetPort'> <http:address location="http://www.compapp.dcu.ie/cgi-bin/humphrys/mir/wwm/mind/cgiscript"/> </port> </service> <message name='NeuralNet.SetNumberOfLayers'> <part name='layercount' type='xsd:int'/> </message> <message name='NeuralNet.SetNumberOfLayersResponse'> <part name='worked' type='xsd:boolean'/> </message> <message name='NeuralNet.RestartTraining'> <part name='seed' type='xsd:int'/> </message> <message name='NeuralNet.RestartTrainingResponse'> <part name='worked' type='xsd:boolean'/> </message> <portType name='NeuralNetPort'> <operation name='SetNumberOfLayers'> <input message='wsdlns:NeuralNet.SetNumberOfLayers' /> <output message='wsdlns:NeuralNet.SetNumberOfLayersResponse' /> </operation> <operation name='RestartTraining'> <input message='wsdlns:NeuralNet.RestartTraining' /> <output message='wsdlns:NeuralNet.RestartTrainingResponse' /> </operation> </portType> </definitions> |
| Fig. 23.. A neural network service with two operations, described using a slimmed down version of WSDL (note the absence of the binding). |
We propose that specific groups or communities with-in sub-sybmolic AI define their own schema to define their data at layer 2. This would mean that a new XML language is defined for each section. This should not pose a difficulty since those worlds and minds defined within a particular community would only ever be expected to work with eachother. The format for the schema would most probably be driven by the most popular world or mind server in the community. Wrappers could be written for existing layer 1 servers so that they conform to the layer 2 schema. No change would be required to AIML. The AIML messages still only carry data between the <data> tags. The client still ignores this data and passes it on to the other server involved in the run. It just happens that this data conforms to an XML standard, in fact, what exists between the <data> tags is a ful XML document.
Layer 2 will most likely take off for data long before profiles. At layer 1 we already have sufficient power to describe a profile, and there is not much that layer 2 can add to this. The same cannot be said for data. At layer 1, data is completely unformatted (at least not in any way controlled by the protocol). Layer 2 introduces strong and restrictive formatting, with the use of an XML schema for a community and the representation of data in conformance to that schema.
However, it could be the case that a client wishes to start a run involving a world from one sub community and a mind from another, then there will be problems, since both sets of data are formatted according to different schema. We are attempting to creat alignment software for the client. This software will analyse the two schema and attempt to match similar tags and attbiutes, so that it can alter the data from complying to one schema to complying with the other. This is a non-trivial task, and will involve the user. The client will search for possible matches but will then query the user the ask if the match is correct. The user can have the benefit of reading the documentation. If the user feels that the final match is a good one, then the mapping can be represented using a language such as XSL-T and published by the user for others to use. Alternatively, if the changes were minor, then substitution groups could be added to one or other of the schema. These are used to show that one tag has the same semantics as another, despite naming differences. We will base our work on similar projects such as Chimarea [McGuinness, Fikes, Rice and Wilder, 2000] and Prompt [Noy and Musen, 2000].
At the upper layer we will support semantic web [Berners-Lee, 2001] technologies such as RDF and DAML for descritpion of service profiles and data. For further discussion of this see [O'Leary and Humphrys, 2002]. We have not yet decided on how integration with lower layers will take place. We will discuss this further when we have implemented layer 2.
The data and the profiles described at the upper layers will all be carried on the core set of five messages as defined above.
Client software will be provided by the creators of the WWM which will do the following
Got state from world, presenting it to mind.
It should be clear that the five messages supported by the protocol (newrun, endrun, getstate, getaction and takeaction) are the only messages that the client needs to start, continue and end a run. The client is simply involved in constantly sending getaction and takeaction messages to the two servers. However, we outlined above, the fact that a server could publish its profile, listing all the additional messages and arguments it supports. If a server supports non-standard messages or arguments, then the client will need to find this information somewhere. The client will be designed to prompt the user for additional arguments that are required whenever a standard message with additional arguments is being sent. The user can also interrupt a run at any stage, and get the client to send a non-standard message. The client will be able to construct the message from its profile, and will only have to prompt the user for the arguments that are to be sent. The client can even present the user with default values, if these are included in the profile.
We can describe a run in the graphical client more completely now. It is important to note that the user is the person who is using the client which is a piece of software.
New Run option in client menu.
getprofile requests to both servers. When it gets the responses it presents the results to the user. The information the client can present (if it is supported by the server) will be:
Restart button. endrun requests to both servers.Pause button, or stopped using the Stop button.
newrun request to both of the servers. If there should be any additional arguments send with the newrun message then the client prompts the user for the value. The client only permits the user to enter values that are of the specific type of the argument (e.g. int, string...).getstate, getaction or takeaction then the user is prompted for a value for the argument, the first time the message is sent. The user can choose to use that value for just this message, for the next x number of messages, or for all subsequent messages.
Pause button. When the run is interrupted, the user can look up a list of non-standard messages (that the client got using the getprofile request). The user can choose one of these messages to send to the server it belongs to. The client will issue the request to the server, and present the response graphically to the user. The user can then continue with the runnewrun for example), or to allow all without being notified. Information about messages going through the client are automatically echoed for the information display on the client, so the user can see what messages are passing through even if they choose to allow all messages.A onestep client written in Perl is currently available from the WWM portal site [w2mind.org]. A graphical and batch client written in Java (using JDK1.3) is also available, but with only a limited number of the features listed above. Two servers are available to test the clients, these servers are available at
http://www.compapp.dcu.ie/cgi-bin/humphrys/mir/wwm/world/cgiscript: A Grid World serverhttp://www.compapp.dcu.ie/cgi-bin/humphrys/mir/wwm/mind/cgiscript: A Mind serverThe protocol defined in this paper will form the entry level protocol for the WWM. We have attempted to make the protocol as simple as possible, as have therefore rejected a number of protocols available on the web and the semantic web. We do allow for use of these protocols at higher layers of the WWM.