uncloseai.

Reverse Retrieval Augmented Generation

Abstract

Traditional Retrieval Augmented Generation (RAG) requires a server-side pipeline: documents are chunked, embedded into vectors, stored in a database, and retrieved by similarity search at query time. This architecture demands infrastructure, indexing latency, and maintenance of embedding models and vector stores.

Reverse Retrieval Augmented Generation (Reverse RAG) inverts this entirely. Instead of the server fetching documents to augment the prompt, the client extracts live content from the page the user is currently viewing and injects it directly into the conversation context. The data comes to the model. No vector database. No embeddings. No indexing pipeline. No server-side retrieval.

This technique is implemented as an AGPL-3.0-only algorithm in uncloseai.js, a single-file JavaScript library that adds a machine learning chat interface to any webpage. By feeding the model the full, fresh content of whatever page the user is on, small 8B-parameter models produce answers that rival much larger models on page-specific questions.

The Problem with Traditional RAG

Standard RAG systems follow a retrieval-then-generate pattern:

  1. Ingest: Crawl documents, split into chunks of ~512 tokens
  2. Embed: Run each chunk through an embedding model (e.g., OpenAI text-embedding-3, sentence-transformers)
  3. Store: Insert vectors into a database (Pinecone, Weaviate, ChromaDB, pgvector)
  4. Query: When a user asks a question, embed the query, find top-k similar chunks by cosine similarity
  5. Generate: Stuff the retrieved chunks into the prompt, send to the LLM

This pipeline has real costs:

Reverse RAG: The Client Has the Context

Reverse RAG starts from a different observation: the user is already looking at the document they want to ask about. The browser has the full, rendered, up-to-the-second content right there in the DOM. Why retrieve it again from a database?

The algorithm:

  1. Extract: Walk the live DOM tree. Pull text, links (as markdown), metadata, structured data. Wait for dynamic content to settle (MutationObserver with 500ms quiet period).
  2. Analyze: Run 13 deterministic analyzers on the extracted content. Zero API calls. Compute reading metrics, readability scores, code block detection, link topology, entity patterns, media inventory, form detection, and more.
  3. Classify: Send a 4000-character preview to the model for one-shot page classification: type, author, topics, tone, domain, audience, key phrases, freshness.
  4. Inject: Concatenate the computed intelligence, classification, and full page content into the system message. Lock it in for the entire conversation session.
  5. Converse: Every subsequent user message is sent with the full page context already in the system prompt. The model has complete knowledge of the page at all times.

There is no step where a server fetches documents. There is no vector similarity search. The context is always the entire page, not a "most relevant" fragment chosen by an embedding model that might be wrong.

Architecture

Stage 1: Content Extraction

The extraction pipeline handles static HTML, dynamic SPAs, and server-rendered content through three mechanisms:

URI Translation: Known dynamic page patterns (GitLab CI logs, API documentation portals) are mapped to their raw content endpoints. A GitLab job page fetches /raw instead of parsing the rendered HTML. This handles cases where the visible DOM is a thin shell over data loaded asynchronously.

DOM Settlement: A MutationObserver watches for DOM changes. Extraction waits until 500ms of silence (no mutations), with a hard timeout at 3 seconds. This handles React/Vue/Svelte apps that hydrate after initial page load.

Recursive DOM Walk: The full document body is traversed. Text nodes become plain text. Anchor tags become markdown links: [link text](href). The output preserves page structure without HTML noise.

// Simplified extraction logic
function extractDOMContent() {
    const title = document.title;
    const meta = document.querySelector('meta[name="description"]')?.content;
    const body = walkDOM(document.body); // recursive text + markdown links
    return `**Page Title**: ${title}\n\n${meta}\n\n${body}`;
}

Stage 2: Page Intelligence (13 Deterministic Analyzers)

Before any model call, 13 analyzers extract ground-truth metrics from the page. Every analyzer runs locally in the browser. Zero network requests. Zero tokens consumed.

