Build a Local AI Ticket Router

Route support tickets with local AI, n8n, and no cloud API key.

Introduction

30 Second Summary

Support teams often receive a clear outage report beside a routine account question in the same inbox. Without a reliable sorting process, the issue blocking every checkout can wait behind less urgent requests.

In this project, you will build a private support-ticket workflow in n8n. A local Gemma 3 model running through Ollama transforms each submission into structured AI output for automatic routing.

What You'll Build

You submit a checkout outage through the browser form and see it emerge in the urgent queue with an AI-written reply saved beside the original message.

By the end of this project, you'll have:

  • A browser intake form that starts your local workflow whenever you submit a customer issue.
  • A structured triage result that shows category, urgency, summary, and draft_reply for every ticket.
  • A visible audit trail where urgent and routine tickets appear in an n8n Data Table with their processing history.
  • Secret Mission: Add a 0.75 confidence threshold that diverts uncertain classifications to human_review.

Are there any prerequisites?

You'll need a Mac running macOS Sonoma 14 or newer with at least 4 GB of RAM.

The initial downloads need internet access and enough storage for Docker Desktop resources plus the 806 MB model.

Before We Start

Before the hands-on work begins, take a moment to define who your support workflow serves. This gives every routing decision a clear purpose when urgent requests need faster attention.

Set Up Your Local Automation Stack

Your ticket router needs a workflow engine that can receive each request. It also needs a local model that can interpret the issue.

Docker Desktop gives n8n a local runtime with persistent storage. Ollama provides the model service that n8n reaches from that runtime.

In this step, get ready to:
  • Install Docker Desktop for Mac.
  • Run n8n Community 2.47.3 with persistent local storage.
  • Prepare Ollama 0.40.16 with the gemma3:1b model.
Install and Start Docker Desktop

n8n runs inside a Container managed by Docker Desktop. The container isolates the automation engine while a Docker volume preserves your workflows between restarts.

Check Your Mac First

Docker Desktop needs at least 4 GB of RAM. Ollama requires macOS Sonoma 14 or newer.

An M-series Mac uses the Apple silicon installer. A Mac with an Intel processor uses the Intel installer.

  • Choose the tab that matches the current Docker Desktop state on your Mac.

✔️ Docker Desktop is running

Docker Desktop is already available for the n8n installer.

  • Leave Docker Desktop running in the background.

ⓧ Docker Desktop is installed but closed

  • Press Cmd+Space to open Spotlight.
  • Type Docker into Spotlight.
  • Press Enter to open Docker Desktop.
  • Wait until Docker Desktop reports that its engine is running.

Docker Desktop can now accept commands from Terminal.

ⓧ Docker Desktop is not installed

Docker provides separate installers for Apple silicon Macs and Intel Macs. The correct installer matches the processor in your Mac.

The disk image shows the Docker icon beside the Applications destination.

  • Drag the Docker icon into Applications.

The displayed agreement can feel formal. Personal learning fits Docker Desktop's free-use terms.

  • Review the displayed agreement.
  • Accept the displayed agreement.
  • Press Cmd+Space to open Spotlight.
  • Type Docker into Spotlight.
  • Press Enter to open Docker Desktop.
  • Wait until Docker Desktop reports that its engine is running.

Docker Desktop is now ready to host your local automation engine.

  • Confirm the Docker command-line tools are available by running these checks in Terminal:
docker --version
docker compose version

What Do These Checks Prove?

  • The first command confirms Terminal can reach the Docker command-line interface.
  • The second command confirms the Docker Compose plugin is available for the n8n setup.

You should see one version line for Docker. You should also see one version line for Docker Compose.

Docker Commands Not Working?

  • Confirm Docker Desktop is still open.
  • Wait for the Docker engine to finish starting.
  • Quit Terminal after a fresh Docker installation. Reopen Terminal before running the checks again.

Help me fix my Docker Desktop command-line setup.

That is the first layer ready. Docker can now host the n8n services that power your visual workflow.

Install n8n Community

The n8n one-line installer creates the local configuration files for your automation engine. It also creates persistent Docker storage for workflows and execution history.

  • Choose the tab that matches the n8n installation currently on your Mac.

✔️ I see version 2.47.3

Your existing n8n installation matches the version used in this project.

  • Keep the existing n8n services running.

ⓧ I see an older version

The official upgrade keeps your workflows and settings. It updates the n8n services to the current release.

  • Return to Terminal.
  • Upgrade the n8n installation on your Desktop by running these commands:
cd ~/Desktop
curl -fsSL https://get.n8n.io | sh -s -- --upgrade

What Does This Upgrade Do?

The first command moves Terminal to your Desktop. The second command updates the n8n service versions while preserving the data in the existing Docker volume.

The upgrade output should identify n8n 2.47.3 when the services start.

ⓧ n8n is not installed

