One Conversation Multiple Agents and Routing

I know that rasa_core does not support multiple domains, however, regarding having one conversation, having one agent start the conversation and another finish the conversation, what is the best way to go about this?

Some ideas I have is to subclass the agent class and implement a transfer class where I can simply transfer the tracker and any other items to a new agent and have the same input chanel handle input but the input goes to a new agent?

Maybe Create a Conversation class that can keep track of a sender_id conversation and it’s current agent that it is talking to?

I have no clue where to get started.

My reasoning for this is I want an agent to be able to rout to other agents that are trained at a higher probability to handle intents and custom actions, rather than to have a huge agent with a lot of intents and low probability for them and a lot of confusion.

Any Ideas?


Hi @adrianhumphrey111, if I’m not mistaken you can many agents at the same time pointing to the same Redis endpoint where the tracker information will be stored. So you wouldn’t need to write your own class for context transfer, since all agents can fetch the context from the object store. Disclaimer: I didn’t test this idea yet. Please keep me posted in case you try :wink:


We have tested Redis that has one conversation tracker( using user id) and able to continue the conversation in different languages(one bot in each language)

Use the redis tracker and user id will be unique key that determines the state of the conversation. Keep in mind what policies you have used while training. Tracker state is a feature that determines what the bot should do next

1 Like

That you very much will try to implement this now. Just a quick question, what exactly do you mean by “Use the redis Tracker.”

So this is your tracker -

By default, It is stored in InMemoryTracker which you can also access but then it is restricted to one server running one bot. If you want to share the tracker between multiple agents running on multple servers or containers, you need to store it somewhere global but the persistence level is usually not that long. You don’t want the bot to remember conversations for one particular user that happened a long time ago. Ideally you can use a tracker_store

Rasa provides Redis implementation, you can extend it to use your own (RabbitMQ, MongoDB) , If you use the RedisTrackerStore basically you spin up a Redis server where you save the tracker state. pass the tracker store when you create your agent


