# RAG-Anything Comparison & Analysis

## Overview

This document records our analysis of [RAG-Anything](https://github.com/HKUDS/RAG-Anything) (arXiv:2510.12323, ~20K stars, v1.3.0) against our schema discovery search service. RAG-Anything is the multimodal successor to [LightRAG](https://github.com/HKUDS/LightRAG) -- it processes documents containing interleaved text, images, tables, and equations through a unified pipeline that builds a multimodal knowledge graph and answers queries spanning all content modalities.

We evaluated it to identify transferable techniques, as we did with [LightRAG](lightrag-comparison.md) and [ChromaFs](chromafs-comparison.md).

**Last updated**: 2026-05-10 (RAG-Anything v1.3.0, 20,001 stars (up from 19,996), 2,284 forks, 101 open issues. Last push May 6. DoclingParser switched from CLI to Python API (breaking). OMML equation extraction added. New in v1.3.0: MiniMax provider support, Ollama integration example, configurable LLM/vision model names via env vars, DoclingParser remote URL support, MinerU subprocess timeout. v1.2.10 additions: vLLM backend, PaddleOCR parser, custom parser plugin system, processing events/callbacks, retry/circuit breaker, multilingual prompts, path traversal fix. Parent project LightRAG at 34,977 stars. @coda/search post-PR-198 with engine decomposition, graph exploration RPCs, progressive examples, cookbook.)

---

## How RAG-Anything works

RAG-Anything extends LightRAG with a five-stage pipeline for multimodal document ingestion and retrieval:

### Stage 1 -- Document parsing

Pluggable parsers (MinerU, Docling, PaddleOCR) decompose documents (PDF, DOCX, PPTX, XLSX, images) into typed content blocks -- text, image, table, equation -- while preserving page/section hierarchy. A custom parser registry allows runtime registration via `register_parser()` / `unregister_parser()`.

### Stage 2 -- Content routing

Each content block is auto-categorized by type and routed to a specialized processor.

### Stage 3 -- Multimodal analysis

Four specialized processors generate textual descriptions of non-text content:

| Processor                | Input                 | Technique                                    |
| ------------------------ | --------------------- | -------------------------------------------- |
| `ImageModalProcessor`    | Base64-encoded images | VLM captioning with surrounding-text context |
| `TableModalProcessor`    | Markdown tables       | LLM statistical/relational analysis          |
| `EquationModalProcessor` | LaTeX equations       | LLM domain mapping                           |
| `GenericModalProcessor`  | Custom types          | Extensible fallback                          |

### Stage 4 -- Knowledge graph indexing

Built on LightRAG's graph engine: LLM entity extraction, graph nodes/edges, cross-modal relationships, entity deduplication and description merging.

### Stage 5 -- Modality-aware retrieval

Three query types: text queries (standard LightRAG search), VLM-enhanced queries (auto-loads referenced images for multimodal reasoning), multimodal queries (user supplies specific tables/equations/images alongside query).

---

## How our system differs

| Aspect                  | RAG-Anything                                                         | @coda/search                                                               |
| ----------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| **Purpose**             | Answer questions about document content                              | Discover relevant schemas for an AI agent's next action                    |
| **Corpus**              | Unstructured multimodal documents (PDF, DOCX, images)                | Structured schema metadata (GraphQL types, Snowflake tables)               |
| **Graph source**        | LLM-extracted entities/relations from text + multimodal descriptions | Structurally derived (type->field edges, FK inference from `_ID` columns)  |
| **Retrieval signals**   | Entity VDB, relation VDB, chunk VDB, graph traversal                 | BM25 keyword, HNSW vector, glossary boost, graph degree, proximity -> RRF  |
| **Score fusion**        | Round-robin positional interleaving (inherited from LightRAG)        | Reciprocal Rank Fusion -- score-based, N-signal, mathematically principled |
| **Indexing cost**       | Very high (LLM + VLM calls per chunk/image/table)                    | Zero LLM calls (tokenize + embed only)                                     |
| **Query latency**       | ~500ms-5s (LLM keyword extraction + optional VLM reasoning)          | ~10-15ms (in-memory BM25 + HNSW)                                           |
| **Multimodal**          | Full (images, tables, equations, charts)                             | None (text metadata only)                                                  |
| **Lexical matching**    | None                                                                 | BM25 with Porter stemming, prefix fallback, camelCase splitting            |
| **Incremental updates** | Re-extract entities via LLM (expensive)                              | Diff-based add/update/remove on HybridSearch (cheap)                       |
| **Test infrastructure** | 19 test files                                                        | ~1,386 total tests, 40 golden queries, NDCG=0.887, MRR=0.943               |

---

## Why we are not adopting RAG-Anything

### 1. Our corpus is structured -- multimodal parsing adds no value

RAG-Anything's headline feature is decomposing documents into text, images, tables, and equations. Our corpus is already structured metadata. The entire parsing + content routing + modal processing pipeline (stages 1-3) is irrelevant.

### 2. LLM-per-chunk indexing cost is prohibitive at poll frequency

|                            | RAG-Anything       | @coda/search     |
| -------------------------- | ------------------ | ---------------- |
| Cost per 10K items (cold)  | ~$5-15 (LLM + VLM) | ~$0 (local ONNX) |
| Cost per poll (50 changed) | ~$0.25-0.75        | $0               |
| Time per poll (50 changed) | ~30-120s           | ~3s              |

### 3. Query-time LLM calls violate our latency budget

Even keyword extraction alone (~200-500ms) would add 20-50x latency over our 10-15ms budget.

### 4. Round-robin fusion is inferior to RRF for heterogeneous signals

RAG-Anything inherits LightRAG's positional interleaving fusion, ignoring scores. We fuse 6+ signals through RRF.

### 5. No lexical retrieval

Like LightRAG, RAG-Anything has no BM25 or keyword scoring. For schema discovery, exact keyword matching (`ARTIST_ID` -> `ARTIST_ID` column) is critical.

---

## What we could adopt from RAG-Anything

After thorough evaluation, **nothing new to adopt**. The patterns transferable from the LightRAG family were already adopted from LightRAG itself.

| RAG-Anything feature (new since v1.2.6) | Our equivalent                                            | Gap?                       |
| --------------------------------------- | --------------------------------------------------------- | -------------------------- |
| Custom parser plugin system             | `SchemaFetcher<TRaw>` + `DocumentTransformer<TRaw, TDoc>` | None                       |
| Events and callbacks system             | `EventBus` with 28 typed events, OTel-compatible          | None (ours is more mature) |
| Circuit breaker + retry utilities       | `@coda/async` circuit breaker, retry, semaphore           | None                       |
| Offline mode                            | In-memory ONNX embedding (no network required)            | None                       |
| Batch dry-run                           | Not needed (polling model, not batch ingest)              | N/A                        |
| OMML equation extraction (v1.3.0)       | Not applicable (no document parsing)                      | N/A                        |

---

## Enterprise readiness comparison

| Dimension                   | RAG-Anything                                | @coda/search                                                 |
| --------------------------- | ------------------------------------------- | ------------------------------------------------------------ |
| **Deployment model**        | Python library; user manages infrastructure | Node.js service with ConnectRPC; Fargate-deployed            |
| **Health checks**           | None built-in                               | `isReady()`, `isDegraded()`, per-index health                |
| **State management**        | File-based working directory                | State machine (CREATED->READY->DEGRADED->DESTROYED)          |
| **Graceful degradation**    | Circuit breaker on LLM calls (v1.2.10)      | Two-phase init, keyword-only fallback, per-stage fallback    |
| **Observability**           | Callbacks (v1.2.10)                         | 28 event types, OTel-compatible traces, admin UI             |
| **Incremental updates**     | Full re-extraction per changed document     | Diff-based add/update/remove; ~3s for 50-item delta          |
| **Resource predictability** | Unbounded (LLM calls scale with corpus)     | Bounded (~55MB for 10K uint8-quantized vectors + BM25 index) |
| **CI / testing**            | 19 test files; no benchmark suite           | ~1,386 tests, 40 golden queries, regression guards           |
| **Cost at scale**           | $5-15 per 10K items (LLM + VLM)             | $0 (local ONNX, no external calls)                           |

---

## Developer experience comparison

| Dimension            | RAG-Anything                                   | @coda/search                                                   |
| -------------------- | ---------------------------------------------- | -------------------------------------------------------------- |
| **Minimal example**  | ~60 lines (process_document_complete + aquery) | ~15 lines given configured fetcher                             |
| **Type safety**      | Python dynamic typing; no generics             | Full TypeScript generics: `SearchEngine<TRaw, TDoc, TContext>` |
| **Composability**    | Monolithic -- must use full pipeline           | Mix-and-match: stages, signals, fusion independently usable    |
| **Sub-path exports** | Single package entrypoint                      | 9 sub-path exports                                             |
| **Dependency count** | Heavy: huggingface_hub, lightrag-hku, mineru   | Minimal: `@coda/data-structures`, `lru-cache`                  |

---

## Scope & limitations

### RAG-Anything limitations

1. No lexical retrieval -- vector-only search misses exact identifiers
2. No score fusion -- round-robin interleaving, no meaningful relevance scores
3. LLM dependency at every stage -- no degraded mode without an LLM
4. No incremental diff -- changed documents require full re-extraction
5. No quantized vectors -- no memory efficiency optimization
6. Weak test infrastructure -- no benchmark suite, no regression guards
7. No state machine -- no formal lifecycle management

### @coda/search limitations

1. No multimodal support -- text metadata only
2. No document ingestion -- cannot parse PDFs or Office documents
3. No LLM-powered entity extraction -- misses implicit relationships
4. Schema-specific -- optimized for schema metadata patterns

---

## Verdict & recommendations

### If we started fresh, what would we adopt from this project?

**Nothing that we have not already adopted from LightRAG.** RAG-Anything's innovations are in multimodal document parsing (stages 1-3), which is orthogonal to our structured-metadata search problem.

### What are we doing better?

- **Retrieval precision**: 8-signal RRF fusion produces NDCG=0.887, MRR=0.943. RAG-Anything uses round-robin interleaving with no quality measurement.
- **Latency**: 10-15ms vs 500ms-5s. 50-500x faster.
- **Cost**: $0 per query and per index build. RAG-Anything costs $5-15 per 10K items.
- **Lexical precision**: BM25 with Porter stemming, camelCase splitting, prefix fallback. RAG-Anything has no keyword search at all.
- **Composability**: 12 pluggable interfaces vs a monolithic `RAGAnything` class.
- **Test coverage**: ~1,386 tests vs 19 test files.

### What are we missing for enterprise-level production readiness?

- **Multimodal support**: If our corpus ever includes non-text content, we have no processing pipeline.
- **LLM-powered entity extraction**: Our graph is structurally derived. RAG-Anything's LLM-extracted entities capture implicit relationships we miss.
- **Community size**: 19,996 stars vs private internal project.

### Overall assessment

**No action needed.** RAG-Anything's core innovations address problems we do not have. The graph-RAG ecosystem has not added BM25/lexical search -- our primary differentiator persists.

---

## References

- Guo, Z. et al.: [RAG-Anything: Multimodal RAG for Any Content Type](https://arxiv.org/abs/2510.12323) (arXiv:2510.12323, 2025)
- [RAG-Anything GitHub](https://github.com/HKUDS/RAG-Anything) -- v1.3.0 (2026-05-06), 20,001 stars, 2,284 forks, MIT license
- LightRAG comparison: [lightrag-comparison.md](lightrag-comparison.md)
- ChromaFs comparison: [chromafs-comparison.md](chromafs-comparison.md)
