x-laravel/embedding
Laravel package that auto-generates and stores vector embeddings for Eloquent models via laravel/ai. Supports single or multi-slot embeddings with field-based triggers, queued generation per slot, driver-based similarity search across many databases, and optional reranking.
Installation:
composer require x-laravel/embedding laravel/ai
php artisan migrate
Basic Setup:
Add the Embeddable trait and define toEmbeddingText() in your Eloquent model:
use XLaravel\Embedding\Concerns\Embeddable;
use XLaravel\Embedding\Contracts\HasEmbeddings;
class Post extends Model implements HasEmbeddings
{
use Embeddable;
public function toEmbeddingText(): string
{
return $this->title . ' ' . $this->body;
}
}
First Use Case: Trigger embedding generation on a new post:
$post = Post::create(['title' => 'Laravel Embedding', 'body' => '...']);
$post->embed(); // Dispatches a queued job to generate embeddings
toEmbeddingText() and $embeddable configuration.similarTo() or similarToText() for basic retrieval.php artisan embedding:status to verify setup.Single-Slot Models:
class Post extends Model implements HasEmbeddings
{
use Embeddable;
protected array $embeddable = ['title', 'body'];
public function toEmbeddingText(): string
{
return $this->title . ' ' . $this->body;
}
}
title or body changes.$post->embed() or $post->embedSync().Multi-Slot Models:
class Post extends Model implements HasEmbeddings
{
use Embeddable;
protected array $embeddable = [
'title' => ['title'],
'body' => ['body'],
'full' => ['title', 'body'],
];
public function toEmbeddingText(): string|array
{
return [
'title' => $this->title,
'body' => $this->body,
'full' => $this->title . ' ' . $this->body,
];
}
}
title skips body slot).$post->embed('title') or $post->embeddings() to fetch all slots.Attribute-Based Configuration:
use XLaravel\Embedding\Attributes\EmbedOn;
#[EmbedOn(['title', 'body'])]
class Post extends Model implements HasEmbeddings { ... }
RAG Pipeline:
similarToText():
$results = Post::similarToText('Laravel AI', limit: 5);
$reranked = $results->rerankWithScores('Laravel AI performance', take: 3);
Bulk Embedding:
embedding:generate for backfilling:
php artisan embedding:generate "App\Models\Post" --limit=1000
Similarity Search with Filters:
$results = Post::similarTo($vector, threshold: 0.8)
->where('published_at', '>', now()->subYear());
embedding-pgsql-driver) for native vector search.composer require x-laravel/embedding-pulse-plugin
Then include Livewire cards in your Pulse dashboard.Blocking Operations:
embedSync() in production; use queued jobs (embed()) for scalability.embedding:status.Slot Mismatches:
$embeddable won’t auto-cleanup old embeddings.php artisan embedding:clean --invalid-slots-only to prune stale slots.Soft Deletes:
protected bool $keepEmbeddingOnSoftDelete = true;
Driver Conflicts:
php and pgsql) may cause unexpected behavior.config/embedding.php:
'similarity' => ['driver' => 'pgsql'],
Reranking Limits:
take parameter to control batch size:
->rerankWithScores('query', take: 10)
embedding.failures Pulse card or queue logs.embedding:status to verify slot coverage:
php artisan embedding:status "App\Models\Post"
config/embedding.php:
'debug' => [
'log_queries' => true,
],
Embedding Disabled:
Post::disableEmbedding() may persist across requests.Post::enableEmbedding();
Vector Dimensions:
laravel/ai and embedding models use the same vector dimension (e.g., 1536 for OpenAI).config/ai.php:
'default' => [
'model' => 'openai',
'options' => [
'embedding' => [
'model' => 'text-embedding-ada-002',
'dimensions' => 1536,
],
],
],
Queue Stuck Jobs:
php artisan queue:retry all
Custom Drivers:
XLaravel\Embedding\Contracts\SimilarityDriver for unsupported databases.app(SimilarityManager::class)->extend('custom', fn() => new MyDriver());
Event Hooks:
ModelEmbedding/ModelEmbedded events for auditing or side effects:
Post::onEmbedded(fn($post, $slot) => Log::info("Embedded slot {$slot} for post {$post->id}"));
Dynamic Slots:
toEmbeddingText() to generate slots dynamically (e.g., per-user embeddings):
public function toEmbeddingText(): array
{
return [
'user_' . $this->user_id => $this->content,
];
}
How can I help you explore Laravel packages today?