back to projects
// case study — project 03
Live in production

n8n Multi-Tool AI Agent

A single webhook endpoint that accepts any sales-ops request in plain English and lets an LLM decide which CRM, calendar, search, and Slack tools to invoke — in what order — to fulfill it.

n8nGroq Llama 3.3 70BHubSpot CRMGoogle CalendarSerperSlackGoogle SheetsRailwayPostgres
// problem & solution
The Problem

Fixed automation workflows break the moment a request doesn't match a predefined trigger. Sales-ops teams field open-ended requests — "look up this person, schedule a follow-up, ping the team" — that don't fit one rigid flow. Encoding every variant as its own workflow doesn't scale.

The Solution

A single AI agent with four tools. The LLM reads the natural-language request, decides which tools to call and in what order, executes them, and returns a plain-English confirmation. Adding a new capability is one new tool node with a description — no workflow rebuild.

// how it works

The agent loop, node-by-node.

Ten stages. One webhook in, one structured response out. Tool selection is the LLM's job, not the workflow's.

01

Webhook Receives Request

POST /webhook/ai-agent accepts { request, channel? }. n8n Webhook node configured for "Respond via Respond to Webhook Node" mode.

02

Input Validation

IF node checks $json.body.request is non-empty. Empty → returns 400 with a clean error. Non-empty → continues.

03

Variable Extraction

Set node creates clean references (userRequest, slackChannel, timestamp). Slack channel defaults to #make-testing if omitted.

04

AI Agent (Llama 3.3 70B)

Tools Agent node, OpenAI Chat Model sub-node pointed at api.groq.com, temp 0.1, max 2000 tokens. System prompt enforces no-hallucination + ISO 8601 Asia/Manila date formatting.

05

Tool Selection (ReAct)

Agent picks from 4 tools, each wired with $fromAI() parameter injection. ReAct loop: reason → call tool → read result → repeat until answer is complete.

06

Response Formatting

Set node extracts output, tool metadata, and success status from the agent’s result.

07

Audit Logging

Google Sheets Append Row to "n8n Agent — Request Log". Configured "Continue on Error" so logging failures never block the user response.

08

Final Response Builder

Second Set node assembles the clean JSON body { status, response, tools_used, timestamp }. Added during testing to dodge JSON-template escape issues.

09

Respond to Webhook

Sends the JSON body back to the caller with a 200.

10

Error Handler Workflow

Separate workflow with Error Trigger → Slack post. Wired as the main workflow’s Error Workflow. Fires on actual crashes, not graceful tool failures the agent handles itself.

// proof it works

Tested honestly. Failures owned.

Real test runs against the live agent. The wins are documented — and so are the deferred tests that didn't make it through the day's quota.

The no-hallucination test

Test 7 sent unknown@nowhere.com. Agent responded: "The contact for unknown@nowhere.com was not found in HubSpot." Zero invented details. Driven by an explicit system-prompt rule.

Ambiguity handling

Test 8 sent "create a task for the ACME account" with no specific contact. Agent refused to call tools and asked: "Which contact at ACME should I associate this with?" — a real product-design call, not a hack.

Natural-language → ISO 8601

"Send proposal next Monday 10am to john@startup.io" produced a Calendar event Mon Jun 1, 10:00–10:30 AM with the right attendee. Agent enriches metadata with HubSpot lookups when possible.

Result

7 clean passes · 1 partial · 0 fails · 5 deferred (Groq free-tier daily quota during back-to-back runs). Deferred tests are honestly labeled as not-run, not assumed-pass.

// inside the build

Every node, every side effect.

Real screens from the production workflow. Click any to expand.

