Skip to main content

Writing Flows

A flow in CALM is a structured sequence of steps describing only the business logic needed to complete a specific user goal—like blocking a credit card, changing an address, or adding a payee. By separating the business logic from the rest of the conversation, you get:

  • Clarity: Each flow focuses on a single job or outcome (e.g., “Block Credit Card”).
  • Reusability: Flow logic can be called from other flows or triggered on its own.
  • Maintainability: You can refine or change the flow logic without affecting the entire conversation design.

There are two types of flows in CALM: flows that you write to express your business logic and patterns or syste flows that come out of the box with CALM. Before we move on to explain how flows work, a word on these conversation patterns:

Conversation Patterns (System Flows)

In addition to the flows you write for your domain-specific tasks, Rasa provides patterns—pre-defined, reusable flows that handle “meta” conversational situations or repairs. For instance, if a user cancels a flow midway or wants to clarify a previously collected piece of information, a pattern steps in to handle this detour. These patterns work like templates: they can be triggered whenever relevant, so your assistant can handle common conversational patterns consistently.

Read more about customizing patterns under Customizing Pattenrs

How Do Flows Work?

Triggering Flows

CALM uses an LLM “command generator” prompt that contains the conversation history, the relevant flows, slots, and conversation patterns. Essentially, CALM leverages the LLM to parse the user’s request into structured commands, referencing all pertinent context—including conversation history, current state, and flow definitions. This approach ensures that when the user’s goal matches the description of a given flow, that flow will be triggered. Flows can also be:

  • Started by a direct NLU trigger (e.g., when a recognized intent maps to a flow).
  • Linked or called from inside another flow (for subflows or follow-up tasks).

Dialogue Stack

When a flow (or pattern) is activated, it’s placed on top of a dialogue stack (like stacking plates). The topmost flow is always active. Once that flow finishes or is canceled, the system returns to the next flow on the stack. This structure ensures that your assistant’s logic remains organized, even when users interrupt or pivot to new tasks.

How to Write Flows

Writing a flow in CALM involves capturing the essential steps to fulfill a user request without hardcoding every possible conversation path. You define flows as YAML in your flows.yml (or multiple YAML files), focusing on the business logic:

  1. Give the flow an ID and a clear description

    flows.yml
    flows:
    block_card:
    description: Block a user's credit card when requested
    steps: []
    • The description is critical for the LLM to understand when to pick this flow.
  2. Add the steps

    Each step specifies what your assistant should do:

    • Collect user information:

      flows.yml
      flows:
      block_card:
      description: Block a user's credit card when requested
      steps:
      - collect: card_number
      description: “The 16-digit card number to block”
    • Take an action (e.g., a custom action or a response):

      flows.yml
      flows:
      block_card:
      description: Block a user's credit card when requested
      steps:
      # ...
      - action: action_block_card_in_backend
    • Set or reset slots:

      flows.yml
      flows:
      block_card:
      description: Block a user's credit card when requested
      steps:
      # ...
      - set_slots:
      - card_number: null
    • Call or link other flows for subflows or follow-ups:

      flows.yml
      flows:
      block_card:
      description: Block a user's credit card when requested
      steps:
      # ...
      - call: authenticate_user_flow
      flows.yml
      flows:
      block_card:
      description: Block a user's credit card when requested
      steps:
      # ...
      - link: collect_feedback

    More information on different step types can be found on the reference page.

  3. Include branching if needed

    You can add simple conditional logic (like checking if a slot is filled or if a user is already authenticated):

    flows.yml
    flows:
    block_card:
    description: Block a user's credit card when requested
    steps:
    # ...
    - collect: user_authenticated
    next:
    - if: not slots.user_authenticated
    then:
    - action: utter_ask_for_login
    - link: authenticate_user_flow
  4. Leverage conversation patterns

    You don’t need to write custom branching logic for every possible user detour. Flows represent the business logic your assistant is supposed to drive throughout conversation. Instead, rely on patterns (built-in flows) to accommodate user detours.

Flows in CALM can do more than these basics—such as advanced branching, slot validation, or subflow calls. For a deeper look at each property, step type, or YAML configuration, check out the Flows reference.

Importance of Clear Descriptions

Each flow has a description that briefly explains what the flow accomplishes. The LLM reads these descriptions to decide which flow to start. A concise, specific description reduces errors in flow selection. For example:

Good: “Block a user’s credit card if they suspect fraud or want to freeze it”

Less useful: “Card blocking request”

Key Takeaways

  1. Flows define business logic: They are not full conversation scripts but the critical steps your organization wants to guarantee.
  2. LLMs + flows: The LLM remains flexible in interpreting user input and context, while flows make sure the assistant sticks to rules and processes.
  3. Write clear and detailed descriptions: They help the LLM reliably select the right flow at the right time.
  4. Use patterns for conversation repair: Don’t clutter your flow with every possible detour. Let patterns handle cancellations, clarifications, or other unexpected conversation turns.

With flows, you maintain control over complex processes while giving the LLM room to shine in adapting to user input. Start by mapping out the tasks your assistant must support, split them into distinct flows, and keep descriptions tight. That’s all you need to harness the best of both worlds: rigid business logic and flexible, human-like conversations.