Skip to main content

Documentation Index

Fetch the complete documentation index at: https://koreai.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

Adding Structured Steps to Agents

Any agent can include a FLOW section with structured steps for deterministic, step-by-step control over the conversation path. Use steps for booking flows, order tracking, data collection wizards, and any workflow that needs predictable branching. Adding a FLOW section does not change what kind of agent it is — it is still the same agent, with structured steps added for parts of the conversation that benefit from deterministic control.

Create an Agent with a Flow

Define the flow

AGENT: Order_Tracker
GOAL: "Help customers look up and track their orders"

PERSONA: |
  Efficient order specialist. Provides clear status updates.
  Empathetic when orders are delayed.

TOOLS:
  lookup_order(order_id: string) -> {order_id: string, status: string, tracking_number: string, estimated_delivery: string}
    description: "Look up an order by ID"

  get_shipping_details(tracking_number: string) -> {carrier: string, status: string, location: string, history: object[]}
    description: "Get shipping and tracking information"

FLOW:
  entry_point: ask_order_id

  steps:
    - ask_order_id
    - lookup
    - show_status
    - shipping_details

  ask_order_id:
    REASONING: false
    GATHER:
      - order_id:
          prompt: "What is your order number? (Format: ORD-XXXXX)"
          type: string
          required: true
    THEN: lookup

  lookup:
    REASONING: false
    CALL: lookup_order(order_id)
    ON_SUCCESS:
      SET: tracking_number = result.tracking_number
      THEN: show_status
    ON_FAIL:
      RESPOND: "I could not find that order. Please check the number and try again."
      THEN: ask_order_id

  show_status:
    REASONING: false
    RESPOND: |
      Order: {{order_id}}
      Status: {{status}}
      Estimated delivery: {{estimated_delivery}}

      Would you like shipping details?
    ON_INPUT:
      - IF: input contains "yes" OR input contains "shipping" OR input contains "track"
        THEN: shipping_details
      - ELSE:
        THEN: COMPLETE

  shipping_details:
    REASONING: false
    CALL: get_shipping_details(tracking_number)
    ON_SUCCESS:
      RESPOND: |
        Carrier: {{carrier}}
        Current location: {{location}}
        Status: {{status}}
      THEN: COMPLETE
    ON_FAIL:
      RESPOND: "Shipping details are unavailable right now."
      THEN: COMPLETE

COMPLETE:
  - WHEN: order_status_shown == true
    RESPOND: "Is there anything else I can help with?"
Each step in this flow sets REASONING: false for deterministic execution — the agent follows the defined path rather than reasoning autonomously. The THEN keyword defines the next step. ON_INPUT branches based on user responses.

Key flow constructs

Entry point:
FLOW:
  entry_point: welcome
If omitted, the first step in the steps list is the entry point. Step list shorthand:
FLOW:
  welcome -> collect_info -> process -> confirm
This shorthand declares the step order. You still define each step separately. Tool calls with branching:
process_payment:
  REASONING: false
  CALL: charge_card(card_number, amount)
  ON_SUCCESS:
    RESPOND: "Payment of ${{amount}} processed."
    THEN: confirmation
  ON_FAIL:
    RESPOND: "Payment failed. Try a different card?"
    THEN: collect_payment
Conditional branching on input:
choose_action:
  REASONING: false
  ON_INPUT:
    - IF: input contains "track"
      THEN: tracking_flow
    - IF: input contains "cancel"
      THEN: cancel_flow
    - IF: input contains "return"
      THEN: return_flow
    - ELSE:
      RESPOND: "Please choose: track, cancel, or return."
      THEN: choose_action

Flow with SET assignments

calculate_total:
  REASONING: false
  SET: nights = checkout_date - checkin_date
  SET: total = room_price * nights
  RESPOND: "Your total for {{nights}} nights is ${{total}}."
  THEN: confirm_booking

Flow with MAX_ATTEMPTS

verify_identity:
  REASONING: false
  MAX_ATTEMPTS: 3
  ON_EXHAUSTED: escalate_to_human
  GATHER:
    - ssn_last_four:
        prompt: "Last 4 digits of your SSN?"
        type: string
        required: true
  CALL: verify_identity(ssn_last_four)
  ON_SUCCESS:
    THEN: authenticated
  ON_FAIL:
    RESPOND: "That did not match. Please try again."
    THEN: verify_identity

Troubleshooting

  • Flow skips a step: Verify every step has a THEN pointing to the correct next step. Missing THEN causes the flow to end.
  • User input not matched: ON_INPUT conditions are evaluated top-to-bottom. Place more specific conditions before general ones, and always include an ELSE branch.
  • Step runs twice: Check for circular THEN references. Use THEN: COMPLETE to exit the flow.

Mix Reasoning and Deterministic Steps

Within a single flow, you can combine deterministic steps (REASONING: false) with reasoning steps (REASONING: true). This lets you use deterministic control for data collection and confirmations, while leveraging LLM autonomy for open-ended research or analysis.

Add a reasoning step inside a flow

AGENT: Travel_Advisor
GOAL: "Help users plan trips by collecting preferences and then researching options autonomously"

