Building Local RAG Workflows in Laravel with NativeRAG Developer Hamzi released NativeRAG, a Laravel package that builds small-to-medium retrieval-augmented generation workflows using local models via Ollama or LM Studio. The package provides chat completions, embeddings, vector search, streaming responses, model indexing, and conversation persistence, storing embeddings and conversations in the application's own database instead of requiring a separate vector database. It offers an Embeddable trait so Eloquent models can be chunked and indexed for contextual search. AI features are becoming normal in web applications, but a lot of teams still hesitate when the first step requires sending private application data to an external API. That is the problem NativeRAG tries to solve for Laravel developers. NativeRAG is a Laravel package for building small to medium retrieval-augmented generation workflows using local models through Ollama or LM Studio. It gives you chat completions, embeddings, vector search, streaming responses, model indexing, and conversation persistence without needing a separate vector database to get started. The goal is simple: keep the Laravel developer experience familiar while making local AI workflows easier to wire into a real application. Retrieval-augmented generation usually has a few moving parts: In many setups, those pieces quickly turn into multiple services. That can be the right architecture at scale, but it is not always what you want on day one. Sometimes you just need to index Eloquent models, search relevant chunks, and ask a local model a question using that context. NativeRAG keeps those pieces inside Laravel as much as possible. The package currently supports: Embeddable trait It is not trying to replace a dedicated vector database for every use case. Instead, it gives Laravel applications a practical starting point for local RAG features. Install the package with Composer: composer require hamzi/nativerag Then publish the configuration and migrations: php artisan vendor:publish --tag="nativerag-config" php artisan vendor:publish --tag="nativerag-migrations" php artisan migrate The package stores embeddings and conversations in your application database. You can use Ollama as the default driver: NATIVE RAG DRIVER=ollama OLLAMA BASE URL=http://localhost:11434 OLLAMA CHAT MODEL=llama3 OLLAMA EMBEDDING MODEL=nomic-embed-text Or LM Studio: NATIVE RAG DRIVER=lmstudio LMSTUDIO BASE URL=http://localhost:1234 LMSTUDIO CHAT MODEL=meta-llama-3-8b-instruct LMSTUDIO EMBEDDING MODEL=nomic-embed-text You can also tune chunking and search behavior: NATIVE RAG CHUNK SIZE=1000 NATIVE RAG CHUNK OVERLAP=200 NATIVE RAG MIN SCORE=0.35 The simplest use case is sending messages to a local chat model: php use Hamzi\NativeRag\Facades\NativeRag; $response = NativeRag::chat 'role' = 'system', 'content' = 'You are a concise Laravel assistant.', , 'role' = 'user', 'content' = 'Explain service containers in simple terms.', , ; echo $response- content; This keeps the API close to common chat message formats while still using Laravel's facade and manager patterns under the hood. One of the most useful parts of the package is the Embeddable trait. You can make a model searchable by implementing EmbeddableContract and returning the text that should be embedded: php namespace App\Models; use Hamzi\NativeRag\Contracts\EmbeddableContract; use Hamzi\NativeRag\Traits\Embeddable; use Illuminate\Database\Eloquent\Model; class Article extends Model implements EmbeddableContract { use Embeddable; public function toEmbeddableString : string { return "Title: {$this- title}\n\nContent: {$this- content}"; } } When the model is saved, NativeRAG can chunk the text, generate embeddings, and store them in the embeddings table. This is especially useful for documentation, knowledge bases, product content, internal notes, support articles, and other text-heavy records. Once content is indexed, you can search using either a plain text query or a precomputed embedding vector: php use Hamzi\NativeRag\Facades\NativeRag; $results = NativeRag::search query: 'How do I run database migrations?', limit: 5, minScore: 0.4, ; foreach $results as $chunk { echo $chunk- chunk content; } For many Laravel applications, this is enough to start building contextual AI features without introducing more infrastructure. A common flow looks like this: Example: php use Hamzi\NativeRag\Facades\NativeRag; use Hamzi\NativeRag\Services\PromptCompiler; $question = 'How can users reset their password?'; $chunks = NativeRag::search $question, limit: 4 ; $context = $chunks - pluck 'chunk content' - implode "\n\n---\n\n" ; $prompt = app PromptCompiler::class - buildRagPrompt systemInstruction: 'Answer using only the provided context.', context: $context, query: $question, ; $response = NativeRag::chat 'role' = 'user', 'content' = $prompt , ; echo $response- content; This pattern is intentionally straightforward. You can replace the prompt, filtering, scoring threshold, or context formatting based on your application's needs. For UI experiences, waiting for a full response can feel slow. NativeRAG supports streaming through server-sent events: php use Hamzi\NativeRag\Facades\NativeRag; use Illuminate\Support\Facades\Route; Route::post '/ai/stream', function { return NativeRag::stream 'role' = 'user', 'content' = request 'message' , , ; } ; That makes it easier to build chat interfaces with Livewire, Alpine.js, Vue, React, or any frontend that can consume an event stream. NativeRAG also includes conversation models for persistent chat history: php use Hamzi\NativeRag\Models\NativeRagConversation; $conversation = NativeRagConversation::create 'name' = 'Support session', ; $conversation- addSystemMessage 'You are a helpful support assistant.' ; $reply = $conversation- ask 'How do I publish the config file?' ; echo $reply- content; The conversation stores user and assistant messages, then sends the current history to the selected driver. History can be pruned by message count or an approximate token budget. System messages can also be preserved so the assistant keeps its instructions. Embedding generation can take time, especially when indexing larger records. NativeRAG can dispatch embedding sync to Laravel queues: NATIVE RAG QUEUE INDEXING=true NATIVE RAG QUEUE CONNECTION=redis NATIVE RAG QUEUE NAME=default That lets normal application requests stay responsive while workers handle chunking and embedding generation in the background. Running models locally gives you more control over where prompts, documents, and embeddings live. That is useful for internal tools and privacy-sensitive applications. But local RAG also has tradeoffs: The package gives you the Laravel plumbing. You still need to choose good models, test outputs, and decide what quality bar makes sense for your product. NativeRAG is a good fit when you want to: It may not be the right fit if you already need distributed vector indexing, advanced ranking pipelines, or large-scale retrieval over millions of chunks. What I like about this approach is that it keeps the first version boring in the best way. You install a Laravel package, publish config and migrations, add a trait to a model, and start searching your own data. The architecture can evolve later, but the early developer experience stays simple. For many teams, that is exactly the right place to start. Repository: https://github.com/hamdyelbatal122/nativerag Package: composer require hamzi/nativerag