Skip to main content
PreviewAgent Builder is currently in preview and may change before general availability.
In this tutorial, you build a mortgage advisor chatbot — a Chat Driven conversational AI app that guides users through mortgage product selection. The app detects what the user wants, answers questions from a knowledge base, collects financial data across conversation turns, and generates personalized recommendations using a combination of AI and deterministic business rules. What you will build:
  • A main Chat Driven workflow that uses an Intent Classification Agent to route messages
  • Built-in session memory that carries financial data across conversation turns
  • A knowledge base Q&A handler that answers mortgage questions from uploaded documents
  • A data collection handler that extracts user financial data from free-text messages
  • A personalized offer generator using hybrid AI extraction + business rule calculations
  • A small talk responder and fallback handler
AI node types used: Intent Classification Agent, Text Generation, Custom Agent (with Knowledge Base and Send as Chat Reply) Patterns demonstrated: Intent classification, Knowledge base RAG, Hybrid AI + business rules, Session state management

Architecture overview

The app is a Chat Driven workflow that uses an Intent Classification Agent to classify each user message and route it to the right handler. Each intent maps to a separate output branch on the node, eliminating the need for a Condition node. Each handler terminates in a Custom Agent node with Send as Chat Reply enabled, which delivers the response directly to the Chat component and updates session memory.
In Chat Driven workflows, responses are delivered to the user by Custom Agent nodes with Send as Chat Reply enabled, not by the End Flow node. The End Flow node has no body configuration.

Data model

In a Chat Driven workflow, the Start node provides Chat Session ID, User Message, and an optional UI Flow Context as dedicated input fields — you reference them as ${sessionId}, ${userMessage}, and ${context} in downstream nodes. These are not keys you declare in the data model.

mainChat data model

The mainChat workflow does not need any chat-specific keys in its data model — everything comes from the Start node fields and from handler subworkflow outputs.

answerPersonalisedOffer data model

Built-in session memoryChat Driven workflows retrieve the last 30 turns of the conversation automatically and send them to the model in full. Any Custom Agent node with Use conversation memory enabled receives this history as LLM context, so data mentioned in earlier turns (age, income, loan amount) is available to later turns without manual persistence. See Session state management and Chat-driven workflows — Session memory.

Prerequisites

Before starting, make sure you have:
  • Access to a FlowX Designer workspace with AI Platform enabled
  • Familiarity with creating workflows in FlowX
  • A Knowledge Base data source with mortgage-related documents uploaded (see Step 4)

Step 1: Build the main orchestration workflow

Create a workflow named mainChat and select Chat Driven as the workflow type.
Create workflow modal with Chat Driven selected as the workflow type
The workflow type cannot be changed after creation. Make sure you select Chat Driven — Output Focused workflows cannot be used from the Chat component.

Review the Start node

The Start node is created automatically with three fields:
  • Chat Session ID — a UUID populated by the Chat component at runtime (referenced as ${sessionId})
  • User Message — the user’s text message (referenced as ${userMessage})
  • UI Flow Context — optional JSON object passed from the UI (referenced as ${context})
No Start body configuration is needed in Chat Driven workflows.

Add the Intent Classification Agent

From the node palette, drag an Intent Classification Agent node (under AI Agents) onto the canvas and connect it to the Start node. Configure the node: User Message: ${userMessage} Intents:
Intent labels are read by the classifier LLM as guidance — richer phrasing reduces misclassifications. If a plain label like Offer routes user phrases like “Give me recommendations” to the wrong branch, broaden the text to cover more phrasings (as shown above). Turn on Include Reason for Selection while tuning to see the classifier’s rationale for each decision.
Response Key: intentResult The If No Intent Matches branch is a default output port that fires when the classifier can’t confidently match any intent. It’s always present on the node — you just need to connect it to the fallback handler in Step 2.
Intent Classification Agent node showing intents list with the If No Intent Matches default branch
Use conversation memory: OFF for this tutorial. The Intent Classification Agent also supports the Use conversation memory toggle — leave it OFF if each user message should be classified on its own. Turn it ON only if you want the classifier to resolve ambiguous follow-ups (“yes”, “the first one”, “tell me more”) against prior conversation turns.
Use conversation memory toggle on the Intent Classification Agent
Toggle Include Reason for Selection ON while tuning intent labels. When enabled, the agent includes a rationale explaining why it chose each intent in its response — useful for diagnosing misclassifications. Turn it off once the intents are stable.
Each intent creates a separate output port on the node. When the agent classifies a message, the workflow continues along the matching branch — no Condition node needed.

