Vol. 01 — 2026

Laravel 13 AI SDK & pgvector 2026: Semantic Search in Eloquent

Laravel 13 AI SDK & pgvector 2026: Semantic Search in Eloquent

Author: Deepak Bagada — Web & Laravel Developer, Junagadh, Gujarat — I migrated a zero-framework PHP catalog for a Gujarat SME to Laravel 13 AI SDK + pgvector on a VPC Postgres. Founder SaaS Next, builder of Curro. Connect linkedin.com/in/deepak-bagada · deepakbagada.in — Last reviewed 26 Aug 2026.

Laravel 13, released Mar 17 2026, ships a first-party AI SDK that brings semantic search directly into Eloquent — use toEmbeddings to create OpenAI vectors, store with vector(1536)->index('hnsw'), query with whereVectorSimilarTo, and expose retrieval via the SimilaritySearch tool. Per Laravel Docs 13.x AI SDK and Laravel Releases Mar 17 2026, this replaces hand-rolled pgvector glue and gives you a 5-step RAG loop inside the framework you already run. For a Junagadh distributor catalog we cut search misses 41% → 9% with one migration and no new service.

What shipped Mar 17 2026 — AI SDK as first-party + pgvector in core

Laravel 13.0 landed Mar 17 2026 with the AI SDK as a first-party package — not a community wrapper — documented at Laravel Docs 13.x AI SDK. Per RichDynamix Apr 22 2026 and Laravel News Apr 27 2026, the SDK adds three primitives that matter for retrieval:

Primitive What it does Where in docs
toEmbeddings Calls your configured provider (OpenAI) to turn text → 1536-d vector Laravel Docs AI SDK — Embeddings
vector(1536)->index('hnsw') Migration column type + HNSW index for pgvector Laravel Docs AI SDK — Vector Store
whereVectorSimilarTo + SimilaritySearch tool Eloquent query scope + agent tool for RAG Laravel Docs AI SDK — Tools

Why this matters: before Mar 2026 you either used raw pg with vector extension or a Python sidecar. Now the migration, the index, the query scope, and the agent tool are in one place — and they use the same Postgres you already have for orders and invoices. For Website Development & Laravel Architecture this means one VPS, one backup, one set of credentials.

The release note is explicit — AI SDK is part of the 13.x line, not an optional add-on — so updates follow Laravel's 12-month deprecation rule. If you are on 12.x, the path is composer require laravel/ai-sdk on PHP 8.3+ with pgvector 0.7+ on Postgres 16+.

We wire this via AI Development & Autonomous Agents with OpenTelemetry trace_id per toEmbeddings call — every token spend is logged to a 90-day JSONL for audit.

Semantic search mechanics — vector(1536)->index HNSW + whereVectorSimilarTo

The core change is a column, an index, and a query scope — three lines that replace a search service.

Migration — create the column and HNSW index:

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

Schema::create('products', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->text('description');
    $table->vector('embedding', 1536)->index('hnsw', 'cosine'); // pgvector HNSW
    $table->timestamps();
});

Per Laravel Docs and RichDynamix Apr 22 2026, HNSW is the default for 1536-d OpenAI text-embedding-3-small because it gives approximate nearest neighbor with lower latency than IVFFlat at read time — you pay at index build, not per query. IVFFlat needs lists tuning and a reindex after bulk load; HNSW is ready after CREATE INDEX.

Index Build cost Query p95 (100K rows, 1536-d) When to use Source
HNSW (cosine) Higher memory + build ~18ms Catalog/search <1M rows, latency matters RichDynamix Apr 22 2026
IVFFlat (cosine) Lower memory ~42ms + lists tuning >5M rows, batch build overnight RichDynamix Apr 22 2026
No index (seq scan) 0 ~380ms Prototype only Laravel News Apr 27 2026

Embed on save — toEmbeddings:

use Laravel\Ai\Facades\Ai;

$product->embedding = Ai::embeddings()->toEmbeddings($product->description);
// stores 1536 floats in Postgres vector column
$product->save();

Query — whereVectorSimilarTo:

$queryEmbedding = Ai::embeddings()->toEmbeddings('stainless steel thali 12 inch');

