---
id: migration-guide
sidebar_label: Version Migration Guide
title: Version Migration Guide
description: |
  Information about changes between major versions of chatbot framework Rasa Core
  and how you can migrate from one version to another.
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

This page contains information about changes between major versions and
how you can migrate from one version to another.


## Rasa 3.0 to 3.1

### Machine Learning Components

#### TensorFlow Upgrade

Due to the TensorFlow upgrade, we can't guarantee the exact same output and hence
model performance if your configuration uses `LanguageModelFeaturizer`.
This applies to the case where the model is re-trained with the new Rasa
version without changing the configuration, random seeds, and data as well as to the
case where a model trained with a previous version of Rasa is loaded with
this new version for inference.

Please check whether your trained model still performs as expected and retrain if needed.

### NLU JSON Format

[NLU training data](nlu-training-data.mdx) in JSON format is deprecated and will be
removed in Rasa 4.0.
Please use `rasa data convert nlu -f yaml --data <path to NLU data>` to convert your
NLU JSON data to YAML format before support for NLU JSON data is removed.

## Rasa 2.x to 3.0

### Markdown Data

Markdown is no longer supported — all the supporting code that was previously deprecated is
now removed, and the convertors are removed as well.

The related CLI commands `rasa data convert responses` and `rasa data convert config`
were removed.