Connect handler nodes to each branch

Add the following nodes and connect each to its corresponding intent output:
Each branch delivers its response directly via a Custom Agent node with Send as Chat Reply enabled. No response-normalizer script is needed — the Chat component receives each reply as Markdown and persists it to session memory automatically.

Add the End Flow node

Add an End Flow node from the palette (it is not auto-created for Chat Driven workflows) and connect every handler branch to it. The End Flow node has no body configuration — responses are already delivered by the Custom Agent nodes upstream.

Step 2: Build the inline handlers

The Greetings and No Match branches are handled by Custom Agent nodes placed directly in the mainChat workflow — no subworkflow needed.
Shared Custom Agent settings for this tutorialEvery Custom Agent in mainChat uses the same two defaults:
  • Use only referenced values as input: ON — keeps each call scoped to the values referenced with ${...} in the Context field and reduces token usage. See Custom Agent node for details.
  • Include Task for Prompt Suggestions: OFF — turn ON only if you want AI-generated follow-up prompts shown in the Chat component (5.7.0+). See Custom Agent node.
Only the Use conversation memory and Send as Chat Reply toggles vary per handler, so those are called out on each node below.

answerSmalltalk (Custom Agent)

Add a Custom Agent node named answerSmalltalk to the Greetings branch. Instructions:
Context:
The Instructions field is static — the node rejects ${...} references inside it with “This field is static. Use Context for dynamic values.” Put dynamic values in the Context field, which accepts mixed text and ${...} keys. This split applies to every AI node in this tutorial.
Use conversation memory: ON — lets the agent see the last few turns so it can tie small talk back to anything the user already shared. Send as Chat Reply: ON — sends the response to the Chat component as Markdown and hides the Response Schema field.
With Use conversation memory enabled, you do not need to interpolate conversation history into the prompt manually. FlowX retrieves the last 30 turns of the conversation and attaches them to the LLM call automatically.

fallback (Custom Agent)

Add a Custom Agent node named fallback on the No Match branch. Instructions:
Context:
Use conversation memory: OFF — the fallback response is self-contained. Send as Chat Reply: ON.

Step 3: Build the data input handler

The Intent 4 branch combines a Script node (for deterministic data extraction) followed by a Custom Agent node (to confirm what was captured and send the chat reply). Script nodes cannot send chat replies on their own — only Custom Agent nodes can.

3a: handleDataInput Script

Add a Script node named handleDataInput on the Intent 4 branch. Since the Intent Classification Agent already routed the message here, the script can assume the user is providing personal data and uses simple string matching to extract values.
Workflow Script nodes run Python in a sandbox: import statements and file or OS access are blocked. Note that Python business rules in BPMN processes are more restricted (on the default provider there, avoid enumerate() and .get() with a default value) — the script below sticks to basic loops and in checks so it runs unchanged in either context.
Script node (Python):
handleDataInput Script node in the mainChat workflow with the Python data-extraction script
The age/duration disambiguation checks whether the word after a number + “years” is “old”. For example, “30 years old” sets age = 30, while “25 years” sets loan_duration = 25.

3b: Confirmation Custom Agent

Add a Custom Agent node after handleDataInput to deliver the confirmation as a chat reply. Instructions:
Context:
Use conversation memory: OFF — the Script already captured everything it needed from the current message. Send as Chat Reply: ON.
This two-node handler keeps extraction deterministic (Script) while letting the LLM phrase the response naturally (Custom Agent). You could also send ${confirmationText} verbatim from a simpler Custom Agent without an LLM rewrite — trade off naturalness against token cost.

Step 4: Build the knowledge base Q&A handler

The KB question branch is a single Custom Agent node placed inline in the mainChat workflow (on the Intent 3 branch) with a Knowledge Base attached and Send as Chat Reply enabled.

Set up the Knowledge Base

1

Create a Knowledge Base data source

In the Integration Designer, add a new Knowledge Base data source. Name it something descriptive like MortgageKnowledgeBase.
2

Upload mortgage documents

Upload PDF documents covering:
  • Mortgage product sheets (rates, terms, eligibility criteria)
  • FAQ documents (common questions about mortgages, DTI, LTV)
  • Regulatory guides (required documents, application process)
Wait for automatic chunking and vector indexing to complete.
3

Test queries

Use the Knowledge Base test interface to verify that queries like “What is DTI?” and “What documents do I need?” return relevant chunks.
For detailed Knowledge Base setup, see the Knowledge Base integration documentation.

Configure the Custom Agent node

