PHPackages                             sellinnate/rag-engine - 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. [API Development](/categories/api)
4. /
5. sellinnate/rag-engine

ActiveLibrary[API Development](/categories/api)

sellinnate/rag-engine
=====================

Enterprise Retrieval-Augmented Generation engine for Laravel: ingestion, parsing, chunking, embedding, vector store, retrieval, reranking, BYOK security and multi-tenancy.

v1.2.0(today)00MITPHPPHP ^8.2CI passing

Since Jun 27Pushed todayCompare

[ Source](https://github.com/Sellinnate/laravel-ultimate-rag)[ Packagist](https://packagist.org/packages/sellinnate/rag-engine)[ Docs](https://github.com/Sellinnate/laravel-ultimate-rag)[ GitHub Sponsors](https://github.com/:vendor_name)[ RSS](/packages/sellinnate-rag-engine/feed)WikiDiscussions main Synced today

READMEChangelog (4)Dependencies (14)Versions (5)Used By (0)

 [![RAG Engine for Laravel — semantic search & AI answers](art/banner.png)](art/banner.png)

RAG Engine for Laravel
======================

[](#rag-engine-for-laravel)

![Tests](https://camo.githubusercontent.com/aec4a0df2e2d724466b3761a00bcf62755b2f120a4c12a847a48bf364ff3243c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f74657374732d34323925323070617373696e672d627269676874677265656e)![Coverage](https://camo.githubusercontent.com/d199f8dfc0ccc91cfcf397e3f8ade5fab92a5fd35b728bb1310218d0a12ce3a9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f7665726167652d25453225383925413539302532352d627269676874677265656e)![PHPStan](https://camo.githubusercontent.com/1b02b2f6c2946c9b9ad2e14b1c79c5932fdcef4ea31b4d6e79d54af7d7e7a2a7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c253230382d626c7565)![PHP](https://camo.githubusercontent.com/5ed842996550cad148e16d3ad4738491b8319d2fbf7bba88eeeee0cb4bf9b736/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e322532422d373737626234)![Laravel](https://camo.githubusercontent.com/7df61840a0d13a570921441b8a5da7c66d91b0b27763658f25c7f861881b5cfe/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d3131253230253743253230313225323025374325323031332d666632643230)[![License](https://camo.githubusercontent.com/f8df3091bbe1149f398a5369b2c39e896766f9f6efba3477c63e9b4aa940ef14/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e)](LICENSE.md)[![Docs](https://camo.githubusercontent.com/a67a795bc38e35aa4a7b1655e5255373216e249f38f7ff5ef537b56064cbcf2b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646f63732d6c61726176656c2d2d7261672d2d656e67696e652e73656c6c692e696f2d323536336562)](https://laravel-rag-engine.selli.io)

📖 **Full documentation: [laravel-rag-engine.selli.io](https://laravel-rag-engine.selli.io)**

Add **semantic search and AI answers over your own content** to any Laravel app. RAG Engine owns the whole Retrieval-Augmented Generation pipeline — ingesting documents, splitting them, turning them into searchable vectors, and retrieving the most relevant passages for any query. Writing a final answer with an LLM is an optional layer on top.

> **Infrastructure, not a feature.** The engine owns *ingestion → retrieval*; generation is optional and decoupled. Vertical packages, internal agents and search modules build on top without re-implementing ingestion, chunking, embedding or retrieval.

### What you can build

[](#what-you-can-build)

- 🔎 **Semantic search** — a search box that matches by *meaning*, not keywords.
- 🤖 **AI Q&amp;A / chatbots** — LLM answers grounded in *your* content, with citations.
- 📚 **"Ask your docs / tickets / wiki"** features inside an existing app.
- 🧭 **Similarity / recommendations** — "find records like this one".

Use just the search half (no LLM, no AI bill) or add generation later — same code, one config switch.

Table of contents
-----------------

[](#table-of-contents)

- [Features](#features)
- [Requirements](#requirements)
- [Installation](#installation)
- [Quick start](#quick-start)
- [Indexing Eloquent models](#indexing-eloquent-models)
- [Asking questions with an LLM](#asking-questions-with-an-llm)
- [Configuration](#configuration)
- [Supported drivers](#supported-drivers)
- [Security &amp; multi-tenancy](#security--multi-tenancy)
- [Documentation](#documentation)
- [Testing &amp; development](#testing--development)
- [License](#license)

Features
--------

[](#features)

- **Multi-format ingestion** — raw text, file uploads, URLs (SSRF-guarded), cloud storage and Eloquent records. Safely parses Markdown, HTML, XML, CSV, JSON, DOCX and PDF.
- **Pluggable everything** — parsing, chunking, embedding, vector store, reranking and LLM are swappable drivers behind stable contracts.
- **10 embedding providers** — OpenAI, Azure OpenAI, Mistral, Jina, Voyage, Cohere, Gemini, Hugging Face, Ollama, plus a deterministic `fake` driver for tests.
- **Powerful retrieval** — metadata filters, hybrid (semantic + keyword) search with RRF, MMR diversification, reranking, relevance thresholds and small-to-big (parent-child) context expansion.
- **Embeddable Eloquent models** — make any model searchable via one contract; recursive composition of relations, auto-sync on change, and vector→model trace-back.
- **Security by design** — BYOK envelope encryption with a KMS abstraction (`local` + **AWS KMS**), crypto-shredding for "right to erasure", and PII redaction on by default.
- **OCR for scanned PDFs** — pluggable OCR (Tesseract) kicks in when a PDF has no text layer.
- **Quality evaluation** — measure recall@k, precision@k, hit-rate and MRR over a labelled dataset (`rag:evaluate`).
- **Resilient providers** — LLM, reranker and embedder HTTP calls retry transient failures with exponential backoff.
- **Multi-tenancy** — automatic, fail-closed per-tenant scoping of every query.
- **Operations from day one** — immutable (WORM) audit log, cost tracking, lifecycle events, queued/batchable ingestion and Artisan commands.
- **EU-resident by default** — content and embeddings stay in the EU unless you explicitly opt into a non-EU provider.

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

[](#requirements)

RequirementVersionPHP**8.2+**Laravel**11, 12 or 13**A databaseany Laravel-supported (SQLite is fine to start)A dedicated vector database is **not** required to begin: the default store is in-memory, and the `database` store works on plain Postgres/MySQL/SQLite. Use native `pgvector` or Qdrant at larger scale.

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

[](#installation)

```
composer require sellinnate/rag-engine

php artisan vendor:publish --tag="rag-engine-config"
php artisan vendor:publish --tag="rag-engine-migrations"
php artisan migrate
```

The service provider and `Rag` facade auto-register via package discovery. Out of the box the package uses zero-network, deterministic drivers (`fake` embedder, in-memory store, local KMS) so your test suite runs offline.

Important

The `fake` embedder is for **tests only** — it doesn't understand meaning. For a real search feature, configure a real embedder (see [Configuration](#configuration)).

Quick start
-----------

[](#quick-start)

```
use Sellinnate\RagEngine\Facades\Rag;

// 1. INGEST — register content as a Document (stored & encrypted, not yet searchable).
$document = Rag::ingest(
    Rag::source()->text('Refunds are issued within 14 business days of an approved request.')
);

// 2. PROCESS — run the pipeline: parse → clean & redact PII → chunk → embed → store.
Rag::process($document);            // or: ProcessDocumentJob::dispatch(...) on a queue

// 3. SEARCH — find the most relevant chunks by meaning.
$hits = Rag::search('how long until I get my money back?')->topK(3)->get();

$hits[0]->content;                  // "Refunds are issued within 14 business days..."
$hits[0]->score;                    // relevance score
$hits[0]->metadata['source_ref'];   // provenance: where it came from

// 4. (OPTIONAL) ASK — let an LLM write a cited answer from the retrieved chunks.
$answer = Rag::ask('how long do refunds take?')->using('openai')->generate();
$answer->answer;                    // "Refunds take 14 business days. [1]"
$answer->citations;                 // [['index' => 1, 'document_id' => '…', 'chunk_id' => '…']]
```

Refine retrieval fluently:

```
$hits = Rag::search('envelope encryption')
    ->topK(5)
    ->threshold(0.4)        // drop weak matches
    ->where('tag', 'docs')  // metadata filter
    ->hybrid()              // semantic + keyword (RRF)
    ->rerank()              // precision pass
    ->expandParents()       // small-to-big context
    ->get();
```

Indexing Eloquent models
------------------------

[](#indexing-eloquent-models)

If the content you want to search already lives in your database, make the model embeddable — it then stays in sync automatically as rows change, and every vector traces back to its model.

```
use Sellinnate\RagEngine\Concerns\HasEmbeddings;
use Sellinnate\RagEngine\Contracts\Embeddable;
use Sellinnate\RagEngine\Eloquent\EmbeddableDefinition;

class Article extends Model implements Embeddable
{
    use HasEmbeddings; // auto-indexes on save, removes on delete

    public function toEmbeddable(): EmbeddableDefinition
    {
        return EmbeddableDefinition::make()
            ->add('Title', $this->title)
            ->add('Body', $this->body)
            ->include($this->author, 'author')          // compose a related model
            ->includeMany($this->comments, 'comments');  // recursively
    }
}

// Trace a search hit back to its model:
$article = Rag::models()->resolve($hits[0]); // App\Models\Article instance, or null
```

Model **file fields** (a PDF/DOCX upload) can be embedded too — `addFile()` parses the file to text and folds it into the model's embedding; non-embeddable binaries (zip/exe…) are skipped or rejected per policy. See **[docs/concepts/eloquent-models.md](docs/concepts/eloquent-models.md)**.

Asking questions with an LLM
----------------------------

[](#asking-questions-with-an-llm)

Search returns the relevant chunks; an **LLM** turns them into a written, cited answer via `Rag::ask()`. This layer is optional and decoupled — with the default `null` driver, `ask()` returns the sources with an empty answer, so search-only apps carry no LLM dependency.

The package ships two LLM drivers: **`anthropic`** (Claude) and **`openai`**(OpenAI and any OpenAI-compatible API — Mistral, Ollama, Groq, OpenRouter…).

```
# .env — use Anthropic Claude to answer questions
RAG_LLM=anthropic
RAG_ANTHROPIC_API_KEY=sk-ant-...
RAG_ANTHROPIC_MODEL=claude-sonnet-4-6     # or claude-opus-4-8 / claude-haiku-4-5-...
```

```
$result = Rag::ask('What is our refund policy?')
    ->topK(5)
    ->using('anthropic')   // or omit to use the default RAG_LLM
    ->generate();

$result->answer;     // "Refunds are issued within 14 business days. [1]"
$result->citations;  // [['index' => 1, 'document_id' => '…', 'chunk_id' => '…']]
$result->sources;    // the SearchHits the answer was built from
```

Note

**Anthropic has no embedding API**, so `anthropic` is a *generation-only*driver. Keep a real `RAG_EMBEDDER` (Mistral, OpenAI, Ollama…) for the search side. A common combo is **Mistral/Ollama embeddings + Claude answers**.

Retrieved content is treated as untrusted: the default prompt fences it and tells the model not to follow instructions inside it (prompt-injection hardening). Full guide: **[docs/concepts/generation.md](docs/concepts/generation.md)**.

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

[](#configuration)

Configuration lives in `config/rag-engine.php` and works like Laravel's `config/database.php`: you define named *connections* per subsystem and pick a `default`. Switching provider = changing one name in `.env`.

```
# .env — switch to a real embedder (Ollama is free & local)
RAG_EMBEDDER=ollama
RAG_OLLAMA_BASE_URL=http://localhost:11434

# ...or a hosted provider:
RAG_EMBEDDER=openai
RAG_OPENAI_API_KEY=sk-...
```

Note

**API keys go in `.env`, never in the committed config.** A copy-ready list of every variable ships as [`.env.example`](.env.example). See [docs/getting-started/configuration.md](docs/getting-started/configuration.md).

Supported drivers
-----------------

[](#supported-drivers)

**Embedders** (`RAG_EMBEDDER`)

DriverProviderResidency`openai`OpenAIglobal`azure-openai`Azure OpenAIEU (EU region)`mistral`MistralEU`jina`Jina AIEU`voyage`Voyage AIglobal`cohere`Cohereglobal`gemini`Google Geminiglobal`huggingface`Hugging Face / self-hosted TEIglobal / self-host`ollama`Ollama (BGE/E5/Nomic)self-hosted`fake`deterministic (tests)local**Vector stores** (`RAG_VECTOR_STORE`): `memory` (tests/dev) · `database`(portable SQL: Postgres/MySQL/SQLite, brute-force) · `pgvector` (**native**Postgres ANN: `vector` column + HNSW + ``) · `qdrant` (EU self-hostable, ANN at scale). Full setup, including **where to configure the Postgres connection**, is in the [Vector stores guide](https://laravel-rag-engine.selli.io/concepts/vector-stores).

**LLMs** (`RAG_LLM`, for `ask()`): `anthropic` (Claude) · `openai` (OpenAI and any OpenAI-compatible API: Mistral, Ollama, Groq, OpenRouter…) · `null`/`fake`. Anthropic is generation-only (no embeddings). Answers can be **streamed** with `Rag::ask(...)->stream()`.

**Rerankers** (`RAG_RERANKER`, optional cross-encoder pass): `cohere` · `jina`(EU) · `null`/`fake`.

**KMS** (`RAG_KMS`, BYOK key management): `local` (dev) · `aws` (AWS KMS, production).

**OCR** (`RAG_OCR`, scanned-PDF fallback): `null` · `tesseract`.

**Parsers**: plain text · Markdown · HTML · XML · CSV/TSV · JSON · DOCX · PDF (+ OCR for scans).

**Chunkers**: `recursive` (default) · `sentence` · `markdown` · `fixed`(char- or token-based), with optional parent-child and contextual headers.

All drivers share one contract — switching backends needs no code changes, and you can register your own (see [docs/guides/custom-drivers.md](docs/guides/custom-drivers.md)).

Security &amp; multi-tenancy
----------------------------

[](#security--multi-tenancy)

- **BYOK envelope encryption** — content is encrypted at rest with per-item DEKs wrapped by a tenant KEK in a KMS; the plaintext key never persists.
- **Crypto-shredding** — honour "right to erasure" by destroying the key, making data unrecoverable everywhere (including DB backups) at once.
- **PII redaction** — emails, cards (Luhn), IBANs (mod-97), Italian fiscal codes and phone numbers are redacted before indexing, by default.
- **Fail-closed multi-tenancy** — every query is automatically scoped to the current tenant; scope can never be widened from a query (a tested invariant).
- **Tamper-evident audit log** — append-only with database-level WORM triggers.

```
use Sellinnate\RagEngine\Facades\Rag;

// Run work scoped to a tenant (previous tenant restored afterwards):
Rag::forTenant('tenant-7', fn () => Rag::search('q')->get());

// Right to erasure — crypto-shred a tenant:
Rag::kms()->destroyKey('tenant-7');
```

See [docs/concepts/security.md](docs/concepts/security.md) and [docs/concepts/multi-tenancy.md](docs/concepts/multi-tenancy.md).

Documentation
-------------

[](#documentation)

The full documentation is hosted at **[laravel-rag-engine.selli.io](https://laravel-rag-engine.selli.io)**. The sources live in [`docs/`](docs/) and are built into a static site with [docmd](https://docmd.io):

```
npm install
npm run docs:dev     # local preview
npm run docs:build   # static site into ./site
```

**Start here:**

- 🧠 [What is RAG?](https://laravel-rag-engine.selli.io/getting-started/what-is-rag) — concepts + glossary, from zero.
- 🚀 [Quickstart](https://laravel-rag-engine.selli.io/getting-started/quickstart) — a complete worked example.
- 🏗️ [Architecture](https://laravel-rag-engine.selli.io/concepts/architecture) — how the pieces fit together.
- 📥 [Ingesting content](https://laravel-rag-engine.selli.io/guides/ingestion) · 🔎 [Retrieval &amp; search](https://laravel-rag-engine.selli.io/concepts/retrieval) · 💬 [Generation](https://laravel-rag-engine.selli.io/concepts/generation)
- 🗄️ [Vector stores &amp; configuration](https://laravel-rag-engine.selli.io/concepts/vector-stores) — incl. pgvector Postgres setup.
- 📊 [Evaluating quality](https://laravel-rag-engine.selli.io/guides/evaluation) — recall@k, MRR, `rag:evaluate`.
- 🧩 [Contracts reference](https://laravel-rag-engine.selli.io/reference/contracts) · 🛠️ [Custom drivers](https://laravel-rag-engine.selli.io/guides/custom-drivers)

Testing &amp; development
-------------------------

[](#testing--development)

```
composer test         # run the Pest suite (429 tests)
composer analyse      # PHPStan, level 8
composer format       # Laravel Pint (code style)

# Coverage (needs a coverage driver, e.g. Xdebug/PCOV):
XDEBUG_MODE=coverage vendor/bin/pest --coverage --min=90
```

Quality gates kept green on every change: **429 tests**, **PHPStan level 8**, **Pint** clean, **≥90% coverage**.

License
-------

[](#license)

MIT — see [LICENSE.md](LICENSE.md).

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance100

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

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 ~0 days

Total

4

Last Release

0d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/8df9dced104a057028a8e34fb75f3206562b0d0d700fb2dcaea834e490a6cdc8?d=identicon)[sellinnate](/maintainers/sellinnate)

---

Top Contributors

[![FilippoCalabrese](https://avatars.githubusercontent.com/u/15164324?v=4)](https://github.com/FilippoCalabrese "FilippoCalabrese (52 commits)")

---

Tags

laravelembeddingsqdrantragpgvectorretrieval-augmented-generationvector-searchSellinnate

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/sellinnate-rag-engine/health.svg)

```
[![Health](https://phpackages.com/badges/sellinnate-rag-engine/health.svg)](https://phpackages.com/packages/sellinnate-rag-engine)
```

###  Alternatives

[dedoc/scramble

Automatic generation of API documentation for Laravel applications.

2.1k9.9M90](/packages/dedoc-scramble)[spatie/laravel-pdf

Create PDFs in Laravel apps

1.0k4.3M42](/packages/spatie-laravel-pdf)[defstudio/telegraph

A laravel facade to interact with Telegram Bots

815320.5k3](/packages/defstudio-telegraph)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3913.7k](/packages/rawilk-profile-filament-plugin)[simplestats-io/laravel-client

Analytics for Laravel. Track visitors, registrations, and payments. Discover which channels actually drive revenue, not just traffic. Server-side, GDPR compliant, ad-blocker proof.

5019.3k](/packages/simplestats-io-laravel-client)[spatie/laravel-github-webhooks

Handle GitHub webhooks in a Laravel application

93157.3k5](/packages/spatie-laravel-github-webhooks)

PHPackages © 2026

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