# Custom NLU Components

You can create a custom component to perform a specific task which NLU doesn’t currently offer (for example, sentiment analysis). Below is the specification of the [`rasa.nlu.components.Component`](https://legacy-docs-v1.rasa.com/1.9.1/api/custom-nlu-components/#rasa.nlu.components.Component "rasa.nlu.components.Component") class with the methods you’ll need to implement.

Note

There is a detailed tutorial on building custom components [here](https://blog.rasa.com/enhancing-rasa-nlu-with-custom-components/).

You can add a custom component to your pipeline by adding the module path. So if you have a module called `sentiment` containing a `SentimentAnalyzer` class:

```
pipeline:
- name: "sentiment.SentimentAnalyzer"
```

Also be sure to read the section on the [Component Lifecycle](https://legacy-docs-v1.rasa.com/1.9.1/nlu/choosing-a-pipeline/#component-lifecycle).

To get started, you can use this skeleton that contains the most important methods that you should implement:

|     |     |
| --- | --- |
| ```<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br>31<br>32<br>33<br>34<br>35<br>36<br>37<br>38<br>39<br>40<br>41<br>42<br>43<br>44<br>45<br>46<br>47<br>48<br>49<br>50<br>51<br>52<br>53<br>54<br>55<br>56<br>57<br>58<br>59<br>60<br>61<br>62<br>63<br>64<br>65<br>66<br>67<br>68<br>69<br>70<br>71<br>72<br>73<br>74<br>75<br>76<br>77<br>78<br>79<br>80<br>81<br>82<br>83<br>84<br>85<br>86<br>87<br>88<br>``` | ```<br>import typing<br>from typing import Any, Optional, Text, Dict, List, Type<br>from rasa.nlu.components import Component<br>from rasa.nlu.config import RasaNLUModelConfig<br>from rasa.nlu.training_data import Message, TrainingData<br>if typing.TYPE_CHECKING:<br>    from rasa.nlu.model import Metadata<br>class MyComponent(Component):<br>    """A new component"""<br>    # Which components are required by this component.<br>    # Listed components should appear before the component itself in the pipeline.<br>    @classmethod<br>    def required_components(cls) -> List[Type[Component]]:<br>        """Specify which components need to be present in the pipeline."""<br>        return []<br>    # Defines the default configuration parameters of a component<br>    # these values can be overwritten in the pipeline configuration<br>    # of the model. The component should choose sensible defaults<br>    # and should be able to create reasonable results with the defaults.<br>    defaults = {}<br>    # Defines what language(s) this component can handle.<br>    # This attribute is designed for instance method: `can_handle_language`.<br>    # Default value is None which means it can handle all languages.<br>    # This is an important feature for backwards compatibility of components.<br>    language_list = None<br>    def __init__(self, component_config: Optional[Dict[Text, Any]] = None) -> None:<br>        super().__init__(component_config)<br>    def train(<br>        self,<br>        training_data: TrainingData,<br>        config: Optional[RasaNLUModelConfig] = None,<br>        **kwargs: Any,<br>    ) -> None:<br>        """Train this component.<br>        This is the components chance to train itself provided<br>        with the training data. The component can rely on<br>        any context attribute to be present, that gets created<br>        by a call to :meth:`components.Component.pipeline_init`<br>        of ANY component and<br>        on any context attributes created by a call to<br>        :meth:`components.Component.train`<br>        of components previous to this one."""<br>        pass<br>    def process(self, message: Message, **kwargs: Any) -> None:<br>        """Process an incoming message.<br>        This is the components chance to process an incoming<br>        message. The component can rely on<br>        any context attribute to be present, that gets created<br>        by a call to :meth:`components.Component.pipeline_init`<br>        of ANY component and<br>        on any context attributes created by a call to<br>        :meth:`components.Component.process`<br>        of components previous to this one."""<br>        pass<br>    def persist(self, file_name: Text, model_dir: Text) -> Optional[Dict[Text, Any]]:<br>        """Persist this component to disk for future loading."""<br>        pass<br>    @classmethod<br>    def load(<br>        cls,<br>        meta: Dict[Text, Any],<br>        model_dir: Optional[Text] = None,<br>        model_metadata: Optional["Metadata"] = None,<br>        cached_component: Optional["Component"] = None,<br>        **kwargs: Any,<br>    ) -> "Component":<br>        """Load this component from file."""<br>        if cached_component:<br>            return cached_component<br>        else:<br>            return cls(meta)<br>``` |

Note

If you create a custom tokenizer you should implement the methods of `rasa.nlu.tokenizers.tokenizer.Tokenizer`. The `train` and `process` methods are already implemented and you simply need to overwrite the `tokenize` method. `train` and `process` will automatically add a special token `__CLS__` to the end of list of tokens, which is needed further down the pipeline.

Note

If you create a custom featurizer you should return a sequence of features. E.g. your featurizer should return a matrix of size (number-of-tokens x feature-dimension). The feature vector of the `__CLS__` token should contain features for the complete message.