The first install can take a few minutes while Docker downloads the n8n images. Quiet periods during the download are normal.

  • Create the local n8n installation on your Desktop by running these commands:
cd ~/Desktop
curl -fsSL https://get.n8n.io | sh

What Does This Installation Create?

  • The installer creates the n8n folder on your Desktop.
  • The n8n/compose.yml file defines the local Docker services.
  • The n8n/.env file stores the generated configuration.
  • The Docker volume preserves n8n data across container restarts.

The completed output should identify n8n 2.47.3. It should also show http://localhost:5678 as the local address.

  • Press Cmd+Space to open Spotlight.
  • Type Safari into Spotlight.
  • Press Enter to open Safari.
  • Enter http://localhost:5678 in the address bar.
  • Press Enter to load the local n8n page.

The first visit shows the local owner setup form. This account controls the n8n instance stored on your Mac.

Your owner credentials stay with this local n8n instance. A unique password keeps the local editor protected without reusing an important account password.

  • Enter your name in the owner setup form.
  • Enter an email address you can access.
  • Create a unique password for this local account.
  • Submit the form to create the local owner account.

You should see the n8n workflow editor in Safari. Your local automation engine is running with persistent Docker storage.

n8n Page Not Loading?

  • Confirm the installer finished before refreshing Safari.
  • Confirm Docker Desktop is still running.
  • Check that the address uses port 5678.

Help me reach my local n8n editor.

Install Ollama and Run Gemma 3

Ollama runs the language model natively on macOS. The n8n container reaches that model through Docker Desktop's connection to the Mac host.

  • Choose the tab that matches the Ollama installation currently on your Mac.

✔️ Ollama 0.40.16 is installed

Your installed Ollama version matches the project environment.

  • Keep the Ollama application running.
  • Allow Ollama to create its command-line link if prompted.

ⓧ An older Ollama version is installed

  • Visit the official Ollama release page.
  • Download Ollama.dmg for version 0.40.16.
  • Open the downloaded Ollama.dmg file.

The disk image shows the Ollama application ready to move into Applications.

  • Drag Ollama into the Applications folder.
  • Approve replacing the older application if macOS asks.

Applications now contains the project version of Ollama.

  • Press Cmd+Space to open Spotlight.
  • Type Ollama into Spotlight.
  • Press Enter to open Ollama.
  • Allow Ollama to create its command-line link if prompted.

ⓧ Ollama is not installed

  • Visit the official Ollama release page.
  • Download Ollama.dmg for version 0.40.16.
  • Open the downloaded Ollama.dmg file.

The mounted disk image contains the Ollama application.

  • Drag Ollama into the Applications folder.
  • Press Cmd+Space to open Spotlight.
  • Type Ollama into Spotlight.
  • Press Enter to open Ollama.

Ollama starts its local model server from the macOS menu bar.

  • Allow Ollama to create its command-line link if prompted.

Ollama normally listens on 127.0.0.1:11434. Docker-hosted n8n needs the service to listen on an address reachable from its container.

Use a Trusted Local Network

Binding Ollama to 0.0.0.0:11434 makes the service listen on the Mac's network interfaces. A trusted local network keeps that exposure limited.

  • Set the Ollama host binding for the macOS application by running this command in Terminal:
launchctl setenv OLLAMA_HOST "0.0.0.0:11434"

What Does This Command Do?

The command stores OLLAMA_HOST in the macOS launch environment. Ollama reads that value when the application starts.

The binding lets the n8n container reach Ollama through Docker Desktop later in the project.

  • Quit Ollama from its macOS menu bar control.
  • Press Cmd+Space to open Spotlight.
  • Type Ollama into Spotlight.
  • Press Enter to restart Ollama with the new binding.

Before you check the server, what do you expect a reachable Ollama service to return about its version?

  • Confirm the Ollama server is reachable by running:
curl http://localhost:11434/api/version

What Does This Check Prove?

The request contacts the local Ollama server on port 11434. A JSON response proves the server is accepting requests.

You should see a JSON response containing version 0.40.16.

No Ollama Version Response?

  • Confirm the Ollama application is running in the macOS menu bar.
  • Repeat the application restart after setting OLLAMA_HOST.
  • Restart Terminal after allowing Ollama to create its command-line link.

Help me restore my local Ollama server.

The first model run downloads an 806 MB artifact before opening the prompt. Depending on your connection, the download can take several minutes.

Before you start the model, do you expect the response to come from your Mac or an external AI service?

  • Start the local Gemma 3 model by running:
ollama run gemma3:1b

What Happens During the First Run?

  • Ollama downloads the gemma3:1b artifact if it is missing.
  • Ollama loads the model on your Mac.
  • The interactive prompt accepts messages for local generation.
  • Enter hello at the model prompt.
  • Read the model's response in Terminal.

You should see a text reply from Gemma 3. The prompt remains ready for another local message.