Add a Custom Agent node named knowledgeBaseQA on the Intent 3 branch. Enable the Knowledge Base setting and select your MortgageKnowledgeBase data source. Retrieval parameters: Instructions:
Context:
Use conversation memory: ON — so the agent can resolve follow-ups like “what about the second one?” against the previous answer. Send as Chat Reply: ON.
Without explicit grounding rules in the prompt, the LLM may fall back to its general training data and produce inaccurate mortgage information. Always include the “ONLY from knowledge base” instruction.
For more details on this pattern, see Knowledge base RAG.

Step 5: Build the personalized offer handler

This is the most complex handler. It implements the Hybrid AI + business rules pattern — alternating between AI nodes and deterministic Script nodes. Because this branch benefits from structured intermediate data (calculation results, ranked products) that the other branches do not need, implement it as an Output Focused subworkflow called from mainChat, which returns a reportText string.
Send as Chat Reply and Use conversation memory are Chat Driven only. Custom Agent nodes inside an Output Focused workflow do not expose those toggles — you cannot deliver a chat reply from inside a subworkflow. Instead, the subworkflow returns reportText via End Flow, and a separate Custom Agent in mainChat (on the Offer branch, after the Subworkflow node) handles the chat reply.
Create a workflow named answerPersonalisedOffer with Output Focused as the workflow type.
answerPersonalisedOffer subworkflow showing Start, Text Understanding, financialCalculations Script, scoringRanking Script, and End Flow nodes
In mainChat, connect a Subworkflow node on the Intent 2 branch that calls answerPersonalisedOffer, with Response Key offerOutput. Pass ${userMessage} as the userMessage input. Then add a Custom Agent after the Subworkflow node to deliver the chat reply — see Step 5e below.

Step 5a: AI understanding (extract and filter)

Add a Text Understanding node that extracts the client’s financial profile from their message and filters the product catalog. Instructions:
Context:
Response Schema:
Response Key: filteredProducts

Step 5b: Business rules (financial calculations)

Add a Script node (JavaScript) for deterministic financial calculations. These must be auditable and reproducible.
AI node output in Script nodes arrives as Java HashMaps, not JavaScript objects. Use .get("key") to access properties and .size() / .get(index) for lists. Standard JavaScript methods like Object.keys() and JSON.stringify() do not work on these objects.
The alternating AI-then-rules structure creates a natural audit trail. For any final recommendation, you can trace exactly which AI filtered the products and which formula computed the financial results.

Step 5c: Business rules (scoring, ranking, and report)

Add a second Script node (JavaScript) that scores products, ranks them, and generates the recommendation report text. The script writes the report to reportText, which the terminal Custom Agent node reads.
The report is generated as plain text in the Script node rather than fully inside an LLM node. This keeps the numbers deterministic and auditable. The terminal Custom Agent (Step 5d) rephrases the report into a friendly chat reply.

Step 5d: End Flow (output the report)

Add an End Flow node after the scoring Script. Configure the End Flow body to expose reportText as a workflow output:
That’s it for the subworkflow — save answerPersonalisedOffer.

Step 5e: Terminal Custom Agent in mainChat (Send as Chat Reply)

Switch back to mainChat. On the Offer branch, after the Subworkflow node, add a Custom Agent node. This is where the chat reply is delivered. Instructions:
Context:
Use only referenced values as input: ON (default) Use conversation memory: OFF — the report is fully self-contained. Send as Chat Reply: ON. Include Task for Prompt Suggestions: OFF. Connect this Custom Agent to the End Flow node on mainChat.
If you prefer zero LLM paraphrasing for compliance reasons, keep only ${offerOutput.reportText} in the Context field and set the Instructions to: “Return the system-prepared report verbatim.” The chat reply will then be the exact report string.

Step 6: Connect to the chat UI

You have two options for wiring mainChat to a UI. Pick one.
Chat-Driven UI Flow hosting the mortgage advisor Chat component
1

Create a Chat-Driven UI Flow

Go to UI Flows and create a new UI Flow, selecting Chat-Driven as the experience type. Set mainChat in the AI Conversational Workflow field.
Create UI Flow modal with Chat-Driven selected as the experience type
2

Add a Chat component

Any Chat component added to this UI Flow uses mainChat by default — no per-component configuration needed.
3

Test the chat

Click Run to preview the UI Flow and interact with the chatbot.

Option B: Chat component per UI Flow page

1

Create a UI Flow

Create a standard UI Flow (e.g., chat) and add a Page.
2

Add a Chat component

Drag a Chat component onto the page. In the component settings, set the Workflow property to mainChat.
3