AnalyzerOutputPurpose
Structured DataOpen Graph, JSON-LD, Twitter Cards, canonical URI, author, publish dateMachine-readable page metadata
Heading Outlineh1-h6 hierarchy with textDocument structure map
Reading MetricsWord count, sentence count, paragraph count, reading time (238 wpm Brysbaert 2019)Content scope estimation
ReadabilityFlesch-Kincaid grade level with descriptorAudience calibration
Code BlocksCount, languages detected, total lines, code-to-prose ratioTechnical content identification
Link TopologyInternal vs. external count, top 5 external domainsReference network understanding
User ContextTimezone, browser language, device type, referrerPersonalization signals
Media InventoryImage count, alt-text coverage, video embeds (YouTube/Vimeo)Multimedia awareness
Form DetectionForm count, classified type (login/search/contact/checkout)Interactive element awareness
Table ExtractionUp to 5 tables with headers and row countsStructured data in prose
Entity PatternsEmails, prices, dates, version numbers, IPs, percentages (regex, max 10 each)Factual anchor points

The output is formatted for token efficiency. Empty sections are omitted. A typical page produces 5-15 lines of computed intelligence:

Reading: 2,341 words | 89 sentences | 34 paragraphs | ~10 min read
Readability: Flesch-Kincaid grade 9.2 (high school)
Code: 3 blocks (python, javascript) | 156 lines | 23% code-to-prose
Links: 42 internal, 8 external | top: github.com(3), stackoverflow.com(2)
Structured Data: og:type=article | author=fxhp | published=2025-01-15
Entities: prices: $99.99, $129.99 | versions: v1.2.3, v2.0.0

Stage 3: LLM Page Classification

A single inference call classifies the page. The model receives the first 4000 characters of extracted content and returns a JSON object:

{
    "type": "documentation",
    "author": "fxhp",
    "publishDate": "2025-02-24",
    "topics": ["machine learning", "inference"],
    "entities": ["vLLM", "Hermes", "Qwen"],
    "tone": "technical",
    "domain": "technology",
    "audience": "developers running local inference",
    "keyPhrases": ["dynamic model discovery", "streaming SSE"],
    "summary": "Documentation for running local LLM inference with vLLM",
    "contentLanguage": "en",
    "freshness": "evergreen"
}

This classification is optional. If it fails, the conversation proceeds with computed intelligence and raw content alone. The system never blocks on a failed classification.

Stage 4: Context Injection and Locking

All three layers are concatenated into the system message:

SYSTEM MESSAGE:
  [Base identity: "You are Hermes, embedded on this webpage..."]
  [Computed intelligence: reading metrics, code blocks, entities...]
  [Classification: page type, author, topics, tone, key phrases...]
  [Full page content: entire extracted text with markdown links]
  [Conversation instructions: "You have complete knowledge of this page..."]

This combined context is set once via setSystemMessageAppend() and persists for the entire conversation session. Every subsequent user message carries the full page context in the system prompt. The model never loses sight of what page it's on.

Stage 5: Greeting as Attention Primer

The model generates a 3-paragraph greeting that demonstrates page understanding: what the page is about, what's most interesting, and how it can help. This greeting serves as an attention primer. By forcing the model to summarize the page before the user asks anything, the model's internal representations are already aligned with the page content when the first real question arrives.

Why Small Models Punch Above Their Weight

An 8B-parameter model with the right context in its system prompt will outperform a 70B model that's guessing. This is the core insight of Reverse RAG.

Traditional RAG gives the model fragments: 3-5 chunks of ~512 tokens each, selected by embedding similarity, ripped from their surrounding context. The model must reconstruct meaning from these fragments while also answering the user's question.

Reverse RAG gives the model everything: the full page text, the heading structure, the link network, code block languages, reading level, entity patterns, and a classification of what kind of page this is. The model doesn't need to infer anything about the page. It's all right there.

For page-specific questions ("what does this function do?", "who wrote this?", "summarize the third section"), context completeness beats parameter count. A small model with perfect context is more useful than a large model with partial context.

