Skip to main content

RAGU: Retrieval-Augmented Graph Utility

Turn text into a knowledge graph and query it.

RAGU logo

RAGU is under the MIT license.

Install | Quickstart


Overview

RAGU builds a knowledge graph from raw text and answers questions over it. It is built to move from a laptop to a server without rewrites, and to give you more than one way to retrieve.

  • Retrieval that fits the question. Local graph neighborhoods, global community summaries, naive chunk-vector RAG, and a mix engine — with query planning and optional token-by-token streaming.
  • Reason over structure, not just chunks. Extraction yields Entity and Relation typed by the NEREL ontology (29 entity, 49 relation types), then Leiden community detection clusters the graph — so you can ask broad, thematic questions, not only nearest-neighbor lookups.
  • Async by design. Batched embeddings, batched vector queries, and rate-limited LLM clients throughout.

Partially based on nano-graphrag

Our huggingface community is here

Conceptual documentation

Module documentation


Install

The recommended way is a local build:

git clone https://github.com/AsphodelRem/RAGU.git
cd RAGU
uv pip install -e .

From PyPI:

pip install graph_ragu

If you want to use local models (via transformers etc.), run:

pip install graph_ragu[local]

Quickstart

Simple example of building knowledge graph

import asyncio
import os
import sys
import shutil

from ragu.common.logger import logger
logger.remove()
logger.add(sys.stdout, level="DEBUG")

from ragu import (
    SimpleChunker,
    KnowledgeGraph,
    BuilderArguments,
    Settings,
    TwoStageArtifactsExtractorLLM,
)
from ragu.models.embedder import EmbedderOpenAI
from ragu.models.llm import LLMOpenAI
from ragu.models.openai import CachedAsyncOpenAI
from ragu.utils.ragu_utils import read_text_from_files

client = CachedAsyncOpenAI(
    base_url=os.environ['OPENAI_BASE_URL'],
    api_key=os.environ['OPENAI_API_KEY'],
    rate_min_delay=2,
    rate_max_simultaneous=10,
    retry_times_sec=(2, 2, 2, 2, 2),
    cache='./llm_cache',
    debug_errors_storage='./llm_debug',
)

llm = LLMOpenAI(
    client=client,
    model_name="mistralai/mistral-medium-3",
)
embedder = EmbedderOpenAI(
    client=client,
    model_name="emb-qwen/qwen3-embedding-8b",
    dim=4096,
)

# Configure working directory and language
Settings.storage_folder = "ragu_working_dir"
Settings.language = "english"  # or "russian"

# Remove dir to start building graph from scratch
# shutil.rmtree(Settings.storage_folder, ignore_errors=True)

docs = read_text_from_files("path/to/your/files")

# Initialize chunker
chunker = SimpleChunker(max_chunk_size=1000)

# Set up artifact extractor
from ragu.common.prompts import ICLConfig

icl_config = ICLConfig(
    enabled=True,
    num_examples=2,
)

artifact_extractor = TwoStageArtifactsExtractorLLM(
    llm=llm,
    embedder=embedder,
    icl_config=icl_config,
    do_entity_validation=True,
    do_relation_validation=True,
)

# Configure builder settings
builder_settings = BuilderArguments(
    use_llm_summarization=True,
    use_clustering=False,
    build_only_vector_context=False,
    make_community_summary=True,
    remove_isolated_nodes=True,
)

# Build knowledge graph
knowledge_graph = KnowledgeGraph(
    llm=llm,
    embedder=embedder,
    chunker=chunker,
    artifact_extractor=artifact_extractor,
    builder_settings=builder_settings,
)

asyncio.run(knowledge_graph.build_from_docs(docs))

If you run the code with a storage folder that already contains a knowledge graph, RAGU will automatically load the existing graph.

Example of querying