Gemma 3 Not Responding?

  • Confirm Ollama is still running in the macOS menu bar.
  • Confirm your Mac has enough free storage for the 806 MB model artifact.
  • Keep Terminal open while the first model download finishes.

Help me run Gemma 3 locally with Ollama.

Your Local Stack Checkpoint

Docker Desktop for Mac is running.

n8n Community 2.47.3 is running locally at http://localhost:5678 with persistent Docker storage and a local owner account.

Ollama 0.40.16 is running natively on macOS at 0.0.0.0:11434.

The gemma3:1b model is installed and available locally.

Your local automation stack is ready to receive work. Next, you will create the browser form that captures your first support ticket.

Capture and Store a Support Ticket

Your local automation stack is live. The n8n editor is ready for its first workflow.

A useful automation needs a repeatable event as its starting point. It also needs a visible record of the data that arrived.

In this step, you will build a browser form that captures a raw support ticket. You will save each submission in an n8n Data Table before adding AI.

In this step, get ready to:
  • Create a support intake form with a required Form Trigger.
  • Create a Data Table for the raw ticket fields.
  • Verify a test submission appears as a stored support ticket.
Create the support intake form

A Form Trigger generates a browser form. Each submission starts the workflow with the values entered by the customer.

  • Switch back to the n8n editor in Safari.
  • Use the workflow creation control in the left sidebar to start a blank workflow.

You should see an empty workflow canvas where you can add the first node.

  • Replace the default workflow name in the top-left corner with Local AI Support Triage.
  • Click the add-node control on the blank workflow canvas.

The node search panel opens beside the canvas.

  • Enter n8n Form Trigger in the node search.
  • Select n8n Form Trigger from the results.

The Form Trigger now sits at the start of your workflow. Its settings panel controls the form that customers see.

What does the Form Trigger do?

The Form Trigger creates a form page for collecting information. Submitting that form sends the entered values into the workflow as one item.

  • Use the form-element control in the Form Trigger settings to add the first field.
  • Enter Customer name in Field Label.

The form preview now includes a field labelled Customer name.

  • Enter customer_name in Field Name.
  • Select Text for Element Type.

This field now produces a text value named customer_name for downstream nodes.

  • Turn on Required Field for the customer name field.

The first field is now required before the form can be submitted.

  • Use the form-element control to add the second field.
  • Enter Email in Field Label.

The form preview now includes an Email field.

  • Enter email in Field Name.
  • Select Email for Element Type.

The second field now captures an email value under the name email.

  • Turn on Required Field for the email field.

The email field is now required for every ticket.

  • Use the form-element control to add the third field.
  • Enter Issue in Field Label.

The form preview now includes a field for the customer's issue.

  • Enter issue in Field Name.
  • Select Textarea for Element Type.

The larger text area gives customers space to describe their problem.

  • Turn on Required Field for the issue field.

Your form now requires a customer name, an email address, and an issue description. Every submission produces the three raw fields needed by the workflow.

Can't see all three form fields?

  • Confirm the Form Trigger contains three separate form elements.
  • Check that each Field Name uses lowercase letters with the underscores shown above.
  • Confirm Required Field is enabled on every element.

Ask for help checking the form configuration: Why is my n8n Form Trigger missing one of the required ticket fields?

Build the support ticket table

The form creates workflow data in memory. A Data Table preserves that data inside n8n so you can inspect each ticket after the workflow finishes.

  • Select the Data tables tab from the n8n project navigation.

You should see the project area where n8n stores workflow-generated tables.

  • Use the table creation control to start a new Data Table.
  • Enter support_tickets in Name.

The new table now has its permanent name. Next, its columns define the shape of each saved row.

  • Use Add Column to create a String column named customer_name.
  • Use Add Column to create a String column named email.

The first two columns now match the first two values produced by the form.

  • Use Add Column to create a String column named issue.
  • Confirm the table using the creation control in the dialog.

Good progress. Your support_tickets table now has String columns for customer_name, email, and issue.

Why do the names match?

Matching field names create a clear contract between the form and the table. Each incoming value has one obvious destination when you configure the insert action.

Connect the form to storage

The form can now collect a ticket. The table can now store one. A Data Table node connects those two parts by inserting every submission as a new row.

  • Switch back to the workflow canvas for Local AI Support Triage.
  • Use the Form Trigger output connector to add a Data Table node.

A connection line should now run from the Form Trigger to the Data Table node.

  • Set Resource to Row.
  • Set Operation to Insert.

The node is now configured to create one new row whenever it receives an item.

  • Choose support_tickets as the destination table.
  • Select Map Each Column Manually as the mapping method.

The node now shows inputs for the three columns in your table.

  • Map the Form Trigger's customer_name output to the customer_name column.
  • Map the Form Trigger's email output to the email column.

The first two incoming values now have explicit table destinations.

  • Map the Form Trigger's issue output to the issue column.

