Skip to main content

Epistemic Graph RAG with Spreading Activation — retrieval that understands how knowledge relates, not just what it says

Project description

PRISM — Epistemic Graph RAG with Spreading Activation

Propagation & Retrieval via Informed Semantic Mapping

PyPI Python License GitHub

PRISM layers a typed epistemic knowledge graph over your existing vector store, then uses spreading activation to surface knowledge structured by how it relates — not just how similar it is.


The Problem with Standard RAG

Standard RAG returns a flat ranked list. Every chunk gets a similarity score and nothing else:

query → embed → similarity → [chunk, chunk, chunk, ...]   ← no structure

Chunk B may refute Chunk A. Chunk C may specialise a principle in Chunk D. An older document may have been superseded. Standard RAG can't express any of this.


What PRISM Does

PRISM builds a graph where edges carry epistemic type:

Doc A  ──[supports]──▶  Doc B
Doc C  ──[refutes]───▶  Doc D
Doc E  ──[supersedes]▶  Doc F

Retrieval uses spreading activation: a query fires seed nodes via vector search, activation propagates through typed edges, and nodes reached by multiple independent paths (convergence) rank highest.

The result is a structured epistemic answer with five buckets:

Bucket Contents
PRIMARY Core relevant chunks, highest convergence
SUPPORTING Chunks that reinforce or extend the primary answer
CONTRASTING Chunks that challenge or take a different position
QUALIFYING Chunks that add conditions, exceptions, or nuances
SUPERSEDED Historically relevant context now replaced by newer work

Installation

pip install prism-rag

Requires Python 3.11+, an existing LanceDB vector store, and an embedding provider.


Quick Start

1. Build the epistemic graph (one-time)

from prism import PRISM

# Ollama embeddings (local)
p = PRISM(
    lancedb_path = "/path/to/your/lancedb",
    graph_path   = "/path/to/prism_graph.json.gz",
    ollama_url   = "http://localhost:11434",
    embed_model  = "nomic-embed-text",
    llm_base_url = "https://api.openai.com",
    llm_model    = "gpt-4o-mini",
    llm_api_key  = "sk-...",
)

# Or OpenAI-compatible API embeddings
p = PRISM(
    lancedb_path  = "/path/to/your/lancedb",
    graph_path    = "/path/to/prism_graph.json.gz",
    embed_api_url = "https://api.openai.com/v1/embeddings",
    embed_api_key = "sk-...",
    embed_model   = "text-embedding-3-small",
    llm_base_url  = "https://api.openai.com",
    llm_model     = "gpt-4o-mini",
    llm_api_key   = "sk-...",
)

p.build(k_neighbors=8, cross_source_only=True)

Or via the CLI:

prism-build \
    --lancedb-path /path/to/lancedb \
    --graph-path   /path/to/prism_graph.json.gz \
    --llm-api-key  $OPENAI_API_KEY

2. Retrieve

p.load_graph()
result = p.retrieve("your question here", top_k=5)
print(result.format_for_llm())

Output:

PRISM retrieval for: "your question here"
────────────────────────────────────────────────────────────

## PRIMARY
[1] source-a  p.14  § 2.1  (score: 0.923)
    The core relevant passage...

## SUPPORTING EVIDENCE
[1] source-c  p.201  § 8.2  (score: 0.841  [via: specializes])
    A passage that extends the primary answer...

## QUALIFICATIONS & NUANCES
[1] source-d  p.38  § 3.1  (score: 0.712  [via: qualifies])
    A passage adding conditions or exceptions...

─ 1 primary · 1 supporting · 0 contrasting · 1 qualifying · 0 superseded ─

3. Access results programmatically

for chunk in result.primary:
    print(chunk.source, chunk.page, chunk.final_score, chunk.text)

for chunk in result.contrasting:
    print("Contrasting view:", chunk.text[:200])

# Feed structured context directly into your LLM
context = result.format_for_llm()

Epistemic Edge Types

supports        — A provides evidence reinforcing B
refutes         — A directly contradicts B
supersedes      — A replaces or updates B
derives_from    — A is logically derived from B
specializes     — A is a specific instance of B
contrasts_with  — A and B take different, non-exclusive positions
implements      — A is a concrete method putting B into practice
generalizes     — A is a broader abstraction of which B is a case
exemplifies     — A is a concrete example illustrating B
qualifies       — A adds conditions, exceptions, or nuances to B

Each edge carries a propagation weight (0.40–0.90) and a valence that determines which result bucket its target lands in.


Build Performance

The graph is built once offline. PRISM uses a two-stage pipeline that makes large-corpus builds practical:

Stage 1 — Local pre-filter (fast, free) A local Ollama model (gemma4:31b-cloud by default) screens candidate pairs with a binary yes/no question. ~50% of pairs are discarded before any API call. Runs locally, costs nothing.

PRISM checks the model is available in Ollama before starting and prints a clear warning if not, rather than silently skipping filtering.

Stage 2 — Async LLM classification Surviving pairs are classified with full type + confidence using 20 concurrent API requests, in batches of 20 pairs each.

Build time comparison — 30k-chunk corpus, ~50k candidate pairs:

Pipeline Wall Time
v1 — sync, batch=5 ~40 hours
v2 — async only, batch=20 ~30 minutes
v2 — async + stage-1 filter (default) ~15–20 minutes

Checkpoint / resume — if interrupted, the build saves progress automatically and resumes from where it left off.


No Re-embedding Required

PRISM works on top of your existing vector store. If you have a LanceDB corpus with embeddings, you don't need to re-index anything.

  • Existing vectors → used as-is for seed activation
  • Epistemic graph → built from text via LLM, stored as a separate .json.gz file
  • Fallback → if no graph exists, PRISM automatically falls back to pure vector search

Embedding Providers

Ollama (local):

PRISM(ollama_url="http://localhost:11434", embed_model="nomic-embed-text", ...)

OpenAI-compatible API (OpenAI, Azure, Together, Jina, Mistral, etc.):

PRISM(embed_api_url="https://api.openai.com/v1/embeddings", embed_api_key="sk-...", ...)

Links


License

MIT

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

prism_rag-0.2.1.tar.gz (43.5 kB view details)

Uploaded Source

Built Distribution

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

prism_rag-0.2.1-py3-none-any.whl (34.8 kB view details)

Uploaded Python 3

File details

Details for the file prism_rag-0.2.1.tar.gz.

File metadata

  • Download URL: prism_rag-0.2.1.tar.gz
  • Upload date:
  • Size: 43.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for prism_rag-0.2.1.tar.gz
Algorithm Hash digest
SHA256 917775fc15472d97c711a196ccdfa59dc457aebcc298bdfce425197647acd8ae
MD5 432971de0643be6863c2a658155eff52
BLAKE2b-256 519c52468109eedea7b9a49cda332e46568f8fd6b08f9fac2d87b3053eb2d05b

See more details on using hashes here.

File details

Details for the file prism_rag-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: prism_rag-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 34.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for prism_rag-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 1c257c02d2430681989b94c8f6396e846ead9986bb79ba7a1738ed49cb64661b
MD5 d6f5351101b26724bbae74bcec6f6f63
BLAKE2b-256 fcae177c79ecb6702f972f1c6df547f1bf9cd45ad1fdab8740b8ac45e655e329

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