Full n8n canvas — Webhook → Validate → Set → AI Agent → Set → Sheets → Respond
click to expand ⤢
Full n8n canvas — Webhook → Validate → Set → AI Agent → Set → Sheets → Respond
AI Agent node config — prompt source, expressions, and the connected tool slots
click to expand ⤢
AI Agent node config — prompt source, expressions, and the connected tool slots
HubSpot Contact Lookup tool — proves the "tool description IS the API" pattern
click to expand ⤢
HubSpot Contact Lookup tool — proves the "tool description IS the API" pattern
Live execution — all main nodes green, agent reports "2 items total" through the tools
click to expand ⤢
Live execution — all main nodes green, agent reports "2 items total" through the tools
Calendar event "Send proposal" — Mon Jun 1, 10:00–10:30 AM with attendee. NL→ISO 8601 in action.
click to expand ⤢
Calendar event "Send proposal" — Mon Jun 1, 10:00–10:30 AM with attendee. NL→ISO 8601 in action.
Calendar event "Call Lisa" — agent enriched metadata via HubSpot lookup
click to expand ⤢
Calendar event "Call Lisa" — agent enriched metadata via HubSpot lookup
Slack bot posting "mike@bigco.com is a hot lead" in #make-testing
click to expand ⤢
Slack bot posting "mike@bigco.com is a hot lead" in #make-testing
Google Sheets audit log — every request, tool calls, response, and status
click to expand ⤢
Google Sheets audit log — every request, tool calls, response, and status
Error handler Slack alert — Workflow / Execution ID / Time / Error / Failed node fields
click to expand ⤢
Error handler Slack alert — Workflow / Execution ID / Time / Error / Failed node fields
// tech breakdown

Each tool, its job.

Groq · Llama 3.3 70B Versatile
LLM brain
Routes intent to the right tool(s) and synthesizes the final answer. OpenAI-compatible API; picked over Gemini because Gemini required billing setup in our region.
Serper (Google Search)
Live web search
Returns top 5 Google results with answer boxes for current information — news, prices, comparisons.
HubSpot CRM
Contact lookup
POST /crm/v3/objects/contacts/search with $fromAI(‘email’) filter. Returns name, company, job title, phone.
Google Calendar
Follow-up scheduling
Native n8n node, OAuth2. Agent converts natural-language dates ("next Monday 10am") to ISO 8601 with +08:00 offset. Replaced HubSpot Tasks which isn’t available on the free tier.
Slack (Bot Token)
Team notification
Native n8n node. Channel name has leading # stripped because Slack’s API rejects it.
Google Sheets
Audit log
Append-row logging with Continue-on-Error so logging never blocks responses.
n8n + Railway
Orchestration & hosting
Self-hosted n8n via the Shinyduo/n8n-railway-updated template. Postgres for state. Asia/Manila timezone.
Request Router (bonus workflow)
Architecture pattern
Separate workflow with Webhook → Switch dispatching by event_type (lead / support / ops / fallback) to specialized sub-workflows. Real n8n architecture, not one monster flow.
// engineering decisions

The trade-offs, owned.

Two tools had to be swapped mid-build due to real-world constraints. Both swaps are documented in the repo — clients care more about real judgment calls than a clean linear story.

HubSpot Tasks → Google Calendar

Original design used HubSpot Tasks as the scheduling tool. Free-tier HubSpot doesn't expose the tasks.write scope. Swapped to Google Calendar mid-build — and got better UX (real invites with attendees) as a bonus.

Gemini 2.5 Flash → Groq Llama 3.3 70B

Gemini’s free tier required billing setup in our region. Switched to Groq’s OpenAI-compatible API. Same agent logic, no code changes — just a new base URL and model name.

Two-stage response builder

First Set node parses agent output. Second Set node builds the final JSON. This split was added after JSON-template escape issues with unpredictable agent text — small architectural call, big reliability win.

Bonus: thin router architecture

A separate Request Router workflow (Webhook → Switch by event_type → typed sub-workflows) ships in the repo. Production pattern, not one monster flow — adds the "senior engineer" signal beyond the agent itself.

// let's build

Need an agent like
this one?

Book a free 30-minute discovery call — or send me an email if you prefer. We'll figure out where an AI agent fits in your stack.

Book a Call