You shoud pass the tracker_store as RedisTrackerStore with the endpoints and credentials (take idea from the Above is just an example


This is awesome. I really appreciate the in detail explanation; I usually always try to do it for people and this is the first time I ever got one back. Lol So thank you.

Okay So I understand that part. I can store the specific tracker in my MongoDb and load an agent with that tracker and even instantiate the tracker with a sender_id for different conversations. That is awesome. Maybe you can help me with this next question.

I have two agents. Agent1 and Agent2, I load them both with the same tracker from my MongoDB server. Both Agent1 and Agent2 can handle_message() with the same sender_id, so they are on the same conversation. The question is, how should I go about stop sending my messages to Agent1 and start sending them to Agent2 once a certain variable is set in the same tracker?

1 Like

No worries, usually you are looking at a custom action to indicate and a gateway of some sort that can check and route to the correct agent. I will take an example of a customer contact center.

Let’s say you are doing Topic classification between a query related to payments or credits. You have agent one who answers questions about credits and agent two talking about payments.

You will need a router in between to decide which agent to call. It is similar here

For us, we do the same for separating languages which has the same tracker state. But in your case you will use a slot value let’s say and probably a custom action that calls parse to the second agent. A bit tricky but in my head i think you need a some sort of gateway that routes. We use cookie variables to route to different agents using Botkit as a gateway

1 Like

So in theory I could do this. Create a tracker with a sender_id. Save that tracker in the database. Create two agents. Instantiate those two agents with the same tracker. When a message comes in, with a sender_id, I pull that tracker from the database and parse which agent to route to. That information is inside of the tracker that each agent has access to. So each agent can basically route the conversation back to the other agent. Now I know which agent to handle_message() and pass the sender_id to handle that particular conversation?

But what If I want to have more than one conversation at one time? Then I will not be able to have a new tracker for every new conversation?

It depends on what do you define as your sender-id. Typically we define it over time. Redis you can flush the queque using a job or by config.

In our case, we take a persistent user id, let’s say an employee id, so we can store the conversation over a period of time and given how you manage slots, you can keep some vital information about the user and keep them in slots and use them during the conversation even if the user comes back after a while.

You can use the session-id for each user as your sender-id. Keep in mind, a sender-id is unique to one user who probably can’t have two conversation from the same channel, if you have multiple channels then it is upto your use-case on how do you define user management

FYI the Redis tracker is not theoretical, we actually use it to serve multi-lingual bots in our environment.

1 Like

Thank you man! This information was very helpful and already started architecting somethings out. I will definitely keep you updated on my solution!

1 Like

Hey Souvik,

Another Question, I am going about implementing the saved tracker now with Mongo.

#create a tracker store and save it to mongo

domain = Domain.load(filename=“./agents/superagent/loan_domain.yml”)

tracker = TrackerStore(domain)

mongoTracker = MongoTrackerStore(domain=domain, db=“simba”, collection=“trackers”)

I am getting a timeout error and it gets caught on the ensure_indices() method.

Is this how I would do it? Create a tracker, save it and load agent1 and agent2 from same tracker with no sender Id correct?

I tackle these thing right now too. I run now redis tracker store with ConsoleChannel. But I don’t know how to use it. What I mean: first How can I access the data to have just a raw look?Using redis-cli gives unreadable data with hex numbers in between. So the quetsion is, how can I actually look at the data saved inside the tracker store? Also when I don’t usea tracker store the default is still Inmemory? Where is it then saved (I mean where is this tracker saved physically)?

Redis seems not working with a custom webchannel:

def run_bot(serve_forever=True):
    domain = TemplateDomain.load(os.path.join('./models/dialogue', "domain.yml"))
    # ensures the domain hasn't changed between test and train
    tracker_store = RedisTrackerStore(domain,host="localhost", port=6379)

    interpreter = RasaNLUInterpreter('./nlu')
    agent = Agent.load('./models/dialogue', interpreter = interpreter,tracker_store=tracker_store)
    channel = BotServerInputChannel(agent)

I tried it now with my chat gui and checked the redis store. But nothing changed. How do I handle senderID sent from the webchannel (if that is the reason)?

Tracker Store subclasses DialogueStateTracker, and that class has a method called get_current_values, that returns a dictionary of the current slots.

You can access the tracker in each action I think, since the tracker gets passed into the action run method.

thanks. Does this works the same for a custom webchannel?

Could you give me a little more context on what you mean by custom webchannel. Also RedisTrackerStore sublclasses TrackerStore. And TrackerStore returns a DialogueStateTracker when it is initialized.

In the code I wrote. After agent.load I set a custom channel. _ tried it with the code like above,and then checked the redis server key values and it seems the new data was not saved there. But now I have a senderID from my channel.

My guess it that when we create a trackerstore and save it to the databases, Mongo or Redis, when we load the agent, we can send it messages with a sender_id. I can send the same agent instance the same message with a different sender_id and the agent know that if it is a different sender_id, that it is a new conversation. So my guess it, that if we are loading this agent with a tracker_store now, the agent with know to create a new tracker with that sender_id. So all you have to do is send the sender_id with the message and I think it should take care of the tracker.

Honestly I am still learning how to implement this tracker and these are my assumptions, I am currently trying to code a solution like you.

Hey, thanks. I am still learning too. But this sounds right? And I found out that my webchannel sends the mesage with the senderID already like /conversations/c9b799e3-77ba-4f9d-86f2-f6246762e43d/say?message=hello!&uuid=a5fbc0d6-6c7b-4beb-aae3-8698f6e6e70a with the uuid. So I assume this is alright? I use this nice channel:

tracker = self.agent.tracker_store.get_or_create_tracker(cid)

It seems that the sender_id is the cid, And as you can see that on every message, it will either create a tracker or grab one based on the sender_id, or the cid.