Why map each column manually?

Manual mapping makes the path of each form value visible. This gives you a clear data contract before later steps add routing fields and AI-generated values.

  • Select Execute Workflow to start a test execution.

Safari opens the generated test form. The workflow waits for one submission.

  • Enter Avery Lee in the Customer name field.
  • Enter avery@example.com in the Email field.

The first two required fields now contain your test customer details.

  • Enter I cannot download my latest invoice in the Issue field.

Before you submit the form, which three values do you expect the table to preserve?

  • Use the button at the bottom of the form to submit the ticket.

The workflow execution view returns. You should see successful execution indicators on the Form Trigger and Data Table nodes.

  • Select the Data tables tab from the project navigation.
  • Select the support_tickets table.

You should see a new row containing Avery Lee, avery@example.com, and I cannot download my latest invoice.

You have built the complete intake loop. A browser submission now becomes a persistent raw support ticket that you can inspect after execution.

No row in support_tickets?

  • Confirm the Form Trigger is connected directly to the Data Table node.
  • Check that the Data Table node uses Row for Resource.
  • Check that the Data Table node uses Insert for Operation.
  • Confirm each manual mapping points to the form field with the same name.

Get help tracing the missing row: Why did my n8n form submission fail to create a row in support_tickets?

Your workflow now turns a browser submission into a stored raw ticket. Next, you will add the first routing decision and test it with a realistic outage report.

Expose Keyword Routing Limits

Your intake workflow already turns a browser form submission into a saved row in an n8n Data Table. That gives every support request a durable starting point.

The next goal is deterministic routing with a Switch node. A literal keyword check only recognizes the text it was given.

A real outage can omit that expected word. In this step, you will watch the ticket take the wrong branch.

In this step, get ready to:
  • Add a queue column for each routing result.
  • Build urgent and routine branches around a keyword rule.
  • Submit an outage report that exposes the rule's routing limit.
Add the queue column and keyword rule

A queue value records the branch selected for each ticket. Adding the column first gives the workflow a visible place to save that decision.

  • Switch back to the n8n project from earlier.
  • Select Data tables in the project navigation.
  • Open support_tickets.

You should see the existing customer_name, email, and issue columns from your earlier test.

  • Select Add Column in the table controls.
  • Enter queue as the column name.
  • Choose String as the column type.
  • Use the confirmation button in the column dialog to create the column.

The support_tickets table now shows queue beside the three original columns. Your table is ready to record each routing result.

  • Return to the Local AI Support Triage workflow canvas.
  • Select the connection line between the Form Trigger and the existing Data Table insert.
  • Press Delete to remove that connection.
  • Select the plus connector on the Form Trigger.
  • Enter Switch in the node picker.
  • Select the Switch node.

The Form Trigger now feeds into the Switch. The table insert remains disconnected until both routing branches are ready.

  • Select Rules as the Switch mode.
  • Set the first rule's data type to String.
  • Map issue from the Form Trigger output into the first comparison value.
  • Select contains as the comparison.
  • Enter urgent as the second comparison value.
  • Set the fallback behavior to Extra Output.

The Switch now exposes one output for matching tickets. It also exposes a fallback output for everything else.

Can't see both Switch outputs?

  • Confirm that the Switch uses Rules mode.
  • Check that issue is mapped into the rule's first comparison value.
  • Confirm that the fallback behavior uses Extra Output.

Use this prompt if the branch layout still looks different: Help me configure an n8n Switch node with one contains rule and an Extra Output fallback.

Assign a queue on each branch

Each branch needs to add a queue value without discarding the submitted ticket. This data mapping preserves the original form fields for storage.

  • Select the plus connector on the Switch match output.
  • Add an Edit Fields (Set) node.
  • Select Manual Mapping in the Edit Fields node.

The match branch now has controls for adding fields to tickets that contain the keyword.

  • Configure the node to retain every input field.
  • Add a String field named queue with the value urgent.

The match branch now preserves the submitted ticket. It adds queue with the value urgent.

  • Select the plus connector on the Switch fallback output.
  • Add another Edit Fields (Set) node.
  • Select Manual Mapping in this Edit Fields node.

The fallback branch now has its own field controls. This branch handles every ticket that misses the keyword rule.

  • Configure the fallback node to retain every input field.
  • Add a String field named queue with the value routine.

The fallback branch preserves the submitted ticket. It adds queue with the value routine.

  • Connect the urgent Edit Fields output to the existing Data Table insert node.
  • Connect the routine Edit Fields output to the same Data Table insert node.

Both branches now converge on the table insert. Only the branch selected by the Switch sends an item during each execution.

  • Open the existing Data Table insert node.
  • Keep the manual mappings for customer_name, email, and issue.
  • Add a manual mapping from the incoming queue field to the table's queue column.

