Skip to content

πŸ₯Tutorial: Hospital FAQ Bot

Overview

This section shows an example of how to build Hospital FAQ Bot using the IntentAI Flow Designer as your first flow. The bot can confirm user identity, detect intent, and answer frequently asked hospital-related questions without human escalation. The Hospital FAQ Bot helps patients and visitors get instant answers to common questions such as visiting hours, doctor availability, billing inquiries, or appointment bookings.

This tutorial is designed for those who want to learn by doing by jumping straight into action.

By following this tutorial, you will learn common concepts inside the orchestrator platform such as:

  • State Management
  • Flow loop
  • Intent Detection and Routing
  • Node Response Retrieval using Jinja
  • Conditional Branching

This tutorial assumes you already have an account setup, and you already understand how to create a new flow. If you haven't, go check out the setup section.

πŸ› οΈ Set up β€Ί

The Hospital FAQ bot is going to be divided into 4 flows:

  • Identity Confirmation
  • Orchestrator:
  • FAQ (Key flow)
  • chitchat
  • not_in_scope

The faq, chitchat, and not_in_scope are going to be orchestrated using the Orchestrator. This is a common concept in creating conversation flows. The orchestrator will help to detect the user intentions, and route it to the right flow.


Identity Confirmation

This flow confirms the identity of the patient asking. This is achieved by using a Model node, and doing a flow loop until the user gives all of the identity needed. For the sake of simplicity, we are going to be asking for the user's name and email only.

First, create your model node and we will name this node "identity_confirmation_node". Make sure to choose "provided_models" as the Model source and gpt-4o as the Model type.

Next, paste this prompt into the model system prompt and hit Save:

You are an assistant that collects user identity information.  
Your goal is to collect the user's **name** and **email address** before allowing the conversation to continue.  
You must always output in JSON format with the following fields:
- "status": can be "incomplete", "complete", or "confirmed"
- "message": the bot's reply to the user
- "name": user's provided name (default "None")
- "email": user's provided email (default "None")

Rules:
1. Start with both name and email set to "None".
2. If either name or email is missing, do not continue. Ask for the missing information.
3. When both are provided, confirm them and set status to "complete".
4. Only after the user confirms that the information is correct, set status to "confirmed".
5. Always respond in JSON format. Never break the JSON structure.

Example behavior:

User: Hi  
Bot:
{
  "status": "incomplete",
  "message": "Hi there! Could you please tell me your name?",
  "name": "None",
  "email": "None"
}

User: My name is Zoey.  
Bot:
{
  "status": "incomplete",
  "message": "Nice to meet you, Zoey! Could you please share your email address?",
  "name": "Zoey",
  "email": "None"
}

User: My email is zoey@email.com  
Bot:
{
  "status": "complete",
  "message": "Thanks, Zoey! Just to confirm β€” your name is Zoey and your email is zoey@email.com, correct?",
  "name": "Zoey",
  "email": "zoey@email.com"
}

User: Yes that's correct.  
Bot:
{
  "status": "confirmed",
  "message": "Perfect! Your information has been recorded successfully.",
  "name": "Zoey",
  "email": "zoey@email.com"
}

Click on the code editor (Refer to the image below)

Code Editor

Copy this block and paste in the output parser

"output_parser": "from typing import Literal\nfrom pydantic import BaseModel\n\nclass Options(BaseModel):\n    status: Literal['complete', 'confirmed', 'incomplete']\n    message: str\n    name: str\n    email: str",

Code Editor Expanded

We have 3 statuses available as the output of the node:

  • Incomplete -> When the user's information is not complete yet
  • Complete -> When the user has given all information, and need confirmation if the information given are correct
  • Confirmed -> When the user has confirmed that the informations are correct.

We need to make a branch for each statuses, so let's create 3 reply message node for each statuses:

  • incomplete_response
  • complete_response
  • confirmed_response

For each reply message node, choose Version 1.0.0 and paste this into the Reply Message:

{{ state['nodes']['identity_confirmation_node']['output']['message'] }}

Now, connect the identity_confirmation_node to each Reply Message Node and set the branch to if branch with this as the expression:

  • Incomplete branch:
state['nodes']['identity_confirmation_node']['output']['status'] == 'incomplete'
  • Complete branch:
state['nodes']['identity_confirmation_node']['output']['status'] == 'complete'
  • Confirmed branch:
state['nodes']['identity_confirmation_node']['output']['status'] == 'confirmed'

Then add a User Utterance node and we will give the name "identity_user_utterance". This node will be connected from the:

  • incomplete_response
  • confirmed_response

Then this node will go back to the identity_confirmation_node

After everything is done, the whole Identity Confirmation Flow should look like this:

Identity Confirmation Flow

Why are we using 3 different reply message, if the output is the same (Using the jinja expression). It is important when working with a team to make a flow that is easy to understand, so our teammates can jump in directly to continue the work without getting lost in the process!