Test the chat

Click Run to preview.
For details on configuring chat experiences with built-in session memory, see Chat-driven workflows. For the Chat component reference, see Chat component.

Step 7 (optional): Share captured data across turns

By default, the answerPersonalisedOffer subworkflow re-extracts all financial data from the current user message — it does not see conversation memory (memory is a Chat Driven feature, and the subworkflow is Output Focused). This means users must provide age, income, loan amount, and duration in a single Offer request. If you want the subworkflow to reuse data the user shared in earlier turns (captured by handleDataInput), pass clientProfile from mainChat into the subworkflow.
1

Declare clientProfile as an input on the subworkflow

In answerPersonalisedOffer, open the Data Model panel. Add clientProfile (OBJECT) if not already there, and toggle Input Parameter ON.
2

Map clientProfile on the Subworkflow node in mainChat

In mainChat, open the Subworkflow node on the Offer branch. Map the clientProfile input: clientProfile ← ${clientProfile}. The clientProfile key on the Chat Driven workflow is populated by handleDataInput on previous Data Input turns.
Chat Driven workflow data does not persist across workflow invocations — each new user message starts a fresh workflow. To carry clientProfile across turns, write it to a persistent store (e.g., a FlowX Database keyed by Chat Session ID) from handleDataInput, and read it back at the start of each mainChat invocation. See Session state management for the pattern.
3

Update the Text Understanding node to prefer existing data

In the subworkflow’s Step 5a node, extend the Context field with the prior profile:
Then add this to the Instructions:
4

Update Script 5b to merge sources

In the financial-calculations script, fall back to input.clientProfile when the AI extraction didn’t find a field. Example guard for income:
Apply the same fallback for loanAmount and loanDuration.
This extension trades simplicity for multi-turn reliability. The base tutorial keeps the subworkflow stateless on purpose — it’s easier to reason about and easier to test in isolation. Add this extension only when your users consistently spread financial data across multiple turns.

Testing

1

Test the mainChat workflow directly

Open mainChat and click Run Workflow. In the test modal, provide:
  • Chat Session ID — any valid UUID (e.g., 550e8400-e29b-41d4-a716-446655440000). Reuse the same UUID across test runs to verify multi-turn memory.
  • User Message — the message to test (e.g., What is a debt-to-income ratio?).
The Chat Session ID must be a valid UUID. A plain string like test-session-1 causes a runtime error: Invalid UUID string.
2

Test the full chat flow

Run the UI Flow that embeds the Chat component. With built-in session memory, financial details captured in earlier turns are available to later turns — the user can spread data across messages:
Chat UI showing mortgage recommendation report with eligibility assessment and ranked product recommendations
3

Test edge cases


What you learned

In this tutorial, you built a full-featured Chat Driven app that demonstrates:
  • Chat Driven workflow basics — dedicated Start node fields, ${userMessage} interpolation, simplified End Flow (guide)
  • Built-in session memory — multi-turn context without manually persisting conversation history
  • Intent classification and routing — using an Intent Classification Agent to classify messages and route to handler branches automatically (pattern)
  • Send as Chat Reply — delivering responses to the Chat component directly from Custom Agent nodes
  • Knowledge base RAG with re-ranking — grounding answers in uploaded documents using a Custom Agent with Knowledge Base, hybrid search, and re-rank (pattern)
  • Hybrid AI + business rules — combining AI qualitative filtering with deterministic financial calculations for auditable recommendations (pattern)

Extending the chatbot

Once the base app works, these Chat Driven features can add polish and context-awareness:
  • AI Triggers (5.7.0+) — let different UI Flow pages launch mainChat with parameterized starting messages, e.g., “Help me refinance order $” from an account page
  • Navigate in UI Flow node — add an action branch that opens a mortgage application form with pre-filled data when the user accepts a recommendation
  • Conversation Context (5.7.0+) — pass UI state (active customer ID, current page) to the workflow via the Start node’s UI Flow Context field
  • Knowledge Base metadata filters — as the KB grows beyond a handful of documents, tag each store (e.g., topic: basics | application | faq) and pass metadata filters to the KB Q&A Custom Agent to scope retrieval to the right subset. The 5.7.0 query builder supports typed operators and AND/OR grouping.

Next steps

Chat-driven workflows

Full reference for Chat Driven workflows, AI Triggers, and session memory

AI patterns

Deep-dive into the patterns used in this tutorial

Node types reference

Detailed configuration reference for all AI node types

Knowledge Base integration

Create and manage Knowledge Bases for RAG
Last modified on July 8, 2026