Coexistence Routers | Rasa Documentation

Introduction

The coexistence of CALM and the NLU-based system 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: The predicted intent of the NLU pipeline is used to decide where the message should go.
  2. LLMBasedRouter: 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

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

  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

   model_groups:
     - id: openai_llm
       models:
         - provider: openai
           model: gpt-5-mini-2025-08-07
           timeout: 7
           max_tokens: 256

Configuration of the IntentBasedRouter

The following mandatory configuration parameters need to be configured:

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

config.yml

  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

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).
  2. We route to the NLU-based system otherwise.

LLMBasedRouter

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

  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

   model_groups:
     - id: openai_llm
       models:
         - provider: openai
           model: gpt-5-mini-2025-08-07
           timeout: 7
           max_tokens: 256

Configuring the LLMBasedRouter component

The LLMBasedRouter component has the following configuration parameters:

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

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

Handling failures and downtime of the LLM

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.