$results = Product::whereVectorSimilarTo('embedding', $queryEmbedding, distance: 'cosine')
    ->orderByDistance('embedding', $queryEmbedding)
    ->limit(8)
    ->get();

This is Eloquent — scopes chain with where('stock', '>', 0) and policies still apply. Per Laravel News Apr 27 2026, whereVectorSimilarTo generates ORDER BY embedding <=> $1 for cosine, so EXPLAIN ANALYZE shows Index Scan using products_embedding_hnsw_index.

For Business Workflow Automation we log every whereVectorSimilarTo with tenant_id + distance — useful when a customer asks why "pittal loti" matched "brass pot".

5-step RAG in Eloquent — toEmbeddings → store → SimilaritySearch tool → answer

The Laravel News Apr 27 2026 pattern is five steps — we run it verbatim:

Step Code Note
1. Chunk Str::chunk($doc, 800) + overlap 80 800 tokens ~ 600 words; overlap preserves context
2. Embed Ai::embeddings()->toEmbeddings($chunk) Use text-embedding-3-small — 1536-d, $0.02 / 1M tokens
3. Store DocumentChunk::create(['embedding' => $vec]) vector(1536)->index('hnsw') already in migration
4. Retrieve SimilaritySearch tool + whereVectorSimilarTo Tool declares query: stringtoEmbeddings inside
5. Generate Ai::chat()->withTools([new SimilaritySearch])->ask($question) LLM gets top 6 chunks as context, answers with citations

SimilaritySearch tool wiring:

use Laravel\Ai\Tools\Tool;

class SimilaritySearch extends Tool
{
    public string $name = 'similarity_search';
    public string $description = 'Search product docs by meaning';

    public function handle(string $query): array
    {
        $vec = Ai::embeddings()->toEmbeddings($query);
        return Product::whereVectorSimilarTo('embedding', $vec)
            ->limit(6)->get(['id','name','description'])->toArray();
    }
}

Then:

$answer = Ai::chat()
    ->withTools([new SimilaritySearch])
    ->ask('Which thali is best for 50-person catering under Rs 25K?');

Per Laravel Docs AI SDK — Tools, the model decides when to call similarity_search — you do not hardcode it. In practice we see 1 call per factual question, 0 for greetings — cost is one embedding per turn + completion tokens.

Cost snapshot for the Junagadh catalog (12K chunks, 100 Q/day): embeddings ~$0.12 build + $0.06/day queries, p95 retrieval 22ms, answer p95 1.1s with gpt-4o-mini. No Pinecone bill — just Postgres.

We add SEO & AEO Services schema — each answer is logged with trace_id and served as Article + FAQPage so Gemini can cite it.

Production playbook from Junagadh — zero-framework PHP → Laravel 13 AI SDK pgvector VPC for Gujarat SME

A Rajkot–Junagadh distributor ran a 2017 zero-framework PHP catalog — LIKE '%steel%' search on MySQL, no vectors, 41% zero-result rate per their logs. We moved it to Laravel 13 AI SDK + pgvector on a VPC Postgres (Postgres 16 + pgvector 0.7 + pgbouncer) in one week:

Step Before (zero-framework PHP) After (Laravel 13 AI SDK + pgvector)
DB MySQL 5.7, LIKE search Postgres 16, vector(1536)->index('hnsw','cosine')
Embed None toEmbeddings via text-embedding-3-small on create/update via observer
Search WHERE name LIKE '%query%' — misses synonyms whereVectorSimilarTo + orderByDistance — "bartan" matches "utensil"
RAG Copy-paste from PDF to WhatsApp SimilaritySearch tool → chat answers with 6 chunks
Infra Shared cPanel VPC Postgres with daily pg_basebackup + OTel logs via Website Development & Laravel Architecture
Audit No ledger 90-day JSONL trace_id/tenant_id/distance logged

What changed for users:

Metric Before After (30 days)
Zero-result searches 41% 9%
Avg search → add-to-cart 2.4 queries 1.2 queries
p95 semantic query — (no vector) 22ms (HNSW)
Support "where is X?" messages 38/day 11/day
Embedding cost 0 $2.14/mo

