Intent Relations¶
The interpretation of an utterance may change depending on the context of the conversation. Context-dependant dynamics in the conversation are modeled by the relations intents have with each other. This module defines an API to specify them.
Note
Usage of relations is demonstrated in the example_agent.shop
module of
the Example Agent
Inheritance¶
Since we define intents as Python classes, we can reuse of one of the founding concepts of object oriented programming: inheritance.
@dataclass
class AskCoffee(Intent):
"""Hello, I'd like a light roast coffee"""
roast_level: CoffeeRoastLevel = "medium"
@dataclass
class AskEspresso(AskCoffee):
"""Hello, I'd like a dark roast espresso."""
An intent should subclass another when its meaning includes and specifies the meaning of the other intent. When an intent is a subclass of another:
It will inherit all parameters, types and default values of the parent intent
It will inherit all the other relations of the parent intent
It will inherit the parent’s fulfillment method
It will be rendered as a separate, independent intent
It will not inherit language data such as example utterances and responses
Follow¶
The follow()
relation is a context constraint: an intent that follows another
one can only be predicted after the followed one.
from intents import follow
@dataclass
class AddMilk(Intent):
"""With milk please"""
parent_ask_coffee: AskCoffee = follow()
An intent should follow another when it only makes sense in the parent’s context. In the example, it doesn’t make sense to walk into a cafè and utter “With milk please”; however, it does make sense to say so after asking for a coffee.
Context parameters can be accessed with another OOP fundamental concept: composition.
>>> prediction = connector.predict("I want a dark roast espresso")
>>> prediction = connector.predict("With milk please")
>>> prediction.intent.parent_ask_coffee.roast_level
"dark"
This relation is implemented by looking at the lifespan of intents.
AskCoffee starts with a lifespan of 5 (this can be configured by setting a
lifespan = N property in the parent Intent class). This value is decremented
at each conversation turn; intents that follow AskCoffee can only be predicted
while its lifespan is > 0. follow()
can also replice the current lifespan
of an Intent with a new one (e.g. set it to 0 to kill the context), see its
documentation for details.
It’s worth noting that the follow relation is inherited by subclasses:
If intent AskEspresso is a subclass of AskCoffee, and AddMilk follows AskCoffe, then AddMilk also follows AskEspresso.
If intent AskSkimmedMilk is a subclass of AskMilk, and AskMilk follows AskCoffee, then AskSkimmedMilk also follows AskCoffee (and AskEspresso in the example above)
API¶
-
class
RelationType
(value)[source]¶ Currently, the only available type is RelationType.FOLLOW. If you want to define a follow relation, use
follow()
.
-
follow
(*, new_lifespan=None)[source]¶ This can be used as a value for an Intent Relation field, e.g.
from intents import follow @dataclass class AddMilk(Intent): """With milk please""" parent_ask_coffee: AskCoffee = follow()
This will make “AddMilk” predictable only if AskCoffe was predicted before, meaning, it is present in context with lifespan > 0. Lifespan is a counter that decreases from a given number (default is 5) at each conversation turn.
follow()
can update this number, either to keep the context alive, or to kill it when it’s no more necessary:@dataclass class CancelAskCoffee(Intent): """I don't want coffee anymore...""" parent_ask_coffee: AskCoffee = follow(new_lifespan=0)
Warning
The returned field currently sets default=None as a workaround to some known limitations of dataclasses with inheritance. This behavior may be adjusted again before 1.0
- Parameters
new_lifespan (
Optional
[int
]) – Reset the lifespan of the followed intent to the given value- Return type
Field
-
class
IntentRelation
(relation_type, relation_parameters, field_name, source_cls, target_cls)[source]¶ Represent an Intent Relation definition from a “source” Intent (the one that defines the relation) to a “target” Intent (the one that is referenced in source).
For instance, given
@dataclass class AddMilk(Intent): """With milk please""" parent_ask_coffee: AskCoffee = follow()
Then the follow relation defined in AddMilk can be represented as
IntentRelation( relation_type=RelationType.FOLLOW relation_parameters=None, field_name="parent_ask_coffee", source_cls=AddMilk, target_cls=AskCoffee )
IntentRelation
objects are typically produced byintent_relations()
, and enclosed in its returnedIntentRelationMap
result structure.- Parameters
relation_type (
RelationType
) – One of the relation typesrelation_parameters (
type
) – Relation parameters as they are specified by the relation fieldfield_name (
str
) – Name of the field in source_cls that defines the relationsource_cls (
Type
[Intent
]) – The Intent class where the relation is definedtarget_cls (
Type
[Intent
]) – The other Intent class that is referenced by the relation
-
class
FollowIntentRelation
(relation_parameters, field_name, source_cls, target_cls)[source]¶ - Parameters
relation_parameters (
FollowRelationParameters
) – Relation parameters as they are specified by the relation fieldfield_name (
str
) – Name of the field in source_cls that defines the relationsource_cls (
Type
[Intent
]) – The Intent class where the relation is definedtarget_cls (
Type
[Intent
]) – The other Intent class that is referenced by the relation
-
class
IntentRelationMap
(follow=<factory>)[source]¶ A map of an Intent’s relations, as it is produced by
intent_relations()
.- Parameters
follow (
List
[FollowIntentRelation
]) – A list of intents that are followed by the Relation subject