PHPackages                             oi-lab/oi-laravel-raggable - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Search &amp; Filtering](/categories/search)
4. /
5. oi-lab/oi-laravel-raggable

ActiveLibrary[Search &amp; Filtering](/categories/search)

oi-lab/oi-laravel-raggable
==========================

Make any Eloquent model semantically searchable: a pluggable embedder and vector store turn model content into embeddings for similarity search and RAG retrieval.

v1.2.0(3w ago)029↑33.3%MITPHP ^8.3

Since Jul 6Compare

[ Source](https://github.com/oi-lab/oi-laravel-raggable)[ Packagist](https://packagist.org/packages/oi-lab/oi-laravel-raggable)[ RSS](/packages/oi-lab-oi-laravel-raggable/feed)WikiDiscussions Synced 1w ago

READMEChangelogDependencies (28)Versions (6)Used By (0)

[![OI Laravel Raggable](./assets/github-preview.png)](./assets/github-preview.png)

OI Laravel Raggable
===================

[](#oi-laravel-raggable)

[![Latest Version on Packagist](https://camo.githubusercontent.com/a091a4c244750f47e1679ec15d0eaf56821f70e76d6f7f78155ab75c6a6171b0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6f692d6c61622f6f692d6c61726176656c2d7261676761626c652e737667)](https://packagist.org/packages/oi-lab/oi-laravel-raggable)[![Total Downloads](https://camo.githubusercontent.com/095304b26919d75f9bc2cc23959e273931bad5cdb7c05faaece22cd6e9a0e2e3/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6f692d6c61622f6f692d6c61726176656c2d7261676761626c652e737667)](https://packagist.org/packages/oi-lab/oi-laravel-raggable)[![Tests](https://camo.githubusercontent.com/f21a4e1f7c59601ce6b8eee7ff5f6b34e662ed89028e7db6be47c6e8a3cc1b83/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6f692d6c61622f6f692d6c61726176656c2d7261676761626c652f74657374732e796d6c3f6c6162656c3d7465737473)](https://github.com/oi-lab/oi-laravel-raggable/actions)[![License](https://camo.githubusercontent.com/973d3a28604261696862f20a634cfeba01e663913061a315b2a8cfe477e035be/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6f692d6c61622f6f692d6c61726176656c2d7261676761626c65)](LICENSE)

Make **any** Eloquent model semantically searchable. Add a contract and a trait to a model, describe the text that represents it, and the package embeds that content into vectors, keeps them fresh as the model changes, and answers similarity and RAG-retrieval queries. The embedder and the vector store are both pluggable, so you can start on any database with zero infrastructure and graduate to PostgreSQL + pgvector at scale without touching your models.

Features
--------

[](#features)

- **Plug any model** — implement `Embeddable` and `use HasEmbedding`; nothing else changes about your model.
- **Automatic, incremental indexing** — saving a model re-embeds it on a queue only when its embeddable attributes actually changed (content-hash skip).
- **Pluggable embedder** — a Laravel AI-backed default (`mistral-embed`, OpenAI, Voyage, …) or any provider you implement via the `Embedder` contract.
- **Pluggable vector store** — a portable `database` driver (JSON storage + in-PHP cosine, works on SQLite/MySQL/Postgres) or a `pgvector` driver (native `vector` columns + HNSW indexes) for scale.
- **Chunking built in** — long content is split into overlapping chunks so a single record never exceeds the provider token limit and each vector stays focused.
- **Similarity &amp; RAG queries** — `similarTo()` for related content, `similarToText()` as the retrieval entry point of a RAG pipeline.
- **Runtime-tunable settings** — the cosine threshold, result limit, auto-refresh, and embedding model are read through [`oi-laravel-settings`](https://github.com/oi-lab/oi-laravel-settings) (config is the fallback), so you calibrate without a deploy.
- **Embedding cost tracking** — every embedding request is recorded through [`oi-laravel-ai`](https://github.com/oi-lab/oi-laravel-ai), so embedding usage shows up alongside your agent usage and cost reports.
- **Polymorphic storage** — one `raggable_embeddings` / `raggable_chunks` pair serves every embeddable model; no per-model migration.
- **Typed everywhere** — `spatie/laravel-data` DTOs, a static resolver for every configurable class, and a `raggable:embed` backfill command.

How It Works
------------

[](#how-it-works)

Two polymorphic tables back every embeddable model:

- **`raggable_embeddings`** — one row per model instance (the *document header*): the source text, a content hash, the provider/model used, and a document-level centroid vector.
- **`raggable_chunks`** — the searchable slices. Long text is chunked; each chunk carries its own vector. Similarity search runs at the chunk level for precision, then collapses back to the parent models.

When an `Embeddable` model is saved, `HasEmbedding` dispatches a `GenerateEmbeddingJob` (only if the embeddable attributes changed). The job runs the `EmbeddingService`, which chunks the text, calls the configured `Embedder`, and persists the header + chunks. Queries go through the `SimilarityService`, which turns a source model or a free-text query into a vector and hands it to the configured `VectorStore`.

Requirements
------------

[](#requirements)

- PHP 8.2+
- Laravel 12 or 13
- `laravel/ai` (default embedder) — or your own `Embedder` implementation
- `oi-lab/oi-laravel-ai` — embedding usage/cost tracking
- `oi-lab/oi-laravel-settings` — runtime-tunable settings
- `spatie/laravel-data` ^4.23
- For the `pgvector` driver: PostgreSQL with the `vector` extension available (optionally `pgvector/pgvector`)

Installation
------------

[](#installation)

```
composer require oi-lab/oi-laravel-raggable
```

### Publish &amp; Migrate

[](#publish--migrate)

```
php artisan vendor:publish --tag=oi-laravel-raggable-config
php artisan migrate
```

> **Set the vector dimensions before migrating.** `oi-laravel-raggable.dimensions` must equal your embedding model's output size (e.g. `mistral-embed` = 1024, `text-embedding-3-small` = 1536). The `pgvector` migration reads it to size the column.

Configuration
-------------

[](#configuration)

Key options in `config/oi-laravel-raggable.php`:

```
// Storage driver: 'database' (portable, any DB) or 'pgvector' (Postgres, at scale).
'driver' => env('RAGGABLE_DRIVER', 'database'),

// MUST equal the embedding model output size. Set before migrating.
'dimensions' => (int) env('RAGGABLE_DIMENSIONS', 1024),

// Re-embed automatically when embeddable attributes change.
'auto_refresh' => (bool) env('RAGGABLE_AUTO_REFRESH', true),

// Queue the generation job runs on.
'queue' => env('RAGGABLE_QUEUE', 'default'),

// The embedder — swap for any Embedder implementation.
'embedder' => \OiLab\OiLaravelRaggable\Embedders\LaravelAiEmbedder::class,

'similarity' => [
    'max_distance' => (float) env('RAGGABLE_MAX_DISTANCE', 0.5), // cosine distance cutoff
    'limit' => (int) env('RAGGABLE_LIMIT', 20),
],

// Registry used by `raggable:embed`.
'embeddables' => [
    // 'documents' => \App\Models\Document::class,
],
```

Usage
-----

[](#usage)

### Make a model embeddable

[](#make-a-model-embeddable)

```
use Illuminate\Database\Eloquent\Model;
use OiLab\OiLaravelRaggable\Concerns\HasEmbedding;
use OiLab\OiLaravelRaggable\Contracts\Embeddable;

class Document extends Model implements Embeddable
{
    use HasEmbedding;

    // The text that represents this model. embeddingTextFrom() strips HTML and
    // normalizes whitespace, dropping empty fragments.
    public function toEmbeddingText(): string
    {
        return $this->embeddingTextFrom([$this->title, $this->summary, $this->body]);
    }

    // Only a change to these attributes triggers a re-embed. Keep it tight.
    public function embeddableAttributes(): array
    {
        return ['title', 'summary', 'body'];
    }
}
```

That's it. From now on, every `save()` that changes `title`, `summary`, or `body` refreshes the vector in the background; unchanged content is free.

### Find similar models

[](#find-similar-models)

```
// Related content from an existing record (same type by default).
$related = $document->similar(limit: 5);

// Each result carries the cosine distance (0 = identical).
$related->first()->similarity_distance;
```

### Search from free text (RAG retrieval)

[](#search-from-free-text-rag-retrieval)

```
use OiLab\OiLaravelRaggable\Services\SimilarityService;

$hits = app(SimilarityService::class)
    ->similarToText('How do I reset my password?', Document::class, limit: 8);
```

### Backfill an existing corpus

[](#backfill-an-existing-corpus)

Register the models, then run the command:

```
// config/oi-laravel-raggable.php
'embeddables' => [
    'documents' => \App\Models\Document::class,
],
```

```
php artisan raggable:embed --sync          # inline (dev)
php artisan raggable:embed                 # queued — needs a worker on the configured queue
php artisan raggable:embed documents --fresh
```

Extending
---------

[](#extending)

### Plug your own embedder

[](#plug-your-own-embedder)

Implement the `Embedder` contract and point config at it:

```
use OiLab\OiLaravelRaggable\Contracts\Embedder;
use OiLab\OiLaravelRaggable\Data\EmbeddingResult;

class MyEmbedder implements Embedder
{
    public function embed(array $texts): EmbeddingResult
    {
        // return one vector per input, in order
        return new EmbeddingResult(vectors: $vectors, provider: 'mine', model: 'my-model');
    }
}
```

```
'embedder' => \App\Ai\MyEmbedder::class,
```

### Switch to pgvector at scale

[](#switch-to-pgvector-at-scale)

Set `RAGGABLE_DRIVER=pgvector` (and the correct `dimensions`) on a PostgreSQL connection, then migrate. The migration enables the extension, creates native `vector` columns and HNSW cosine indexes, and the `PgvectorStore` runs nearest-neighbor search in the database. Changing dimensions later means recreating the columns/indexes and re-running `raggable:embed --fresh`.

Runtime settings &amp; cost tracking
------------------------------------

[](#runtime-settings--cost-tracking)

### Tunable settings (oi-laravel-settings)

[](#tunable-settings-oi-laravel-settings)

The values you calibrate after a backfill are read through the setting store first and fall back to config, so they can change at runtime without a deploy:

- `similarity.max_distance`, `similarity.limit`
- `auto_refresh`
- `embedding.provider`, `embedding.model`

The `oi-laravel-settings` adapter is wired automatically. Structural values (`driver`, `dimensions`) intentionally stay in config, because changing them requires re-migrating the vector columns.

```
use OiLab\OiLaravelRaggable\Contracts\SettingStore;

app(SettingStore::class)->set('similarity.max_distance', 0.35, 'Raggable — max distance', 'float');
// OiLaravelRaggable::maxDistance() now returns 0.35, overriding config
```

### Embedding usage (oi-laravel-ai)

[](#embedding-usage-oi-laravel-ai)

Every embedding request is recorded through `oi-laravel-ai` as an `ai_requests` row (token count, linked to the AI catalog when the provider/model are known), so embedding cost appears next to your agent usage in `AiUsageReporter`. Recording is best-effort and skipped when `track_usage` is off:

```
RAGGABLE_TRACK_USAGE=false
```

Database Schema
---------------

[](#database-schema)

- **`raggable_embeddings`** — `embeddable_type` / `embeddable_id` (polymorphic, unique), `content_hash`, `content`, `vector`, `provider`, `model`, `generated_at`.
- **`raggable_chunks`** — `uuid` id, `embedding_id`, `content`, `vector`, `metadata`, `chunk_index`, `token_count`.

Both models are configurable through `oi-laravel-raggable.models.*` so you can subclass them in the host app.

AI Assistant Skills
-------------------

[](#ai-assistant-skills)

This package ships an AI assistant skill so AI coding assistants know how to use it. Install it into your project:

```
php artisan oi:skills oilab-laravel-raggable --project
```

Testing
-------

[](#testing)

```
composer test
```

Contributing
------------

[](#contributing)

Contributions are welcome! Please feel free to submit a Pull Request.

When contributing:

1. Write tests for new features
2. Ensure all tests pass: `vendor/bin/pest`
3. Follow existing code style
4. Update documentation as needed

License
-------

[](#license)

The MIT License (MIT). Please see the [License File](LICENSE) for more information.

Credits
-------

[](#credits)

**[Olivier Lacombe](https://www.olacombe.com)** - Creator and maintainer

Olivier is a Product &amp; Technology Director based in Montpellier, France, with over 20 years of experience innovating in UX/UI and emerging technologies. He specializes in guiding enterprises toward cutting-edge digital solutions, combining user-centered design with continuous optimization and artificial intelligence integration.

**Projects &amp; Resources:**

- [OI Dev Docs](https://dev.olacombe.com) - Documentation for all Open Source OI Lab packages
- [OnAI](https://onai.olacombe.com) - Training courses and masterclasses on generative AI for businesses
- [Promptr](https://promptr.olacombe.com) - Prompt engineering Management Platform

Support
-------

[](#support)

For support, please open an issue on the [GitHub repository](https://github.com/oi-lab/oi-laravel-raggable/issues).

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance95

Actively maintained with recent releases

Popularity9

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~6 days

Total

5

Last Release

23d ago

PHP version history (2 changes)v1.0.0PHP ^8.2

v1.2.0PHP ^8.3

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/369876?v=4)[Olivier Lacombe](/maintainers/olacombe)[@olacombe](https://github.com/olacombe)

---

Tags

laravelaisimilarityembeddingsragpgvectorvector-searchraggable

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/oi-lab-oi-laravel-raggable/health.svg)

```
[![Health](https://phpackages.com/badges/oi-lab-oi-laravel-raggable/health.svg)](https://phpackages.com/packages/oi-lab-oi-laravel-raggable)
```

###  Alternatives

[laravel/ai

The official AI SDK for Laravel.

1.1k4.6M333](/packages/laravel-ai)[laravel/scout

Laravel Scout provides a driver based solution to searching your Eloquent models.

1.7k57.2M686](/packages/laravel-scout)[psalm/plugin-laravel

Psalm plugin for Laravel

3345.4M354](/packages/psalm-plugin-laravel)[anousss007/vigilance

A driver-agnostic control center for Laravel queues, jobs, commands and the scheduler. Monitor what ran (with parameters), see failures, and dispatch jobs or run artisan commands manually from a self-contained dashboard.

1949.9k](/packages/anousss007-vigilance)[illuminate/broadcasting

The Illuminate Broadcasting package.

7127.4M242](/packages/illuminate-broadcasting)[illuminate/notifications

The Illuminate Notifications package.

483.1M1.2k](/packages/illuminate-notifications)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