PERSONA: "Knowledgeable travel advisor with a conversational style"

TOOLS:
  search_flights(origin: string, destination: string, date: string) -> {flights: object[]}
    description: "Search for available flights"
  search_hotels(destination: string, checkin: date, checkout: date) -> {hotels: object[]}
    description: "Search for available hotels"
  get_weather(location: string) -> {forecast: string, temp: number}
    description: "Get weather forecast for a destination"

FLOW:
  steps:
    - collect_preferences
    - research_options
    - present_plan
    - confirm

  collect_preferences:
    REASONING: false
    GATHER:
      - destination: required
        prompt: "Where would you like to go?"
      - travel_dates: required
        type: date
        prompt: "What are your travel dates?"
      - budget: required
        type: string
        prompt: "What is your budget range?"
    THEN: research_options

  research_options:
    REASONING: true
    GOAL: |
      Research travel options for {{destination}} on {{travel_dates}}
      within a {{budget}} budget. Search flights, hotels, and check weather.
      Compile a recommended itinerary with options at different price points.
    AVAILABLE_TOOLS: [search_flights, search_hotels, get_weather]
    EXIT_WHEN: itinerary_compiled == true
    MAX_TURNS: 8
    THEN: present_plan

  present_plan:
    REASONING: false
    RESPOND: |
      Here is your travel plan for {{destination}}:

      {{compiled_itinerary}}

      Would you like to proceed with booking, or adjust anything?
    ON_INPUT:
      - IF: input contains "book" OR input contains "yes"
        THEN: confirm
      - IF: input contains "change" OR input contains "adjust"
        THEN: collect_preferences
      - ELSE:
        THEN: present_plan

  confirm:
    REASONING: false
    RESPOND: "Booking confirmed. You will receive a confirmation email."
    THEN: COMPLETE

COMPLETE:
  - WHEN: booking_confirmed == true
    RESPOND: "Have a wonderful trip!"
The research_options step sets REASONING: true. Within that step, the LLM autonomously calls tools, reasons about results, and builds a response. EXIT_WHEN defines when the reasoning loop ends, and MAX_TURNS caps iterations.

Key properties for reasoning steps

PropertyPurpose
REASONING: trueEnable LLM autonomy for this step
GOALStep-specific goal (overrides agent-level goal)
AVAILABLE_TOOLSSubset of agent tools available in this step
EXIT_WHENCondition to exit the reasoning loop
MAX_TURNSMax reasoning cycles before forced exit (default: 10)
STEP_CONSTRAINTSAdditional constraints for this reasoning zone

Reasoning step with constrained tools

analyze_data:
  REASONING: true
  GOAL: "Analyze the customer's transaction history and identify spending patterns"
  AVAILABLE_TOOLS: [get_transactions, calculate_stats]
  STEP_CONSTRAINTS:
    - "Do not share raw transaction amounts -- only percentages and categories"
    - "Limit analysis to the last 90 days"
  EXIT_WHEN: analysis_complete == true
  MAX_TURNS: 5
  THEN: show_analysis

Deterministic collection followed by reasoning analysis

FLOW:
  steps:
    - collect_symptoms
    - diagnose
    - recommend

  collect_symptoms:
    REASONING: false
    GATHER:
      - symptoms: required
        prompt: "Describe the issue you are experiencing."
      - device_model: required
        prompt: "What device model are you using?"
      - os_version: required
        prompt: "What OS version is installed?"
    THEN: diagnose

  diagnose:
    REASONING: true
    GOAL: |
      Diagnose the technical issue based on:
      - Symptoms: {{symptoms}}
      - Device: {{device_model}}
      - OS: {{os_version}}
      Search the knowledge base and run diagnostics.
    AVAILABLE_TOOLS: [search_knowledge_base, run_diagnostic]
    EXIT_WHEN: diagnosis_found == true
    MAX_TURNS: 6
    THEN: recommend

  recommend:
    REASONING: false
    RESPOND: |
      Diagnosis: {{diagnosis}}

      Recommended fix: {{recommended_fix}}

      Would you like me to walk you through the steps?
    THEN: COMPLETE

Troubleshooting

  • Reasoning step ignores available tools: Verify tool names in AVAILABLE_TOOLS exactly match the names in the TOOLS section.
  • Reasoning step runs too long: Set MAX_TURNS to a lower value (3-5 for focused tasks, 8-10 for research tasks).
  • Reasoning step produces inconsistent results: Add STEP_CONSTRAINTS to narrow the reasoning scope, and use a specific GOAL rather than relying on the agent-level goal.

NLU Intent Classification

Define intents, entities, and categories in ABL to classify user messages and drive flow routing with structured understanding.

Define intents

Add an NLU section to your agent definition with intent patterns:
AGENT: Customer_Support
GOAL: "Route and resolve customer support requests"