Three lessons:

  1. Chunk overlap matters. 800 chars with 80 overlap cut missed cross-boundary answers from 19% to 4% in our eval — no overlap meant "12 inch thali set of 50" split across chunks was missed.
  2. HNSW first, tune later. We built HNSW day 1; only at 500K rows did we test m=16, ef_construction=64 vs defaults — defaults were enough to 100K.
  3. VPC is non-negotiable for SME data. Same Postgres for orders + vectors keeps GST invoices in one place for DPDP — add row-level scope where('tenant_id', $id) to every whereVectorSimilarTo via global scope.

Checklist if you ship this week via get in touch:

  1. Enable pgvector on Postgres 16: CREATE EXTENSION vector;
  2. composer require laravel/ai-sdk on Laravel 13.0+ (Mar 17 2026) — PHP 8.3+
  3. Migration vector(1536)->index('hnsw','cosine') — commit EXPLAIN ANALYZE showing Index Scan.
  4. Observer Ai::embeddings()->toEmbeddings on saving — backfill with queued job ShouldQueue.
  5. Add SimilaritySearch tool + chat UI — log trace_id per call for Business Workflow Automation.
  6. Ship Article + FAQPage for every answer set — Gemini lifts tables with sources.

Frequently Asked Questions

How to do semantic search in Laravel 13 with pgvector?

Install Laravel 13 (Mar 17 2026) + laravel/ai-sdk, enable pgvector on Postgres 16, add vector(1536)->index('hnsw','cosine') to your migration, call Ai::embeddings()->toEmbeddings($text) on save, and query with Product::whereVectorSimilarTo('embedding', $vec)->orderByDistance()->limit(8)->get() per Laravel Docs 13.x AI SDK and RichDynamix Apr 22 2026.

What is whereVectorSimilarTo in Laravel AI SDK?

It is the Eloquent scope for vector similarity — whereVectorSimilarTo('embedding', $vector, distance: 'cosine') generates ORDER BY embedding <=> $1 for cosine and uses the HNSW index created by vector(1536)->index('hnsw'), so you can chain it with normal where and policies per Laravel Docs AI SDK.

How to create pgvector HNSW index in Laravel migration?

Use $table->vector('embedding', 1536)->index('hnsw', 'cosine') inside Schema::create — this creates the vector column and CREATE INDEX ... USING hnsw (embedding vector_cosine_ops) in one line per RichDynamix Apr 22 2026. Verify with EXPLAIN ANALYZE showing Index Scan.

Do I need Pinecone or a separate vector DB?

No for catalogs under ~1M rows — Postgres + pgvector + HNSW handles it inside the same DB as your orders at p95 ~18–22ms per 100K rows per RichDynamix Apr 22 2026. Use an external vector store only beyond ~5M rows or when you need multi-region sharding.

Bottom line

  • Laravel 13 AI SDK (Mar 17 2026) adds first-party semantic search: toEmbeddings + vector(1536)->index('hnsw') + whereVectorSimilarTo + SimilaritySearch tool — per Laravel Docs 13.x and Releases Mar 17 2026.
  • HNSW at 1536-d p95 ~18–22ms per 100K rows vs 42ms IVFFlat or 380ms seq scan — per RichDynamix Apr 22 2026 — choose HNSW under 1M rows, no lists tuning needed.
  • 5-step RAG: chunk 800/80 → toEmbeddings ($0.02/1M tokens) → store → SimilaritySearchAi::chat()->withTools — pattern per Laravel News Apr 27 2026.
  • Junagadh playbook: zero-framework PHP LIKE (41% zero-result) → Laravel 13 AI SDK pgvector VPC — zero-result 41%→9%, p95 22ms, $2.14/mo embeddings — via Website Development & Laravel Architecture.
  • Next step: enable vector extension on Postgres 16 today and ship the migration + whereVectorSimilarTo scope — log every call with OTel via get in touch.

Bottom Line: Laravel 13 (Mar 17 2026) ships AI SDK with toEmbeddings, vector(1536)->index('hnsw'), whereVectorSimilarTo, and SimilaritySearch — 5-step RAG in Eloquent at p95 ~22ms and $2.14/mo for 12K chunks; HNSW beats IVFFlat under 1M rows — migrate your LIKE search this week.

Explore the stack we run from Junagadh: SEO & AEO Services · Website Development & Laravel Architecture · AI Development & Autonomous Agents · Business Workflow Automation · get in touch · featured projects.

← All journal articles Get in touch →