Skip to main content

Backend-agnostic one-shot GraphRAG: fuse vector + graph (label/class/relation) seeds with MMR diversity into a single synthesis. Zero-infra default.

Project description

OmniFuse

Backend-agnostic, one-shot GraphRAG. Fire several retrieval strategies at once — vector/lexical passages + graph label-linking + class enumeration + relation expansion — and fuse them with MMR diversity into a single LLM synthesis. No iterative ReAct tool loop. Zero infra, zero lock-in: the full algorithm runs on a pure-Python in-memory backend (dict + BM25), and swaps to Fuseki / Qdrant / any LLM by passing objects that match three small protocols.

from omnifuse import from_triples

of = from_triples(                                  # nodes are inferred; no DB, no API key
    [("담보", "instanceOf", "규정"), ("담보", "한도", "5억")],
    chunks=[("c1", "담보 한도는 5억원이다", ["담보"])],
)
print(of.search("담보 한도").answer)

Load however you have the data — all zero-dep, same search():

from omnifuse import from_jsonl, from_csv, from_fuseki, build_inmemory
of = from_jsonl(triples="t.jsonl", chunks="c.jsonl")
of = from_csv(triples="triples.csv", chunks="chunks.csv")
of = from_fuseki("http://localhost:3030/ds/query", graph_uri="urn:g", user="admin", password="…")
of = build_inmemory(nodes, triples, chunks)         # explicit Node/Triple/Chunk

Why graph fusion (not just vectors)

Pure vector RAG answers from the top-k passages it happens to embed near the query. A graph store also gives you operations cosine similarity can't:

  • Complete enumerationall instances of a class ("list every regulation"), exact counts.
  • Relations / multi-hop — what an entity is connected to, 1-hop neighbors, paths.
  • Minority evidence survives — MMR diversity keeps the decisive exception/warning that near-duplicate passages would otherwise crowd out of a fixed top-k.

OmniFuse fuses both: the vector seed for content, the graph seeds for structure.

Design — algorithm as a library

The algorithm only talks to three typing.Protocols, never to a database:

class GraphStore(Protocol):
    def search_labels(self, query, *, limit=30) -> list[tuple[Node, float]]: ...   # full-text label search
    def class_instances(self, class_id, *, limit=1000) -> list[Node]: ...          # enumeration
    def neighbors(self, node_id, *, hops=1, limit=100) -> list[tuple[str,str,str]]: ...  # traversal
    def count_class(self, class_id) -> int: ...
    def get_node(self, node_id) -> Node | None: ...

class VectorStore(Protocol):
    def search(self, query, *, limit=20) -> list[tuple[Chunk, float]]: ...
    def fetch(self, ids) -> list[Chunk]: ...

class LLM(Protocol):
    def generate(self, prompt, *, system="", timeout=None) -> str: ...
  • Zero-infra defaultInMemoryGraph indexes node labels with BM25 (CJK character n-grams, so Korean/CJK search works with no morphological analyzer), and InMemoryVector uses cosine when embeddings are present, else BM25 lexical.
  • dependencies = [] — the core needs nothing but the standard library. Real backends are optional extras (pip install "xgen-omnifuse[fuseki,qdrant]").
  • Bring your own LLM — pass anything with generate(...); the bundled EchoLLM returns the fused evidence so the pipeline runs end-to-end with no API key.

The pipeline (OmniFuse.search)

  1. vector/lexical seed → adaptive top-k (score-distribution cut, not fixed k)
  2. graph label-linking → 1-hop relations
  3. class enumeration (complete list/count)
  4. HippoRAG — entities of the retrieved chunks → 1-hop expansion
  5. evidence assembled with MMR diversity (Jaccard, no embeddings needed)
  6. one LLM synthesis over the fused evidence
  7. honest evidence_nodes — only the nodes the answer actually cites

Install

pip install xgen-omnifuse            # core (zero deps)
pip install "xgen-omnifuse[dev]"     # + pytest, ruff

Run the demo with no install:

python examples/quickstart.py

Layout

src/omnifuse/
  protocols.py     # GraphStore / VectorStore / LLM  (the swap points)
  models.py        # Node, Triple, Chunk, SearchResult
  text.py          # tokenizer + BM25 (CJK n-grams)
  fusion.py        # MMR, adaptive top-k, relation ranking
  oneshot.py       # OmniFuse.search — the fusion algorithm
  backends/memory.py  # InMemoryGraph + InMemoryVector (zero infra)
  llm.py           # EchoLLM, CallableLLM
  facade.py        # build_inmemory(...)
examples/  tests/

Two interchangeable modes (same algorithm)

# (a) self-contained — zero infra
from omnifuse import build_inmemory
of = build_inmemory(nodes, triples, chunks)

# (b) backed by Apache Jena Fuseki (or any SPARQL endpoint) — graph-only or with a vector store
from omnifuse import OmniFuse, InMemoryVector
from omnifuse.backends.fuseki import FusekiGraph
graph = FusekiGraph("http://localhost:3030/ds/query", graph_uri="urn:my-graph", user="admin", password="…")
of = OmniFuse(graph, InMemoryVector([]))   # search() unchanged

FusekiGraph is stdlib-only (urllib) and uses portable FILTER(CONTAINS(...)), so it works on any SPARQL 1.1 store — not just jena-text.

Roadmap

  • backends/qdrant.py vector adapter; jena-text fast path for FusekiGraph
  • async pipeline (parallel seeds via asyncio.gather)
  • reranker / cross-encoder hook, query expansion
  • configurable ISA predicates and prompt templates (per domain/language)

CI / Releasing

  • ci.yml — runs pytest (3.10–3.12) + python -m build + twine check on every push/PR.
  • publish.yml — on a GitHub Release, builds and uploads to PyPI via Trusted Publishing (no token in the repo). One-time PyPI setup: project → Publishing → add pending publisher PlateerLab / xgen-omnifuse / publish.yml / pypi. (Token mode: add secrets.PYPI_API_TOKEN.)

Build locally:

pip install build && python -m build      # dist/*.tar.gz + *.whl

License

TBD.

Project details


Download files

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

Source Distribution

xgen_omnifuse-0.2.0.tar.gz (17.8 kB view details)

Uploaded Source

Built Distribution

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

xgen_omnifuse-0.2.0-py3-none-any.whl (18.8 kB view details)

Uploaded Python 3

File details

Details for the file xgen_omnifuse-0.2.0.tar.gz.

File metadata

  • Download URL: xgen_omnifuse-0.2.0.tar.gz
  • Upload date:
  • Size: 17.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for xgen_omnifuse-0.2.0.tar.gz
Algorithm Hash digest
SHA256 9be5a56abc6445cdad1613dfc7aeaffd9e7995cc5b2b5d7dfc17edd5f8a6da13
MD5 196db80e656b80da58877593e7553a7b
BLAKE2b-256 331cf920db04f378f9537d1b0fad11f093193bf56d4723f8a909d00ead5ab046

See more details on using hashes here.

File details

Details for the file xgen_omnifuse-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: xgen_omnifuse-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 18.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for xgen_omnifuse-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 035c22909ac7af450ed31cf39ae57abcceb230d2b133ef3140b1852ea660be88
MD5 4f1dd46786fcaf064f0d12af65219c2b
BLAKE2b-256 cc0a25d0bda78efdbc8f87173d7bfa35757956764239815aba3aafdd0bb3fc12

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page