NLU:
  intents:
    - name: order_status
      patterns:
        - "where is my order"
        - "track my package"
        - "order status"
        - "shipping update"
      examples:
        - "I ordered something last week and it hasn't arrived"
        - "Can you check on order #12345?"
        - "When will my delivery arrive?"
      entities: [order_id]

    - name: return_request
      patterns:
        - "return an item"
        - "send something back"
        - "refund request"
      examples:
        - "I want to return the shoes I bought"
        - "This product is defective, I need a refund"
      entities: [order_id, item_id, reason]

    - name: billing_inquiry
      patterns:
        - "billing question"
        - "charged incorrectly"
        - "payment issue"
      examples:
        - "I was double charged on my last order"
        - "Why is the amount different from what I expected?"
FieldDescription
nameUnique identifier for the intent
patternsShort phrases that characterize the intent
examplesFull example messages (provide 5-10 for best accuracy)
entitiesEntity types expected in messages matching this intent

Define entities

Entities extract structured data from user messages:
NLU:
  entities:
    - name: order_id
      type: pattern
      pattern: "#?\\d{5,8}"
      validation: "Must be 5-8 digits, optionally prefixed with #"

    - name: product_category
      type: enum
      values: ["electronics", "clothing", "home", "sports"]
      synonyms:
        electronics: ["tech", "gadgets", "devices"]
        clothing: ["clothes", "apparel", "fashion"]
        home: ["furniture", "household", "kitchen"]

    - name: date
      type: date

    - name: amount
      type: number

    - name: location
      type: location

    - name: feedback
      type: free_text
Supported entity types:
TypeExtractsConfiguration
enumPredefined values with synonymsvalues, synonyms
patternRegex-matched stringspattern, validation
dateDate expressions (“tomorrow”, “March 15”)Built-in
numberNumeric valuesBuilt-in
locationPlace names and addressesBuilt-in
free_textUnstructured text spansBuilt-in

Define categories for routing

Categories group intents for high-level routing in supervisors:
NLU:
  categories:
    - name: sales
      patterns:
        - "buying"
        - "purchasing"
        - "pricing"
        - "discount"

    - name: support
      patterns:
        - "help"
        - "problem"
        - "issue"
        - "broken"

    - name: account
      patterns:
        - "password"
        - "login"
        - "profile"
        - "settings"
Use categories in supervisor routing:
HANDOFF:
  - TO: Sales_Agent
    WHEN: intent.category == "sales"

  - TO: Support_Agent
    WHEN: intent.category == "support"

  - TO: Account_Agent
    WHEN: intent.category == "account"

Configure NLU models

Specify which models handle intent classification:
NLU:
  models:
    fast: "gpt-4o-mini"
    balanced: "claude-sonnet-4-5-20250929"
  • fast — used for initial classification when speed matters (e.g., routing decisions)
  • balanced — used when accuracy is more important than latency (e.g., entity extraction)

Enable embeddings for semantic matching

For more robust intent matching beyond keyword patterns:
NLU:
  embeddings:
    enabled: true
    provider: "openai"
    model: "text-embedding-3-small"
    threshold: 0.75
    cacheTtl: 3600
Embeddings compute semantic similarity between the user message and intent examples, catching paraphrases and variations that patterns miss.

Use intents in flow steps

Reference classified intents in flow step conditions:
route_by_intent:
  REASONING: false
  THEN:
    - IF: intent.name == "order_status"
      THEN: check_order
    - IF: intent.name == "return_request"
      THEN: start_return
    - ELSE:
      THEN: general_help

Load intents from external files

For large intent libraries, reference an external file:
NLU:
  intents:
    - name: order_status
      examplesFile: "training/order_status_examples.txt"

Configure evaluation logging

Track NLU accuracy for continuous improvement:
NLU:
  evaluation:
    logPredictions: true
    abTest: true
    confidenceThreshold: 0.7
  • logPredictions — log every intent classification for later analysis
  • abTest — compare fast vs. balanced models and log accuracy differences
  • confidenceThreshold — minimum confidence score to accept a classification (below this, the agent asks for clarification)

Troubleshooting

  • Low classification accuracy: Add more examples (10+ per intent). Ensure examples cover diverse phrasings. Enable embeddings for semantic matching.
  • Intent confusion between similar intents: Make patterns more distinct. Add negative examples. Increase the confidence threshold.
  • Entity not being extracted: Check the pattern regex for entity type pattern. For enum entities, add more synonyms.
  • Classification too slow: Use the fast model for routing decisions. Cache embedding results with cacheTtl.

Common Patterns

Start deterministic, add reasoning where needed. Begin with all steps set to REASONING: false for predictable behavior, then selectively enable REASONING: true on steps that benefit from LLM autonomy (research, analysis, open-ended conversation). Always include ELSE branches. Every ON_INPUT block should have an ELSE branch to handle unexpected input. Without it, unmatched input leaves the user stranded. Use COMPLETE_WHEN for data gates. In GATHER steps, COMPLETE_WHEN ensures the flow does not advance until all required data is collected. Keep reasoning steps focused. Give each reasoning step a specific GOAL and a limited AVAILABLE_TOOLS list. Broad goals with many tools lead to unpredictable behavior. Combine NLU with flow routing. Use NLU intent classification at the entry point to route users into the correct flow, then use deterministic steps within each flow.