How to Migrate an Existing RAG Implementation to RAGAnything: A Complete Guide

RAGAnything is a drop-in wrapper around LightRAG that adds multimodal parsing, processing, and querying without requiring data migration or storage changes.

If you're already running a RAG system built on LightRAG, migrating to RAGAnything unlocks support for PDFs, images, tables, equations, and mixed-media documents—while preserving your existing vector store, knowledge graph, and retrieval logic. According to the HKUDS/RAG-Anything source code, the migration path is intentionally thin because the core RAG engine remains unchanged.


What RAGAnything Adds to LightRAG

RAGAnything implements three orthogonal layers on top of LightRAG:

Layer Purpose Core File
Parser & Ingestion Converts PDFs, Office files, images into a unified content_list raganything/parser.py
Multimodal Processors Generates textual descriptions and knowledge-graph entities from images, tables, equations raganything/modalprocessors.py
RAG Engine LightRAG-based retrieval with hybrid ranking and optional VLM-enhanced reasoning raganything/raganything.py

Because raganything/raganything.py detects pre-initialized LightRAG instances and reuses their storages, no data migration is required.


Step 1: Install RAGAnything

Install with optional extras for full parser support:

pip install raganything[all]

For core functionality only:

pip install raganything

Step 2: Load Your Existing LightRAG Instance

Reuse your working directory and configuration exactly as before. In raganything/raganything.py, the __post_init__ method detects self.lightrag is not None and skips re-initialization.

import os
import asyncio
from lightrag import LightRAG
from lightrag.llm.openai import openai_complete_if_cache, openai_embed
from lightrag.utils import EmbeddingFunc

# Load existing LightRAG storage

lightrag = LightRAG(
    working_dir="./my_light_rag",
    llm_model_func=lambda p, **kw: openai_complete_if_cache(
        "gpt-4o-mini", p, api_key=os.getenv("OPENAI_API_KEY"), **kw
    ),
    embedding_func=EmbeddingFunc(
        embedding_dim=3072,
        max_token_size=8192,
        func=lambda texts: openai_embed.func(
            texts, model="text-embedding-3-large", api_key=os.getenv("OPENAI_API_KEY")
        ),
    ),
)

await lightrag.initialize_storages()  # Loads existing KV/graph/vector stores

Step 3: Define a Vision Model Function

RAGAnything requires a vision_model_func for image captioning and multimodal reasoning. This follows the same pattern as LightRAG's LLM functions but accepts image data:

def vision_model_func(prompt, system_prompt=None, history_messages=[], image_data=None, messages=None, **kw):
    """VLM wrapper for GPT-4o image captioning."""
    if messages:
        return openai_complete_if_cache("gpt-4o", "", messages=messages, **kw)
    
    if image_data:
        return openai_complete_if_cache(
            "gpt-4o",
            "",
            messages=[
                {"role": "system", "content": system_prompt} if system_prompt else None,
                {
                    "role": "user",
                    "content": [
                        {"type": "text", "text": prompt},
                        {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{image_data}"}},
                    ],
                },
            ],
            **kw,
        )
    
    # Fallback to text-only LLM

    return lightrag.llm_model_func(prompt, system_prompt, history_messages, **kw)

Step 4: Wrap with RAGAnything

Instantiate RAGAnything by passing your existing LightRAG instance and vision function:

from raganything import RAGAnything, RAGAnythingConfig

rag = RAGAnything(
    lightrag=lightrag,           # Reuse existing storage

    vision_model_func=vision_model_func,
    # Optional: override LLM/embedding funcs inherited from LightRAG

    # llm_model_func=custom_llm,

    # embedding_func=custom_embed,

)

The RAGAnything class in raganything/raganything.py wraps the LightRAG engine while adding multimodal processors from raganything/modalprocessors.py.


Step 5: Replace Ingestion Calls

Old LightRAG Pattern


# Legacy LightRAG ingestion

await lightrag.insert_documents(text_chunks)
await lightrag.build_graph()

New RAGAnything Pattern

Use process_document_complete for full parsing and ingestion:

await rag.process_document_complete(
    file_path="research_report.pdf",    # PDF, DOCX, images, etc.

    output_dir="./tmp_output",          # Parser temporary files

    parse_method="auto",              # Auto-select: minerU, docling, paddleocr

    # Optional: force specific parser

    # parser="docling"

)

Or use insert_content_list if you have pre-parsed content:

from raganything.parser import ContentList

my_content_list = ContentList(...)  # Your parsed content

await rag.insert_content_list(
    content_list=my_content_list,
    file_path="my_doc.pdf",
    display_stats=True,
)

See examples/insert_content_list_example.py for a complete working example.


Step 6: Replace Query Calls

Text-Only Queries


# Old LightRAG

result = await lightrag.query("What are the main findings?", mode="hybrid")

# New RAGAnything

answer = await rag.aquery("What are the main findings?", mode="hybrid")

Multimodal Queries

Use aquery_with_multimodal for explicit multimodal payloads:

answer = await rag.aquery_with_multimodal(
    "Compare the performance numbers in the table with the trends shown in Figure 2",
    multimodal_content=[
        {
            "type": "table",
            "table_data": """Method,Accuracy,Latency
            RAG-Anything,95.2%,120ms
            Baseline,87.3%,180ms""",
            "table_caption": "Performance Comparison",
        },
        {
            "type": "image",
            "img_path": "/absolute/path/to/figure2.jpg",
            "image_caption": ["Figure 2: Latency vs Accuracy Plot"],
        },
    ],
    mode="hybrid",
)

See examples/raganything_example.py for the complete multimodal query pattern.


Step 7: Clean Shutdown

Register graceful shutdown to flush caches:

await rag.finalize_storages()

RAGAnything automatically registers an atexit handler, but explicit cleanup is recommended for long-running services (FastAPI, Celery workers, etc.).


Summary

  • RAGAnything wraps LightRAG without changing the underlying storage or retrieval engine—migration requires no data export/import.
  • Reuse your existing LightRAG instance by passing it to RAGAnything(lightrag=existing_instance).
  • Add a vision_model_func for image captioning and multimodal reasoning.
  • Replace ingestion with process_document_complete or insert_content_list.
  • Replace queries with aquery (text) or aquery_with_multimodal (mixed media).
  • Call finalize_storages() on shutdown for clean cache flushing.

Frequently Asked Questions

Can I migrate without re-indexing my existing documents?

Yes. Because RAGAnything detects pre-initialized LightRAG instances in raganything/raganything.py, your existing vector store, knowledge graph, and KV cache remain intact. Only new documents processed through process_document_complete receive multimodal enhancement.

What parsers does RAGAnything support?

The parser layer in raganything/parser.py supports MinerU, Docling, and PaddleOCR through a pluggable factory (get_parser). Set parse_method="auto" to let the system select based on file type, or specify parser="docling" to force a particular engine.

Do I need a vision model if I only process text documents?

No. The vision_model_func parameter is optional. If omitted, RAGAnything operates in text-only mode using the inherited LightRAG configuration. Multimodal processors in raganything/modalprocessors.py automatically skip image captioning when no vision function is provided.

How do I handle batch document processing?

Use the batch utilities in raganything/batch.py for folder-wide ingestion. The process_directory function wraps process_document_complete with progress callbacks and error handling, enabling efficient migration of large document collections.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →