The 80/20 of Customer Support
In any support queue, roughly 80% of tickets are variations of the same 10–20 questions. The other 20% are genuinely complex and need a human.
Most companies pay humans to answer the 80%. That's an expensive, slow, and demoralising use of human intelligence. Your job is to automate the 80% so your humans can focus on the 20% that actually needs them.
Common 80% Questions (Automate These)
| Category | Example Question |
|---|---|
| Order status | "Where is my order?" |
| Account access | "I forgot my password" |
| Billing | "When is my next payment?" |
| Product info | "Does this work on mobile?" |
| Returns | "How do I return this?" |
| Shipping | "Do you ship to Nigeria?" |
| Refunds | "When will I get my refund?" |
The 20% (Keep for Humans)
- Angry customers who have had a bad experience
- Complex technical issues
- Billing disputes
- VIP customer requests
- Anything requiring judgment calls

Free Stack for AI Support
| Tool | Purpose | Free Tier |
|---|---|---|
| Groq | AI responses | 14,400 req/day |
| Supabase | Knowledge base + ticket storage | 500MB |
| n8n | Workflow orchestration | Free (self-hosted) |
| Tawk.to | Live chat widget | Free forever |
| Gmail | Email support | Free |
Step 1: Build the Knowledge Base
Your AI is only as good as the information it has. Create a structured knowledge base in Supabase:
create table knowledge_base (
id uuid primary key default gen_random_uuid(),
category text not null,
question text not null,
answer text not null,
keywords text[],
updated_at timestamptz default now()
);
-- Insert your FAQs
insert into knowledge_base (category, question, answer, keywords) values
('shipping', 'How long does delivery take?',
'Standard delivery takes 3–5 business days within Lagos and 5–7 days for other states. Express delivery (1–2 days) is available for ₦2,000 extra.',
ARRAY['delivery', 'shipping', 'how long', 'when will', 'arrive']),
('returns', 'What is your return policy?',
'We accept returns within 14 days of delivery. Items must be unused and in original packaging. Initiate a return at returns.yourstore.com or reply to your order confirmation email.',
ARRAY['return', 'refund', 'send back', 'exchange', 'wrong item']),
('account', 'How do I reset my password?',
'Go to yourstore.com/forgot-password and enter your email. You will receive a reset link within 5 minutes. Check your spam folder if you don''t see it.',
ARRAY['password', 'forgot', 'login', 'access', 'locked out']);
Step 2: The AI Response Engine
// lib/support-ai.js
import { createClient } from '@supabase/supabase-js'
import Groq from 'groq-sdk'
const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_SERVICE_KEY)
const groq = new Groq({ apiKey: process.env.GROQ_API_KEY })
export async function handleSupportMessage(message, conversationHistory = []) {
// Step 1: Search knowledge base for relevant articles
const { data: articles } = await supabase
.from('knowledge_base')
.select('category, question, answer')
.textSearch('question', message, { type: 'websearch' })
.limit(5)
const knowledgeContext = articles?.length
? articles.map(a => `Q: ${a.question}\nA: ${a.answer}`).join('\n\n')
: 'No specific articles found for this query.'
// Step 2: Generate response with context
const response = await groq.chat.completions.create({
model: 'llama-3.3-70b-versatile',
messages: [
{
role: 'system',
content: `You are a helpful customer support agent for YourStore.
RULES:
1. Only answer questions using the knowledge base provided
2. If the answer isn't in the knowledge base, say "I'll connect you with our team for this one"
3. Be conversational but professional
4. Keep responses under 150 words
5. If the customer is angry, acknowledge their frustration before answering
6. Never make up information about orders, prices, or policies
KNOWLEDGE BASE:
${knowledgeContext}
CONFIDENCE SCORING:
At the end of your response, on a new line, write: CONFIDENCE: [0-100]
- 90-100: Answer is clearly in the knowledge base
- 60-89: Partial match, answer is reasonable
- 0-59: Escalate to human agent`
},
...conversationHistory.slice(-6),
{ role: 'user', content: message }
]
})
const fullResponse = response.choices[0].message.content
const confidenceMatch = fullResponse.match(/CONFIDENCE:\s*(\d+)/)
const confidence = confidenceMatch ? parseInt(confidenceMatch[1]) : 50
const cleanResponse = fullResponse.replace(/CONFIDENCE:\s*\d+/, '').trim()
return {
message: cleanResponse,
confidence,
shouldEscalate: confidence < 60,
suggestedCategory: articles?.[0]?.category || 'general'
}
},
Step 3: The Escalation Logic
// app/api/support/route.js
import { handleSupportMessage } from '@/lib/support-ai'
import { supabaseAdmin } from '@/lib/supabase'
export async function POST(req) {
const { message, ticketId, conversationHistory } = await req.json()
const result = await handleSupportMessage(message, conversationHistory)
// Log the interaction
await supabaseAdmin.from('support_logs').insert({
ticket_id: ticketId,
user_message: message,
ai_response: result.message,
confidence: result.confidence,
was_escalated: result.shouldEscalate,
})
if (result.shouldEscalate) {
// Notify human agent
await notifyHumanAgent(ticketId, message, result.message)
return Response.json({
message: result.message + "\n\nI've flagged this for our team and someone will follow up shortly.",
escalated: true,
})
}
return Response.json({
message: result.message,
escalated: false,
confidence: result.confidence,
})
},
async function notifyHumanAgent(ticketId, customerMessage, aiDraft) {
// Send to your team via Slack, email, or your helpdesk
await fetch(process.env.SLACK_WEBHOOK, {
method: 'POST',
body: JSON.stringify({
text: `🔴 Escalated ticket #${ticketId}\n*Customer:* ${customerMessage}\n*AI draft:* ${aiDraft}`
})
})
},
Measuring the Impact
Track these metrics monthly:
| Metric | Target | How to Measure |
|---|---|---|
| AI resolution rate | 75–85% | Tickets resolved without escalation / total tickets |
| Average response time | < 30 seconds | Timestamp difference: message received → AI reply |
| Customer satisfaction | > 4.0/5 | Post-resolution survey |
| Escalation rate | < 25% | Escalated tickets / total tickets |
| False positive rate | < 5% | Escalated tickets that AI could have handled |

