Chatboty prešli dlhú cestu od rule-based systémov. Moderný AI chatbot rozumie kontextu a rieši skutočné problémy.

Architektúra moderného chatbota

┌────────────────────────────────────────────────┐
│                    Frontend                     │
│         (Chat UI, Voice, Messaging)             │
└────────────────────┬───────────────────────────┘
                     │
┌────────────────────▼───────────────────────────┐
│              API Gateway                        │
│      (Auth, Rate Limiting, Logging)             │
└────────────────────┬───────────────────────────┘
                     │
┌────────────────────▼───────────────────────────┐
│            Orchestration Layer                  │
│   (Intent Detection, Context Management)        │
└────────────────────┬───────────────────────────┘
                     │
┌────────────────────▼───────────────────────────┐
│                 LLM Layer                       │
│        (OpenAI, Claude, Mistral)                │
└────────────────────┬───────────────────────────┘
                     │
┌────────────────────▼───────────────────────────┐
│              Knowledge Layer                    │
│      (RAG, Vector DB, Business Logic)           │
└────────────────────────────────────────────────┘

Step 1: Základný chat

// app/api/chat/route.ts
import { streamText } from 'ai'
import { openai } from '@ai-sdk/openai'

const SYSTEM_PROMPT = `Si customer support agent pre e-shop.

Pravidlá:
- Odpovedaj stručne a priateľsky
- Pri otázkach o objednávkach žiadaj číslo objednávky
- Ak nevieš, povedz to a eskaluj na človeka
- Používaj slovenčinu`

export async function POST(req: Request) {
  const { messages } = await req.json()

  const result = await streamText({
    model: openai('gpt-4o'),
    system: SYSTEM_PROMPT,
    messages
  })

  return result.toDataStreamResponse()
}

Step 2: RAG pre firemné dáta

import { openai } from '@ai-sdk/openai'
import { retrieveDocuments } from '@/lib/rag'

export async function POST(req: Request) {
  const { messages } = await req.json()
  const lastMessage = messages[messages.length - 1]

  // Retrieve relevant documents
  const docs = await retrieveDocuments(lastMessage.content)

  const systemWithContext = `${SYSTEM_PROMPT}

Relevantné informácie z databázy:
${docs.map(d => d.content).join('\n\n')}

Použite tieto informácie pri odpovedi.`

  const result = await streamText({
    model: openai('gpt-4o'),
    system: systemWithContext,
    messages
  })

  return result.toDataStreamResponse()
}

Step 3: Tools pre akcie

import { tool } from 'ai'
import { z } from 'zod'

const tools = {
  getOrderStatus: tool({
    description: 'Získa stav objednávky',
    parameters: z.object({
      orderId: z.string().describe('Číslo objednávky')
    }),
    execute: async ({ orderId }) => {
      const order = await db.orders.findUnique({ where: { id: orderId } })
      if (!order) return { error: 'Objednávka nenájdená' }
      return {
        status: order.status,
        estimatedDelivery: order.estimatedDelivery,
        items: order.items
      }
    }
  }),

  createTicket: tool({
    description: 'Vytvorí support ticket',
    parameters: z.object({
      subject: z.string(),
      description: z.string(),
      priority: z.enum(['low', 'medium', 'high'])
    }),
    execute: async ({ subject, description, priority }) => {
      const ticket = await createSupportTicket({ subject, description, priority })
      return { ticketId: ticket.id, message: 'Ticket vytvorený' }
    }
  })
}

Step 4: Conversation memory

import { Redis } from '@upstash/redis'

const redis = new Redis({ url: process.env.REDIS_URL })

async function getConversationHistory(sessionId: string) {
  const history = await redis.lrange(`chat:${sessionId}`, 0, 20)
  return history.map(h => JSON.parse(h))
}

async function saveMessage(sessionId: string, message: any) {
  await redis.lpush(`chat:${sessionId}`, JSON.stringify(message))
  await redis.expire(`chat:${sessionId}`, 60 * 60 * 24) // 24h
}

Step 5: Human handoff

const ESCALATION_TRIGGERS = [
  'hovoriť s človekom',
  'skutočný agent',
  'nespokojný',
  'sťažnosť'
]

function shouldEscalate(message: string): boolean {
  return ESCALATION_TRIGGERS.some(t =>
    message.toLowerCase().includes(t)
  )
}

async function handleMessage(message: string, sessionId: string) {
  if (shouldEscalate(message)) {
    await notifyHumanAgent(sessionId)
    return {
      content: 'Prepájam vás na nášho kolegu. Prosím počkajte.',
      metadata: { escalated: true }
    }
  }

  // Normal AI response
  return await generateAIResponse(message)
}

Frontend (React)

'use client'

import { useChat } from 'ai/react'

export function ChatWidget() {
  const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat()

  return (
    <div className="fixed bottom-4 right-4 w-96 bg-white rounded-lg shadow-xl">
      <div className="h-96 overflow-y-auto p-4">
        {messages.map(m => (
          <div key={m.id} className={`mb-4 ${m.role === 'user' ? 'text-right' : ''}`}>
            <span className={`inline-block p-3 rounded-lg ${
              m.role === 'user' ? 'bg-blue-500 text-white' : 'bg-gray-100'
            }`}>
              {m.content}
            </span>
          </div>
        ))}
        {isLoading && <div className="text-gray-400">Píšem...</div>}
      </div>

      <form onSubmit={handleSubmit} className="border-t p-4">
        <input
          value={input}
          onChange={handleInputChange}
          placeholder="Napíšte správu..."
          className="w-full p-2 border rounded"
        />
      </form>
    </div>
  )
}

Metriky na sledovanie

  • Resolution rate - % vyriešených bez eskalácie
  • CSAT - spokojnosť zákazníkov
  • Response time - čas do prvej odpovede
  • Containment rate - % konverzácií bez human handoff

Záver

Moderný chatbot nie je len LLM wrapper. Je to systém s RAG, tools, memory a human handoff. Začnite jednoducho a iterujte na základe reálneho používania.