SYS://VISION.ACTIVE
VIEWPORT.01
LAT 28.0222° N
SIGNAL.NOMINAL
VISION Loading
Back to Blog

Building AI Chatbots with Laravel: From Simple to Sophisticated

Shane Barron

Shane Barron

Laravel Developer & AI Integration Specialist

Beyond Simple Q&A

Modern AI chatbots can maintain context across conversations, remember user preferences, and handle complex multi-turn dialogues. Building one requires thoughtful architecture around conversation state, prompt management, and response handling.

Conversation Architecture

class Conversation extends Model
{
    protected $fillable = ['user_id', 'context', 'metadata'];
    protected $casts = ['context' => 'array', 'metadata' => 'array'];

    public function messages(): HasMany
    {
        return $this->hasMany(Message::class)->orderBy('created_at');
    }

    public function addMessage(string $role, string $content): Message
    {
        return $this->messages()->create([
            'role' => $role,
            'content' => $content,
        ]);
    }

    public function getMessagesForContext(int $limit = 20): array
    {
        return $this->messages()
            ->latest()
            ->take($limit)
            ->get()
            ->reverse()
            ->map(fn ($m) => ['role' => $m->role, 'content' => $m->content])
            ->values()
            ->toArray();
    }
}

The Chat Service

class ChatService
{
    public function __construct(
        private AIClient $ai,
        private string $systemPrompt
    ) {}

    public function respond(Conversation $conversation, string $userMessage): string
    {
        // Store user message
        $conversation->addMessage('user', $userMessage);

        // Build context
        $messages = array_merge(
            [['role' => 'system', 'content' => $this->systemPrompt]],
            $conversation->getMessagesForContext()
        );

        // Get AI response
        $response = $this->ai->chat($messages);

        // Store and return
        $conversation->addMessage('assistant', $response);

        return $response;
    }
}

Context Window Management

AI models have token limits. Manage context intelligently:

class ContextManager
{
    private int $maxTokens = 4000;

    public function buildContext(Conversation $conversation): array
    {
        $messages = [];
        $tokenCount = $this->countTokens($this->systemPrompt);

        foreach ($conversation->messages()->latest()->cursor() as $message) {
            $messageTokens = $this->countTokens($message->content);

            if ($tokenCount + $messageTokens > $this->maxTokens) {
                break;
            }

            array_unshift($messages, [
                'role' => $message->role,
                'content' => $message->content,
            ]);

            $tokenCount += $messageTokens;
        }

        return $messages;
    }

    private function countTokens(string $text): int
    {
        // Rough estimate: 1 token ≈ 4 characters
        return (int) ceil(strlen($text) / 4);
    }
}

Real-Time Streaming

For better UX, stream responses as they're generated:

public function streamResponse(Conversation $conversation, string $message): StreamedResponse
{
    return response()->stream(function () use ($conversation, $message) {
        $conversation->addMessage('user', $message);

        $fullResponse = '';

        $this->ai->streamChat(
            $conversation->getMessagesForContext(),
            function ($chunk) use (&$fullResponse) {
                $fullResponse .= $chunk;
                echo "data: " . json_encode(['content' => $chunk]) . "\n\n";
                ob_flush();
                flush();
            }
        );

        $conversation->addMessage('assistant', $fullResponse);

        echo "data: [DONE]\n\n";
    }, 200, [
        'Content-Type' => 'text/event-stream',
        'Cache-Control' => 'no-cache',
        'X-Accel-Buffering' => 'no',
    ]);
}

Adding Memory and Personalization

class ConversationMemory
{
    public function extractAndStoreFacts(Conversation $conversation, string $message): void
    {
        $facts = $this->ai->extract($message, [
            'user_name',
            'preferences',
            'mentioned_topics',
        ]);

        $conversation->update([
            'metadata' => array_merge(
                $conversation->metadata ?? [],
                array_filter($facts)
            ),
        ]);
    }

    public function buildPersonalizedPrompt(Conversation $conversation): string
    {
        $base = "You are a helpful assistant.";

        if ($name = $conversation->metadata['user_name'] ?? null) {
            $base .= " The user's name is {$name}.";
        }

        if ($prefs = $conversation->metadata['preferences'] ?? null) {
            $base .= " Their preferences: {$prefs}.";
        }

        return $base;
    }
}

Function Calling / Tool Use

Modern AI APIs support function calling for structured interactions:

$tools = [
    [
        'type' => 'function',
        'function' => [
            'name' => 'search_products',
            'description' => 'Search for products in the catalog',
            'parameters' => [
                'type' => 'object',
                'properties' => [
                    'query' => ['type' => 'string'],
                    'category' => ['type' => 'string'],
                    'max_price' => ['type' => 'number'],
                ],
                'required' => ['query'],
            ],
        ],
    ],
];

// Handle tool calls in your response processing
if ($response['tool_calls'] ?? false) {
    foreach ($response['tool_calls'] as $call) {
        $result = $this->executeFunction($call['function']);
        // Feed result back to AI for final response
    }
}

Conclusion

Building a sophisticated chatbot requires more than just API calls. Design for conversation state, manage context windows, stream responses for better UX, and leverage function calling for structured interactions. Start simple and add complexity as your requirements grow.

Share this article
Shane Barron

Shane Barron

Strategic Technology Architect with 40 years of experience building production systems. Specializing in Laravel, AI integration, and enterprise architecture.

Need Help With Your Project?

I respond to all inquiries within 24 hours. Let's discuss how I can help build your production-ready system.

Get In Touch