Your canvas now follows a complete trigger, decision, label, and storage path. The next execution reveals whether the decision reflects the ticket's meaning.

Missing fields at the table insert?

  • Confirm that both Edit Fields nodes retain every input field.
  • Check that each branch creates queue as a String field.
  • Verify that both Edit Fields outputs connect to the existing Data Table insert.

Use this prompt if a mapping is still missing: Help me preserve my Form Trigger fields through both Edit Fields branches.

Submit an outage without the keyword

The routing rule is ready for a realistic test. The issue describes a blocked payment without using the word the Switch expects.

Before you test the rule, which branch do you think will receive the outage ticket? Keep that prediction in mind.

  • Select Execute Workflow in the workflow editor.
  • Enter Avery Chen in the customer_name field on the generated form.
  • Enter avery@example.com in the email field.
  • Enter Our checkout is down and nobody can pay in the issue field.
  • Submit the form.

The workflow follows the fallback branch. The routine Edit Fields node receives the ticket even though the message describes an urgent outage.

This failure is intentional

The Switch checked whether the original issue contained the literal word urgent. The checkout message never used that word.

The rule can compare text without understanding meaning. That limitation makes the outage look routine.

  • Select the executed Switch node on the workflow canvas.
  • Confirm that one item left through the fallback output.
  • Select the routine Edit Fields node.
  • Confirm that its output shows queue as routine.

The execution trace proves that the keyword rule chose the fallback path. Now check that the same mistake reached persistent storage.

  • Return to the project's Data tables tab.
  • Open support_tickets.
  • Locate the row whose issue is Our checkout is down and nobody can pay.
  • Confirm that the row's queue value is routine.

You have reproduced the routing failure the workflow was designed to expose. The stored row shows that literal matching missed the outage's urgent meaning.

Did the wrong branch run?

  • Confirm that the submitted issue matches Our checkout is down and nobody can pay exactly.
  • Check that the Switch compares the original issue field against urgent.
  • Verify that the Switch comparison uses contains.

Use this prompt if your execution takes a different path: Help me inspect why my keyword Switch did not send this outage ticket to the fallback output.

That was the useful failure this workflow needed. Next, you will replace literal matching with local AI triage that can interpret the ticket's meaning.

Add Local AI Triage

Your keyword Switch sent a checkout outage to the routine queue because the message never used the word urgent. That result exposed the limit of literal text matching in n8n.

A local LLM can classify the meaning of the issue. In this step, you will connect the workflow to Ollama and turn its response into predictable fields.

In this step, get ready to:
  • Connect n8n to Ollama through a tested local credential.
  • Build an AI Triage chain that sends each submitted issue to gemma3:1b.
  • Require structured category, urgency, summary, and draft reply fields.
Connect n8n to Ollama

n8n runs inside Docker Desktop. Ollama runs directly on your Mac. The Docker host address gives the workflow a route to the model server.

  • Select the Form Trigger node in the workflow from earlier.
  • Keep its existing connection to the keyword Switch in place.
  • Drag a second connection from the Form Trigger output to an empty area of the canvas.
  • Search for Basic LLM Chain.
  • Select Basic LLM Chain to add the node.
  • Rename the new node to AI Triage.
  • Use the language model attachment on AI Triage to add an Ollama Chat Model.

Why use the Docker host address?

Inside the n8n container, localhost points back to that container. The address http://host.docker.internal:11434 reaches the Ollama server running on your Mac.

Docker Desktop configures host.docker.internal for this connection. Your earlier Ollama host setting makes the server reachable through it.

  • Choose the option to create a credential from the Ollama Chat Model credential selector.
  • Name the credential Local Ollama.
  • Set Base URL to http://host.docker.internal:11434.
  • Leave the optional API key empty.
  • Test the connection from the credential window.

You should see a successful connection result. That connection is now the bridge between your visual workflow and the model running on your Mac.

Connection test failing?

  • Confirm the Ollama application from earlier is still running.
  • Check that the Base URL is exactly http://host.docker.internal:11434.
  • Restart Ollama if the application was open before you configured its host binding.

Help me troubleshoot the connection from Docker-hosted n8n to native Ollama on my Mac.

Create the AI triage prompt

A Basic LLM Chain sends one bounded prompt to the model. This keeps the classification focused on the submitted support issue.

Why a Basic LLM Chain?

This workflow needs one classification response from one input. A Basic LLM Chain fits that fixed path without the memory or tool choices of an AI Agent.

The smaller scope also makes structured parsing more reliable. Every response has one clear job.

  • Select the AI Triage node.
  • Set the prompt source to Define below.
  • Replace the contents of Prompt (User Message) with this prompt:
You classify support tickets for a customer support team.
Read the submitted ticket issue.
Return category, urgency, summary, and draft_reply.
Set urgency to urgent for a service outage, blocked payment, security incident, or another issue that prevents core use.
Use routine for all other tickets.
Ticket issue:

What does this prompt do?

  • The opening line gives the model one support-triage role.
  • The field list defines the information that downstream nodes need.
  • The urgency rule turns business impact into a consistent classification boundary.
  • The final line creates the place where the submitted issue value enters the prompt.
  • Place the cursor after Ticket issue: in the prompt.
  • Insert the incoming issue field from the Form Trigger input.
  • Select the attached Ollama Chat Model.
  • Set Model to gemma3:1b.
  • Set Sampling Temperature to 0.1.

Before you test the chain, consider whether the model will spot the outage even though the issue never uses the word urgent.

  • Select Execute Workflow to open the generated test form.
  • Enter Jordan Lee in customer_name.
  • Enter jordan@example.com in email.
  • Enter Our checkout is down and nobody can pay in issue.
  • Submit the test form.
  • Return to the workflow editor after the execution finishes.
  • Open the output of the AI Triage node.

You should see a response that interprets the checkout problem as an urgent outage. The semantic classification works even though the original keyword is absent.

No useful model response?

  • Confirm the AI Triage node receives an item from the Form Trigger.
  • Check that the submitted issue appears after Ticket issue: in the resolved prompt.
  • Confirm the attached model shows gemma3:1b with a Sampling Temperature of 0.1.

Help me debug why my Basic LLM Chain is not classifying the submitted issue.

Enforce structured AI output

Downstream routing needs structured output with stable field names. A Structured Output Parser uses a JSON example to define those names and their data types.

  • Select the AI Triage node.
  • Turn on Require Specific Output Format.
  • Add a Structured Output Parser through the displayed output parser attachment.
  • Select Generate from JSON Example as the schema option.
  • Define the four required fields by pasting this JSON example:
{
  "category": "payments",
  "urgency": "urgent",
  "summary": "Checkout is unavailable and customers cannot pay.",
  "draft_reply": "We are investigating the checkout outage and will share an update soon."
}

What does this JSON example do?

  • The category field names the broad type of support problem.
  • The urgency field gives deterministic routing nodes a value to inspect.
  • The summary field compresses the original issue into a short description.
  • The draft_reply field gives the support team a response they can review.
  • The example values tell the parser that every required field contains a String.

Before you run the final check, consider whether the same outage will now appear as four separate fields with urgency set to urgent.

  • Select Execute Workflow to open another test form.
  • Enter Jordan Lee in customer_name.
  • Enter jordan@example.com in email.
  • Enter Our checkout is down and nobody can pay in issue.
  • Submit the test form.
  • Return to the workflow editor after the execution finishes.
  • Open the output of the AI Triage node.

You should see category, urgency, summary, and draft_reply as structured fields. The urgency value should be urgent for the checkout outage.

Missing structured fields?

  • Confirm Require Specific Output Format remains turned on.
  • Check that the Structured Output Parser is attached to the output parser connection on AI Triage.
  • Compare the parser keys with category, urgency, summary, and draft_reply.

Help me fix missing or malformed structured output from my AI Triage chain.

Your local model now turns an unstructured customer message into predictable triage data. Next, you will use those fields to route tickets deterministically and preserve the complete result.

Route, Store, and Publish the Workflow

Your n8n AI Triage Basic LLM Chain now interprets support requests as structured fields. Its checkout test correctly classified a blocked payment as urgent.

That classification only becomes useful when the rest of the workflow acts on it. The old keyword rule still decides which queue receives the ticket.

In this step, you will route tickets using structured urgency. You will save complete records before publishing the Form Trigger for production submissions.

In this step, get ready to:
  • Extend support_tickets with four AI output columns.
  • Route each ticket from AI-generated urgency into a stored queue.
  • Publish the form workflow for traceable production submissions.
Add AI fields and update routing

An n8n Data Table keeps structured results available after an execution ends. Deterministic routing converts the model's urgency value into a predictable queue decision.

  • Switch back to the n8n project from earlier.
  • Select Data tables in the project sidebar.
  • Select the existing support_tickets table.
  • Create a String column named category with Add Column in the table toolbar.
  • Create a String column named urgency with Add Column in the table toolbar.

The table now shows both new columns beside the fields you created earlier.

  • Create a String column named summary with Add Column in the table toolbar.
  • Create a String column named draft_reply with Add Column in the table toolbar.

Your table now has all eight columns needed for a complete triage record.

The Switch node already has urgent and fallback outputs. Its rule now needs to inspect the structured result from AI Triage.

  • Return to the Local AI Support Triage workflow.
  • Replace the connection entering the Switch so AI Triage feeds it.
  • Select the existing Switch node.
  • Set the Rules input to the urgency field from AI Triage.
  • Confirm that the String comparison still uses contains.
  • Confirm that the comparison value remains urgent.
  • Confirm that Extra Output still leads to the routine Edit Fields node.
  • Confirm that the matching output still leads to the urgent Edit Fields node.