If you still have training data in Markdown format then the recommended approach is to use Rasa 2.x
to convert your data from Markdown to YAML. Please use the commands described
[here](./migration-guide.mdx#training-data-files).

### Model Configuration

It is required to specify the used `recipe` within the
[model configuration](model-configuration.mdx). As of now Rasa only supports
the `default.v1` recipe and will continue using it even if you don't specify a recipe
in the model configuration. To avoid breaking changes in the future you should
to specify `recipe: "default.v1"` at the top of your model configuration:

<Tabs values={[{"label": "Rasa 2.0 (old)", "value": "old"}, {"label": "Rasa 3.0 (new)", "value": "new"}]}  groupId="3-0-config" defaultValue="new">
  <TabItem value="old">

  ```yaml-rasa
  language: en

  pipeline:
    ...
  policies:
    ...
  ```
  </TabItem>
  <TabItem value="new">

  ```yaml-rasa {1}
  recipe: default.v1

  language: en

  pipeline:
    ...
  policies:
    ...
  ```
  </TabItem>
</Tabs>

### Custom Policies and Custom Components

Rasa 3.0 changed the way [NLU components](components.mdx) and
[policies](policies.mdx) are trained and run during inference. As part of these changes
the interfaces for NLU components and policies have been unified and adapted.

The next sections outline which adaptions are required to run your custom NLU components
and policies with Rasa 3.0.

:::caution

Please read the updated guide on custom graph components [here](custom-graph-components.mdx) before
continuing to follow the step-by-step guide to migrate your own custom graph components.
:::

**Type Annotations**

Until Rasa 3.0 [type annotations](https://docs.python.org/3/library/typing.html)
were not required in custom policies or custom NLU components.
It is now required to use
[type annotations](https://docs.python.org/3/library/typing.html) in custom NLU
components and policies. Rasa uses these type annotations to validate that
your graph components are compatible and correctly configured. As outlined in the custom
[components guide](custom-graph-components.mdx) it is not allowed to use
[forward references](https://www.python.org/dev/peps/pep-0484/#forward-references).

:::info Forward References with Python 3.7
Use the
[`from __future__ import annotations`](https://www.python.org/dev/peps/pep-0563/#enabling-the-future-behavior-in-python-3-7)
import to avoid using forward references with Python 3.7.
:::


<Tabs values={[{"label": "Rasa 2.0 (old)", "value": "old"}, {"label": "Rasa 3.0 (new)", "value": "new"}]}  groupId="3-0-type-annotations" defaultValue="new">
  <TabItem value="old">

  ```python
  from typing import List, Any
  from rasa.core.policies.policy import Policy

  class MyPolicy(Policy):
      def train(
          self,
          training_trackers: List["TrackerWithCachedStates"],
          domain,
          **kwargs: Any,
      ):
          ...
  ```

  </TabItem>
  <TabItem value="new">

  ```python
  from __future__ import annotations
  from typing import List, Any

  from rasa.core.policies.policy import Policy
  from rasa.engine.storage.resource import Resource
  from rasa.shared.core.domain import Domain
  from rasa.shared.core.generator import TrackerWithCachedStates

  class MyPolicy(Policy):
      def train(
          self,
          training_trackers: List[TrackerWithCachedStates],
          domain: Domain,
          **kwargs: Any,
      ) -> Resource:
          ...
  ```

  </TabItem>
</Tabs>

#### Changes to Custom NLU Components

**Inheriting from `GraphComponent`**

NLU components which previously inherited from one of the following classes additionally
need to inherit from the
[`GraphComponent` interface](custom-graph-components.mdx#the-graphcomponent-interface):
- `SparseFeaturizer`
- `DenseFeaturizer`
- `IntentClassifier`
- `EntityExtractor`
- `Component`

This snippet shows the required changes:

<Tabs values={[{"label": "Rasa 2.0 (old)", "value": "old"}, {"label": "Rasa 3.0 (new)", "value": "new"}]}  groupId="3-0-nlu-parent-class" defaultValue="new">
  <TabItem value="old">

  ```python
  from rasa.nlu.featurizers.sparse_featurizer.sparse_featurizer import SparseFeaturizer

  class MyNLUComponent(SparseFeaturizer):
      ...
  ```

  </TabItem>
  <TabItem value="new">

  ```python {3}
  from rasa.engine.graph import GraphComponent
  from rasa.nlu.featurizers.sparse_featurizer.sparse_featurizer import SparseFeaturizer

  class MyNLUComponent(GraphComponent, SparseFeaturizer):
      ...
  ```

  </TabItem>
</Tabs>

** Inheriting from `EntityExtractorMixin` instead of `EntityExtractor`**

The `EntityExtractor` class was renamed to `EntityExtractorMixin`:

<Tabs values={[{"label": "Rasa 2.0 (old)", "value": "old"}, {"label": "Rasa 3.0 (new)", "value": "new"}]}  groupId="3-0-nlu-entity-extractor" defaultValue="new">
  <TabItem value="old">

  ```python
  from rasa.nlu.extractors.extractor import EntityExtractor

  class MyNLUComponent(EntityExtractor):
      ...
  ```

  </TabItem>
  <TabItem value="new">

  ```python {2,4}
  from rasa.engine.graph import GraphComponent
  from rasa.nlu.extractors.extractor import EntityExtractorMixin

  class MyNLUComponent(GraphComponent, EntityExtractorMixin):
      ...
  ```

  </TabItem>
</Tabs>


**Instantiating a NLU Component for Training**

NLU components are no longer instantiated via their constructor. Instead, all NLU
components have to override the `create` method of the
[`GraphComponent` interface](custom-graph-components.mdx#the-graphcomponent-interface). The
passed in configuration is your NLU component's default configuration including any updates
from your model configuration file.


<Tabs values={[{"label": "Rasa 2.0 (old)", "value": "old"}, {"label": "Rasa 3.0 (new)", "value": "new"}]}  groupId="3-0-nlu-init" defaultValue="new">
  <TabItem value="old">

  ```python
  from typing import Optional, Dict, Text, Any
  from rasa.nlu.classifiers.classifier import IntentClassifier

  class MyNLUComponent(IntentClassifier):

    def __init__(self, component_config: Optional[Dict[Text, Any]] = None) -> None:
        super().__init__(component_config)
        ...
  ```

  </TabItem>
  <TabItem value="new">

  ```python
  from typing import Dict, Text, Any

  from rasa.engine.graph import GraphComponent, ExecutionContext
  from rasa.engine.storage.resource import Resource
  from rasa.engine.storage.storage import ModelStorage
  from rasa.nlu.classifiers.classifier import IntentClassifier

  class MyNLUComponent(GraphComponent, IntentClassifier):

    def __init__(self, component_config: Dict[Text, Any]) -> None:
        self.component_config = component_config
      ...

    @classmethod
    def create(
        cls,
        config: Dict[Text, Any],
        model_storage: ModelStorage,
        resource: Resource,
        execution_context: ExecutionContext,
    ) -> GraphComponent:
        return cls(config)
  ```

  </TabItem>
</Tabs>

**Persisting a Trained NLU Component**

NLU components used to be persisted by a call to the NLU component's `persist` method
from outside the NLU component itself.
With Rasa 3.0 NLU components are responsible for persisting themselves.
Use the provided `model_storage` and `resource` parameters
to persist your NLU component at the end of the training and then return the `resource`
as result of your NLU component's `train` method.
See [component persistence](custom-graph-components.mdx#model-persistence) for more details.

<Tabs values={[{"label": "Rasa 2.0 (old)", "value": "old"}, {"label": "Rasa 3.0 (new)", "value": "new"}]}  groupId="3-0-nlu-persistence" defaultValue="new">
  <TabItem value="old">

  ```python
  from pathlib import Path
  from typing import Optional, Any, Text, Dict

  from rasa.nlu.classifiers.classifier import IntentClassifier
  from rasa.nlu.config import RasaNLUModelConfig
  from rasa.shared.nlu.training_data.training_data import TrainingData

  class MyNLUComponent(IntentClassifier):
      def train(
          self,
          training_data: TrainingData,
          config: Optional[RasaNLUModelConfig] = None,
          **kwargs: Any,
      ) -> None:
          ...

      def persist(self, file_name: Text, model_dir: Text) -> Dict[Text, Any]:
          file_path = Path(model_dir) / "{file_name}.model_data.json"
          rasa.shared.utils.io.create_directory_for_file(file_path)
          rasa.shared.utils.io.dump_obj_as_json_to_file(file_path,
              self.get_model_data())

          return {"file": file_name}
      ...
  ```

  </TabItem>
  <TabItem value="new">

  ```python
  from rasa.engine.graph import GraphComponent
  from rasa.engine.storage.resource import Resource
  from rasa.nlu.classifiers.classifier import IntentClassifier
  from rasa.shared.nlu.training_data.training_data import TrainingData

  class MyNLUComponent(GraphComponent, IntentClassifier):
      def train(self, training_data: TrainingData) -> Resource:
          ...
          self.persist()
          return self._resource

      def persist(self) -> None:
          with self._model_storage.write_to(self._resource) as directory:
              model_data_file = directory / "model_data.json"
              rasa.shared.utils.io.dump_obj_as_json_to_file(model_data_file,
                  self.get_model_data())
      ...
  ```

  </TabItem>
</Tabs>


**Instantiating a Trained NLU Component**

Previously NLU components had to persist their own configuration. Now the config passed
into `load` will automatically contain the configuration which your model was trained with.
To instantiate a persisted NLU component, you need to use `model_storage` and `resource` in your NLU component's
`load` method.


<Tabs values={[{"label": "Rasa 2.0 (old)", "value": "old"}, {"label": "Rasa 3.0 (new)", "value": "new"}]}  groupId="3-0-nlu-loading" defaultValue="new">
  <TabItem value="old">

  ```python
  import json
  from pathlib import Path
  from typing import Text, Dict, Any, Optional

  from rasa.nlu.classifiers.classifier import IntentClassifier
  from rasa.nlu.model import Metadata

  class MyNLUComponent(IntentClassifier):
      @classmethod
      def load(
          cls,
          meta: Dict[Text, Any],
          model_dir: Text,
          model_metadata: Metadata = None,
          cached_component: Optional["DIETClassifier"] = None,
          should_finetune: bool = False,
          **kwargs: Any,
      ) -> "MyNLUComponent":
          file_name = meta.get("file")
          file_path = Path(model_dir) / "{file_name}.model_data.json"
          model_data = json.loads(rasa.shared.utils.io.read_file(file_path))

          return cls(model_data)
      ...
  ```

  </TabItem>
  <TabItem value="new">

  ```python
  from __future__ import annotations
  import json
  from typing import Any, Text, Dict

  from rasa.engine.graph import GraphComponent, ExecutionContext
  from rasa.engine.storage.resource import Resource
  from rasa.engine.storage.storage import ModelStorage
  from rasa.nlu.classifiers.classifier import IntentClassifier
  from rasa.shared.exceptions import FileIOException

  class MyNLUComponent(GraphComponent, IntentClassifier):
      @classmethod
      def load(
          cls,
          config: Dict[Text, Any],
          model_storage: ModelStorage,
          resource: Resource,
          execution_context: ExecutionContext,
          **kwargs: Any,
      ) -> MyNLUComponent:
          model_data = {}

          try:
              with model_storage.read_from(resource) as path:

                  model_data_file = path / "model_data.json"
                  model_data = json.loads(rasa.shared.utils.io.read_file(model_data_file))

          except (ValueError, FileNotFoundError, FileIOException):
              logger.debug(
                  f"Couldn't load metadata for component '{cls.__name__}' as the persisted "
                  f"model data couldn't be loaded."
              )

          return cls(
              config, model_data=model_data
          )
  ```
  </TabItem>
</Tabs>

**Providing a Default Configuration for an NLU Component**

The default configuration is no longer a static class property but instead returned
by the static method `get_default_config`:

<Tabs values={[{"label": "Rasa 2.0 (old)", "value": "old"}, {"label": "Rasa 3.0 (new)", "value": "new"}]}  groupId="3-0-nlu-default-config" defaultValue="new">
  <TabItem value="old">

  ```python
  from rasa.nlu.classifiers.classifier import IntentClassifier

  class MyNLUComponent(IntentClassifier):
      ...
      defaults = {"key1": "value1"}
  ```

  </TabItem>
  <TabItem value="new">

  ```python
  from typing import Text, Any, Dict

  from rasa.engine.graph import GraphComponent
  from rasa.nlu.classifiers.classifier import IntentClassifier

  class MyNLUComponent(GraphComponent, IntentClassifier):
      ...
      @staticmethod
      def get_default_config() -> Dict[Text, Any]:
          return {"key1": "value1"}

  ```

  </TabItem>
</Tabs>

**Augmenting Training Data in an NLU Component**

NLU Components like [tokenizers](components.mdx#tokenizers) or
[featurizers](components.mdx#featurizers) augment the training data with their
output during the model training. Their output is required by NLU components later in the
pipeline. Typically, featurizers require *tokenized* messages and intent
classifiers require *featurized* training data to train themselves. Rasa
3.0 makes these different purposes explicit. Previously both NLU component training and
training data augmentation were done as part of the `train` method. In Rasa
3.0 they are split into `train` and `process_training_data`:

<Tabs values={[{"label": "Rasa 2.0 (old)", "value": "old"}, {"label": "Rasa 3.0 (new)", "value": "new"}]}  groupId="3-0-component-train-process-split" defaultValue="new">
  <TabItem value="old">

  ```python
  from typing import Optional, Any

  from rasa.nlu.featurizers.sparse_featurizer.sparse_featurizer import SparseFeaturizer
  from rasa.nlu.config import RasaNLUModelConfig
  from rasa.shared.nlu.training_data.training_data import TrainingData

  class MyNLUComponent(SparseFeaturizer):
      def train(
          self,
          training_data: TrainingData,
          config: Optional[RasaNLUModelConfig] = None,
          **kwargs: Any,
      ) -> None:
          self.train_featurizer(training_data)

          for message in training_data.training_examples:
              self.add_features(message)
  ```

  </TabItem>
  <TabItem value="new">

  ```python
  from rasa.engine.graph import GraphComponent
  from rasa.engine.storage.resource import Resource
  from rasa.nlu.featurizers.sparse_featurizer.sparse_featurizer import SparseFeaturizer
  from rasa.shared.nlu.training_data.training_data import TrainingData

  class MyNLUComponent(GraphComponent, SparseFeaturizer):
      def train(self, training_data: TrainingData) -> Resource:
          self.train_featurizer(training_data)

          self.persist()
          return self._resource

      def process_training_data(self, training_data: TrainingData) -> TrainingData:
          for message in training_data.training_examples:
              self.add_features(message)

          return training_data
  ```
  </TabItem>
</Tabs>

**Handling Lists of Messages During Inference in an NLU Component**

NLU components used to receive a single `Message` object during inference.
Starting with Rasa 3.0 all NLU components have to support a list of
messages during inference. Unless your component supports batch predictions the easiest
way to handle this is to loop over the messages. It is also required to return the
message objects at the end of the `process` method.

<Tabs values={[{"label": "Rasa 2.0 (old)", "value": "old"}, {"label": "Rasa 3.0 (new)", "value": "new"}]}  groupId="3-0-component-process-messages-split" defaultValue="new">
  <TabItem value="old">

  ```python
  from typing import Any

  from rasa.nlu.classifiers.classifier import IntentClassifier
  from rasa.shared.nlu.training_data.message import Message

  class MyNLUComponent(IntentClassifier):
      def process(self, message: Message, **kwargs: Any) -> None:
        self.predict(message)
  ```

  </TabItem>
  <TabItem value="new">

  ```python
  from typing import List

  from rasa.engine.graph import GraphComponent
  from rasa.nlu.classifiers.classifier import IntentClassifier
  from rasa.shared.nlu.training_data.message import Message

  class MyNLUComponent(GraphComponent, IntentClassifier):
      def process(self, messages: List[Message]) -> List[Message]:
          for message in messages:
              self.predict(message)

          return messages
  ```
  </TabItem>
</Tabs>


**Registering your NLU Component**

Before you can use your custom NLU component you have to register your NLU component using the
`DefaultV1Recipe.register` decorator. The NLU component types correspond to the existing
parent classes:

* `Tokenizer`: `ComponentType.MESSAGE_TOKENIZER`
* `SparseFeaturizer` / `DenseFeaturizer`: `ComponentType.MESSAGE_FEATURIZER`
* `IntentClassifier`: `ComponentType.INTENT_CLASSIFIER`
* `EntityExtractor`: `ComponentType.ENTITY_EXTRACTOR`
* If your NLU component provides a pretrained model which should be used by other
  NLU components during training and inference use `ComponentType.MODEL_LOADER`

Specify `is_trainable=True` if the `train` method of your component should be called
during training.


<Tabs values={[{"label": "Rasa 2.0 (old)", "value": "old"}, {"label": "Rasa 3.0 (new)", "value": "new"}]}  groupId="3-0-nlu-register" defaultValue="new">
  <TabItem value="old">

  ```python
  from rasa.nlu.classifiers.classifier import IntentClassifier

  class MyNLUComponent(IntentClassifier):
      ...
  ```

  </TabItem>
  <TabItem value="new">

  ```python {5-7}
  from rasa.engine.recipes.default_recipe import DefaultV1Recipe
  from rasa.nlu.classifiers.classifier import IntentClassifier
  from rasa.engine.graph import GraphComponent

  @DefaultV1Recipe.register(
      DefaultV1Recipe.ComponentType.INTENT_CLASSIFIER, is_trainable=True
  )
  class MyNLUComponent(GraphComponent, IntentClassifier):
      ...
  ```

  </TabItem>
</Tabs>

**Using a Model Provider with your NLU Component**

If your NLU component requires a pretrained model such as a [Spacy](components.mdx#spacynlp) or
[Mitie](components.mdx#mitienlp) language model you have to specify the NLU component which
provides this model in your model's pipeline before the NLU component which requires
the model. In addition to this you now also need to specify the model loading component in the `model_from`
parameter in the `register` decorator. The model will then be passed to your model's
`train`, `process_training_data` and `process` methods:

<Tabs values={[{"label": "Rasa 2.0 (old)", "value": "old"}, {"label": "Rasa 3.0 (new)", "value": "new"}]}  groupId="3-0-nlu-model-provider" defaultValue="new">
  <TabItem value="old">

  ```python
  from typing import Optional, Any

  from rasa.nlu.config import RasaNLUModelConfig
  from rasa.nlu.classifiers.classifier import IntentClassifier
  from rasa.shared.nlu.training_data.message import Message
  from rasa.shared.nlu.training_data.training_data import TrainingData

  class MyNLUComponent(IntentClassifier):
      def train(
          self,
          training_data: TrainingData,
          cfg: Optional[RasaNLUModelConfig] = None,
          **kwargs: Any,
      ) -> None:
          """Train the featurizer."""
          spacy_nlp = kwargs.get("spacy_nlp")
          ...

      def process(self, message: Message, **kwargs: Any) -> None:
          spacy_nlp = kwargs.get("spacy_nlp", None)
          ...
  ```

  </TabItem>
  <TabItem value="new">

  ```python
  from typing import List

  from rasa.engine.graph import GraphComponent
  from rasa.engine.recipes.default_recipe import DefaultV1Recipe
  from rasa.engine.storage.resource import Resource
  from rasa.nlu.classifiers.classifier import IntentClassifier
  from rasa.nlu.utils.spacy_utils import SpacyModel
  from rasa.shared.nlu.training_data.message import Message
  from rasa.shared.nlu.training_data.training_data import TrainingData

  @DefaultV1Recipe.register(
      DefaultV1Recipe.ComponentType.INTENT_CLASSIFIER, is_trainable=True, model_from="SpacyNLP"
  )
  class MyNLUComponent(GraphComponent, IntentClassifier):
      def train(
          self, training_data: TrainingData, model: SpacyModel) -> Resource:
          spacy_nlp = model.model
          ...

      def process(self, messages: List[Message], model: SpacyModel) -> List[Message]:
          spacy_nlp = model.model
          ...
  ```

  </TabItem>
</Tabs>

#### Changes to Custom Policies
This guide leads you through the migration of a custom policy step by step.

**Instantiating a Policy for Training**

Policies are no longer instantiated via their constructor. Instead, all policies have
to implement a `create` method. During the policy instantiation the configuration from
the [model configuration](model-configuration.mdx) is passed in as a dictionary instead
of as separate parameters. Similarly, the`featurizers` are no longer instantiated
outside of policies.
Instead, the super class `rasa.core.policies.policy.Policy` instantiates the
featurizers itself.

<Tabs values={[{"label": "Rasa 2.0 (old)", "value": "old"}, {"label": "Rasa 3.0 (new)", "value": "new"}]}  groupId="3-0-policy-init" defaultValue="new">
  <TabItem value="old">

  ```python
  from typing import Optional, Any

  from rasa.core.constants import DEFAULT_POLICY_PRIORITY
  from rasa.core.featurizers.tracker_featurizers import TrackerFeaturizer
  from rasa.core.policies.policy import Policy

  class MyPolicy(Policy):
      def __init__(
          self,
          featurizer: Optional[TrackerFeaturizer] = None,
          priority: int = DEFAULT_POLICY_PRIORITY,
          max_history: Optional[int] = None,
          **kwargs: Any
      ) -> None:
          super().__init__(featurizer, priority, **kwargs)
          ...
  ```

  </TabItem>
  <TabItem value="new">

  ```python
  from typing import Optional, Dict, Text, Any

  from rasa.core.featurizers.tracker_featurizers import TrackerFeaturizer
  from rasa.core.policies.policy import Policy
  from rasa.engine.graph import ExecutionContext
  from rasa.engine.storage.resource import Resource
  from rasa.engine.storage.storage import ModelStorage

  class MyPolicy(Policy):
      def __init__(
          self,
          config: Dict[Text, Any],
          model_storage: ModelStorage,
          resource: Resource,
          execution_context: ExecutionContext,
          featurizer: Optional[TrackerFeaturizer] = None,
      ) -> None:
          super().__init__(
            config, model_storage, resource, execution_context, featurizer
          )
          ...
      ...

    @classmethod
    def create(
        cls,
        config: Dict[Text, Any],
        model_storage: ModelStorage,
        resource: Resource,
        execution_context: ExecutionContext,
    ) -> MyPolicy:
        return cls(config, model_storage, resource, execution_context)

  ```

  </TabItem>
</Tabs>

**Persisting a Trained Policy**

Policies used to be persisted by a call to the policy's `persist` method from outside the policy itself.
With Rasa 3.0 policies are responsible for persisting themselves.
Use the provided `model_storage` and `resource` parameters
to persist your graph component at the end of the training and then return the `resource`
as result of your policy's `train` method. See [graph component persistence](custom-graph-components.mdx#model-persistence) for more details.

<Tabs values={[{"label": "Rasa 2.0 (old)", "value": "old"}, {"label": "Rasa 3.0 (new)", "value": "new"}]}  groupId="3-0-policy-persistence" defaultValue="new">
  <TabItem value="old">

  ```python
  from pathlib import Path
  from typing import List, Any, Union, Text

  from rasa.core.policies.policy import Policy
  from rasa.shared.core.domain import Domain
  from rasa.shared.core.generator import TrackerWithCachedStates
  from rasa.shared.nlu.interpreter import NaturalLanguageInterpreter

  class MyPolicy(Policy):
      def train(
          self,
          training_trackers: List[TrackerWithCachedStates],
          domain: Domain,
          interpreter: NaturalLanguageInterpreter,
          **kwargs: Any,
      ) -> None:
          ...

      def persist(self, path: Union[Text, Path]) -> None:
          if self.featurizer is not None:
              self.featurizer.persist(path)

          file_path = Path(path) / "model_data.json"
          rasa.shared.utils.io.create_directory_for_file(file_path)
          rasa.shared.utils.io.dump_obj_as_json_to_file(file_path,
              self.get_model_data())
      ...
  ```

  </TabItem>
  <TabItem value="new">

  ```python
  from typing import List, Any

  from rasa.core.policies.policy import Policy
  from rasa.engine.storage.resource import Resource
  from rasa.shared.core.domain import Domain
  from rasa.shared.core.generator import TrackerWithCachedStates

  class MyPolicy(Policy):
      def train(
          self,
          training_trackers: List[TrackerWithCachedStates],
          domain: Domain,
          **kwargs: Any,
      ) -> Resource:
          ...
          self.persist()
          return self._resource

      def persist(self) -> None:
          with self._model_storage.write_to(self._resource) as directory:
              if self.featurizer is not None:
                  self.featurizer.persist(directory)

              file_path = directory / "model_data.json"
              rasa.shared.utils.io.dump_obj_as_json_to_file(file_path,
                  self.get_model_data())
      ...
  ```

  </TabItem>
</Tabs>

**Instantiating a Trained Policy**

Previously policies had to persist their own configuration. Now the config passed
into `load` will automatically contain the configuration which your model was trained with.

To instantiate a persisted policy, you need to use `model_storage` and `resource` in your policy's
`load` method.

<Tabs values={[{"label": "Rasa 2.0 (old)", "value": "old"}, {"label": "Rasa 3.0 (new)", "value": "new"}]}  groupId="3-0-policy-loading" defaultValue="new">
  <TabItem value="old">

  ```python
  import json
  from pathlib import Path
  from types import Union
  from typing import Text, Any

  from rasa.core.policies.policy import Policy

  class MyPolicy(Policy):
      @classmethod
      def load(cls, path: Union[Text, Path], **kwargs: Any) -> "Policy":
          featurizer = None
          if (Path(path) / FEATURIZER_FILE).is_file():
              featurizer = TrackerFeaturizer.load(path)

          model_data = {}
          model_data_file = Path(path) / "model_data.json"
          if metadata_file.is_file():
              model_data = json.loads(rasa.shared.utils.io.read_file(model_data_file))

          return cls(model_data, featurizer)
      ...
  ```

  </TabItem>
  <TabItem value="new">

  ```python
  import json
  from typing import Dict, Text, Any

  from rasa.core.featurizers.tracker_featurizers import TrackerFeaturizer
  from rasa.core.policies.policy import Policy
  from rasa.engine.graph import ExecutionContext
  from rasa.engine.storage.resource import Resource
  from rasa.engine.storage.storage import ModelStorage
  from rasa.shared.exceptions import FileIOException

  class MyPolicy(Policy):
      @classmethod
      def load(
          cls,
          config: Dict[Text, Any],
          model_storage: ModelStorage,
          resource: Resource,
          execution_context: ExecutionContext,
          **kwargs: Any,
      ) -> MyPolicy:
          featurizer = None
          model_data = {}

          try:
              with model_storage.read_from(resource) as path:
                  if (Path(path) / FEATURIZER_FILE).is_file():
                      featurizer = TrackerFeaturizer.load(path)

                  model_data_file = path / "model_data.json"
                  model_data = json.loads(rasa.shared.utils.io.read_file(model_data_file))

          except (ValueError, FileNotFoundError, FileIOException):
              logger.debug(
                  f"Couldn't load metadata for policy '{cls.__name__}' as the persisted "
                  f"metadata couldn't be loaded."
              )

          return cls(
              config, model_storage, resource, execution_context,
              featurizer=featurizer, model_data=model_data
          )
  ```

  </TabItem>
</Tabs>

**Providing a Default Configuration for a Policy**

The default configuration is no longer provided via default values in your policy's
constructor but instead returned by the static method `get_default_config`:

<Tabs values={[{"label": "Rasa 2.0 (old)", "value": "old"}, {"label": "Rasa 3.0 (new)", "value": "new"}]}  groupId="3-0-policy-default-config" defaultValue="new">
  <TabItem value="old">

  ```python
  from typing import Text
  from rasa.core.policies.policy import Policy

  class MyPolicy(Policy):

      def __init__(key1: Text = "value1") -> None:
          ...
  ```

  </TabItem>
  <TabItem value="new">

  ```python
  from typing import Dict, Text, Any
  from rasa.core.policies.policy import Policy

  class MyPolicy(Policy):

      def __init__(self, config: Dict[Text, Any]) -> None:
          ...

      @staticmethod
      def get_default_config() -> Dict[Text, Any]:
          return {"key1": "value1"}
  ```

  </TabItem>
</Tabs>

**Using End-To-End Features in a Policy**

To use a custom [end-to-end policy](stories.mdx#end-to-end-training) in Rasa
Open Source 2, you had to use the `interpreter` parameter to featurize the tracker
events manually. In Rasa 3.0,
you need to [register](custom-graph-components.mdx#registering-graph-components-with-the-model-configuration) a policy that requires end-to-end features with type `ComponentType.POLICY_WITH_END_TO_END_SUPPORT`. The features
will be precomputed and passed into your policy during training and inference.

:::caution
End-To-End features will only be computed and provided to your policy if your training
data actually contains [end-to-end training data](stories.mdx#end-to-end-training).
:::

<Tabs values={[{"label": "Rasa 2.0 (old)", "value": "old"}, {"label": "Rasa 3.0 (new)", "value": "new"}]}  groupId="3-0-policy-end-to-end-features" defaultValue="new">
  <TabItem value="old">

  ```python
  from typing import List, Any

  from rasa.core.policies.policy import Policy, PolicyPrediction
  from rasa.shared.core.domain import Domain
  from rasa.shared.core.generator import TrackerWithCachedStates
  from rasa.shared.core.trackers import DialogueStateTracker
  from rasa.shared.nlu.interpreter import NaturalLanguageInterpreter

  class MyPolicy(Policy):
      def train(
          self,
          training_trackers: List[TrackerWithCachedStates],
          domain: Domain,
          interpreter: NaturalLanguageInterpreter,
          **kwargs: Any,
      ) -> None:
          ...
          model_data, label_ids = self._prepare_for_training(
              training_trackers, domain, interpreter, **kwargs
          )
          ...

      def predict_action_probabilities(
          self,
          tracker: DialogueStateTracker,
          domain: Domain,
          interpreter: NaturalLanguageInterpreter,
          **kwargs: Any,
      ) -> PolicyPrediction:
          ...
          tracker_state_features = self._featurize_tracker_for_e2e(
              tracker, domain, interpreter
          )
          ...
  ```

  </TabItem>
  <TabItem value="new">

  ```python {12,19,23,31,37}
  from typing import List, Optional, Dict, Text, Any

  from rasa.core.featurizers.precomputation import MessageContainerForCoreFeaturization
  from rasa.core.policies.policy import PolicyPrediction, Policy
  from rasa.engine.recipes.default_recipe import DefaultV1Recipe
  from rasa.engine.storage.resource import Resource
  from rasa.shared.core.domain import Domain
  from rasa.shared.core.generator import TrackerWithCachedStates
  from rasa.shared.core.trackers import DialogueStateTracker

  @DefaultV1Recipe.register(
      DefaultV1Recipe.ComponentType.POLICY_WITH_END_TO_END_SUPPORT, is_trainable=True
  )
  class MyPolicy(Policy):
      def train(
          self,
          training_trackers: List[TrackerWithCachedStates],
          domain: Domain,
          precomputations: Optional[MessageContainerForCoreFeaturization] = None,
      ) -> Resource:
          ...
          model_data, label_ids = self._prepare_for_training(
            training_trackers, domain, precomputations,
          )
          ...

      def predict_action_probabilities(
          self,
          tracker: DialogueStateTracker,
          domain: Domain,
          precomputations: Optional[MessageContainerForCoreFeaturization] = None,
          rule_only_data: Optional[Dict[Text, Any]] = None,
          **kwargs: Any,
      ) -> PolicyPrediction:
          ...
          tracker_state_features = self._featurize_tracker(
              tracker, domain, precomputations, rule_only_data=rule_only_data
          )
          ...
  ```

  </TabItem>
</Tabs>

**Registering a Policy**

Before you can use your custom policy you have to register your policy using the
`DefaultV1Recipe.register` decorator. If your policy requires end-to-end features
specify the graph component type `POLICY_WITH_END_TO_END_SUPPORT`. Otherwise, use
`POLICY_WITHOUT_END_TO_END_SUPPORT`. Specify `is_trainable=True` if the `train`
method of your policy should be called during the training. If your policy is only
used during inference use `is_trainable=False`.


<Tabs values={[{"label": "Rasa 2.0 (old)", "value": "old"}, {"label": "Rasa 3.0 (new)", "value": "new"}]}  groupId="3-0-policy-register" defaultValue="new">
  <TabItem value="old">

  ```python
  from rasa.core.policies.policy import Policy

  class MyPolicy(Policy):
      ...
  ```

  </TabItem>
  <TabItem value="new">

  ```python {4-6}
  from rasa.core.policies.policy import Policy
  from rasa.engine.recipes.default_recipe import DefaultV1Recipe

  @DefaultV1Recipe.register(
      DefaultV1Recipe.ComponentType.POLICY_WITH_END_TO_END_SUPPORT,
      is_trainable=True
  )
  class MyPolicy(Policy):
      ...
  ```

  </TabItem>
</Tabs>

**Providing Rule-only Data to a Policy**

Rasa allows excluding [forms](forms.mdx) or [slots](domain.mdx#slots) which
are completely handled by
[rules](rules.mdx) from becoming features in other policies.
In Rasa 2 this information was passed onto the
policies using the `set_shared_policy_states` method which set the policy attribute
`_rule_only_data`. Rasa passes the names of rule-only slots and forms via the
`predict_action_probabilities` method. The passed `rule_only_data` can be `None`
in case the [`RulePolicy`](policies.mdx#rule-policy) is not part of your model
configuration.

<Tabs values={[{"label": "Rasa 2.0 (old)", "value": "old"}, {"label": "Rasa 3.0 (new)", "value": "new"}]}  groupId="3-0-policy-rule-only-data" defaultValue="new">
  <TabItem value="old">

  ```python
  from rasa.core.policies.policy import Policy
  from typing import Any

  class MyPolicy(Policy):

      def set_shared_policy_states(self, **kwargs: Any) -> None:
          """Sets policy's shared states for correct featurization."""
          self._rule_only_data = kwargs.get("rule_only_data", {})
  ```

  </TabItem>
  <TabItem value="new">

  ```python {12}
  from typing import Optional, Dict, Text, Any

  from rasa.core.policies.policy import Policy, PolicyPrediction
  from rasa.shared.core.domain import Domain
  from rasa.shared.core.trackers import DialogueStateTracker

  class MyPolicy(Policy):
      def predict_action_probabilities(
          self,
          tracker: DialogueStateTracker,
          domain: Domain,
          rule_only_data: Optional[Dict[Text, Any]] = None,
    ) -> PolicyPrediction:
        ...
  ```

  </TabItem>
</Tabs>

### Training data

#### Upgrading `version` from `2.0` to `3.0`

At the top of your training data files, you need to change `version: "2.0"` to `version: "3.1"`.

We follow semantic versioning for training data versions. This means breaking changes result in a new
major version, while new features result in a new minor version. The latest training data version is 3.1.

The improvements to `slot mappings` in Rasa 3.0 were breaking changes, so we needed to upgrade
from major version `2.0` to major version `3.0`.

#### `TrainingDataImporter`

`TrainingDataImporter` and all its implementations are updated to contain only synchronous methods.
If you have a custom data importer or rely on some functions provided by `TrainingDataImporter`, you need
to update your implementation and function calls.

For example, this is how data loading should look like in Rasa 3.0:

```python
from typing import Text
from rasa.shared.importers.importer import TrainingDataImporter

def load_data(domain_path: Text, config_path: Text):
    file_importer = TrainingDataImporter.load_from_config(
        config_path, domain_path
    )
    # note that all the functions below were async before:
    config = file_importer.get_config()
    domain = file_importer.get_domain()
    stories = file_importer.get_stories()
    nlu_data = file_importer.get_nlu_data()
```

Since any custom importer implements `TrainingDataImporter`, you should update your custom
importer to contain only sync methods as well:

```python
from typing import Dict

from rasa.shared.core.domain import Domain
from rasa.shared.importers.importer import TrainingDataImporter


class MyImporter(TrainingDataImporter):
    """Example partial implementation of a custom importer component."""

    # this function was async before
    def get_domain(self) -> Domain:
        pass

    # this function was also async before
    def get_config(self) -> Dict:
        pass

    # ...
```

`template_variables` and `e2e` arguments also got removed from `get_stories` method of `TrainingDataImporter`.
Its new signature looks this way:

```python
from typing import Optional

from rasa.shared.nlu.interpreter import RegexInterpreter
from rasa.shared.core.training_data.structures import StoryGraph

class TrainingDataImporter:
    # ...

    def get_stories(
        self,
        interpreter: "NaturalLanguageInterpreter" = RegexInterpreter(),
        exclusion_percentage: Optional[int] = None,
    ) -> StoryGraph:
        pass

    # ...
```

### Training

#### `rasa train --dry-run`
Due to changes in the model architecture the behavior of `rasa train --dry-run` changed.
The exit codes now have the following meaning:

* `0` means that the model does not require an expensive retraining. However, the
  responses might still require updating by running `rasa train`
* `1` means that one or multiple components require to be retrained.
* `8` means that the `--force` flag was used and hence any cached results are ignored
  and the entire model is retrained.

### Machine Learning Components

#### Normalization of Confidences in `DIETClassifier` and `ResponseSelector`

`DIETClassifier` and `ResponseSelector` will no longer automatically report
re-normalized confidences when `ranking_length` is set to a value greater than `0`.
This change affects the reported confidences but does not influence the final
predicted intent, which might be used by policies.
However, since the reported confidences are affected you might have to tune the
thresholds for fallback mechanisms again.
The previous behavior can still be enforced by setting `renormalize_confidences=True`
when using `model_confidence=softmax`.

#### Normalization of confidences in `TEDPolicy`

Predictions of `TEDPolicy` will no longer be modified by masking and renormalizing
confidences. This change can affect the maximum confidence predicted by the
`TEDPolicy` and thereby affect the final result of the policy ensemble.
However, the previous behavior can still be enforced by setting
`ranking_length=10` and `renormalize_confidences=True`.

#### Removed Policies

Several dialogue policies that were deprecated in Rasa 2.x have been removed in Rasa 3.0.
If you are migrating a config file with a removed policy,
consult the following migration guides for the individual policies:

- `FallbackPolicy` [migration guide](#manually-migrating-from-the-fallback-policy)
- `TwoStageFallbackPolicy` [migration guide](#manually-migrating-from-the-two-stage-fallback-policy)
- `MappingPolicy` [migration guide](#manually-migrating-from-the-mapping-policy)
- `FormPolicy` [migration guide](#forms)
- `SklearnPolicy` should be replaced with [TEDPolicy](/policies#ted-policy).
  It is recommended to use the [default TEDPolicy config](/model-configuration#suggested-config) as a starting point.

#### Removed Tokenizers and Featurizers

The `ConveRTTokenizer`, `LanguageModelTokenizer`, and `HFTransformersNLP` featurizer
components were deprecated in Rasa 2.x and have been removed in Rasa 3.0. See the
[migration guide for Rasa 2.x](#deprecations-2) for replacing these components in your pipeline.

### Slot Mappings

As of version 3.0, there is a single explicit mechanism for slot filling enabled by defining slot mappings for each slot
in the `slots` section of the domain file. This approach keeps slots up to date over the course of a conversation, and
removes duplicated effort in mapping the same slots in multiple forms. It is still possible to fill slots from arbitrary
custom actions and not update them on every turn of the conversation if that behavior is desired.

This new mechanism replaces the implicit slot setting via auto-fill of slots with entities of the same name.
The `auto_fill` key in the domain is no longer available, as well as the `auto_fill` parameter in the constructor of
the `Slot` class.

While forms continue to request the next slot, slot extraction is now delegated to the default
action [`action_extract_slots`](./default-actions.mdx#action_extract_slots). This action runs in the background
automatically after each user turn. Like `action_listen`, it should not be included in stories.

Each slot in the `slots` section must include the `mappings` key. The same keys used for predefined mappings in 2.0 are
available in 3.0. Additionally, you can define slots with custom mappings implemented in a custom action which will be
run on every user turn, for example:

```yaml
slots:
  is_existing_customer:
    type: bool
    mappings:
    - type: custom
      action: action_verify_customer_status
```

You can use [slot validation actions](./slot-validation-actions.mdx) to either validate slots with predefined
mappings, or to both extract and validate slots with custom mappings.

Slots which will be filled by arbitrary custom actions in the course of the conversation, and which should not be updated
on every user turn, should be listed with mappings of type `custom` and no action. For example:

```yaml
slots:
  handoff_completed:
    type: bool
    initial_value: false
    mappings:
    - type: custom
```

This slot's value will only change when a custom action is predicted that sets it. This mapping maintains the behavior
from 2.x for a slot which was not filled by an entity or by slot mappings in a form.

:::note
The `required_slots` of a form used to be a list of slot mappings.
Since slot mappings are relocated to the `slots` section of the domain, `required_slots` has been converted to a list of
slot names only.

:::

#### Automatic migration from 2.0 domain format to the 3.0 format

The only data file that has changed in format is the domain file.
To migrate automatically to the 3.0 domain format, you can run the following command:

```bash
rasa data migrate -d DOMAIN --out OUT_PATH
```

In addition to creating a valid 3.0 domain in the indicated out path, this command will automatically backup your
original domain file(s) in a file labeled `original_domain.yml` or `original_domain` directory if a directory was
provided instead.

To maintain the behavior of forms in the 2.0 format, all migrated slot mappings will include mapping conditions for
each form. This can be changed manually according to your use case.
See the docs on [mapping conditions](./domain.mdx#mapping-conditions) for more information.

#### Manually migrating from 2.0 domain format to the 3.0 format

Each slot in the `slots` section of the domain will need a new key `mappings`.
This key is a list of mappings moved from forms, while the `required_slots` field collapses to a list of slot names.

Let's consider the following 2.0 domain file:

```yaml
entities:
 - cuisine
 - number
slots:
   cuisine:
     type: text
   num_people:
     type: float
   outdoor_seating:
     type: bool
forms:
   restaurant_form:
     required_slots:
         cuisine:
           - type: from_entity
             entity: cuisine
         num_people:
           - type: from_entity
             entity: number
         outdoor_seating:
           - type: from_intent
             intent: affirm
             value: true
           - type: from_intent
             intent: deny
             value: false
```

The initial result of migrating this domain to 3.0 format would look like this:

```yaml
entities:
 - cuisine
 - number
slots:
   cuisine:
     type: text
     mappings:
     - type: from_entity
       entity: cuisine
   num_people:
     type: float
     mappings:
     - type: from_entity
       entity: number
   outdoor_seating:
     type: bool
     mappings:
     - type: from_intent
       intent: affirm
       value: true
     - type: from_intent
       intent: deny
       value: false
forms:
   restaurant_form:
     required_slots:
     - cuisine
     - num_people
     - outdoor_seating
```

For slots that should be filled only in the context of a form, add [mapping conditions](./domain.mdx#mapping-conditions)
to specify which form(s) should be active, as well as indicate if the `requested_slot` should be the same slot.
Adding `conditions` is required to preserve the behavior of slot mappings from 2.0, since without them
the mappings will be applied on each user turn regardless of whether a form is active or not.

```yaml
 slots:
   outdoor_seating:
     type: bool
     mappings:
     - type: from_intent
       intent: affirm
       value: true
       conditions:
       - active_loop: restaurant_form
         requested_slot: outdoor_seating
     - type: from_intent
       intent: deny
       value: false
       conditions:
       - active_loop: restaurant_form
         requested_slot: outdoor_seating
```

#### Rasa-SDK Modifications

If you have used `FormValidationAction` to define custom extraction and validation code in which you override the
`required_slots` method, note that `slots_mapped_in_domain` argument has been replaced by the `domain_slots` argument.
You must make this replacement to continue using your custom code.

If you have been dynamically filling slots not present in the form's `required_slots` defined in the `domain.yml`
file, note that this behaviour is no longer supported in 3.x. Any dynamic slots with custom mappings, which are set in
the last user turn, will be filled **only if** they are returned by the `required_slots` method of the custom action
inheriting from `FormValidationAction`. To maintain the 2.x behaviour, you must now override the `required_slots` method
of this custom action as per the strong recommendation listed in the [dynamic form documentation](./forms.mdx#dynamic-form-behavior).

To extract custom slots that are not defined in any form's `required_slots`, you should now use a global [custom slot mapping](./domain.mdx#custom-slot-mappings)
and extend the [ValidationAction class](./action-server/validation-action.mdx#validationaction-class).

:::note
If you have custom validation actions extending `FormValidationAction` which override `required_slots` method, you should
double-check the dynamic form behavior of your migrated assistant. Slots set by the default action
[`action_extract_slots`](./default-actions.mdx#action_extract_slots) may need to be reset within the context of your
form by the custom validation actions for the form's required slots. For example, if your form dynamically adds a required
slot after the first slot is filled, you may want to reset the potential required slot as part of the first required slot's
validation method to ensure it will be empty when added.

:::

## Rasa 2.7 to 2.8

:::caution
This release **breaks backward compatibility of machine learning models**.
It is not possible to load models trained with previous versions of Rasa. Please re-train
your assistant before using this version.

:::

### Deprecations

#### Tracker Featurizers

`training_states_actions_and_entities` method of `TrackerFeaturizer`, `FullDialogueTrackerFeaturizer` and
`MaxHistoryTrackerFeaturizer` classes is deprecated and will be removed in Rasa 3.0 .
If you had a custom tracker featurizer which relied on this method from any of the above classes, please use
`training_states_labels_and_entities` instead.

`training_states_and_actions` method of `TrackerFeaturizer`, `FullDialogueTrackerFeaturizer` and
`MaxHistoryTrackerFeaturizer` classes is deprecated and will be removed in Rasa 3.0 .
If you had a custom tracker featurizer which relied on this method from any of the above classes, please use
`training_states_and_labels` instead.

#### State Featurizer

`encode_all_actions` method of `SingleStateFeaturizer` class is deprecated and will be removed in Rasa 3.0 .
It is recommended to use the method `encode_all_labels` instead.


### Incremental Training

Users don't need to specify an additional buffer size for sparse featurizers anymore during incremental training.

Space for new sparse features are created dynamically inside the downstream machine learning
models - `DIETClassifier`, `ResponseSelector`. In other words, no extra buffer is created in
advance for additional vocabulary items and space will be dynamically allocated for them inside the model.

This means there's no need to specify `additional_vocabulary_size` for
[`CountVectorsFeaturizer`](./components.mdx#countvectorsfeaturizer) or
`number_additional_patterns` for [`RegexFeaturizer`](./components.mdx#regexfeaturizer).
These parameters are now deprecated.

**Before**
```yaml
pipeline:
  - name: "WhitespaceTokenizer"
  - name: "RegexFeaturizer"
    number_additional_patterns: 100
  - name: "CountVectorsFeaturizer"
    additional_vocabulary_size: {text: 100, response: 20}
```

**Now**
```yaml
pipeline:
  - name: "WhitespaceTokenizer"
  - name: "RegexFeaturizer"
  - name: "CountVectorsFeaturizer"
```

### Machine Learning Components

The option `model_confidence=linear_norm` is deprecated and will be removed in Rasa `3.0.0`.

Rasa `2.3.0` introduced `linear_norm` as a possible value for `model_confidence`
parameter in machine learning components such as `DIETClassifier`, `ResponseSelector` and `TEDPolicy`.
Based on user feedback, we have identified multiple problems with this option.
Therefore, `model_confidence=linear_norm` is now deprecated and
will be removed in Rasa `3.0.0`. If you were using `model_confidence=linear_norm` for any of the mentioned components,
we recommend to revert it back to `model_confidence=softmax` and re-train the assistant. After re-training,
we also recommend to [re-tune the thresholds for fallback components](./fallback-handoff.mdx#fallbacks).

## Rasa 2.5 to 2.6

### Forms

#### New `ignored_intents` parameter in Forms

There is a new parameter under Forms called `ignored_intents`. This parameter
can be used to prevent any required slots in a form from being filled with the specified
intent or intents. Please see the [Forms documentation](forms.mdx) for examples and more
information on how to use it in your `domain.yml` file.

Before, if a user did not want to fill any slots of a form with a specified intent
they would have to define it under the `not_intent` parameter for every slot mapping
as shown in the following example :

```yaml-rasa title="domain.yml"
forms:
  restaurant_form:
      cuisine:
      - type: from_entity
        entity: cuisine
        not_intent: chitchat
      num_people:
      - type: from_entity
        entity: number
        intent: [inform, request_restaurant]
        not_intent: chitchat
      feedback:
      - type: from_entity
        entity: feedback
        not_intent: chitchat
```

By introducing the `ignored_intents` parameter, we now only need to define it
in one place and it will affect all the slots of the form :

```yaml-rasa title="domain.yml"
forms:
  restaurant_form:
    ignored_intents: chitchat
    required_slots:
      cuisine:
      - type: from_entity
        entity: cuisine
      num_people:
      - type: from_entity
        entity: number
        intent: [inform, request_restaurant]
      feedback:
      - type: from_entity
        entity: feedback
      - type: from_text
```


## Rasa 2.4 to 2.5

### Machine Learning Components

#### `DIET`, `TED`, and `ResponseSelector`

The former `weight_sparsity` parameter of the `DIETClassifier`, `TEDPolicy`, and the `ResponseSelector`,
is now deprecated and superseded by the new `connection_density` parameter.
The old `weight_sparsity` is roughly equivalent to `1 - connection_density`, except at very low densities
(high sparsities).

To avoid deprecation issues, you should set `connection_density` to
`1 - your former weight_sparsity setting` throughout the config file. (If you left
`weight_sparsity` at its default setting, you don't need to do anything.)

#### SpaCy 3.0

Rasa now supports spaCy 3.0. This means that we can support more features for more
languages but this also introduced a breaking change. SpaCy 3.0 deprecated the
`spacy link <language model>` command. So from now on you need to use the
[the full model name](https://spacy.io/models) in the `config.yml` file.

**Before**

Before you could run `spacy link en en_core_web_md` and then we would be able
to pick up the correct model from the `language` parameter.

```yaml
language: en

pipeline:
   - name: SpacyNLP
```

**Now**

This behavior will be deprecated and instead you'll want to be explicit in `config.yml`.

```yaml
language: en

pipeline:
   - name: SpacyNLP
     model: en_core_web_md
```

**Fallback**

To make the transition easier, Rasa will try to fall back to a medium spaCy model whenever
a compatible language is configured for the entire pipeline in `config.yml`, even if you don't
specify a `model`. This fallback behavior is temporary and will be deprecated in Rasa 3.0.0.

We've updated our docs to reflect these changes. All examples now show a direct link to the
correct spaCy model. We've also added a warning to the [SpaCyNLP](components.mdx#spacynlp)
docs that explains the fallback behavior.

## Rasa 2.3 to Rasa 2.4

### Deprecating `template` for `response`
NLG Server
- Changed request format to send `response` as well as `template` as a field. The `template` field will be removed in Rasa 3.0.0.

`rasa.core.agent`
- The terminology `template` is deprecated and replaced by `response`. Support for `template` from the NLG response will be removed in Rasa 3.0.0. Please see [here](./nlg.mdx) for more details.

`rasa.core.nlg.generator`
- `generate()` now takes in  `utter_action` as a parameter.
- The terminology `template` is deprecated and replaced by `response`. Support for `template` in the `NaturalLanguageGenerator` will be removed in Rasa 3.0.0.

`rasa.shared.core.domain`
- The property `templates` is deprecated. Use `responses` instead. It will be removed in Rasa 3.0.0.
- `retrieval_intent_templates` will be removed in Rasa 3.0.0. Please use `retrieval_intent_responses` instead.
- `is_retrieval_intent_template` will be removed in Rasa 3.0.0. Please use `is_retrieval_intent_response` instead.
- `check_missing_templates` will be removed in Rasa 3.0.0. Please use `check_missing_responses` instead.

Response Selector
- The field `template_name` will be deprecated in Rasa 3.0.0. Please use `utter_action` instead. Please see [here](./components.mdx#selectors) for more details.
- The field `response_templates` will be deprecated in Rasa 3.0.0. Please use `responses` instead. Please see [here](./components.mdx#selectors) for more details.

## Rasa 2.3.3 to Rasa 2.3.4

:::caution
This is a release **breaking backwards compatibility of machine learning models**.
It is not possible to load previously trained models if they were trained with `model_confidence=cosine` or
`model_confidence=inner` setting. Please make sure to re-train the assistant before trying to use it with this improved version.

:::

### Machine Learning Components

Rasa `2.3.0` introduced the option of using cosine similarities for model confidences by setting `model_confidence=cosine`. Some post-release experiments revealed that using `model_confidence=cosine` is wrong as it can change the order of predicted labels. That's why this option was removed in Rasa version `2.3.4`.

`model_confidence=inner` is deprecated as it produces an unbounded range of confidences which can break
the logic of assistants in various other places.

We encourage you to try `model_confidence=linear_norm` which will produce a linearly normalized version of dot product similarities with each value in the range `[0,1]`. This can be done with the following config:
```
- name: DIETClassifier
  model_confidence: linear_norm
  constrain_similarities: True
```

If you trained a model with `model_confidence=cosine` or `model_confidence=inner` setting using previous versions of Rasa, please re-train by either removing the `model_confidence` option from the configuration or setting it to `linear_norm`.


## Rasa 2.2 to Rasa 2.3

### General

If you want to use Tensorboard for `DIETClassifier`, `ResponseSelector`, or `TEDPolicy` and log metrics after
every (mini)batch, please use 'batch' instead of 'minibatch' as 'tensorboard_log_level'.


### Machine Learning Components

A few changes have been made to the loss function inside machine learning (ML)
components `DIETClassifier`, `ResponseSelector` and `TEDPolicy`. These include:
1. Configuration option `loss_type=softmax` is now deprecated and will be removed in Rasa 3.0.0. Use `loss_type=cross_entropy` instead.
2. The default loss function (`loss_type=cross_entropy`) can add an optional sigmoid cross-entropy loss of all similarity values to constrain
them to an approximate range. You can turn on this option by setting `constrain_similarities=True`. This should help the models to perform better on real world test sets.

A new option `model_confidence` has been added to each ML component. It affects how the model's confidence for each label is computed during inference. It can take one of three values:
1. `softmax` - Dot product similarities between input and label embeddings are post-processed with a softmax function, as a result of which confidence for all labels sum up to 1.
2. `cosine` - Cosine similarity between input and label embeddings. Confidence for each label will be in the range `[-1,1]`.
3. `linear_norm` - Dot product similarities between input and label embeddings are post-processed with a linear normalization function. Confidence for each label will be in the range `[0,1]`.

The default value is `softmax`, but we recommend trying `linear_norm`. This should make it easier to [tune thresholds for triggering fallback](./fallback-handoff.mdx#fallbacks).
The value of this option does not affect how confidences are computed for entity predictions in `DIETClassifier`.

We encourage you to try both the above recommendations. This can be done with the following config:
```
- name: DIETClassifier
  model_confidence: linear_norm
  constrain_similarities: True
  ...
```
Once the assistant is re-trained with the above configuration, users should also [tune fallback confidence thresholds](./fallback-handoff.mdx#fallbacks).

**EDIT**: Some post-release experiments revealed that using `model_confidence=cosine` is wrong as it can change the order of predicted labels. That's why this option was removed in Rasa version `2.3.4`.

## Rasa 2.1 to Rasa 2.2

### General

`TEDPolicy`'s  `transformer_size`, `number_of_transformer_layers`,
and `dense_dimensions` parameters have been renamed.
Please update your configuration files using the following mapping:

|      Old Model Parameter    |                 New Model Parameter                    |
|-----------------------------|--------------------------------------------------------|
|`transformer_size`           |dictionary `transformer_size` with keys                 |
|                             |`text`, `action_text`, `label_action_text`, `dialogue`  |
|`number_of_transformer_layers`|dictionary `number_of_transformer_layers` with keys    |
|                             |`text`, `action_text`, `label_action_text`, `dialogue`  |
|`dense_dimension`            |dictionary `dense_dimension` with keys                  |
|                             |`text`, `action_text`, `label_action_text`, `intent`,   |
|                             |`action_name`, `label_action_name`, `entities`, `slots`,|
|                             |`active_loop`                                           |

For example:

```yaml-rasa title="config.yml"
policies:
  - name: TEDPolicy
    transformer_size:
      text: 128
      action_text: 128
      label_action_text: 128
      dialogue: 128
    number_of_transformer_layers:
      text: 1
      action_text: 1
      label_action_text: 1
      dialogue: 1
    dense_dimension:
      text: 128
      action_text: 128
      label_action_text: 128
      intent: 20
      action_name: 20
      label_action_name: 20
      entities: 20
      slots: 20
      active_loop: 20
```


### Deprecations

#### Markdown Data
Training and test data in Markdown format is now deprecated. This includes:
- reading and writing of story files in Markdown format
- reading and writing of NLU data in Markdown format
- reading and writing of retrieval intent data in Markdown format

Support for Markdown data will be removed entirely in Rasa 3.0.0.

Please convert your existing Markdown data by using the commands
described [here](./migration-guide.mdx#training-data-files).


### Policies

[Policies](./policies.mdx) now require a `**kwargs` argument in their constructor and `load` method.
Policies without `**kwargs` will be supported until Rasa version `3.0.0`.
However when using [incremental training](./command-line-interface.mdx#incremental-training)
`**kwargs` **must** be included.


#### Other

* `Domain.random_template_for` is deprecated and will be removed in Rasa
   3.0.0. You can alternatively use the `TemplatedNaturalLanguageGenerator`.
* `Domain.action_names` is deprecated and will be removed in Rasa
   3.0.0. Please use `Domain.action_names_or_texts` instead.


## Rasa 2.0 to Rasa 2.1

### Deprecations

`ConveRTTokenizer` is now deprecated. [ConveRTFeaturizer](./components.mdx#convertfeaturizer) now implements
its behaviour. To migrate, replace `ConveRTTokenizer` with any other tokenizer, for e.g.:

```yaml
pipeline:
    - name: WhitespaceTokenizer
    - name: ConveRTFeaturizer
      model_url: <Remote/Local path to model files>
    ...
```

`HFTransformersNLP` and `LanguageModelTokenizer` components are now deprecated.
[LanguageModelFeaturizer](./components.mdx#languagemodelfeaturizer) now implements their behaviour.
To migrate, replace both the above components with any tokenizer and specify the model architecture and model weights
as part of `LanguageModelFeaturizer`, for e.g.:

```yaml
pipeline:
    - name: WhitespaceTokenizer
    - name: LanguageModelFeaturizer
      model_name: "bert"
      model_weights: "rasa/LaBSE"
    ...
```

## Rasa 1.10 to Rasa 2.0

### General

A lot has changed in version 2.0. Make sure you read
through this guide thoroughly, to make sure all parts of your bot are updated.
A lot of updates can be done automatically with inbuilt commands, others will need
some manual conversion. If you have any feedback about these updates or the migration process, please post it
in the [forum](https://forum.rasa.com/t/rasa-open-source-2-0-is-out-now-internal-draft/35577).

### Training data files

As of version 2.0, the new default training data format is yaml. Markdown is still supported,
but this will be deprecated in Rasa 3.0.0.

You can convert existing NLU, Stories, and NLG (i.e. `responses.md`) training data
files in the Markdown format to the new YAML format using following commands:

```bash
rasa data convert nlu -f yaml --data={SOURCE_DIR} --out={TARGET_DIR}
rasa data convert nlg -f yaml --data={SOURCE_DIR} --out={TARGET_DIR}
rasa data convert core -f yaml --data={SOURCE_DIR} --out={TARGET_DIR}
```

Converted files will have the same names as the original ones but with a
`_converted.yml` suffix.

If you are using [forms](./migration-guide.mdx#forms) or [response selectors](./migration-guide.mdx#response-selectors),
some additional changes will need to be made as described in their respective sections.

### Policies

With the introduction of [rules](./rules.mdx) and the [RulePolicy](./policies.mdx#rule-policy),
the following policies are deprecated:

- [Mapping Policy](https://rasa.com/docs/rasa/2.x/policies#mapping-policy)
- [Fallback Policy](https://rasa.com/docs/rasa/2.x/policies#fallback-policy)
- [Two-Stage Fallback Policy](https://rasa.com/docs/rasa/2.x/policies#two-stage-fallback-policy)
- [Form Policy](https://rasa.com/docs/rasa/2.x/policies#form-policy)


To migrate the policies automatically, you can run the following command:

```bash
rasa data convert config
```

This command will take care of updating your `config.yml` and `domain.yml`, while
making backups of your existing files using the `.bak` suffix. It will also add a
`rules.yml` if necessary.

Your forms will still function as normal in the old format after this update, but this command
does not convert them into the new format automatically. This should be done manually, as
described in the section on [forms](./migration-guide.mdx#forms).

You can also migrate the individual policies manually, if you don't want to use the automatic conversion command.

#### Manually migrating from the Mapping Policy

If you previously used the [Mapping Policy](https://rasa.com/docs/rasa/2.x/policies#mapping-policy), you
can follow the documentation on [FAQs](./chitchat-faqs.mdx) to convert your mapped
intents to rules. Suppose you previously mapped an intent `ask_is_bot` as follows:

```yaml-rasa title="domain.yml"
intents:
 - ask_is_bot:
     triggers: action_is_bot
```

This becomes the following rule:

```yaml-rasa title="rules.yml"
rules:
- rule: Rule to map `ask_is_bot` intent
  steps:
  - intent: ask_is_bot
  - action: action_is_bot
```

And you can safely remove any `triggers:` from your domain:

```yaml-rasa title="domain.yml"
intents:
 - ask_is_bot
```

Finally, you can replace the Mapping Policy with the
[Rule Policy](./policies.mdx#rule-policy) in your model configuration:

```yaml-rasa title="config.yml"
policies:
  # Other policies
  - name: RulePolicy
```

#### Manually migrating from the Fallback Policy

If you previously used the [Fallback Policy](https://rasa.com/docs/rasa/2.x/policies#fallback-policy), the following model
configuration would translate as follows given a previous configuration like this:

```yaml-rasa title="config.yml"
policies:
  - name: "FallbackPolicy"
    nlu_threshold: 0.4
    core_threshold: 0.3
    fallback_action_name: "action_default_fallback"
    ambiguity_threshold: 0.1
```

The new configuration would then look like:

```yaml-rasa title="config.yml"
recipe: default.v1
pipeline:
  # Other components
  - name: FallbackClassifier
    threshold: 0.4
    ambiguity_threshold: 0.1

policies:
  # Other policies
  - name: RulePolicy
    core_fallback_threshold: 0.3
    core_fallback_action_name: "action_default_fallback"
```

In addition, you need to add a [rule](./rules.mdx) to specify which action to run
in case of low NLU confidence:

```yaml-rasa title="rules.yml"
rules:
  - rule: Ask the user to rephrase whenever they send a message with low NLU confidence
    steps:
    - intent: nlu_fallback
    - action: utter_please_rephrase
```

See the documentation on [fallback](./fallback-handoff.mdx#fallbacks) for more
information.

#### Manually migrating from the Two-Stage-Fallback Policy

If you previously used the
[Two-Stage Fallback Policy](https://rasa.com/docs/rasa/2.x/policies#two-stage-fallback-policy), with a configuration
like this for example:

```yaml-rasa title="config.yml"
policies:
  - name: TwoStageFallbackPolicy
    nlu_threshold: 0.4
    ambiguity_threshold: 0.1
    core_threshold: 0.3
    fallback_core_action_name: "action_default_fallback"
    fallback_nlu_action_name: "action_default_fallback"
    deny_suggestion_intent_name: "out_of_scope"
```

The new configuration would look like this:

```yaml-rasa title="config.yml"
recipe: default.v1
pipeline:
  # Other components
  - name: FallbackClassifier
    threshold: 0.4
    ambiguity_threshold: 0.1

policies:
  # Other policies
  - name: RulePolicy
    core_fallback_threshold: 0.3
    core_fallback_action_name: "action_default_fallback"
```

In addition you need to add a [rule](./rules.mdx) to activate the Two-Stage Fallback for
messages with low NLU confidence.

```yaml-rasa title="rules.yml"
rules:
  - rule: Implementation of the TwoStageFallbackPolicy
    steps:
    # This intent is automatically triggered by the `FallbackClassifier` in the NLU
    # pipeline in case the intent confidence was below the specified threshold.
    - intent: nlu_fallback
    # The Fallback is now implemented as a form.
    - action: action_two_stage_fallback
    - active_loop: action_two_stage_fallback
```

Note that the previous parameters `fallback_nlu_action_name` and
`deny_suggestion_intent_name` are no longer configurable and have the fixed values
`action_default_fallback` and `out_of_scope`.

See the [fallback](./fallback-handoff.mdx#fallbacks) documentation for more
information.

### Forms

As of version 2.0 the logic for [forms](./forms.mdx) has been moved from the
Rasa SDK to Rasa to simplify implementation and make it easier to write
action servers in other languages.

This means that forms are no longer implemented using a `FormAction`, but instead
defined in the domain. Any customizations around requesting slots or
[slot validation](./forms.mdx#validating-form-input) can be handled with a `FormValidationAction`.

Consider a custom form action from 1.x like this:

```python
from typing import Text, List, Any, Dict, Union
from rasa_sdk import Tracker
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.forms  import FormAction

class RestaurantForm(FormAction):
    def name(self) -> Text:
        return "restaurant_form"

    @staticmethod
    def required_slots(tracker: Tracker) -> List[Text]:
        return ["cuisine"]

    def slot_mappings(self) -> Dict[Text, Union[Dict, List[Dict]]]:
        return {
            "cuisine": self.from_entity(entity="cuisine", not_intent="chitchat"),
        }

    @staticmethod
    def cuisine_db() -> List[Text]:
        """Database of supported cuisines"""

        return ["caribbean", "chinese", "french"]

    def validate_cuisine(
        self,
        value: Text,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> Dict[Text, Any]:
        """Validate cuisine value."""

        if value.lower() in self.cuisine_db():
            # validation succeeded, set the value of the "cuisine" slot to value
            return {"cuisine": value}
        else:
            dispatcher.utter_message(template="utter_wrong_cuisine")
            # validation failed, set this slot to None, meaning the
            # user will be asked for the slot again
            return {"cuisine": None}

    def submit(
        self,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> List[Dict]:
        """Define what the form has to do
            after all required slots are filled"""

        # utter submit template
        dispatcher.utter_message(template="utter_submit")
        return []
```

Start the migration by removing the FormPolicy and adding the [RulePolicy](./policies.mdx#rule-policy)
(if not there already) to your model configuration:

```yaml-rasa title="config.yml"
policies:
  # Other policies
  # ...
  - name: RulePolicy
```

Then you need to define the form, required slots and their slot mappings
in the domain as described in the documentation on [forms](./forms.mdx#defining-a-form):

```yaml-rasa title="domain.yml"
forms:
  restaurant_form:
    cuisine:
    - type: from_entity
      entity: cuisine
      not_intent: chitchat
```
If you ran the command to [convert your stories](./migration-guide.mdx#training-data-Files),
you will have a story that handles form activation and deactivation like this:

```yaml-rasa title="stories.yml"
stories:
  - story: cuisine form
    steps:
    - intent: request_restaurant
    - action: restaurant_form
    - active_loop: restaurant_form
    - active_loop: null
    - action: utter_submit
```

This will work fine, but the best way to handle form behavior is to remove this story and instead
define two separate rules for form activation and submission:

```yaml-rasa title="rules.yml"
rules:
  - rule: Activate form
    steps:
    - intent: request_restaurant
    - action: restaurant_form
    - active_loop: restaurant_form

  - rule: Submit form
    condition:
    # Condition that form is active.
    - active_loop: restaurant_form
    steps:
    - action: restaurant_form
    - active_loop: null
    # The action we want to run when the form is submitted.
    - action: utter_submit
```

The last step is to implement a custom action to validate the form slots. Start by
adding the custom action to your domain:

```yaml-rasa title="domain.yml"
actions:
  # Other actions
  # ...
  - validate_restaurant_form
```

Then add a custom action which validates the `cuisine` slot:

```python
from typing import Text, List, Any, Dict, Union
from rasa_sdk import Tracker
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk import FormValidationAction
from rasa_sdk.types import DomainDict

class RestaurantFormValidator(FormValidationAction):
    def name(self) -> Text:
        return "validate_restaurant_form"

    @staticmethod
    def cuisine_db() -> List[Text]:
        """Database of supported cuisines"""

        return ["caribbean", "chinese", "french"]

    def validate_cuisine(
        self,
        slot_value: Any,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: DomainDict,
    ) -> Dict[Text, Any]:
        """Validate cuisine value."""

        if slot_value.lower() in self.cuisine_db():
            # validation succeeded, set the value of the "cuisine" slot to value
            return {"cuisine": slot_value}
        else:
            # validation failed, set this slot to None, meaning the
            # user will be asked for the slot again
            return {"cuisine": None}
```

You can also migrate forms from Rasa SDK to Rasa 2 iteratively. You can for
example migrate one form to the Rasa 2 implementation while continue using
the deprecated Rasa SDK implementation for another form. To continue to use
the deprecated Rasa SDK `FormAction`s, add a custom action with the name of your form to your domain. Note that you should complete the migration as soon as possible as the deprecated `FormAction`
will be removed from the Rasa SDK in Rasa 3.

```yaml-rasa title="domain.yml"
actions:
# Adding a custom action for a form will
# instruct Rasa to use the
# deprecated Rasa SDK implementation of forms.
- my_form

forms:
 my_form:
```

See the [forms](./forms.mdx) documentation for more details.

### Response Selectors

Response Selectors are a stable feature as of version 2.0.

The [conversion command](./migration-guide.mdx#training-data-files) will automatically
convert your `responses.md` file, stories and nlu training data to the new yaml format.
It will also take care of adding the `utter_` prefix to your responses.
Additionally you will need to rename the `respond_` actions in your stories files to use the
`utter_` prefix instead. Run the following command to apply these changes:

```bash
rasa data convert responses --data {SOURCE_DIR} --out={TARGET_DIR}
```

You can also apply these changes manually. For example:

```yaml-rasa
stories:
  - story: chitchat
    steps:
    - intent: chitchat
    - action: respond_chitchat
```
becomes

```yaml-rasa
stories:
  - story: chitchat
    steps:
    - intent: chitchat
    - action: utter_chitchat
```

and you will need to add the `utter_` prefix to the response names in your `responses.md`
as well. For example:

```yaml-rasa
responses:
  chitchat/ask_name:
    - text: Oh yeah, I am called the retrieval bot.

  chitchat/ask_weather:
    - text: Oh, it does look sunny right now in Berlin.
```

becomes

```yaml-rasa
responses:
  utter_chitchat/ask_name:
    - text: Oh yeah, I am called the retrieval bot.

  utter_chitchat/ask_weather:
    - text: Oh, it does look sunny right now in Berlin.
```

Finally, you should remove any actions with the `respond_` prefix from the actions
list in your domain.

This behavior will work fine when defined as a story, but even better when defined
as a rule. You should consider transferring your retrieval stories to rules. More information
on what that looks like in the [chitchat and FAQs documentation](./chitchat-faqs.mdx).


Response Selectors are now trained on retrieval intent labels by default instead
of the actual response text. For most models, this should improve training time
and accuracy of the `ResponseSelector`.

If you want to revert to the pre-2.0 default behavior, add the `use_text_as_label: true`
parameter to your `ResponseSelector` component:

```yaml-rasa
pipeline:
  # other components
  - name: ResponseSelector
    use_text_as_label: true
```

The output schema of `ResponseSelector` has changed. An example output looks like this:

```json {3-4,10,11,20}
{
  "response_selector": {
    "all_retrieval_intents": [
      "faq"
    ],
    "default": {
      "response": {
        "id": 1388783286124362000,
        "confidence": 1,
        "intent_response_key": "faq/is_legit",
        "response_templates": [
          {
            "text": "absolutely",
            "image": "https://i.imgur.com/nGF1K8f.jpg"
          },
          {
            "text": "I think so."
          }
        ]
        "template_name": "utter_faq/is_legit"
      },
      "ranking": [
        {
          "id": 1388783286124362000,
          "confidence": 1,
          "intent_response_key": "faq/is_legit"
        }
      ]
    }
  }
}
```
As a result of this, if you were previously querying for the key `full_retrieval_intent` as:
```python {2}
response_selector_output.get("default")
                        .get("full_retrieval_intent")
```
you should instead now do this:
```python {2-3}
response_selector_output.get("default")
                        .get("response")
                        .get("intent_response_key")
```


### Unfeaturized Slots

[Slots](domain.mdx#slots) of type `unfeaturized` are
deprecated and will be removed in version 3.0. To ignore slot values during
a conversation, set the `influence_conversation` property of the slot to `false`.

The following snippet is an example of the deprecated unfeaturized slot usage:

```yaml-rasa
slots:
  username:
    type: unfeaturized
```

To update this to the new format, you can specify the expected data type `text` and
define that the slot should be ignored during the conversation.

```yaml-rasa
slots:
  username:
    type: text
    # Set `influence_conversation` to `false`
    # to ignore the slot value during the conversation.
    influence_conversation: false
```

If you don't require the slot to have a specific data type, you can use the new slot
type [any](domain.mdx#any-slot). This slot type is always ignored during a conversation
and does not make any assumptions regarding the data type of the slot value.

```yaml-rasa
slots:
  username:
    type: any
```

Please see the updated [slots documentation](domain.mdx#slots) for more information.

### Conversation sessions

[Conversation sessions](domain.mdx#session-configuration) are now enabled by default
if your [Domain](domain.mdx) does not contain a session configuration. Previously a
missing session configuration was treated as if conversation sessions were disabled.
You can explicitly disable conversation sessions using the following snippet:

```yaml-rasa title="domain.yml"
session_config:
  # A session expiration time of `0`
  # disables conversation sessions
  session_expiration_time: 0
```


### Dialogue Featurization

This section is only relevant if you explicitly defined [featurizers](./policies.mdx#featurizers)
in your policy configuration.

LabelTokenizerSingleStateFeaturizer is deprecated and will be removed in the future.
It should be replaced with SingleStateFeaturizer and some changes should be made to the NLU pipeline.
Add a `Tokenizer` with the option `intent_tokenization_flag: True` and `CountVectorsFeaturizer`
to the NLU pipeline.

For example:
```yaml-rasa {3-5}
language: en
pipeline:
  - name: WhitespaceTokenizer
    intent_tokenization_flag: True
  - name: CountVectorsFeaturizer
  # other components
policies:
  # other policies
  - name: TEDPolicy
    featurizer:
    - name: SingleStateFeaturizer

```

BinarySingleStateFeaturizer is deprecated and will be removed in the future.
You should replace it with `SingleStateFeaturizer` and a NLU pipeline
where `intent_tokenization_flag` of a Tokenizer is set to `False`.

For example:
```yaml-rasa {4}
language: en
pipeline:
  - name: WhitespaceTokenizer
    intent_tokenization_flag: False
  # other components
policies:
  # other policies
  - name: TEDPolicy
    featurizer:
    - name: SingleStateFeaturizer

```

### Deprecations

The deprecated [event brokers](./event-brokers.mdx) FileProducer, KafkaProducer, PikaProducer
and SQLProducer have been removed. If you used these brokers in your
`endpoints.yml` make sure to use the renamed variants instead:
  - FileProducer became FileEventBroker
  - KafkaProducer became KafkaEventBroker
  - PikaProducer became PikaEventBroker
  - SQLProducer became  SQLEventBroker

The deprecated EmbeddingIntentClassifier has been removed. If you used this
component in your pipeline configuration (`config.yml`) you can replace it
with [DIETClassifier](./components.mdx#dietclassifier).
It accepts the same configuration parameters.

The deprecated KerasPolicy has been removed. If you used this
component in your policies configuration (`config.yml`) you can replace it
with [TEDPolicy](./policies.mdx#ted-policy). It accepts the same configuration parameters.

## Rasa 1.7 to Rasa 1.8

:::caution
This is a release **breaking backwards compatibility**.
It is not possible to load previously trained models. Please make sure to retrain a
model before trying to use it with this improved version.

:::

### General

* The [TED Policy](./policies.mdx#ted-policy) replaced the `keras_policy` as recommended machine
  learning policy. New projects generated with `rasa init` will automatically use
  this policy. In case you want to change your existing model configuration to use the
  [TED Policy](./policies.mdx#ted-policy) add this to the `policies` section in your `config.yml`
  and remove potentially existing `KerasPolicy` entries:

  ```yaml-rasa
  policies:
  # - ... other policies
  - name: TEDPolicy
    max_history: 5
    epochs: 100
  ```

  The given snippet specifies default values for the parameters `max_history` and
  `epochs`. `max_history` is particularly important and strongly depends on your stories.
  Please see the docs of the [TED Policy](./policies.mdx#ted-policy) if you want to customize them.

* All pre-defined pipeline templates are deprecated. **Any templates you use will be
  mapped to the new configuration, but the underlying architecture is the same**.
  Take a look at [Tuning Your Model](./tuning-your-model.mdx) to decide on what components you should use
  in your configuration file.

* The Embedding Policy was renamed to [TED Policy](./policies.mdx#ted-policy). The functionality of the policy stayed the same.
  Please update your configuration files to use `TEDPolicy` instead of `EmbeddingPolicy`.

* Most of the model options for `EmbeddingPolicy`, `EmbeddingIntentClassifier`, and `ResponseSelector` got
  renamed. Please update your configuration files using the following mapping:

  |      Old model option       |                  New model option                   |
  |-----------------------------|-----------------------------------------------------|
  |hidden_layers_sizes_a        |dictionary “hidden_layers_sizes” with key “text”     |
  |hidden_layers_sizes_b        |dictionary “hidden_layers_sizes” with key “label”    |
  |hidden_layers_sizes_pre_dial |dictionary “hidden_layers_sizes” with key “dialogue” |
  |hidden_layers_sizes_bot      |dictionary “hidden_layers_sizes” with key “label”    |
  |num_transformer_layers       |number_of_transformer_layers                         |
  |num_heads                    |number_of_attention_heads                            |
  |max_seq_length               |maximum_sequence_length                              |
  |dense_dim                    |dense_dimension                                      |
  |embed_dim                    |embedding_dimension                                  |
  |num_neg                      |number_of_negative_examples                          |
  |mu_pos                       |maximum_positive_similarity                          |
  |mu_neg                       |maximum_negative_similarity                          |
  |use_max_sim_neg              |use_maximum_negative_similarity                      |
  |C2                           |regularization_constant                              |
  |C_emb                        |negative_margin_scale                                |
  |droprate_a                   |droprate_dialogue                                    |
  |droprate_b                   |droprate_label                                       |
  |evaluate_every_num_epochs    |evaluate_every_number_of_epochs                      |
  |evaluate_on_num_examples     |evaluate_on_number_of_examples                       |

  Old configuration options will be mapped to the new names, and a warning will be thrown.
  However, these will be deprecated in a future release.

* The Embedding Intent Classifier is now deprecated and will be replaced by [DIETClassifier](./components.mdx#dietclassifier)
  in the future.
  `DIETClassfier` performs intent classification as well as entity recognition.
  If you want to get the same model behavior as the current `EmbeddingIntentClassifier`, you can use
  the following configuration of `DIETClassifier`:

  ```yaml-rasa
  pipeline:
  # - ... other components
  - name: DIETClassifier
    hidden_layers_sizes:
      text: [256, 128]
    number_of_transformer_layers: 0
    weight_sparsity: 0
    intent_classification: True
    entity_recognition: False
    use_masked_language_model: False
    BILOU_flag: False
    scale_loss: True
    use_sparse_input_dropout: False
    use_dense_input_dropout: False
    # ... any other parameters
  ```

  See [DIETClassifier](./components.mdx#dietclassifier) for more information about the new component.
  Specifying `EmbeddingIntentClassifier` in the configuration maps to the above component definition, and results in
  the same behaviour within the same Rasa version.

* `CRFEntityExtractor` is now deprecated and will be replaced by `DIETClassifier` in the future. If you want to
  get the same model behavior as the current `CRFEntityExtractor`, you can use the following configuration:

  ```yaml-rasa
  pipeline:
  # - ... other components
  - name: LexicalSyntacticFeaturizer
    features: [
      ["low", "title", "upper"],
      [
        "BOS",
        "EOS",
        "low",
        "prefix5",
        "prefix2",
        "suffix5",
        "suffix3",
        "suffix2",
        "upper",
        "title",
        "digit",
      ],
      ["low", "title", "upper"],
    ]
  - name: DIETClassifier
    intent_classification: False
    entity_recognition: True
    use_masked_language_model: False
    number_of_transformer_layers: 0
    # ... any other parameters
  ```

  `CRFEntityExtractor` featurizes user messages on its own, it does not depend on any featurizer.
  We extracted the featurization from the component into the new featurizer [LexicalSyntacticFeaturizer](./components.mdx#lexicalsyntacticfeaturizer). Thus,
  in order to obtain the same results as before, you need to add this featurizer to your pipeline before the
  [DIETClassifier](./components.mdx#dietclassifier).
  Specifying `CRFEntityExtractor` in the configuration maps to the above component definition, the behavior
  is unchanged from previous versions.

* If your pipeline contains `CRFEntityExtractor` and `EmbeddingIntentClassifier` you can substitute both
  components with [DIETClassifier](./components.mdx#dietclassifier). You can use the following pipeline for that:

  ```yaml-rasa
  pipeline:
  # - ... other components
  - name: LexicalSyntacticFeaturizer
    features: [
      ["low", "title", "upper"],
      [
        "BOS",
        "EOS",
        "low",
        "prefix5",
        "prefix2",
        "suffix5",
        "suffix3",
        "suffix2",
        "upper",
        "title",
        "digit",
      ],
      ["low", "title", "upper"],
    ]
  - name: DIETClassifier
    number_of_transformer_layers: 0
    # ... any other parameters
  ```

## Rasa 1.6 to Rasa 1.7

### General

* By default, the `EmbeddingIntentClassifier`, `EmbeddingPolicy`, and `ResponseSelector` will
  now normalize the top 10 confidence results if the `loss_type` is `"softmax"` (which has been
  default since 1.3, see [Rasa 1.2 to Rasa 1.3](./migration-guide.mdx#rasa-12-to-rasa-13)). This is configurable via the `ranking_length`
  configuration parameter; to turn off normalization to match the previous behavior, set `ranking_length: 0`.

## Rasa 1.2 to Rasa 1.3

:::caution
This is a release **breaking backwards compatibility**.
It is not possible to load previously trained models. Please make sure to retrain a
model before trying to use it with this improved version.

:::

### General

* Default parameters of `EmbeddingIntentClassifier` are changed. See
  the Components page for details.
  Architecture implementation is changed as well, so **old trained models cannot be loaded**.
  Default parameters and architecture for `EmbeddingPolicy` are changed. See [Policies](./policies.mdx) for details.
  It uses transformer instead of lstm. **Old trained models cannot be loaded**.
  They use `inner` similarity and `softmax` loss by default instead of
  `cosine` similarity and `margin` loss (can be set in config file).
  They use `balanced` batching strategy by default to counteract class imbalance problem.
  The meaning of `evaluate_on_num_examples` is changed. If it is non zero, random examples will be
  picked by stratified split and used as **hold out** validation set, so they will be excluded from training data.
  We suggest to set it to zero (default) if data set contains a lot of unique examples of dialogue turns.
  Removed `label_tokenization_flag` and `label_split_symbol` from component. Instead moved intent splitting to `Tokenizer` components via `intent_tokenization_flag` and `intent_split_symbol` flag.

* Default `max_history` for `EmbeddingPolicy` is `None` which means it'll use
  the `FullDialogueTrackerFeaturizer`. We recommend to set `max_history` to
  some finite value in order to use `MaxHistoryTrackerFeaturizer`
  for **faster training**. See [Featurizers](./policies.mdx#featurizers) for details.
  We recommend to increase `batch_size` for `MaxHistoryTrackerFeaturizer`
  (e.g. `"batch_size": [32, 64]`)

* **Compare** mode of `rasa train core` allows the whole core config comparison.
  Therefore, we changed the naming of trained models. They are named by config file
  name instead of policy name. Old naming style will not be read correctly when
  creating **compare** plots (`rasa test core`). Please remove old trained models
  in comparison folder and retrain. Normal core training is unaffected.

* We updated the **evaluation metric** for our **NER**. We report the weighted precision and f1-score.
  So far we included `no-entity` in this report. However, as most of the tokens actually don't have
  an entity set, this will influence the weighted precision and f1-score quite a bit. From now on we
  exclude `no-entity` from the evaluation. The overall metrics now only include proper entities. You
  might see a drop in the performance scores when running the evaluation again.

* `/` is reserved as a delimiter token to distinguish between retrieval intent and the corresponding response text
  identifier. Make sure you don't include `/` symbol in the name of your intents.


## Rasa NLU 0.14.x and Rasa Core 0.13.x to Rasa 1.0

:::caution
This is a release **breaking backwards compatibility**.
It is not possible to load previously trained models. Please make sure to retrain a
model before trying to use it with this improved version.

:::

### General

* The scripts in `rasa.core` and `rasa.nlu` can no longer be executed. To train, test, run, … an NLU or Core
  model, you should now use the command line interface `rasa`. The functionality is, for the most part, the same as before.
  Some changes in commands reflect the combined training and running of NLU and Core models, but NLU and Core can still
  be trained and used individually. If you attempt to run one of the old scripts in `rasa.core` or `rasa.nlu`,
  an error is thrown that points you to the command you
  should use instead. See all the new commands at [Command Line Interface](./command-line-interface.mdx).

* If you have written a custom output channel, all `send_` methods subclassed
  from the `OutputChannel` class need to take an additional `\*\*kwargs`
  argument. You can use these keyword args from your custom action code or the
  templates in your domain file to send any extra parameters used in your
  channel's send methods.

* If you were previously importing the `Button` or `Element` classes from
  `rasa_core.dispatcher`, these are now to be imported from `rasa_sdk.utils`.

* Rasa NLU and Core previously used <a href="https://legacy-docs.rasa.com/docs/nlu/0.15.1/migrations/?&_ga=2.218966814.608734414.1560704810-314462423.1543594887#id1" target="_blank" rel="nofollow noopener noreferrer">separate configuration files</a>.
  These two files should be merged into a single file either named `config.yml`, or passed via the `--config` parameter.

### Script parameters

* All script parameter names have been unified to follow the same schema.
  Any underscores (`_`) in arguments have been replaced with dashes (`-`).
  For example: `--max_history` has been changed to `--max-history`. You can
  see all of the script parameters in the `--help` output of the commands
  in the [Command Line Interface](./command-line-interface.mdx).

* The `--num_threads` parameter was removed from the `run` command. The
  server will always run single-threaded, but will now run asynchronously. If you want to
  make use of multiple processes, feel free to check out the [Sanic server
  documentation](https://sanicframework.org/en/guide/deployment/running.html#gunicorn).

* To avoid conflicts in script parameter names, connectors in the `run` command now need to be specified with
  `--connector`, as `-c` is no longer supported. The maximum history in the `rasa visualize` command needs to be
  defined with `--max-history`. Output paths and log files cannot be specified with `-o` anymore; `--out` and
  `--log-file` should be used. NLU data has been standarized to be `--nlu` and the name of
  any kind of data files or directory to be `--data`.

### HTTP API

* There are numerous HTTP API endpoint changes which can be found [here](./http-api.mdx).
