|
| 1 | +:desc: Extend your Rasa conversational AI assistant using Rasa-SDK to connect to |
| 2 | + external APIs or improve dialogue with custom actions written in Python. |
| 3 | + |
| 4 | +.. _rasa-sdk: |
| 5 | + |
| 6 | +Rasa SDK |
| 7 | +======== |
| 8 | + |
| 9 | +.. edit-link:: |
| 10 | + |
| 11 | +Rasa SDK provides the tools you need to write custom actions in python. |
| 12 | + |
| 13 | +.. contents:: |
| 14 | + :local: |
| 15 | + |
| 16 | +Installation |
| 17 | +------------ |
| 18 | + |
| 19 | +Use ``pip`` to install ``rasa-sdk`` on your action server. |
| 20 | + |
| 21 | +.. code-block:: bash |
| 22 | +
|
| 23 | + pip install rasa-sdk |
| 24 | +
|
| 25 | +.. note:: |
| 26 | + |
| 27 | + You do not need to install ``rasa`` for your action server. |
| 28 | + E.g. if you are running Rasa in a docker container, it is recommended to |
| 29 | + create a separate container for your action server. In this |
| 30 | + separate container, you only need to install ``rasa-sdk``. |
| 31 | + |
| 32 | +Running the Action Server |
| 33 | +------------------------- |
| 34 | + |
| 35 | +If you have ``rasa`` installed, run this command to start your action server: |
| 36 | + |
| 37 | +.. code-block:: bash |
| 38 | +
|
| 39 | + rasa run actions |
| 40 | +
|
| 41 | +Otherwise, if you do not have ``rasa`` installed, run this command: |
| 42 | + |
| 43 | +.. code-block:: bash |
| 44 | +
|
| 45 | + python -m rasa_sdk --actions actions |
| 46 | +
|
| 47 | +
|
| 48 | +The file that contains your custom actions should be called ``actions.py``. |
| 49 | +Alternatively, you can use a package directory called ``actions`` or else |
| 50 | +manually specify an actions module or package with the ``--actions`` flag. |
| 51 | + |
| 52 | +The full list of options for running the action server with either command is: |
| 53 | + |
| 54 | +.. program-output:: rasa run actions --help |
| 55 | + |
| 56 | +Actions |
| 57 | +------- |
| 58 | + |
| 59 | +The ``Action`` class is the base class for any custom action. It has two methods |
| 60 | +that both need to be overwritten, ``name()`` and ``run()``. |
| 61 | + |
| 62 | +.. _custom_action_example: |
| 63 | + |
| 64 | +In a restaurant bot, if the user says "show me a Mexican restaurant", |
| 65 | +your bot could execute the action ``ActionCheckRestaurants``, |
| 66 | +which might look like this: |
| 67 | + |
| 68 | +.. testcode:: |
| 69 | + |
| 70 | + from rasa_sdk import Action |
| 71 | + from rasa_sdk.events import SlotSet |
| 72 | + |
| 73 | + class ActionCheckRestaurants(Action): |
| 74 | + def name(self) -> Text: |
| 75 | + return "action_check_restaurants" |
| 76 | + |
| 77 | + def run(self, |
| 78 | + dispatcher: CollectingDispatcher, |
| 79 | + tracker: Tracker, |
| 80 | + domain: Dict[Text, Any]) -> List[Dict[Text, Any]]: |
| 81 | + |
| 82 | + cuisine = tracker.get_slot('cuisine') |
| 83 | + q = "select * from restaurants where cuisine='{0}' limit 1".format(cuisine) |
| 84 | + result = db.query(q) |
| 85 | + |
| 86 | + return [SlotSet("matches", result if result is not None else [])] |
| 87 | + |
| 88 | + |
| 89 | +You should add the the action name ``action_check_restaurants`` to |
| 90 | +the actions in your domain file. The action's ``run()`` method receives |
| 91 | +three arguments. You can access the values of slots and the latest message |
| 92 | +sent by the user using the ``tracker`` object, and you can send messages |
| 93 | +back to the user with the ``dispatcher`` object, by calling |
| 94 | +``dispatcher.utter_message``. |
| 95 | + |
| 96 | +Details of the ``run()`` method: |
| 97 | + |
| 98 | +.. automethod:: rasa_sdk.Action.run |
| 99 | + |
| 100 | +Details of the ``dispatcher.utter_message()`` method: |
| 101 | + |
| 102 | +.. automethod:: rasa_sdk.executor.CollectingDispatcher.utter_message |
| 103 | + |
| 104 | + |
| 105 | +.. _custom_session_start: |
| 106 | + |
| 107 | +Customising the session start action |
| 108 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 109 | + |
| 110 | +The default behaviour of the session start action is to take all existing slots and to |
| 111 | +carry them over into the next session. Let's say you do not want to carry over all |
| 112 | +slots, but only a user's name and their phone number. To do that, you'd override the |
| 113 | +``action_session_start`` with a custom action that might look like this: |
| 114 | + |
| 115 | +.. testcode:: |
| 116 | + |
| 117 | + from typing import Text, List, Dict, Any |
| 118 | + |
| 119 | + from rasa_sdk import Action, Tracker |
| 120 | + from rasa_sdk.events import SlotSet, SessionStarted, ActionExecuted, EventType |
| 121 | + from rasa_sdk.executor import CollectingDispatcher |
| 122 | + |
| 123 | + |
| 124 | + class ActionSessionStart(Action): |
| 125 | + def name(self) -> Text: |
| 126 | + return "action_session_start" |
| 127 | + |
| 128 | + @staticmethod |
| 129 | + def fetch_slots(tracker: Tracker) -> List[EventType]: |
| 130 | + """Collect slots that contain the user's name and phone number.""" |
| 131 | + |
| 132 | + slots = [] |
| 133 | + |
| 134 | + for key in ("name", "phone_number"): |
| 135 | + value = tracker.get_slot(key) |
| 136 | + if value is not None: |
| 137 | + slots.append(SlotSet(key=key, value=value)) |
| 138 | + |
| 139 | + return slots |
| 140 | + |
| 141 | + async def run( |
| 142 | + self, |
| 143 | + dispatcher: CollectingDispatcher, |
| 144 | + tracker: Tracker, |
| 145 | + domain: Dict[Text, Any], |
| 146 | + ) -> List[EventType]: |
| 147 | + |
| 148 | + # the session should begin with a `session_started` event |
| 149 | + events = [SessionStarted()] |
| 150 | + |
| 151 | + # any slots that should be carried over should come after the |
| 152 | + # `session_started` event |
| 153 | + events.extend(self.fetch_slots(tracker)) |
| 154 | + |
| 155 | + # an `action_listen` should be added at the end as a user message follows |
| 156 | + events.append(ActionExecuted("action_listen")) |
| 157 | + |
| 158 | + return events |
| 159 | + |
| 160 | +.. note:: |
| 161 | + |
| 162 | + You need to explicitly add ``action_session_start`` to your domain to override this |
| 163 | + custom action. |
| 164 | + |
| 165 | +Events |
| 166 | +------ |
| 167 | + |
| 168 | +An action's ``run()`` method returns a list of events. For more information on |
| 169 | +the different types of events, see :ref:`Events`. There is an example of a ``SlotSet`` event |
| 170 | +:ref:`above <custom_action_example>`. The action itself will automatically be added to the |
| 171 | +tracker as an ``ActionExecuted`` event. If the action should not trigger any |
| 172 | +other events, it should return an empty list. |
| 173 | + |
| 174 | +Tracker |
| 175 | +------- |
| 176 | + |
| 177 | +The ``rasa_sdk.Tracker`` lets you access the bot's memory in your custom |
| 178 | +actions. You can get information about past events and the current state of the |
| 179 | +conversation through ``Tracker`` attributes and methods. |
| 180 | + |
| 181 | +The following are available as attributes of a ``Tracker`` object: |
| 182 | + |
| 183 | +- ``sender_id`` - The unique ID of person talking to the bot. |
| 184 | +- ``slots`` - The list of slots that can be filled as defined in the |
| 185 | + "ref"`domains`. |
| 186 | +- ``latest_message`` - A dictionary containing the attributes of the latest |
| 187 | + message: ``intent``, ``entities`` and ``text``. |
| 188 | +- ``events`` - A list of all previous events. |
| 189 | +- ``active_form`` - The name of the currently active form. |
| 190 | +- ``latest_action_name`` - The name of the last action the bot executed. |
| 191 | + |
| 192 | +The available methods from the ``Tracker`` are: |
| 193 | + |
| 194 | +.. automethod:: rasa_sdk.interfaces.Tracker.current_state |
| 195 | + |
| 196 | +.. automethod:: rasa_sdk.interfaces.Tracker.is_paused |
| 197 | + |
| 198 | +.. automethod:: rasa_sdk.interfaces.Tracker.get_latest_entity_values |
| 199 | + |
| 200 | +.. automethod:: rasa_sdk.interfaces.Tracker.get_latest_input_channel |
| 201 | + |
| 202 | +.. automethod:: rasa_sdk.interfaces.Tracker.events_after_latest_restart |
| 203 | + |
| 204 | +.. automethod:: rasa_sdk.interfaces.Tracker.get_slot |
0 commit comments