RAGU ships four retrieval strategies plus a query-planning wrapper. Each engine exposes a_search() (retrieval only) and a_query() (retrieval + LLM answer); sync wrappers search() / query() are also available. For the conceptual workflow of each strategy see docs/en/ragu_components.md; for full parameters see ragu/search_engine/README.md.

Local search

Graph-neighborhood retrieval: find relevant entities, then expand to their relations, community summaries, and source chunks.

from ragu import LocalSearchEngine

local_search = LocalSearchEngine(llm=llm, knowledge_graph=knowledge_graph, embedder=embedder)
local_answer = await local_search.a_query("Who wrote Romeo and Juliet?", use_summary=True, use_chunks=True)
print(local_answer.response)

Global search

Answers broad, corpus-wide questions from community summaries.

from ragu import GlobalSearchEngine

global_search = GlobalSearchEngine(llm=llm, knowledge_graph=knowledge_graph)
global_answer = await global_search.a_query("Your broad query here")
print(global_answer.response)

Naive search (vector RAG)

Chunk-vector RAG without graph expansion.

from ragu import NaiveSearchEngine

naive_search = NaiveSearchEngine(llm=llm, knowledge_graph=knowledge_graph, embedder=embedder)
naive_answer = await naive_search.a_query("Your query here")
print(naive_answer.response)

Mixed search

Runs several engines and asks the LLM to synthesize a single answer from their responses.

from ragu import MixSearchEngine

mix_search = MixSearchEngine(llm=llm, engines=[local_search, naive_search, global_search])
mixed_answer = await mix_search.a_query("Your query here")
print(mixed_answer.response)

Query planning wrapper

Wraps any engine, decomposes a complex question into dependent subqueries, and feeds intermediate answers forward.

from ragu import QueryPlanEngine

planned_local = QueryPlanEngine(local_search)
result = await planned_local.a_query("Who wrote the novel 'Quo Vadis' and what country was the author from?")
print(result.response)

Advanced Configuration

Builder Settings

Configure the knowledge graph building pipeline using BuilderArguments:

from ragu import BuilderArguments, KnowledgeGraph

builder_arguments = BuilderArguments(
    use_llm_summarization=True,  # Enable LLM-based entity/relation summarization
    use_clustering=False,  # Apply clustering before summarization. Use it if your text contains many similar entities.
    build_only_vector_context=False,  # Skip graph extraction, only chunk embeddings
    make_community_summary=True,  # Generate community summaries
    remove_isolated_nodes=True,  # Remove entities without relations
    cluster_only_if_more_than=10000,  # Minimum entities before clustering kicks in
    summarize_only_if_more_than=7,  # Summarize descriptions only when there are many duplicates
    max_cluster_size=128,  # Maximum entities per cluster
    random_seed=42,
)

knowledge_graph = KnowledgeGraph(
    llm=llm,
    embedder=embedder,
    chunker=chunker,
    artifact_extractor=artifact_extractor,
    builder_settings=builder_arguments,
)
await knowledge_graph.build_from_docs(docs)

Common presets (naive vector RAG only, fast graph extraction without summarization, full GraphRAG with communities, and large-corpus clustering) with explanations and ready-to-run scripts are in ragu/graph/README.md.


Client and Rate Limiting Configuration

CachedAsyncOpenAI is the network-level client shared by LLMOpenAI and EmbedderOpenAI. It controls rate limiting, retries, caching, and timeouts.

client = CachedAsyncOpenAI(
    base_url="https://api.openai.com/v1",
    api_key="sk-...",
    rate_max_simultaneous=10,
    rate_max_per_minute=100,
    cache="./llm_cache",
)

llm = LLMOpenAI(client=client, model_name="gpt-4o-mini")
embedder = EmbedderOpenAI(client=client, model_name="text-embedding-3-large", dim=3072)

For the full parameter tables (rate_*, retry_times_sec, embed_timeout, EmbedderOpenAI batching and tokenizer overrides), the shared vs. separate clients guidance for large corpora, and the debug store, see ragu/models/README.md.