The Switch rule now displays urgency as its input. The original issue text no longer controls the branch.

Before you test the updated route, do you expect the checkout outage to enter the urgent branch or the routine branch?

  • Select Execute Workflow to load the test form.
  • Enter Morgan Lee in customer_name.
  • Enter morgan@example.com in email.
  • Enter Our checkout is down and nobody can pay in issue.
  • Submit the test form.

You should see the urgent branch highlighted in the execution. The urgent Edit Fields node should output queue as urgent.

That closes the routing gap from the earlier keyword test. The ticket now reaches the correct queue because the model understood its meaning.

Ticket Still Entering the Routine Queue?

  • Confirm that AI Triage connects directly to the Switch input.
  • Check that the Switch reads urgency from the structured AI output.
  • Check that the comparison value is the lowercase literal urgent.

Help me diagnose my AI urgency route.

Map and test the complete record

A complete row needs the customer's original form values. It also needs every AI field plus the queue assigned by the active branch.

One shared insert node can receive either branch. Manual mapping lets that node collect values from each earlier stage.

  • Select the existing Data Table insert node after the urgent Edit Fields branch.
  • Connect the routine Edit Fields output to the same insert node.

The shared insert node should now have one incoming connection from each queue branch.

Removing the redundant insert node only cleans up duplicate workflow wiring. Your existing table rows stay untouched.

  • Remove the unused Data Table insert node from the routine branch.
  • Select the shared Data Table insert node.
  • Confirm that Resource is set to Row.
  • Confirm that Operation is set to Insert.
  • Confirm that the selected table is support_tickets.
  • Select Map Each Column Manually.

Why Use Manual Mapping?

The customer fields come from the Form Trigger. The structured result comes from AI Triage.

The queue comes from whichever Edit Fields branch ran. Manual mapping preserves those sources in one stored record.

  • Map the customer_name column from the Form Trigger output.
  • Map the email column from the Form Trigger output.

The first two mappings should display their Form Trigger sources in the insert node.

  • Map the issue column from the Form Trigger output.
  • Map the category column from the AI Triage output.

The insert node now preserves the original request plus its AI category.

  • Map the urgency column from the AI Triage output.
  • Map the summary column from the AI Triage output.

The next two mappings capture the model's routing decision plus its condensed explanation.

  • Map the draft_reply column from the AI Triage output.
  • Map the queue column from the current Edit Fields input.

All eight table columns should now show a mapped source.

Before you run both forms, which branch should receive the checkout outage? Which branch should receive an account-detail request?

  • Select Execute Workflow to load an urgent test form.
  • Enter Jordan Kim in customer_name.
  • Enter jordan@example.com in email.
  • Enter Our checkout is down and nobody can pay in issue.
  • Submit the urgent test ticket.

You should see the urgent branch run. The shared insert node should complete after the urgent Edit Fields node.

  • Select Execute Workflow to load a routine test form.
  • Enter Casey Patel in customer_name.
  • Enter casey@example.com in email.
  • Enter Please change the email address on my account in issue.
  • Submit the routine test ticket.

You should see the routine branch run. The shared insert node should complete after the routine Edit Fields node.

  • Return to Data tables in the project sidebar.
  • Select support_tickets.
  • Inspect the two latest rows.

The urgent row should show queue as urgent. The routine row should show queue as routine.

Each row should contain the original ticket fields. Each row should also contain all four AI-generated fields.

You have the complete audit trail now. Both routing outcomes can be traced from form submission to stored result.

Stored Row Missing Fields?

  • Check that the three original fields reference the Form Trigger output.
  • Check that the four structured fields reference the AI Triage output.
  • Check that queue references the active Edit Fields input.

Help me fix an incomplete support ticket row.

Publish and inspect the production run

Publishing makes the current workflow version live. Its Production URL gives real form submissions a stable entry point.

  • Return to the Local AI Support Triage workflow.
  • Select Publish in the workflow editor.
  • Select the Form Trigger node.
  • Record the displayed Production URL: your Form Trigger Production URL.
  • Switch back to Safari from earlier.
  • Open a new browser tab.
  • Paste your Form Trigger Production URL into the address bar.
  • Press Enter to load the production form.
  • Enter Taylor Reed in customer_name.
  • Enter taylor@example.com in email.
  • Enter A security incident is blocking every account login in issue.

Before you submit the production form, which queue do you expect this security incident to reach?

  • Submit the production form.
  • Return to the workflow in n8n.
  • Select the Executions tab.
  • Select the latest production execution.

You should see the Form Trigger feed AI Triage. The Switch should highlight the urgent branch.

The urgent Edit Fields node should assign queue as urgent. The shared Data Table insert should complete successfully.

  • Return to Data tables in the project sidebar.
  • Select support_tickets.
  • Inspect the latest production-form row.

