
August 15, 2026
10 min read
Table of Contents
By Kokil Thapa | Last reviewed: August 2026
Implementing AI powered search for Laravel products requires moving beyond simple SQL LIKE queries or basic full-text indexes to embrace semantic understanding and vector embeddings. In my experience building eCommerce platforms like Nepal Gift Card and various WooCommerce stores, users expect search to understand intent ("red dress for wedding") rather than just matching exact keywords. This guide covers the practical integration of Laravel Scout with Meilisearch and OpenAI-compatible embedding APIs to build a production-grade semantic search system that actually converts.
If you are new to optimizing catalog architecture before adding AI layers, review our guide on scalable product catalog architecture for e-commerce to ensure your database schema supports efficient indexing. A solid foundation prevents expensive rework once vectors enter the picture.
How does AI powered search for Laravel products differ from standard Scout?
Standard Laravel Scout provides an excellent abstraction over search engines like Algolia or Meilisearch, but out of the box, it primarily handles lexical (keyword) matching. When a customer searches "warm winter jacket", traditional search looks for documents containing those specific tokens. It fails if your product is titled "Thermal Insulated Parka" without the word "jacket". AI powered search for Laravel products solves this by mapping both the query and the product description into a high-dimensional vector space where meaning, not spelling, determines proximity.
In practice, this means your Laravel application must perform two distinct operations during indexing: generating searchable text attributes for typo tolerance and generating dense vector representations for semantic matching. Meilisearch v1.12+ supports native vector storage and hybrid search, making it the most pragmatic choice for Laravel developers in 2026 who want self-hosted infrastructure without the per-query costs of managed SaaS providers. For teams evaluating backend options, our comparison of Laravel Meilisearch integration covers baseline setup before adding vectors.
How do you generate and store vector embeddings in Laravel?
The core of AI powered search for Laravel products is the embedding generation pipeline. You need to convert product titles, descriptions, and attributes into numerical vectors whenever a model is created or updated. While you can call external APIs synchronously during saves, this creates latency and failure points. On production eCommerce sites I maintain, we always decouple embedding generation using Laravel Queues.
Creating the Embedding Job
Create a dedicated job that handles API communication and retries. Never embed inside the controller or model observer directly.
<?php
namespace App\Jobs;
use App\Models\Product;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class GenerateProductEmbedding implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public int $tries = 3;
public int $backoff = 60;
public function __construct(
private Product $product
) {}
public function handle(): void
{
$textToEmbed = sprintf(
'%s %s %s',
$this->product->name,
$this->product->short_description,
$this->product->category?->name ?? ''
);
try {
$response = Http::timeout(30)->withToken(config('services.embedding_api_key'))
->post('https://api.openai.com/v1/embeddings', [
'model' => 'text-embedding-3-small',
'input' => $textToEmbed,
'dimensions' => 1024,
]);
if ($response->successful()) {
$vector = $response->json('data.0.embedding');
// Store vector separately to avoid bloating main table
$this->product->embedding()->updateOrCreate(
['product_id' => $this->product->id],
['vector' => json_encode($vector)]
);
// Trigger Scout re-index to push vector to Meilisearch
$this->product->searchable();
}
} catch (\Exception $e) {
Log::error('Embedding generation failed', [
'product_id' => $this->product->id,
'error' => $e->getMessage(),
]);
throw $e;
}
}
} This job targets OpenAI’s text-embedding-3-small model with 1024 dimensions, which offers the best cost-to-performance ratio for product catalogs in 2026. If you are operating under strict data residency requirements or budget constraints common in Nepal-based projects, consider running nomic-embed-text or bge-m3 locally via Ollama on the same VPS. Local models eliminate API costs entirely but require sufficient RAM (minimum 8GB dedicated to inference).
Integrating with Model Observers
Dispatch the job from an observer to keep controllers clean. Always check if the relevant fields actually changed before regenerating embeddings to save API credits.
class ProductObserver
{
public function saved(Product $product): void
{
if ($product->wasChanged(['name', 'short_description', 'category_id'])) {
GenerateProductEmbedding::dispatch($product);
}
}
} For large existing catalogs, never run synchronous bulk embedding. Use Scout’s scout:import command combined with a custom Artisan command that chunks products and dispatches jobs with rate limiting to respect API quotas. A typical 10,000-product catalog takes 2–4 hours to embed at standard rate limits.
How do you configure Meilisearch for hybrid search in Laravel?
Once vectors exist in your database, Meilisearch needs explicit configuration to use them alongside keyword matching. Hybrid search combines BM25 textual relevance with vector cosine similarity, weighted by a parameter you tune based on your catalog’s characteristics. Pure vector search often misses exact SKU matches; pure keyword search misses synonyms. Hybrid gives you both.
Configuring Index Settings
Add vector configuration to your Scout config or apply it programmatically via the Meilisearch PHP SDK during deployment. This step is frequently missed in tutorials.
// In a custom Artisan command or deploy script
$client = new \Meilisearch\Client(config('scout.meilisearch.host'), config('scout.meilisearch.key'));
$client->index('products')->updateSettings([
'embedders' => [
'default' => [
'source' => 'userProvided',
'dimensions' => 1024,
],
],
'searchableAttributes' => [
'name',
'sku',
'short_description',
'category_name',
'tags',
],
'filterableAttributes' => ['price', 'category_id', 'in_stock', 'brand'],
'sortableAttributes' => ['price', 'created_at'],
]); Note source: userProvided. This tells Meilisearch you are supplying pre-computed vectors rather than asking it to call an embedding API itself. This is critical for Laravel applications because it keeps embedding logic within your application boundary where you control caching, rate limiting, and model selection.
Executing Hybrid Searches
Laravel Scout’s builder doesn’t natively expose hybrid parameters as of 2026. You need to extend the builder or use the Meilisearch engine directly for advanced queries.
use Laravel\Scout\Builder;
use Meilisearch\Client;
$meilisearch = new Client(config('scout.meilisearch.host'), config('scout.meilisearch.key'));
$results = $meilisearch->index('products')->search($query, [
'hybrid' => [
'semanticRatio' => 0.7,
'embedder' => 'default',
],
'vector' => $queryVector, // Generated from user query at request time
'limit' => 20,
'filter' => 'in_stock = true AND price <= ' . $maxPrice,
]); The semanticRatio controls the balance. Start at 0.7 for fashion/lifestyle catalogs where synonym matching matters heavily. Drop to 0.3–0.5 for technical/electronics catalogs where exact model numbers dominate. Test with real user queries from your analytics before committing to a value.
What are the performance and cost trade-offs of AI search?
Adding AI powered search for Laravel products introduces computational overhead that must be planned for, especially when hosting in Nepal or on budget VPS instances. Understanding these trade-offs prevents surprise bills and degraded UX.
| Factor | Standard Scout (BM25) | AI Powered Hybrid Search |
|---|---|---|
| Indexing Latency | < 100ms per document | 200–800ms + embedding API call |
| Query Latency | 5–20ms | 15–50ms (includes query embedding) |
| Storage per Product | ~2–5 KB | ~6–10 KB (vectors add ~4KB @ 1024 dims) |
| RAM Requirements | 512MB–1GB for 100K docs | 2–4GB for 100K docs with vectors |
| Ongoing Cost | Server only | Server + embedding API (~$0.02/1M tokens) |
| Relevance Quality | Good for exact matches | Superior for intent/synonyms |
Query-time embedding is the hidden bottleneck. Every search request must embed the user’s query before hitting Meilisearch. Cache aggressively. For an eCommerce site serving Kathmandu customers, I cache query embeddings in Redis with a 1-hour TTL keyed by normalized query string. This reduces API calls by 60–80% for popular searches and cuts p95 latency from 120ms to 25ms.
// Cache query embeddings in your search service
$cacheKey = 'search_embedding:' . md5(strtolower(trim($query)));
$queryVector = Cache::remember($cacheKey, 3600, function () use ($query) {
return $this->embeddingService->generate($query);
}); For teams concerned about vendor lock-in or API availability, local embedding models via Ollama provide zero-cost alternatives at the expense of GPU/CPU resources. The nomic-embed-text model runs comfortably on a 4-core 8GB VPS and produces 768-dimension vectors compatible with Meilisearch. This is often the right choice for Nepal-based legal-tech portals or SMB eCommerce sites where margins are thin and traffic is predictable. Learn more about balancing performance in our article on improving web performance with caching strategies.
How do you evaluate and tune semantic search relevance?
Deploying AI powered search for Laravel products without evaluation leads to silent failures where results look plausible but miss key items. Establish a ground-truth test set before going live. Collect 50–100 real user queries from your logs and manually label the top 5 expected results for each.
- Build an automated relevance test suite using PHPUnit or Pest that runs your labeled queries against the search index and calculates NDCG@5 (Normalized Discounted Cumulative Gain). Track this metric in CI.
- A/B test semantic ratios in production using feature flags. Serve 0.5, 0.7, and 0.9 to different user cohorts and measure click-through rate and conversion, not just relevance scores.
- Monitor zero-result rates daily. A spike usually indicates embedding model drift, API failures, or new product categories lacking proper metadata.
- Implement fallback logic: if hybrid search returns fewer than 3 results above a confidence threshold, automatically retry with pure BM25. This prevents empty pages when the vector model misinterprets niche terminology.
On a legal-tech portal I built, initial vector search performed poorly for Nepali legal terminology because English-trained embedding models didn’t capture local context. We solved this by prepending English translations to the indexed text and boosting exact-match Nepali terms via filterable attributes. This hybrid approach preserved semantic discovery while respecting domain-specific precision needs. Always validate assumptions against your actual user base, not benchmark leaderboards.
Practical Next Steps for Your Laravel Search Implementation
AI powered search for Laravel products delivers measurable conversion improvements when implemented correctly, but it demands disciplined engineering over hype. Start with Meilisearch hybrid search using pre-computed embeddings, cache query vectors aggressively, and establish relevance testing before scaling. Avoid over-engineering: most eCommerce catalogs under 100,000 SKUs perform excellently on a single 4GB VPS with this stack. Monitor costs, tune semantic ratios based on real behavior, and remember that search quality is a product decision, not just a technical one. If you need hands-on implementation support for your Laravel eCommerce platform or legal-tech portal, get in touch to discuss your specific requirements.