The tradeoff is clear: Reverse RAG uses more prompt tokens per message (the full page is in every system prompt). But inference on small models is cheap. The tokens spent on context are worth far more than the infrastructure costs of running a RAG pipeline to produce worse context.

Two-Layer Context: Ground Truth + Semantic Understanding

The 13 deterministic analyzers and the LLM classification serve different roles:

Layer 1: Computed Intelligence (ground truth). These are facts the model cannot hallucinate because they're computed directly from the DOM. The page has exactly 2,341 words. The Flesch-Kincaid grade is exactly 9.2. There are exactly 3 code blocks in Python and JavaScript. The model receives these as pre-computed facts and can cite them with confidence.

Layer 2: LLM Classification (semantic understanding). The model's own classification of the page type, tone, audience, and key phrases. This is subjective and can be wrong, but it primes the model's attention toward the right framing. A page classified as "recipe" triggers different conversational patterns than one classified as "documentation."

Together, these layers give the model both what the page is (computed) and what the page means (classified). Neither layer alone is sufficient. Ground truth without semantic framing produces dry, unfocused answers. Semantic framing without ground truth produces confident but potentially wrong answers.

Reverse RAG vs. Traditional RAG

DimensionTraditional RAGReverse RAG
Data flowServer retrieves documents for the modelClient pushes page content to the model
InfrastructureVector DB, embedding model, chunking pipeline, reindexing jobsNone. Runs in the browser.
FreshnessHours to days behind (reindex lag)Real-time. Extracted from live DOM.
Context scopeTop-k chunks (~2500 tokens)Entire page + computed intelligence
Context qualityFragments selected by cosine similarity (can miss critical content)Complete page with structure preserved
Retrieval failuresCommon. Embedding similarity is not understanding.Impossible. The entire page is included.
Token cost per queryLower (only retrieved chunks)Higher (full page in system prompt)
Best model sizeLarge (must reason over fragments)Small (8B is sufficient with full context)
Use caseQuestion answering over large document corporaContextual assistance on the page you're viewing
Setup timeDays to weeks (pipeline, embeddings, tuning)One script tag. Done.

These are not competing techniques. Traditional RAG excels at searching across thousands of documents. Reverse RAG excels at deep understanding of the one document the user is actively reading. They solve different problems.

Implementation

Reverse RAG is implemented in uncloseai.js as an AGPL-3.0-only algorithm. The complete source is available and auditable. The implementation spans these files:

FileRole
content.jsDOM extraction, URI translation, page analysis prompts
page-intelligence.js13 deterministic analyzers (zero API calls)
config.jsSystem message assembly, context concatenation
chat.jsMessage delivery with token budget management
uncloseai-embed-modal.jsPipeline orchestration, greeting generation

Installation

<script src="https://uncloseai.com/uncloseai.js" type="module"></script>

One line. The Reverse RAG pipeline runs automatically when the user opens the chat modal. No configuration required. The model receives the full page context on the first interaction.

Graceful Degradation

Every stage of the pipeline is independently failable:

The system never blocks on a failure. A partial context is always better than no context.

Token Budget Management

Full page injection consumes prompt tokens. The system manages this with adaptive token budgeting:

This adaptive strategy ensures the model always has room to generate a meaningful response, even when the page content is large relative to the context window.

License

The Reverse RAG algorithm as implemented in uncloseai.js is licensed under AGPL-3.0-only. You may use, study, and modify the code, but any networked deployment of modified versions must release the source under the same license. This ensures the technique remains open and auditable.

The surrounding uncloseai.js library (chat interface, TTS, translation, vault encryption) is public domain. Only the Reverse RAG pipeline (content extraction, page intelligence, context injection) carries the AGPL-3.0-only license.

Citation

fxhp et al. "Reverse Retrieval Augmented Generation: Client-Side Context
Injection for Small Language Models." uncloseai.com, 2026.
https://uncloseai.com/reverse-rag.html