The latest row should contain Taylor's original form values. It should also contain the AI-generated fields with queue set to urgent.

Your production automation is working from end to end. A browser submission now becomes a classified ticket with a traceable queue decision.

Production Submission Missing From Executions?

  • Confirm that you selected Publish after completing the workflow edits.
  • Confirm that Safari loaded the Form Trigger's Production URL.
  • Inspect the shared Data Table insert mappings if the execution succeeds with an incomplete row.

Help me trace a missing production submission.

Your local support router is published with structured storage plus deterministic branching. The optional Secret Mission pushes this workflow safeguard further.

Secret mission

Add a Human-Review Confidence Gate

Your workflow already routes clear support tickets automatically. This extension adds a numeric confidence gate that sends uncertain classifications to human review. You will store the score with every new triage record before publishing the updated workflow.

Clean Up Your Resources

Choose whether to keep your local stack running, pause it for later, or remove the n8n project state. This personal-learning setup has no ongoing usage charges, but Docker Desktop requires a paid subscription for larger-enterprise commercial use.

Resources you used:

  • A local n8n Community instance with its persistent Docker volume.
  • The published Local AI Support Triage workflow with its active Form Trigger Production URL.
  • The Local Ollama credential.
  • The support_tickets Data Table with its saved triage records.
  • The ./n8n/compose.yml file with the ./n8n/.env setup file.

Keep everything running

No action is needed. Choose this if you are still testing your support-ticket router or demonstrating its production form.

  • Leave Docker Desktop running while you use the production form.
  • Leave Ollama running while AI Triage calls gemma3:1b.
  • Keep your Mac awake while someone submits a ticket through the local form.

The n8n Community instance has no ongoing usage charge for this personal-learning setup. Local Ollama calls also have no usage charge.

Pause - I'll come back to this later

Shut down the local services to free system resources while preserving your workflow data.

  • Stop n8n while preserving its persistent data by running this command:
docker compose -f ./n8n/compose.yml down

What does this command do?

The command stops the n8n containers. It keeps the persistent Docker volume that holds your workflow data.

Terminal returns to its prompt when n8n has stopped. The production form becomes unavailable while the containers are down.

n8n Did Not Stop?

  • Confirm Docker Desktop is running before you try the command again.
  • Help me diagnose why my local n8n containers are not stopping.
  • Quit Ollama from the macOS menu bar.

When you return, Ollama must be running before AI Triage can call the local model.

  • Start n8n again by running this command:
docker compose -f ./n8n/compose.yml up -d

What does this command do?

The command starts the existing n8n containers in the background. Your persistent volume restores the saved workflow state.

  • Restart Ollama before submitting another ticket.
  • Return to the Form Trigger Production URL in Safari.

You should see the support form load again. This confirms that the saved local stack is available.

Production Form Still Unavailable?

  • Confirm Docker Desktop is running before you retry the start command.
  • Wait for n8n to finish starting before you refresh the production form.
  • Help me restore my local n8n production form.

Delete - I don't want to use this again

Remove the local n8n project state if you want to start fresh.

Deletion Is Permanent

Deleting the Docker volume removes the published workflow. It also removes the credential, execution history, and Data Table records.

The Form Trigger Production URL stops working after removal. Save anything you want to keep before continuing.

  • Remove the n8n containers, persistent volume, and local setup folder by running these commands from the directory that contains ./n8n:
docker compose -f ./n8n/compose.yml down -v
rm -rf ./n8n

What do these commands remove?

The first command stops the n8n containers. It deletes the persistent volume that stores n8n data.

The second command removes the local setup folder. This includes the Compose file and environment configuration.

  • Check the location that previously contained ./n8n.

You should no longer see the n8n folder in that location.

  • Return to the Form Trigger Production URL in Safari.

The support form no longer loads. This confirms that the published local workflow has been removed.

Cleanup Command Did Not Finish?

  • Confirm Docker Desktop is running before you retry the first cleanup command.
  • Confirm you are running the commands from the directory that contains ./n8n.
  • Help me remove my local n8n Docker resources safely.

Docker Desktop, Ollama, and the gemma3:1b model remain installed after this cleanup. They stay available for future local projects.

Nice Work!

Nice Work!

You made it! Your local support-ticket router is published in n8n with structured triage powered by Ollama.

You've learned how to:

  • Build a browser-triggered intake that preserves each customer_name, email, plus issue in a local ticket record.
  • Connect Docker-hosted n8n to Ollama so gemma3:1b returns structured model output with category, urgency, summary, plus draft_reply.
  • Publish a deterministic router that separates urgent tickets from routine tickets using AI-assigned urgency. Every production run remains available through execution history.
  • Secret Mission: Add a confidence gate that sends values below 0.75 to human_review. Confident tickets continue through the automatic urgent or routine route.

Ready to quiz yourself?