Search by

ahmednour / eloquent-rag

ahmed-nour-dev

The Eloquent synchronization layer for Laravel AI's RAG stack — model lifecycle sync, dependency tracking, invalidation, chunk management, and rebuild tooling.

v0.2.0-beta.1 2026-09-28 13:49 UTC

README

Latest version on Packagist Tests License: MIT PHP 8.3+ Laravel 13.29+

Keep your Eloquent models' RAG index correct, automatically — including when the data a document depends on lives in other models.

Eloquent RAG is the synchronization layer between your Eloquent models and Laravel AI's embeddings and native vector search: model lifecycle sync, dependency tracking, invalidation, chunking, and rebuild tooling. It does not implement vector search itself; it keeps what Laravel's vector search reads up to date.

Example

use Ahmednour\EloquentRag\Concerns\HasRag;
use Ahmednour\EloquentRag\Rag;
use Ahmednour\EloquentRag\RagDefinition;

class Product extends Model
{
    use HasRag;

    public function toRagDefinition(): RagDefinition
    {
        return Rag::make()
            ->content(['name', 'description', 'price'])  // this model's own attributes
            ->relation('category.name')                  // data from related models,
            ->relation('features.name');                 // tracked as dependencies
    }
}

// Saving a product re-syncs its document on the queue. Renaming a category
// re-syncs every product that depends on it, in bounded batches.
Product::create([...]);
$category->update(['name' => 'Audio']);

// Hydrated Product models, most relevant first:
$products = Product::searchRag('wireless speaker for the shower', limit: 5);

// Or with scores and the matching text, for grounding an LLM answer:
foreach (Product::searchRagWithScores('wireless speaker', limit: 5) as $result) {
    $result->model;   // Product
    $result->score;   // cosine similarity, 0.0–1.0
    $result->chunk(); // the matching chunk of the rendered document (null if stale)
}

Embeddings are generated with php artisan rag:sync, or automatically after each save with RAG_AUTO_EMBED=true — see automatic embedding.

Why not just call Laravel AI's vector search directly?

Embedding a row and searching it is the easy part. The hard part is knowing when an embedding has gone stale. A product's document includes its category's name, so renaming that category changes 50,000 products' documents, but none of those product rows changed, so nothing re-embeds them. Eloquent RAG records, per document, which related models it was rendered from. When one of those changes, it finds every affected document through an indexed reverse lookup and re-syncs them in bounded, coalesced queue batches (ten quick edits to one category produce one pass, not ten), skipping documents whose rendered content didn't actually change. See fan-out behavior and the benchmarks (1,000,000 dependent documents resolved and dispatched in under 3 seconds on SQLite).

Requirements

Target Supported Requirement
MariaDB 11.7+ ✅ Laravel 13.29+ (vector query builder API)
PostgreSQL + pgvector ✅ Laravel 13.x
Plain MySQL / SQLite ⚠️ dev only No native vector search; opt-in portable fallback for development and small data

PHP 8.3+, and laravel/ai 0.11.2+ or 1.x. See docs/backend-support.md and docs/support-policy.md.

Installation

composer require ahmednour/eloquent-rag
php artisan migrate
php artisan rag:doctor

rag:doctor checks your Laravel version, database backend, embedding dimensions, and queue setup before anything gets indexed. See docs/installation.md for the full setup.

Status

Beta (v0.2.0-beta.1 on Packagist), and not yet recommended for production. The correctness-critical paths are covered by unit and feature tests plus acceptance suites that run in CI against real MariaDB 11.7 and PostgreSQL+pgvector servers across the supported PHP/Laravel matrix. What's missing before a stable 1.0:

  • Production usage history. No deployment has run it under real traffic yet. If you try it, start with a non-critical model and run php artisan rag:verify on a schedule.
  • Real-backend performance numbers. Fan-out is benchmarked on SQLite only so far; the MariaDB/PostgreSQL run is wired up but not published (see docs/benchmarks.md).
  • API stability. While pre-1.0, a minor release may contain breaking changes (always called out in the changelog).

The portable fallback is never meant for production, whatever the version. Changes are tracked in CHANGELOG.md.

Documentation

Contributing

See CONTRIBUTING.md. Please report security issues privately, as described in SECURITY.md.

License

MIT. See LICENSE.