Module 08 · ai · intermediate
Lesson 08 · AI Support Agent
Goal
Build an AI agent: a model that decides which tools to call to answer a customer, instead of following a fixed flow. You'll see the difference between a chatbot that talks and an agent that acts.
Prerequisites
- Module 06 (OpenAI credential, cluster nodes)
- Module 04 helps: tools are like sub-workflows the model can call
Concepts
- Chat Trigger: gives you a hosted chat page (public URL) and a chat API. Each browser session gets a
sessionId. - AI Agent: a root node that loops: read the conversation → maybe call a tool → read the result → answer. You control it with the system message.
- Tools: sub-nodes the agent can call. The tool description is how the model decides when to use it, so write it like documentation. With an input schema, the model fills in structured arguments.
- Memory: Simple Memory keeps the last N messages per
sessionId, so the agent can understand "when will it arrive?". - Grounding: the system message lists the only facts the agent may state. Everything else must come from tools. This is how you prevent made-up answers.
Build it
Step 1: Chat Trigger
Chat Trigger Support Chat: Make Chat Publicly Available on, mode Hosted Chat, initial message introducing what the bot can do. Options: title, subtitle, input placeholder.
Step 2: The agent
AI Agent Support Agent (source for prompt: Connected Chat Trigger Node). Options → System Message:
- Who it is (Brewlab support assistant) and today's date (
{{ $now.toFormat('yyyy-MM-dd') }}) - Store policies: shipping times, free-shipping threshold, returns, order ID format, human support hours. "The only facts you may state about the store."
- Rules: always use
lookup_orderfor order questions and never guess; usecreate_support_ticketfor damage, unresolved issues or "I want a human"; max 80 words; stay on topic.
Options → Max Iterations: 6.
Step 3: Model and memory
- Chat Model input → OpenAI Chat Model,
gpt-5-mini - Memory input → Simple Memory
Conversation Memory, context window 10
Step 4: Tools
Add two Code Tool sub-nodes. With Specify Input Schema → Generate From JSON Example, the model passes an object you read as query:
lookup_order: description "Look up an order by its ID (format A1234). Returns status, items, carrier, tracking number and estimated delivery…". Example input{"order_id": "A1001"}. The code holds a small demoordersobject and returnsJSON.stringify(...)of the match, or{found: false, message: …}.create_support_ticket: description "Create a ticket for the human support team. Use when…". Example input{"summary": "...", "customer_contact": "...", "priority": "normal"}. Returns a randomT-12345ticket ID.
Tool node names are the tool names the model sees, so keep them snake_case and descriptive. Tools must return a string.
Step 5: Try it
Publish, open the Chat Trigger's chat URL (http://localhost:5678/webhook/<id>/chat) and try:
- "Where is my order A1001?" → carrier + tracking
- "When will it arrive?" → uses memory
- "Order A1003 arrived damaged, I want a human" → ticket ID
Test it
./test/test.sh # chat page
WITH_CREDS=1 ./test/test.sh # 5-turn conversation: tools, memory, unknown order, hand-off, off-topic
LLM answers vary, so the tests check for key facts (tracking number, ticket ID format), not exact wording.
Common problems
- The agent invents order details: the tool description is too vague, or the system message doesn't say "never guess". Check the agent's Logs panel to see if the tool was called.
- "Tool output must be a string": return
JSON.stringify(...)from Code tools. - Forgets the previous message: memory isn't connected, or the client isn't sending the same
sessionId. - Simple Memory resets on restart: it lives in n8n's process memory. Use Postgres/Redis memory in production (Exercise 3).
- Long, chatty answers: put the word limit in the rules and lower the model's max tokens.