GraphRAG for Research¶
v1.5.0's second pillar — Pillar B: GraphRAG — gave FCC a retrieval surface designed for research corpora that are both large and cross-disciplinary. Classic vector-RAG works well when the relevant chunk is semantically close to the query. Research rarely works that way: the relevant chunk is often three semantic hops away, sitting in a neighbouring discipline that shares an ontology but not a vocabulary. GraphRAG addresses that head-on by combining semantic retrieval, a knowledge-graph walk, a Zachman-cell filter, and optional LYRA harmonic-expansion into a single reproducible pipeline.
This page is the scientist-facing reference for GraphRAG in FCC v1.5.x. It covers corpus setup, the Zachman filter for cross-disciplinary work, LYRA augmentation, reproducibility anchors, and citation formatting for academic output.
The GraphRAG pipeline in one paragraph¶
A GraphRAG query threads four stages: (1) the semantic retriever
surfaces seed nodes from the corpus; (2) a breadth-first graph walk
expands those seeds out to max_hops neighbours along the knowledge
graph's typed edges; (3) a ZachmanCell filter narrows the expanded
subgraph to the relevant enterprise perspective (e.g., only
ARCHITECT/WHAT cells for a data-model question); (4) the LYRA bridge
(when available) augments the filtered result with cross-namespace
harmonic concepts via SKOS-proxy edges. The output is a frozen
GraphRAGResult containing the surviving nodes and edges, a ranked
list of (node_id, score) pairs, and a pre-assembled LLM-ready context
block. Every stage is deterministic; a replay with the same seed
corpus, same query, same max_hops, and same filter produces
byte-identical output.
Source code: src/fcc/rag/graphrag.py. See also
ADR-011 — GraphRAG + Zachman filtering
for the architectural rationale.
Setting up a research corpus¶
GraphRAG's input is a KnowledgeGraph populated from your corpus.
FCC ships five corpus builder functions under
src/fcc/knowledge/builders.py; for custom corpora, the contract is
simple.
Step 1 — ingest documents¶
Use DocumentChunker from fcc.rag.chunking. Six chunking strategies
ship: fixed-size, sentence, paragraph, section-heading, sliding-window,
and semantic-boundary. For literature reviews, section-heading usually
works best because academic papers have predictable internal structure.
from fcc.api import DocumentChunker
chunker = DocumentChunker(strategy="section-heading")
chunks = chunker.chunk_directory("corpus/papers/")
Step 2 — build the knowledge graph¶
A minimal research KG has three node types: Document, Concept,
Author. Edges include cites, discusses, authored_by. For a
richer graph, add Dataset, Method, Finding, and
contradicts / replicates edges.
from fcc.api import KnowledgeGraph
from fcc.knowledge.models import KnowledgeNode, KnowledgeEdge, NodeType
kg = KnowledgeGraph(namespace="my_research_project")
# Populate nodes from chunks, edges from metadata.
# See the Pool D-maintained evolution guide for richer patterns.
Step 3 — add a semantic retriever¶
from fcc.api import SemanticRetriever, MockEmbeddingProvider
retriever = SemanticRetriever(
embedding_provider=MockEmbeddingProvider(dim=384),
chunks=chunks,
)
Any EmbeddingProvider works. For production research use, swap
MockEmbeddingProvider for a sentence-transformers-backed provider.
The MockEmbeddingProvider is deterministic — excellent for
reproducibility tests but not for semantic quality.
Step 4 — assemble the GraphRAG instance¶
from fcc.rag.graphrag import GraphRAG
graphrag = GraphRAG(
kg=kg,
retriever=retriever,
lyra_bridge=None, # lazy-resolved via get_lyra_bridge() if omitted
)
You now have a research-grade GraphRAG instance.
Zachman-cell filtering for cross-disciplinary queries¶
The Zachman 6×6 cross-cut (introduced in v1.4.1) classifies every entity in the FCC ecosystem — personas, actions, workflow nodes, and selected knowledge-graph nodes — into exactly one of 36 cells defined by six perspectives (PLANNER, OWNER, ARCHITECT, ENGINEER, SUBCONTRACTOR, USER) and six abstractions (WHAT, HOW, WHERE, WHO, WHEN, WHY).
Research questions are often implicitly Zachman-typed. A question about experimental methodology lives in ENGINEER/HOW; a question about study motivation lives in PLANNER/WHY; a question about subject- recruitment protocol lives in USER/WHO. GraphRAG's Zachman filter lets you make that typing explicit.
from fcc.classification.zachman import ZachmanCell, Perspective
result = graphrag.query(
query="How do hospital-based BCI studies handle informed consent?",
max_hops=2,
zachman_filter=ZachmanCell(
perspective=Perspective.USER,
abstraction="WHO",
),
)
The filter prunes the expanded subgraph to nodes whose own Zachman
cell matches (or is compatible with — the filter's compatibility
relation is documented in src/fcc/classification/zachman.py). Cross-
disciplinary queries benefit especially: ask about
methodology across medicine, finance, and energy verticals filtered
on ENGINEER/HOW, and the filter keeps the three-discipline results
coherently scoped.
Filter tips for cross-disciplinary work¶
- Start broad, then narrow. Run once without the filter, inspect the top-20 scored nodes, decide which cell actually contains the relevant evidence, then re-run with the filter.
- Use perspective without abstraction for exploratory queries.
Passing only
Perspective.ARCHITECT(without an abstraction) widens the filter to the whole architect row — useful when the abstraction isn't yet obvious. - Layer filters across runs for triangulation. Run the same query against ENGINEER/HOW and ARCHITECT/HOW, then compare the two result sets. Disagreement between the two is itself an interesting finding.
LYRA augmentation for cross-namespace queries¶
LYRA — the Graph-of-Thought bridge promoted to stable in v1.5.0 — expands GraphRAG results across namespace boundaries using SKOS-proxy edges and broad-match chains. The metaphor of the Greek lyre's harmonic expansion is taken seriously: LYRA adds notes in neighbouring keys, not arbitrary distant notes.
from fcc.api import get_lyra_bridge
graphrag = GraphRAG(
kg=kg,
retriever=retriever,
lyra_bridge=get_lyra_bridge(), # picks mock fallback if live is unavailable
)
result = graphrag.query(
query="What retention policies apply to brain-imaging data?",
max_hops=2,
lyra_expand=True,
)
When lyra_expand=True, the LYRA bridge receives the filtered
subgraph and returns a list of cross-namespace candidate concepts.
Typical candidates for a neuroscience query might include DICOM
retention policy, HIPAA PHI retention, and institutional IRB data
management plans. GraphRAG merges these into the final ranked list
with a clear provenance marker so the scientist can distinguish
direct-hit nodes from LYRA-augmented nodes.
LYRA currently has a mock bridge as the stable default — the live LYRA backend is incubating and will land in a future release. The mock bridge walks a 7-node / 6-edge seed graph; it is useful for demonstration and deterministic testing but not for production research. When the live backend lands, the import path does not change — only the availability sentinel flips.
For the bridge origin reasoning, see the Codename Decoder entry on LYRA.
Reproducibility — the three anchors¶
Research retrieval is only useful if it's reproducible. GraphRAG pins reproducibility on three anchors:
Anchor 1 — deterministic BFS and ranking¶
The breadth-first walk is deterministic given a stable node-iteration
order. FCC's KnowledgeGraph stores nodes in insertion order; the
walk visits neighbours in the same order. Ranking (the persona boost
and Zachman filter) is also deterministic. Identical inputs → identical
outputs, every run.
Anchor 2 — frozen results¶
GraphRAGResult is a @dataclass(frozen=True) of immutable tuples.
You can serialize it to JSON (to_dict()), archive it to POLARIS
(see the LTAS walk-through in
Long-Term Archive Stewardship),
and replay it at any future date. The result structure will be
unchanged across v1.x because of the SemVer contract enforced by
KGSE.
Anchor 3 — FAIR + Open Science audit¶
Every GraphRAG query can emit an OPEN-SCI-009 Agent Transparency Card
via the compliance subsystem. The card captures the query, the seed
nodes, the filter parameters, the LYRA augmentation flag, the result
summary, and the embedding-provider hash. For published research, the
card is the citable artifact — the thing you link to from your
"Methods: Retrieval Pipeline" section.
from fcc.compliance.pipeline import CompliancePipeline
pipeline = CompliancePipeline()
card = pipeline.emit_transparency_card(
subject=graphrag,
query_spec={"query": "...", "max_hops": 2, "zachman_filter": "USER/WHO"},
result=result,
)
Store the card alongside the paper. When a reviewer asks "how did you retrieve the supporting evidence?", you point at the card.
Citation formatting¶
A GraphRAG-supported finding has two layers of citation.
Layer 1 — traditional citations¶
The documents retrieved are normal academic sources. Cite them as you
would any other: author, year, title, venue. GraphRAG's
result.nodes includes a KnowledgeNode per document with a
metadata dict that carries the canonical citation.
Layer 2 — methodological citation¶
Add a Methods subsection to the paper that cites the pipeline itself. A minimal citation skeleton:
Evidence retrieval was performed with FCC GraphRAG (v1.5.3). Seed nodes were surfaced via a
SemanticRetrieverover 384-dimensional embeddings; the subgraph was expanded to max_hops=2 and filtered on the ZachmanCell{perspective}/{abstraction}. LYRA harmonic expansion was{enabled|disabled}. The query specification and result summary are recorded in Open-Science Transparency CardOPEN-SCI-009-{card_id}, archived under POLARIS retention classcoldas{archive_id}.
Every bracketed token is filled from the card and the archive metadata. Reviewers with access to the same FCC version, the same corpus, and the same query can reproduce the result bit-identically.
Worked example — a cross-disciplinary BCI study¶
A scientist is drafting a paper on brain-computer-interface patient recruitment. The corpus spans three disciplines: neuroscience, clinical trial methodology, and bioethics.
Step 1: Formulate the question. "What are the consent protocols for BCI clinical trials with patients who have motor neuron disease?"
Step 2: Type the question.
This is a USER/WHO question (patient perspective, consent protocol).
The Zachman filter is Perspective.USER, abstraction="WHO".
Step 3: Run GraphRAG.
result = graphrag.query(
query="consent protocols for BCI clinical trials with MND patients",
max_hops=2,
zachman_filter=ZachmanCell(perspective=Perspective.USER, abstraction="WHO"),
lyra_expand=True,
)
Step 4: Triangulate with a second run. Re-run filtered on ENGINEER/HOW to catch methodology-framed passages the first run may have missed.
Step 5: Emit the transparency card. Record query spec + result summary on the card; archive to POLARIS.
Step 6: Draft the Methods subsection. Cite the card, cite the archive_id, cite the FCC version. The retrieval is now reproducible.
This sequence — formulate, type, run, triangulate, archive, cite — is the recommended GraphRAG research pattern across disciplines.
Interplay with FAIR¶
GraphRAG reinforces the FAIR principles that are core to the FCC scientist tier:
- Findable. The knowledge graph gives every document a stable node_id. The transparency card is findable via the Open-Science index.
- Accessible. Archived queries are pullable from POLARIS at any retention tier. The card carries the access policy.
- Interoperable. The knowledge graph can be serialized to
OWL / RDF / SKOS / JSON-LD via
fcc.knowledge.serializers. The LYRA bridge adds cross-namespace interoperability. - Reusable. The frozen result structure means that any downstream researcher can replay the query on the same corpus and get the same result.
See FAIR Workflow for the FCC-wide FAIR-compliance framing.
Limitations and honest caveats¶
GraphRAG is not a search engine replacement. Some honest caveats:
- Corpus quality dominates. A noisy graph produces noisy results no matter how clever the filter.
- Mock embeddings are deterministic but not semantic. For production research, use a real embedding provider.
- LYRA is currently mocked. Cross-namespace augmentation is limited until the live LYRA backend ships.
- Zachman classification is only as good as the classifier. If
your custom nodes lack a
zachman_cellattribute, the filter silently drops them — verify withfcc audit knowledge --strict. - Persona-boosting can over-concentrate. If you pass a
persona_idhint, the walk over-weights nodes the persona has historically interacted with. This is a feature (personalised retrieval) but also a reproducibility hazard — always record the persona_id in the transparency card.
Related resources¶
- FAIR Workflow — FAIR-compliance framing.
- Literature Review Agents — classic RAG pipeline; GraphRAG builds on the same chunker + retriever.
- Reproducibility Guide — deterministic simulation and trace recording; same discipline extended to retrieval.
Next steps¶
- Walk
docs/tutorials/advanced-capabilities/graphrag-deep-dive.md(Pool B) for a hands-on GraphRAG tutorial. - Run notebook
46_graphrag_advanced_patterns.ipynb(Pool F) — the v1.5.3 notebook that makes the pipeline interactive. - Skim notebook
44_lyra_graphrag_preview.ipynbfor the v1.5.0 LYRA preview that shipped alongside GraphRAG. - Read ADR-011 — GraphRAG + Zachman filtering for the architectural rationale.
- Consult the Codename Decoder for LYRA origin reasoning and canonical status.
- Read the Decision Archaeology page if you need to reconstruct the rationale for a retrieval pipeline choice retrospectively.
- Browse
docs/tutorials/sample-prompts/pillar-graphrag-prompts.md(Pool C) for ready-to-run prompts.