## Introduction

The [coexistence of CALM and the NLU-based system](/content/docs/pro/calm-with-nlu/migrating-from-nlu/index.html) depends on a routing mechanism, that routes messages based on their content to either system. You can choose between two different router components:

1. [`IntentBasedRouter`](/content/docs/reference/config/components/coexistence-routers/#intentbasedrouter/index.html): The predicted intent of the NLU pipeline is used to decide where the message should go.
2. [`LLMBasedRouter`](/content/docs/reference/config/components/coexistence-routers/#llmbasedrouter/index.html): This component leverages an LLM to decide whether a message should be routed to the NLU-based system or CALM.

You can only use one of the router components in your assistant.

## IntentBasedRouter [​](/content/docs/reference/config/components/coexistence-routers/#intentbasedrouter/index.html)

The `IntentBasedRouter` uses the predicted intent from the NLU components and routes the message dependent on that intent. The router needs to be added to the pipeline in your config file.

### Important

The position of the `IntentBasedRouter` needs to be _after_ the NLU components and _before_ the Command Generators.

#### Example Configuration

Depending on the other components you choose, your config file could look like the following.

**config.yml**  
```yaml
  recipe: default.v1
  language: en
  pipeline:
  - name: WhitespaceTokenizer
  - name: CountVectorsFeaturizer
  - name: CountVectorsFeaturizer
    analyzer: char_wb
    min_ngram: 1
    max_ngram: 4
  - name: LogisticRegressionClassifier
  - name: IntentBasedRouter
    # additional configuration parameters
  - name: CompactLLMCommandGenerator
    llm:
      model_group: openai_llm

policies:
  - name: FlowPolicy
  - name: RulePolicy
  - name: MemoizationPolicy
    max_history: 10
  - name: TEDPolicy
```

**endpoints.yml**  
```yaml
   model_groups:
     - id: openai_llm
       models:
         - provider: openai
           model: gpt-5-mini-2025-08-07
           timeout: 7
           max_tokens: 256
```

### Configuration of the IntentBasedRouter [​](/content/docs/reference/config/components/coexistence-routers/#configuration-of-the-intentbasedrouter/index.html)

The following mandatory configuration parameters need to be configured:

- `nlu_entry`:
  - `sticky`: List of intents which should route to the NLU-based system in a sticky fashion.
  - `non_sticky`: List of intents which should route to the NLU-based system in a non sticky fashion.
- `calm_entry`:
  - `sticky`: List of intents which should route to CALM in a sticky fashion.

A full configuration of the `IntentBasedRouter` could for example look like the following.

**config.yml**  
```yaml
  pipeline:
  # ...
  - name: IntentBasedRouter
    nlu_entry:
      sticky:
        - transfer_money
        - check_balance
        - search_transactions
      non_sticky:
        - chitchat
    calm_entry:
      sticky:
        - book_hotel
        - cancel_hotel
        - list_hotel_bookings
  # ...
```

### Handling missing intents [​](/content/docs/reference/config/components/coexistence-routers/#handling-missing-intents/index.html)

If an intent is predicted by an NLU component, but the intent is not part of any of the intents listed in the `IntentBasedRouter` and the routing session is currently not set, the message is routed according to the following rules:

1. We route to CALM if given the intent any of the NLU triggers of flows are activated (see [NLU triggers documentation](/content/docs/reference/primitives/starting-flows/#nlu-trigger/index.html)).
2. We route to the NLU-based system otherwise.

## LLMBasedRouter [​](/content/docs/reference/config/components/coexistence-routers/#llmbasedrouter/index.html)

The `LLMBasedRouter` uses an LLM, by default `gpt-5-mini-2025-08-07`, to decide whether a message should be routed to the NLU-based system or CALM.

### Important

In order to use this component for your coexistence solution, you need to add it as the _first_ component to your pipeline in the config file.

#### Example Configuration

Depending on the other components you choose, your config file could look like the following.

**config.yml**  
```yaml
  recipe: default.v1
  language: en
  pipeline:
  - name: LLMBasedRouter
    nlu_entry:
      sticky: ...
      non_sticky: ...
    calm_entry:
      sticky: handles everything around hotel bookings
    llm:
      model_group: openai_llm
    # additional configuration parameters
  - name: WhitespaceTokenizer
  - name: CountVectorsFeaturizer
  - name: CountVectorsFeaturizer
    analyzer: char_wb
    min_ngram: 1
    max_ngram: 4
  - name: LogisticRegressionClassifier
  - name: CompactLLMCommandGenerator
    llm:
      model_group: openai_llm

policies:
  - name: FlowPolicy
  - name: RulePolicy
  - name: MemoizationPolicy
    max_history: 10
  - name: TEDPolicy
```

**endpoints.yml**  
```yaml
   model_groups:
     - id: openai_llm
       models:
         - provider: openai
           model: gpt-5-mini-2025-08-07
           timeout: 7
           max_tokens: 256
```

### Configuring the LLMBasedRouter component [​](/content/docs/reference/config/components/coexistence-routers/#configuring-the-llmbasedrouter-component/index.html)

The `LLMBasedRouter` component has the following configuration parameters:

- `nlu_entry`:
  - `sticky`: Describes the general NLU-based system functionality. By default the value is `"handles everything else"`.
  - `non_sticky`: Describes the functionality of the NLU-based system that should not result in sticky routing to the NLU-based system. By default the value is `"handles chitchat"`.
- `calm_entry`:
  - `sticky` (required): Describes the functionality implemented in the CALM system of the assistant.
- `llm`:
  Configuration of the llm.
- `prompt`:
  File path to the prompt template (a jinja2 template) to use.

You can modify the prompt by writing your own prompt as a jinja2 template and provide it to the component as a file:

```yaml
pipeline:
# ...
- name: LLMBasedRouter
  prompt: prompts/llm-based-router-prompt.jinja2
# ...
```

### Handling failures and downtime of the LLM [​](/content/docs/reference/config/components/coexistence-routers/#handling-failures-and-downtime-of-the-llm/index.html)

If the LLM predicts an invalid answer, e.g. another character than `A`, `B`, or `C`, or if the API of the LLM is down and the LLM cannot be reached, the message is routed to the NLU-based system in a sticky fashion.
