The same questions arrive dozens of times a day: "How much is shipping?", "Has my order shipped?", "Can I pay by card?". Your support staff paste identical answers, and messages sent after hours wait until morning, by which time some buyers have gone elsewhere.
An AI chatbot can absorb those routine questions, but only if it has firm boundaries. A careless bot is worse than none: it answers confidently and wrongly, or traps customers in loops with no way to reach a person. This guide covers planning, building, and measuring a support chatbot, with a table design and Laravel code.
1. Keep the Scope Narrow
Export one or two months of chat history and group the questions. Most usually fall into a few buckets: pricing and stock, shipping costs, order status, payment methods, and returns. Pick the three to five buckets with the highest volume and clear answers. That is version one.
Also write down what the bot must not handle: damaged goods complaints, refunds, custom pricing, and anything involving personal data beyond the requester's own. Those go straight to a human.
2. Choose an Approach
| Approach | Pros | Cons | Best for |
|---|---|---|---|
| Menu or rule-based bot | Cheap, always accurate | Rigid, fails off-menu | A tiny, stable FAQ |
| Hosted chatbot platform | Fast setup, dashboard, channel integrations | Monthly fees, limited customization, data held by a vendor | Teams without developers |
| Build on a language model API | Full control, can read live order data | Needs a developer and maintenance | Businesses with their own web app |
3. Prepare the Knowledge Base
A language model does not know your policies. It answers correctly only when you give it correct source text. This pattern is called retrieval-augmented generation: find the relevant snippets first, then send them with the question.
- Write one short article per topic, such as "30-day return policy" or "Same-day delivery areas".
- Use plain language, one fact per sentence, and exact figures such as order cut-off times.
- Date every article. A stale answer hurts trust more than no answer.
- Assign one owner to update content whenever a policy changes.
4. Table Design
CREATE TABLE kb_articles (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(200) NOT NULL,
body TEXT NOT NULL,
is_active TINYINT(1) DEFAULT 1,
updated_at TIMESTAMP NULL,
FULLTEXT KEY ft_kb (title, body)
);
CREATE TABLE chat_conversations (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
channel VARCHAR(20) NOT NULL, -- web, messenger
customer_ref VARCHAR(100) NULL,
status VARCHAR(20) DEFAULT 'bot', -- bot, human, closed
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL
);
CREATE TABLE chat_messages (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
conversation_id BIGINT UNSIGNED NOT NULL,
role VARCHAR(10) NOT NULL, -- user, bot, agent
content TEXT NOT NULL,
created_at TIMESTAMP NULL,
INDEX (conversation_id)
);
The conversation status drives hand-off: once it is human, the bot stays silent and an agent takes over.
5. A Laravel Implementation
This service calls a language model through the widely supported chat completions format. Endpoint, key, and model name live in config/services.php, read from .env, so you can switch providers without code changes.
namespace App\Services;
use App\Models\ChatConversation;
use App\Models\KbArticle;
use Illuminate\Support\Facades\Http;
class SupportBot
{
public function reply(ChatConversation $conv, string $question): ?string
{
if ($conv->status !== 'bot') {
return null; // a human is handling it
}
$context = KbArticle::where('is_active', true)
->whereFullText(['title', 'body'], $question)
->limit(3)
->get()
->map(fn ($a) => "## {$a->title}\n{$a->body}")
->implode("\n\n");
$system = "You are a store support assistant. Answer briefly and ONLY from the "
. "information below. If the answer is not there, reply exactly: ESCALATE.\n\n"
. $context;
$response = Http::withToken(config('services.llm.key'))
->timeout(20)
->post(config('services.llm.url'), [
'model' => config('services.llm.model'),
'messages' => [
['role' => 'system', 'content' => $system],
['role' => 'user', 'content' => $question],
],
'temperature' => 0.2,
]);
$answer = trim($response->json('choices.0.message.content') ?? '');
if ($response->failed() || $answer === '' || str_contains($answer, 'ESCALATE')) {
$conv->update(['status' => 'human']);
return 'I have passed your question to our team. Someone will reply shortly.';
}
return $answer;
}
}
Low temperature keeps answers consistent, the "only from the information below" instruction reduces invented answers, and every failure path, including an API outage, ends with a human rather than an error message. whereFullText needs a FULLTEXT index in MySQL or PostgreSQL. At higher volume, move the API call into a queued job so messaging webhooks do not time out.
6. Conversation Flow and Hand-off
- An honest greeting stating that this is an automated assistant and what it can help with.
- Quick-reply buttons for the top three questions.
- Escalation keywords such as "agent", "complaint", or "refund" switch the status to
human. - Retry limit: if a customer repeats the same question twice, treat it as a bot failure and hand off.
- Business hours: after hours, say when a person will reply.
7. Measure and Improve Weekly
| Metric | How to calculate | What to do if it is poor |
|---|---|---|
| Bot resolution rate | Conversations closed without human status รท total | Add knowledge articles for frequently escalated topics |
| Time to first reply | Gap between first user message and first reply | Check API timeouts and queues |
| Wrong answers | Read a sample of 20 conversations each week | Fix the source text, not just the prompt |
| Satisfaction | "Was this helpful?" at the end | Review low-rated conversations |
Estimating cost
Language model APIs bill per token across the question, the context, and the answer. Measure the average conversation length during testing, multiply by your expected monthly volume, and compare with your provider's price list. Cap the context at the top three articles and set a monthly spending limit in the provider dashboard.
Privacy and Security
Do not send sensitive data such as government ID numbers or card details to a third-party API. Strip long number patterns before sending, keep API keys only in .env, and disclose in your privacy policy that conversations are processed by an AI service. For the application side, review 10 must-have web security practices.
Launch Checklist
- Written scope, including topics that must always go to a human.
- Knowledge base reviewed and dated.
- Bot tested against at least 50 real questions from chat history.
- Hand-off works, including when the API fails.
- Someone reads sample conversations every week.
- Customers know they are talking to an automated assistant.
A good chatbot does not replace your support team. It filters routine questions so people have time for the cases that need judgment. If you are still choosing whether to build on your own stack, the trade-offs in buy or build apply here too.