Introduction
Integrating ChatGPT into customer support systems can transform how businesses handle inquiries, reduce response times, and improve customer satisfaction. This guide covers everything from basic integration to advanced prompt engineering and fallback strategies.
Setting Up OpenAI API
import OpenAI from 'openai';
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
// Basic chat completion
async function getChatResponse(messages: Array<{role: string, content: string}>) {
const completion = await openai.chat.completions.create({
model: 'gpt-4-turbo',
messages,
temperature: 0.7,
max_tokens: 500,
});
return completion.choices[0].message.content;
}
Building a Support Chatbot
interface Message {
role: 'system' | 'user' | 'assistant';
content: string;
}
class SupportChatbot {
private conversationHistory: Message[] = [];
private systemPrompt = `You are a helpful customer support agent for YugaMatix, a web development agency.
Your responsibilities:
- Answer questions about our services
- Help troubleshoot technical issues
- Provide pricing information
- Escalate complex issues to human agents
Guidelines:
- Be polite and professional
- Keep responses concise (under 150 words)
- If uncertain, admit it and offer to connect with a human agent
- Never make up information
`;
constructor() {
this.conversationHistory.push({
role: 'system',
content: this.systemPrompt,
});
}
async sendMessage(userMessage: string): Promise<string> {
// Add user message to history
this.conversationHistory.push({
role: 'user',
content: userMessage,
});
// Get AI response
const response = await openai.chat.completions.create({
model: 'gpt-4-turbo',
messages: this.conversationHistory,
temperature: 0.7,
});
const assistantMessage = response.choices[0].message.content || '';
// Add assistant response to history
this.conversationHistory.push({
role: 'assistant',
content: assistantMessage,
});
return assistantMessage;
}
clearHistory() {
this.conversationHistory = [{
role: 'system',
content: this.systemPrompt,
}];
}
}
Prompt Engineering for Support
function createContextualPrompt(
userQuery: string,
userContext: UserContext
): string {
return `
User Query: ${userQuery}
User Context:
- Name: ${userContext.name}
- Plan: ${userContext.plan}
- Account Status: ${userContext.status}
- Previous Tickets: ${userContext.ticketCount}
- Last Interaction: ${userContext.lastInteraction}
Knowledge Base Matches:
${userContext.relevantDocs.map(doc => `- ${doc.title}: ${doc.summary}`).join('\n')}
Instructions:
1. Address the user by name
2. Reference their plan if relevant
3. Use knowledge base information
4. Be empathetic and helpful
5. If you cannot fully resolve the issue, offer to create a ticket
`;
}
Context Management
class ConversationManager {
private maxTokens = 4000;
trimConversation(messages: Message[]): Message[] {
// Keep system message and recent messages within token limit
const systemMessage = messages[0];
let recentMessages = messages.slice(1);
let totalTokens = this.estimateTokens(systemMessage.content);
// Add messages from most recent, working backwards
const trimmed: Message[] = [];
for (let i = recentMessages.length - 1; i >= 0; i--) {
const msgTokens = this.estimateTokens(recentMessages[i].content);
if (totalTokens + msgTokens > this.maxTokens) {
break;
}
trimmed.unshift(recentMessages[i]);
totalTokens += msgTokens;
}
return [systemMessage, ...trimmed];
}
private estimateTokens(text: string): number {
// Rough estimation: ~4 characters per token
return Math.ceil(text.length / 4);
}
}
Implementing Fallbacks
class RobustChatbot {
async sendMessage(message: string): Promise<{
response: string;
source: 'ai' | 'fallback' | 'human';
}> {
try {
// Try AI first
const aiResponse = await this.getAIResponse(message);
// Check confidence
if (this.isHighConfidence(aiResponse)) {
return { response: aiResponse, source: 'ai' };
}
// Low confidence - use template
const templateResponse = this.getTemplateResponse(message);
if (templateResponse) {
return { response: templateResponse, source: 'fallback' };
}
// Escalate to human
await this.createHumanTicket(message);
return {
response: 'I've created a ticket for our support team. They'll respond within 2 hours.',
source: 'human'
};
} catch (error) {
// API error - use fallback
return {
response: 'I'm experiencing technical difficulties. Please try again or contact support@yugamatix.com',
source: 'fallback'
};
}
}
private isHighConfidence(response: string): boolean {
// Check for uncertainty phrases
const uncertaintyPhrases = [
'i'm not sure',
'i don't know',
'unclear',
'might be',
'possibly'
];
return !uncertaintyPhrases.some(phrase =>
response.toLowerCase().includes(phrase)
);
}
}
Streaming Responses
async function* streamChatResponse(messages: Message[]) {
const stream = await openai.chat.completions.create({
model: 'gpt-4-turbo',
messages,
stream: true,
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content || '';
if (content) {
yield content;
}
}
}
// Usage in API route
export async function POST(req: Request) {
const { messages } = await req.json();
const encoder = new TextEncoder();
const stream = new ReadableStream({
async start(controller) {
for await (const chunk of streamChatResponse(messages)) {
controller.enqueue(encoder.encode(chunk));
}
controller.close();
},
});
return new Response(stream);
}
Rate Limiting and Cost Control
import rateLimit from 'express-rate-limit';
const chatLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 20, // 20 requests per window
message: 'Too many messages, please try again later',
});
// Token usage tracking
class UsageTracker {
async trackUsage(userId: string, tokens: number, cost: number) {
await db.usage.create({
data: {
userId,
tokens,
cost,
timestamp: new Date(),
},
});
// Check if user exceeded budget
const monthlyUsage = await this.getMonthlyUsage(userId);
if (monthlyUsage.cost > USER_MONTHLY_LIMIT) {
throw new Error('Monthly AI usage limit exceeded');
}
}
async getMonthlyUsage(userId: string) {
const startOfMonth = new Date();
startOfMonth.setDate(1);
const usage = await db.usage.aggregate({
where: {
userId,
timestamp: { gte: startOfMonth },
},
_sum: { tokens: true, cost: true },
});
return {
tokens: usage._sum.tokens || 0,
cost: usage._sum.cost || 0,
};
}
}
Monitoring and Analytics
interface ChatMetrics {
conversationId: string;
messageCount: number;
averageResponseTime: number;
satisfactionScore?: number;
escalatedToHuman: boolean;
resolved: boolean;
}
class ChatAnalytics {
async trackConversation(metrics: ChatMetrics) {
await db.chatMetrics.create({ data: metrics });
}
async getInsights() {
return {
avgMessagesPerConversation: await this.avgMessages(),
resolutionRate: await this.getResolutionRate(),
escalationRate: await this.getEscalationRate(),
avgSatisfaction: await this.avgSatisfaction(),
};
}
private async getResolutionRate(): Promise<number> {
const total = await db.chatMetrics.count();
const resolved = await db.chatMetrics.count({
where: { resolved: true }
});
return (resolved / total) * 100;
}
}