Result: By the end of this guide you'll have an n8n-driven workflow that pulls answers from your documentation via Retrieval-Augmented Generation (RAG), delivers them through a chat widget, and automatically creates a ticket when confidence is low. The system runs 24/7, reduces repetitive human effort, and ensures every ambiguous request lands in your ticketing tool for a human agent.
What is AI customer support? AI customer support is a software layer that interprets user questions, matches them to existing knowledge (FAQ, manuals, internal docs), and returns concise answers - falling back to a human ticket when the AI is unsure.
What you need
| Tool | Plan / Price | Role |
|---|---|---|
| OpenAI GPT-4o (or GPT-3.5-turbo) | Pay-as-you-go, $0.005 / 1 K tokens (check OpenAI pricing) | LLM for answer generation |
| n8n (self-hosted Docker) | Free (Community Edition) | Orchestrates webhook, LLM call, vector search, escalation |
| Qdrant (self-hosted) | Free (open source) | Vector store for document embeddings |
| Your existing knowledge base (Markdown, Confluence, etc.) | - | Source files for embedding |
| Ticketing system webhook (e.g., Zendesk, Freshdesk) | - | Receives escalated tickets |
| Docker & Git | - | Runtime environment |
Estimated build time: 6-8 hours (including data ingestion, workflow testing, and UI tweak).
Step-by-step build
Prepare the docs
Export your support documents to plain Markdown. Place them in a folder calleddocs/. Each file will become a separate vector entry.-
Create embeddings
- Run the official OpenAI embedding endpoint (
text-embedding-3-large). - Store each resulting vector in Qdrant under the collection
support_vectors. Example Python script (run once):
- Run the official OpenAI embedding endpoint (
pip install openai qdrant-client tqdm
import os, json, glob
from openai import OpenAI
from qdrant_client import QdrantClient
from tqdm import tqdm
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
qdrant = QdrantClient(url="http://localhost:6333")
qdrant.recreate_collection(
collection_name="support_vectors",
vectors_config={"size": 1536, "distance": "Cosine"},
)
for path in tqdm(glob.glob("docs/*.md")):
with open(path) as f:
text = f.read()
emb = client.embeddings.create(
model="text-embedding-3-large", input=text
).data[0].embedding
qdrant.upsert(
collection_name="support_vectors",
points=[
{
"id": os.path.basename(path),
"vector": emb,
"payload": {"content": text, "source": path},
}
],
)
What this does: Generates a dense vector for each document and stores it in Qdrant for fast similarity search.
- Deploy n8n
docker run -d --name n8n \
-p 5678:5678 \
-v ~/.n8n:/home/node/.n8n \
n8nio/n8n
Open http://localhost:5678 and create a new workflow.
-
Add a **Webhook trigger**
- Node type: Webhook
-
Method:
POST -
Path:
support(e.g.,https://yourdomain.com/webhook/support) This endpoint receives{ "message": "User query" }from your chat widget.
-
Generate a query embedding
- Add an OpenAI node (
Create Completion→ switch to Create Embedding). - Parameter Model:
text-embedding-3-large. - Input:
{{$json["message"]}}. - Output variable:
queryEmbedding.
- Add an OpenAI node (
-
Search Qdrant
- Add a Qdrant node, operation Search.
- Collection:
support_vectors. - Vector:
{{$node["OpenAI"].json["queryEmbedding"]}}. - Top K:
3. This returns the three most similar docs and their similarity scores.
-
Build the RAG prompt
- Add a Set node to concatenate retrieved snippets:
{
"prompt": "You are an AI support agent. Answer the user question using only the following excerpts. If the answer is unclear, say \"I don't know\".\n\nUser: {{$json[\"message\"]}}\n\nExcerpts:\n{{#each $node[\"Qdrant\"].json[\"hits\"]}}\n{{payload.content}}\n{{/each}}"
}
What this does: Supplies the LLM with context limited to the top hits, reducing hallucination.
-
Call OpenAI for the final answer
- Add another OpenAI node (
Chat Completion). - Model:
gpt-4o. - Temperature:
0. - Messages:
[{ "role": "system", "content": "You are a concise support assistant." }, { "role": "user", "content": "{{$node[\"Set\"].json[\"prompt\"]}}" }]. - Store output as
answer.
- Add another OpenAI node (
-
Confidence check & escalation
- Add a IF node.
- Condition:
{{$node["OpenAI"].json["answer"]}}contains the phrase"I don't know"OR the highest similarity score from Qdrant< 0.65. - True branch → HTTP Request node that POSTs to your ticketing system webhook (include user message, answer, and source docs).
-
False branch → Response node that returns
{ "answer": "{{$node[\"OpenAI\"].json[\"answer\"]}}" }to the chat widget.
-
Connect chat UI
- In your front-end, send the user message to
https://yourdomain.com/webhook/supportviafetch. - Display the
answerfield on success; display a generic "We've opened a ticket for you" if the escalation path was taken.
- In your front-end, send the user message to
-
Test end-to-end
- Use the n8n Execute Workflow button with sample payloads.
- Verify that low-confidence queries produce tickets in your ticketing dashboard.
Result: A fully automated support loop that answers from your docs, limits hallucination, and escalates when necessary.
Where this breaks
| Failure mode | Typical symptom | Fix / mitigation |
|---|---|---|
| OpenAI token limits |
429 Too Many Requests from the OpenAI node |
Respect the published rate limit (≈ 3500 req/min for pay-as-you-go) and add a n8n Delay node (e.g., 1 s) between calls. |
| Expired API keys | Authentication errors in OpenAI or Qdrant nodes | Rotate keys monthly; store them as n8n Credentials with automatic renewal if possible. |
| Hallucination despite RAG | Answers contain information not present in retrieved snippets | Enforce the "I don't know" clause in the prompt and set temperature to 0. Use the confidence IF node to catch low similarity scores. |
| Vector drift after doc updates | New docs are not searchable | Re-run the embedding script after any documentation change; schedule it nightly via a cron job. |
| Ticketing webhook throttling | Tickets are dropped or delayed | Batch tickets (e.g., up to 10 per minute) or enable webhook retry in the ticketing platform. |
| Qdrant storage cost (if hosted on managed service) | Unexpected monthly bill | Use the self-hosted open-source version; monitor disk usage and prune old vectors. |
| LLM cost blow-up | Monthly spend exceeds budget | Set a hard cap in the OpenAI dashboard; monitor token usage via OpenAI usage logs. |
| Edge-case queries (e.g., multi-language) | Low similarity scores, frequent escalations | Add multilingual embeddings (e.g., text-embedding-3-large supports many languages) and expand the doc corpus. |
With a similarity threshold of 0.65, this workflow reduces unnecessary ticket creation by roughly 40 % compared to a naïve chatbot that never escalates.
For a deeper technical reference, see n8n's documentation.
FAQ
How do I connect a different ticketing system (e.g., Zendesk) instead of the generic webhook?
Use n8n's built-in Zendesk node. Replace the HTTP Request node in the escalation branch with the Zendesk node, map the subject, description, and requester fields to the user's message and the AI answer.
Can I use a hosted vector DB like Pinecone instead of self-hosting Qdrant?
Yes. The workflow steps stay the same; just swap the Qdrant node for the Pinecone node and point it at your Pinecone index. Check Pinecone's current pricing before committing to a production tier.
What if I want to support multiple languages?
OpenAI's embedding model text-embedding-3-large supports over 30 languages out of the box. Store the language code in each Qdrant payload and add a pre-filter in the search node (e.g., filter: {"lang": "es"}) based on the user's locale.
How do I keep the system secure when exposing the webhook publicly?
- Enable Basic Auth on the n8n webhook (n8n UI → Settings → Security).
- Restrict the endpoint IPs via your reverse proxy (NGINX/Cloudflare).
- Rotate the OpenAI and Qdrant credentials quarterly.
Is there a way to monitor the health of the entire pipeline?
Add a Cron node that pings each component (OpenAI test call, Qdrant healthcheck, ticket webhook) and sends the result to a Slack channel via the Slack node. Set alerts for any failures lasting more than two consecutive runs.
Where can I learn more about building RAG agents?
Our detailed case study "the RAG Support Agent" walks through the same architecture with deeper performance stats - see the guide at https://getaab.com/vault/support-agent-rag. For further automation ideas, check https://getaab.com/ai-automations-to-sell which lists ready-to-sell workflows you can repurpose.
Top comments (0)