Token Limits and Settings

RAGU centralises token-limit and tokenizer configuration in the Settings singleton. These defaults are used by EmbedderOpenAI (for embedding input truncation) and search engines (for LLM context truncation).

from ragu import Settings

# Embedder truncation (applied automatically inside EmbedderOpenAI)
Settings.embedder_token_limit = 8_192                    # max tokens per embedding input
Settings.tokenizer_embedder_backend = "tiktoken"         # "tiktoken" or "local"
Settings.tokenizer_embedder_name = "text-embedding-3-large"

# LLM context truncation (applied by search engines before answer generation)
Settings.llm_context_token_limit = 30_000                # max tokens for search-engine context
Settings.tokenizer_llm_backend = "tiktoken"              # "tiktoken" or "local"
Settings.tokenizer_llm_name = "gpt-4o"

Per-instance overrides on EmbedderOpenAI take precedence over Settings.

For a local BGE model with a 512-token context, set Settings.embedder_token_limit = 512, Settings.tokenizer_embedder_backend = "local", and Settings.tokenizer_embedder_name = "BAAI/bge-large-en-v1.5" (requires pip install graph_ragu[local]).


Serializing Global Settings

Settings.save(path) writes a JSON snapshot of the configuration; Settings.load(path) restores it. Serialization is never invoked automatically. For the list of serialized/excluded fields and the validation behavior, see ragu/common/README.md.

from ragu import Settings

Settings.save("./runs/exp_42/ragu_settings.json")   # persist
Settings.load("./runs/exp_42/ragu_settings.json")   # restore in a fresh process

In-Context Learning (Few-Shot Examples)

RAGU extractors can use few-shot examples to improve extraction quality. When enabled, the extractor selects relevant examples and includes them in the LLM prompt.

from ragu.common.prompts import ICLConfig

icl_config = ICLConfig(
    enabled=True,                       # Enable/disable ICL
    num_examples=2,                     # Number of examples per extraction call (1-3 recommended)
    selection_strategy="semantic",      # "semantic" | "bm25" | "hybrid" | "random"
)

artifact_extractor = TwoStageArtifactsExtractorLLM(
    llm=llm,
    embedder=embedder,                  # Required for "semantic" and "hybrid"; optional for "bm25" and "random"
    icl_config=icl_config,
)

Four selection strategies are available ("semantic", "bm25", "hybrid", "random"). Pre-built example files ship in ragu/common/prompts/icl_examples/; to generate custom ones, run python scripts/generate_icl_examples.py --config config/icl_generation.yaml. For the strategy comparison table and per-strategy embedder requirements, see ragu/common/prompts/README.md.


Knowledge Graph Construction

Each text in the corpus is processed to extract structured information. It consists of:

  • Entities — textual representation, entity type, and a contextual description.
  • Relations — textual description of the link between two entities (or a relation class), as well as its confidence/strength.

RAGU uses entity and relation classes from NEREL. The full type tables are available in English and Russian: docs/en/ontology.md | docs/ru/ontology.md. Pass custom entity_types / relation_types to the extractors to override the defaults.

Entity and Relation are base graph model classes. They can be inherited to create richer domain-specific node and edge types, provided the storage Node / Edge contract is preserved. See graph docs and storage docs.

Extraction pipelines

1. Single-step LLM pipeline

File: ragu/triplet/llm_artifact_extractor.py. A baseline pipeline that uses an LLM to extract entities, relations, and their descriptions in a single step. Supports optional in-context learning with few-shot examples and artifact validation.

2. Two-stage LLM pipeline

File: ragu/triplet/two_stage_extractor.py. Extracts entities first, then extracts relations constrained by the entity list. It can separately validate entity and relation outputs. Supports optional in-context learning with few-shot examples.

3. RAGU-lm (Russian language)