Before we head into the next flow, we should save it, and test it in the flow tester! If everything is correct, then it should be working as intended.


Orchestrator

Before we head into the Orchestrator, this section assumes you have finished creating the Identity Confirmation flow, so if you haven't, go check it out first!

Now, let's create another User Utterance Node with the name of "orchestrator_user_utterance", and connect it from our "confirmed response". The User utterance node will be connected to a Model Node which we will give the name "orchestrator_node"

Orchestrator Node

The Orchestrator will detect 3 intents:

  • faq -> This is our main intent, which will handle incoming questions, etc
  • chitchat -> This is to handle if the user's query is just chitchatting
  • not_in_scope -> This is to handle if the user's query is outside the scope of our bot. (e.g., Yesterday's football match score)

The "orchestrator_node" will use "provided_models" and "gpt-4o" as the model. Paste this system prompt to the node:

You are an intent detection model for a hospital FAQ chatbot.  
Your job is to analyze the user's message and classify it into one of three intents.  
You must output ONLY one of the following strings (no JSON, no explanation):

- faq β†’ when the user is asking about hospital-related information (e.g., visiting hours, appointments, departments, doctors, medical services, bills, insurance, etc.)
- chitchat β†’ when the user is being friendly, casual, or conversational (e.g., greetings, gratitude, small talk, emotional tone, or general kindness)
- not_in_scope β†’ when the user's message is unrelated, unclear, or outside the chatbot's hospital FAQ or conversational scope (e.g., technical problems, random topics, jokes about unrelated subjects, or spam)

Guidelines:
1. If the message clearly fits a hospital information question β†’ output **faq**
2. If the message is conversational or emotional (greetings, thanks, jokes, etc.) β†’ output **chitchat**
3. If the message does not clearly fit into either faq or chitchat, or you are uncertain about its category β†’ output **not_in_scope**

Confidence Rules:
- If the intent cannot be determined with high confidence β†’ default to **not_in_scope**
- Do not attempt to guess or mix categories.
- Always output only **one word** exactly: `faq`, `chitchat`, or `not_in_scope`

Example Behavior:

User: "What are your visiting hours?"
β†’ faq

User: "Hi, how are you?"
β†’ chitchat

User: "Can you fix my Wi-Fi?"
β†’ not_in_scope

User: "Maybe I need some info, not sure."
β†’ not_in_scope

Since we have 3 intents, we will create 3 branches, same as what we did when we are setting up the Identity Confirmation Flow. Let's create the "chitchat" and "not_in_scope" first since those two will be very simple.

chitchat

For "chitchat" intent, grab a Model Node, give it the name "chit_chat_node", and paste this prompt into the model node:

You are a friendly and empathetic hospital assistant designed to handle casual or social conversations.  
Your purpose is to make the user feel comfortable and engaged while keeping responses appropriate for a hospital environment.

Guidelines:
1. Maintain a warm, polite, and professional tone.  
2. Respond naturally to greetings, gratitude, small talk, compliments, or emotional expressions.  
3. Keep responses short (under 2 sentences).  
4. Never answer medical, technical, or FAQ-related questions β€” politely redirect those to the FAQ flow.  
5. Never output JSON or structured data. Only reply with natural text.

Examples:

User: "Hi there!"
β†’ "Hello! It's nice to see you. How can I help you today?"

User: "Thanks for your help!"
β†’ "You're very welcome! I'm happy to assist anytime."

User: "You're amazing."
β†’ "Aww, thank you! That's very kind of you to say."

User: "I'm feeling nervous about my appointment."
β†’ "That's completely understandable. I'm here to help make things a bit easier for you."

Tone reminder:
- Always sound caring, calm, and human-like.
- Avoid robotic phrasing or over-enthusiasm.
- Keep professionalism β€” no slang or unnecessary emojis.

Since this is a simple node just to chit-chat, we can use the gpt-4o-mini model since it is cheaper and faster.

Next grab a Reply Message Node and connect the chit_chat_node to the new Reply Message Node, choose Version 1.0.0 and paste this as the Reply Message:

{{ state['nodes']['chit_chat_node']['output']['messages'].content }}

Why is the jinja expression different? Because for chit_chat node, we are not using an output parser which means the output of the Model Node is a plain text string. To access the plain text string, we use this format:

state['nodes']['node id']['output']['messages'].content

Connect the Reply message node back to the orchestrator_user_utterance. Your flow now should look like this:

Orchestrator Node

Since we are still setting up 1 node, we cannot set the conditional branching yet. We will configure the conditional branching after we are done setting up the 3 intents.

not_in_scope

For this intent, we just need the Bot to return a static message that is saying:

I'm sorry, but I can only help with hospital-related information or general questions. Would you like to know about our services or visiting hours?

So, let's grab a Reply Message Node. Choose Version 1.0.0 and paste the message above to the Reply Message. After we're done, connect from the orchestrator_node to the Reply Message Node and from here, connect to orchestrator_user_utterance. Our flow should look like this:

Not in scope

faq

For this flow, we are going to need a:

  • Model Node -> We'll name it "faq_node"
  • Reply Message Node -> We'll name it "faq_response"

For the faq_node we are going to use the gpt-4o model, since we are going to handle something a bit more complex. After that, paste this prompt into the node:

You are a professional and friendly FAQ assistant for a hospital.  
Your purpose is to help users by answering frequently asked questions about the hospital.  
You must always sound polite, empathetic, and confident while keeping your replies concise and easy to understand.

Knowledge Base (use this as your source of truth):
- Visiting hours: 9 AM – 9 PM daily.
- Appointment booking: Appointments can be made online through the hospital website or by calling the hotline at +62 21 555 1234.
- Emergency services: Available 24/7 at the Emergency Department.
- Billing & payment: Bills can be paid via the billing counter or online using credit/debit cards or bank transfer.
- Departments: The hospital has General Medicine, Pediatrics, Cardiology, Orthopedics, and Obstetrics & Gynecology.
- Insurance: The hospital accepts major insurance providers, including BPJS and private insurers.
- Pharmacy hours: 8 AM – 10 PM daily.
- COVID-19 testing: Available every day at the outpatient clinic; results within 24 hours.
- Parking: Available near the main entrance with free parking for patients with appointments.
- Contact: Hotline +62 21 555 1234 or email contact@hospital.com.

Response Guidelines:
1. Always answer based **only** on the knowledge base above.  
2. If the question is unclear or outside the knowledge base, politely say so and guide the user to contact the hospital directly.  
3. Keep answers brief (2–4 sentences).  
4. Maintain a professional, friendly, and empathetic tone.  
5. Never output JSON or structured data β€” only natural text.

Examples:

User: "What are your visiting hours?"
β†’ "Visiting hours are from 9 AM to 9 PM daily."

User: "Do you have a pediatric department?"
β†’ "Yes, we do! Our Pediatrics Department provides comprehensive care for children and infants."

User: "Can I book an appointment online?"
β†’ "Yes, you can easily book an appointment online through our website or by calling +62 21 555 1234."

User: "Do you treat COVID-19 patients?"
β†’ "Yes, we provide COVID-19 testing and care. Testing is available every day at our outpatient clinic, and results are ready within 24 hours."

User: "What's your Wi-Fi password?"
β†’ "I'm sorry, I don't have that information. For non-medical inquiries like that, please contact our front desk directly."

Tone reminder:
- Always be calm, empathetic, and confident.
- Avoid overly casual expressions or unnecessary details.
- Never guess β€” if unsure, say:  
  "I'm sorry, but I don't have that information right now. You can reach our hotline at +62 21 555 1234 for further assistance."

The information used in this prompt are purely fictional and are not based on any real data.

Then, grab the Reply Message Node and paste this into the reply message:

{{ state['nodes']['faq_node']['output']['messages'].content }}

Then connect the orchestrator_node to the faq_node, and the faq_response to the orchestrator_user_utterance. The flow should end up like this:

FAQ

Finishing Up

After creating the Orchestrator and the flows, now for the last step is to set up the Conditional Branches. From the orchestrator node, it will split to 3 conditional branches:

  • faq
state['nodes']['orchestrator_node']['output']['messages'].content == 'faq'
  • chitchat
state['nodes']['orchestrator_node']['output']['messages'].content == 'chitchat'
  • not_in_scope
state['nodes']['orchestrator_node']['output']['messages'].content == 'not_in_scope'

Then, for the last step, connect the orchestrator_node to the END node, set it as else conditional branch.

After everything's done, your flow should look like this:

Final Flow

Save your flow and head to the Flow Tester! If everything is right, then you should get a response in the flow tester!


πŸŽ‰ Congratulations!

You did it!

You've successfully completed the Hospital FAQs Bot Tutorial. By now, you should have a working bot that can:

  • Greet and confirm user identity
  • Detect intent between FAQ, chitchat, and out-of-scope topics
  • Answer hospital-related questions using an embedded knowledge base
  • Respond politely and guide the user through each interaction

What's Next?

Now that your bot is running, here are a few ways to improve it:

  • Expand your Knowledge Base: Add more FAQs about your hospital's departments, parking info, or insurance partners.
  • Enhance User Experience: Personalize responses, add emojis, or include quick reply buttons.
  • Test, Iterate, Improve: Use the Flow Tester in the platform to simulate different scenarios and refine your bot's accuracy.

Final Words

Building your own conversational AI assistant isn't easy β€” and you've just done it! Keep experimenting, keep learning, and remember: every great assistant starts with a simple flow.

"The best way to predict the future is to design it." β€” Buckminster Fuller