Watsonx Assistant and watsonx Orchestrate are great tools for low-code and no-code developers to build conversational experiences. Additionally, they provide extensibility options for pro-code developers for more flexibility and to run custom business logic.
Watsonx Assistant and watsonx Orchestrate share the same functionality to build conversational experiences. Both can be utilized to build assistants, bots and other natural language-based experiences. There are different options to build these applications.
1. watsonx Assistant User Interface
In many cases, coding is not required so that no-code and low-code users can build their own experiences declaratively.
2. Custom Applications with watsonx Assistant as Backend Service
Furthermore, custom applications can be developed which integrate watsonx Assistant via APIs. This requires development, deployment and operation skills to run these types of applications.
3. watsonx Assistant User Interface plus Extensions
Recently a new feature has been added, called Conversational Skills
. In this case watsonx Assistant runs custom skills as extensions, similarly to how it is done for integrations of custom search providers. Watsonx Assistant invokes these extensions, rather than being invoked by applications via API.
Conversational Skills can be implemented in various languages. They only need to provide certain REST endpoints (SPI - Service Provider Interface). There is an SDK for Java and another one for JavaScript. The endpoints can be deployed, for example, on IBM Code Engine.
Scenario
Let’s look at an example. BluePoints is an application to award colleagues. Employees get certain amounts of blue points each year which they give away to colleagues. In a conversational application they might want to enter the following texts.
- I would like to send BluePoints.
- I would like to send BluePoints to Peter Miller.
- I would like to send 50 BluePoints to Peter Miller.
- I would like to send 50 BluePoints to Peter Miller with comment “Great job!”.
In the last example text all information is provided; in the other cases the Assistant needs to ask for missing information. This process is often referred to as Information Gathering
and Slot Filling
.
Once all slots are filled, a confirmation can be requested before business logic is executed.
The following screenshots show the conversation flow where every slot is filled sequentially.
As a more natural way users can provide all information in one step. See also the screenshot at the top of this article.
Read the documentation Gathering information with slots for details.
Conversational Skills
With the new feature Conversational Skills, skills can be implemented via code by implementing certain IBM watsonx Assistant Toolkit Endpoints.
The slots are defined via code. watsonx Assistant uses the slot names, descriptions and names to automatically fill the slots with information from the user input. As you would expect Assistant leverages a Large Language Model from the Granite series to do this.
Via the Java SDK conversational skills can be implemented as a subclass of the com.ibm.watson.conversationalskills.sdk.Skill class:
1
2
3
4
5
6
7
8
9
10
11
12
public class BluePointsSkill extends Skill {
private AmountSlotHandler amountSlotHandler = new AmountSlotHandler();
private ReceiverCommentSlotHandler receiverCommentSlotHandler = new ReceiverCommentSlotHandler();
private RecipientSelectorSlotHandler recipientSelectorSlotHandler = new RecipientSelectorSlotHandler();
private RecipientSlotHandler recipientSlotHandler = new RecipientSlotHandler();
...
public SlotHandler[] getSlotHandlers() {
return new SlotHandler[] {
this.recipientSlotHandler, this.recipientSelectorSlotHandler, this.amountSlotHandler,
this.receiverCommentSlotHandler
};
}
For each slot a qualifier is defined.
1
2
3
4
5
6
7
@Qualifier
@Retention(RUNTIME)
@Target({
METHOD, FIELD, PARAMETER, TYPE
})
public @interface Amount {
}
Each slot must be implemented as a subclass of com.ibm.conversationalskills.sdk.SlotHandler:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Amount
public class AmountSlotHandler extends SlotHandler {
private static String SLOT_NAME = "amount";
public AmountSlotHandler() {
super(new SlotInFlight().name(SLOT_NAME).type(SlotInFlight.TypeEnum.NUMBER));
}
@Override
public boolean isShownByDefault() {
return true;
}
@Override
public void onFill(State state) {
state.getLocalVariables().put("amount", getNormalizedValue());
}
@Override
public void onRepair(State state) {
onFill(state);
}
}
Skills need to provide an ‘orchestrate’ endpoint.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import com.ibm.watson.conversationalskills.sdk.Skill;
import com.ibm.watson.conversationalskills.sdk.SkillOrchestrator;
...
@RequestMapping(
method = RequestMethod.POST,
value = "/providers/{provider_id}/conversational_skills/{conversational_skill_id}/orchestrate",
produces = { "application/json" },
consumes = { "application/json" }
)
ResponseEntity<OrchestrationResponse> orchestrate(
@PathVariable("provider_id") String providerId,
@PathVariable("conversational_skill_id") String conversationalSkillId,
@Valid @RequestBody(required = false) OrchestrationRequest orchestrationRequest
) throws Exception {
Skill[] skills = {new BluePointsSkill()};
...
var skillOrchestrator = new SkillOrchestrator();
var orchestrationResponse = skillOrchestrator.orchestrate(skillWithID, orchestrationRequest);
return new ResponseEntity<>(orchestrationResponse, HttpStatus.OK);
}
After all slots have been filled, confirmation messages can optionally be required. After this business logic can be run.
1
2
3
4
5
6
7
8
@Override
public ConversationalResponseGeneric onConfirmed(ResourceBundle resourceBundle, State state) {
var conversationalResponseGeneric = new ConversationalResponseGeneric();
conversationalResponseGeneric.setResponseType("text");
conversationalResponseGeneric.setText(getConfirmationStringSubstitutor(state).replace(resourceBundle.getString("confirmation")));
// your business code goes here
return conversationalResponseGeneric;
}
Setup
The custom skills need to be deployed somewhere so that Assistant can access them. IBM Code Engine is a good deployment option.
1
2
3
4
5
6
7
8
9
10
11
12
podman build -f src/main/docker/Dockerfile.jvm --platform linux/amd64 -t quarkus/bluepoints-conversational-skill-provider-jvm:2 .
podman run -i --rm -p 8080:8080 localhost/bluepoints-conversational-skill-provider-jvm:2
curl -X GET localhost:8080/providers/:provider_id/conversational_skills
ibmcloud plugin install container-registry
ibmcloud plugin install ce
ibmcloud login --sso -r eu-de
ibmcloud target -g niklas
ibmcloud cr login
// create namespace
podman tag localhost/bluepoints-conversational-skill-provider-jvm:2 icr.io/niklas/bluepoints-conversational-skill-provider:2
podman push icr.io/niklas/bluepoints-conversational-skill-provider:2
After this the skill needs to be registered.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
curl -X POST 'https://api.us-south.assistant.watson.cloud.ibm.com/instances/xxx/v2/providers?version=2021-11-27' \
-u "apikey:xxx" \
--header 'Content-Type: application/json' \
--data '{
"provider_id": "niklas-myProCodeProvider",
"specification": {
"servers": [
{
"url": "https://niklas-conversational-quarkus.xxx.eu-de.codeengine.appdomain.cloud/"
}
],
"components": {
"securitySchemes": {
"authentication_method": "basic",
"basic": {
"username": {
"type": "value",
"value": "myBasicUserName"
}
}
}
}
},
"private": {
"authentication": {
"basic": {
"password": {
"type": "value",
"value": "myBasicPassword"
}
}
}
}
}'
Once registered the Assistant user interface will show the ‘Skill-based’ option.
You will be able to select your custom skill.
Next Steps
Check out the following resources to learn more.