Workflow Builder

Decision node

Ask a decision model typed questions about your data and get values you can branch on

Purpose

The Decision node asks a decision model a set of typed questions about your data, and writes one output field per question. It generates no text.

Each question has a type, and the type decides the shape of the answer:

  • probability gives you a number from 0 to 1 for a yes/no question
  • choice gives you exactly one of the named options you defined
  • score gives you a position on an ordered scale you defined

Use it for classification, routing, triage, scoring and sentiment. Anywhere you currently ask an agent for a label and then parse its reply, a Decision node gives you the value directly.

The Decision node is linear. It does not branch.

It has one outgoing connection, like an Agent node. To route on an answer, follow it with a Condition node reading the field the Decision node wrote.

This is deliberate. One Decision node can answer several questions at once, so a branching node would need a branch set per question. Separating the two keeps the answer and the routing independently readable.

How it differs from the other nodes

Agent nodeGuardrail nodeDecision node
ReturnsText, and tool callsA pass or a failTyped values
BranchesNoYes, two fixedNo
Questions per callOne promptOne policyUp to 32
ModelAny chat modelThe workflow defaultA decision-capable configuration
Output shapeFree text you parse_guardrailOne field per question

Configuration

A decision-capable LLM configuration, meaning one with Supports Decisions turned on and a decision endpoint set.

Chat-only configurations are refused at run time, not silently used. See Decision models for how to set one up.

The text describing what is being decided about. It supports {{variables}}:

Customer message: {{input.message}}
Account tier: {{input.tier}}

The model sees only this text. Anything the questions depend on has to be in here, so a question about the account tier needs the tier in the state.

Maximum 20,000 characters.

From 1 to 32 questions. Each has a key, a type, instructions, and criteria.

The key becomes the output field name, so it must be lowercase snake_case: start with a lowercase letter, then lowercase letters, digits or underscores, up to 64 characters.

See Question types below.

Question types

probability

A yes/no question answered as a number. The criteria say what a yes and a no mean.

{
  "is_urgent": {
    "type": "probability",
    "instructions": "Does this message convey urgency?",
    "criteria": {
      "true": "Explicitly time-sensitive, or the customer is escalating",
      "false": "No urgency expressed"
    }
  }
}

Output: <node-id>.is_urgent.probability, a number from 0 to 1.

choice

Pick exactly one option. The criteria map each option key to what that option means. You need 2 to 255 options.

{
  "intent": {
    "type": "choice",
    "instructions": "Which team should handle this?",
    "criteria": {
      "billing": "Payments, refunds, invoices",
      "technical": "Bugs, outages, integration errors",
      "sales": "Pricing questions and new business"
    }
  }
}

Outputs:

FieldContains
<node-id>.intent.choiceOne of your option keys
<node-id>.intent.probabilitiesThe probability of every option
<node-id>.intent.confidenceHow confident the model is

score

Place the state on an ordered scale. The criteria are the scale labels, lowest to highest. You need 2 to 255 labels.

{
  "frustration": {
    "type": "score",
    "instructions": "How frustrated does the customer sound?",
    "criteria": ["Calm", "Mildly annoyed", "Frustrated", "Very angry"]
  }
}

Outputs:

FieldContains
<node-id>.frustration.scoreA fractional index into the scale, where 0 is the first label
<node-id>.frustration.legendThe index-to-label mapping
<node-id>.frustration.probabilitiesThe probability of each label
<node-id>.frustration.confidenceHow confident the model is

Limits

LimitValue
Questions per node32
Options per choice, labels per score2 to 255
Option key length64 characters
Instructions length2,000 characters
One criterion length1,000 characters
State length20,000 characters

Routing on an answer

Follow the Decision node with a Condition node in variable mode.

Branch on a choice

Set variable_path to <node-id>.<question>.choice with the equals operator.

{
  "id": "route-by-team",
  "type": "conditional",
  "config": {
    "condition_type": "variable",
    "variable_path": "route.intent.choice",
    "branches": [
      { "operator": "equals", "compare_value": "billing", "goto": "billing-agent" },
      { "operator": "equals", "compare_value": "technical", "goto": "tech-agent" },
      { "operator": "equals", "compare_value": "sales", "goto": "sales-agent" }
    ]
  }
}

Branch on a probability

Use a numeric operator and a threshold.

{
  "condition_type": "variable",
  "variable_path": "route.is_urgent.probability",
  "branches": [
    { "operator": "greater_than", "compare_value": 0.7, "goto": "fast-track" }
  ],
  "default_goto": "normal-queue"
}

Branch on a score

A score is a fractional index, so compare it against an index, not a label. With the scale ["Calm", "Mildly annoyed", "Frustrated", "Very angry"], a score above 2 means at least "Frustrated".

{
  "condition_type": "variable",
  "variable_path": "triage.frustration.score",
  "branches": [
    { "operator": "greater_than", "compare_value": 2, "goto": "escalate" }
  ],
  "default_goto": "standard-reply"
}

Add a default branch to the Condition node. A decision model always returns one of your options, but a default branch protects you if someone later edits the option keys on the Decision node and forgets the Condition node.

Metadata

Alongside the answers, the node writes a _metadata object holding the model used, a decision ID, the latency in milliseconds, and the number of attempts. It appears in the execution timeline, which makes a slow or retried decision easy to spot. See Execution artifacts.

Retries

The node makes one bounded retry of its own, with a short backoff, rather than leaving it to the workflow engine.

Only failures classed as transient are retried: a 429, a 5xx, a timeout or a connection error. These fail immediately with no retry:

  • A bad configuration
  • A model that is not decision-capable
  • A project that is denied access to the model
  • An exceeded token quota

Examples

Example 1: Support triage in one call

One node answers three questions, and the Condition nodes after it route on two of them.

{
  "id": "triage",
  "type": "decision",
  "config": {
    "llm_config_id": "<a decision-capable configuration>",
    "state": "Customer message: {{input.message}}\nAccount tier: {{input.tier}}",
    "questions": {
      "intent": {
        "type": "choice",
        "instructions": "Which team should handle this?",
        "criteria": {
          "billing": "Payments, refunds, invoices",
          "technical": "Bugs, outages, integration errors",
          "sales": "Pricing questions and new business"
        }
      },
      "is_urgent": {
        "type": "probability",
        "instructions": "Does this message convey urgency?",
        "criteria": {
          "true": "Explicitly time-sensitive or escalating",
          "false": "No urgency expressed"
        }
      },
      "frustration": {
        "type": "score",
        "instructions": "How frustrated does the customer sound?",
        "criteria": ["Calm", "Mildly annoyed", "Frustrated", "Very angry"]
      }
    }
  },
  "next": "check-urgency"
}

Asking all three in one call costs one round trip. Three separate nodes would cost three.

Example 2: Score a document and route on the result

{
  "id": "score-cv",
  "type": "decision",
  "config": {
    "llm_config_id": "<a decision-capable configuration>",
    "state": "Role: {{input.role}}\n\nCandidate CV:\n{{cv-text.content}}",
    "questions": {
      "fit": {
        "type": "score",
        "instructions": "How well does this candidate match the role?",
        "criteria": ["No match", "Weak match", "Possible match", "Strong match"]
      },
      "has_required_certification": {
        "type": "probability",
        "instructions": "Does the CV evidence the certification the role requires?",
        "criteria": {
          "true": "The certification is named and current",
          "false": "Not named, or expired"
        }
      }
    }
  },
  "next": "shortlist-check"
}

Best practices

Troubleshooting

Next steps

MagOneAI© 2026 Magure, Inc.

On this page