A compact model (Qwen-3-0.6B) fine-tuned on the NEREL dataset. Recognizes and normalizes entities, generates descriptions, and extracts relations. Full prompts, a worked example, and an F1 comparison live in docs/en/ragu_lm.md (RU: docs/ru/ragu_lm.md).


Prompt Customization

All RAGU components that use LLMs inherit from RaguGenerativeModule, which provides get_prompt, get_prompts, and update_prompt to view and override instructions.

from ragu import LocalSearchEngine

search_engine = LocalSearchEngine(
    llm=llm,
    knowledge_graph=knowledge_graph,
    embedder=embedder,
)

all_prompts = search_engine.get_prompts()           # {'local_search': RAGUInstruction(...)}
local_search_prompt = search_engine.get_prompt("local_search")
print(local_search_prompt.messages.to_str())        # rendered prompt text
print(local_search_prompt.pydantic_model)           # response schema

To override an instruction, build a new RAGUInstruction and call search_engine.update_prompt("local_search", custom_instruction). Do not edit DEFAULT_PROMPT_TEMPLATES directly — update_prompt scopes the change to a single module instance. Full examples (including custom messages and few-shot formatters) are in ragu/common/prompts/README.md.


Contributors

Main Idea & Inspiration

  • Ivan Bondarenko — idea, smart_chunker, NER model, ragu-lm

Core Development

  • Mikhail Komarov

Benchmarks & Evaluation

  • Roman Shuvalov
  • Yanya Dement'yeva
  • Alexandr Kuleshevskiy
  • Nikita Kukuzey
  • Stanislav Shtuka

Small Models Pipeline

  • Matvey Solovyev
  • Ilya Myznikov

Star History

RAGU star history

Citation

If you find this work useful, please consider citing our paper:

@misc{komarov2026ragumultistepgraphragengine,
      title={RAGU: A Multi-Step GraphRAG Engine with a Compact Domain-Adapted LLM}, 
      author={Mikhail Komarov and Ivan Bondarenko and Stanislav Shtuka and Oleg Sedukhin and Roman Shuvalov and Yana Dementyeva and Matvey Solovyov and Nikolay O. Nikitin},
      year={2026},
      eprint={2607.11683},
      archivePrefix={arXiv},
      primaryClass={cs.CL},
      url={https://arxiv.org/abs/2607.11683}, 
}

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

graph_ragu-0.0.5.tar.gz (887.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

graph_ragu-0.0.5-py3-none-any.whl (932.9 kB view details)

Uploaded Python 3

File details

Details for the file graph_ragu-0.0.5.tar.gz.

File metadata

  • Download URL: graph_ragu-0.0.5.tar.gz
  • Upload date:
  • Size: 887.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for graph_ragu-0.0.5.tar.gz
Algorithm Hash digest
SHA256 22cece6aea5794bcfd8a7f09ab68c35449be9afb639027862fd0d698a5e6d6bf
MD5 ad5409b062be252df2b9909793cf8e93
BLAKE2b-256 0210bb845234457337a7d938b48504ae332ee1d369de428aab7e3e7c416ab8b0

See more details on using hashes here.

File details

Details for the file graph_ragu-0.0.5-py3-none-any.whl.

File metadata

  • Download URL: graph_ragu-0.0.5-py3-none-any.whl
  • Upload date:
  • Size: 932.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for graph_ragu-0.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 1126d40c73da72313946b268fbd9ac77ef9a09dd220f1c58c33df849cd5828cf
MD5 281680b323cc6cd6f271ddb2b9a405b3
BLAKE2b-256 c8b359bc19b317e6ae135149558f0ef147921e98d9c4776fba9a9bbd8c327f10

See more details on using hashes here.

Release history Release notifications | RSS feed

0.1.0

2 files

This release

0.0.5 This release

2 files

0.0.4

2 files

0.0.3

2 files

0.0.2

2 files

0.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page