Graphs & GraphRAG
Ask a new hire where the supplier of your main hardware part is based and they cannot answer from any one document. They read the spec sheet, then the purchase order, then the vendor's letterhead, and join the three in their head. Plain search cannot do that join. It scores each page against the question, finds each one only vaguely related, and stops. GraphRAG is the join.
What a knowledge graph is
A graph is just things and the links between them. The things are entities (a company, a person, a part, a place) and the links are relationships (depends on, supplied by, reports to, located in). "Component K9 is supplied by Helios Dynamics" is one link between two entities. Stack thousands of these and you have a map of how everything in your documents relates.
A vector index knows that two passages sound similar. A graph knows that two entities are connected, even when the passages that mention them sound nothing alike and live in different files.
The question vector search cannot answer
Say three documents between them contain: "the Greenfield platform depends on Component K9", "Component K9 is supplied by Helios Dynamics", and "Helios Dynamics is headquartered in Lisbon". Now ask: "where is the supplier of Greenfield's hardware dependency based?"
No single chunk contains that answer. The chunk about Greenfield never mentions Lisbon. The chunk about Lisbon never mentions Greenfield. Vector search scores each chunk against the question, finds each only loosely related, and cannot make the three hops needed to connect them. You get a shrug or a guess.
How GraphRAG bridges it
When GraphRAG is on, ingest does an extra pass. As it reads each chunk it pulls out the entities and the relationships between them and records them as links, each one keyed back to the chunk it came from. So alongside the vector index you get a graph: Greenfield depends-on K9, K9 supplied-by Helios, Helios headquartered-in Lisbon. Provenance is the reason for that keying. A fact with no chunk behind it is unciteable, and an unciteable fact is indistinguishable from a hallucination by the time it reaches your user.
At query time the vector search still runs first and still finds the chunks nearest the question. The entities named in those chunks become the entry points, and from each one the graph is walked outward a couple of hops to collect connected facts. Two hops is the useful depth in practice. One hop rarely adds anything the chunk did not already say, and by four hops you have pulled in half the graph and reintroduced exactly the noise problem retrieval exists to solve. The model receives the usual passages plus a short list of relationships it can chain, so Greenfield to K9 to Helios to Lisbon is sitting right there in the prompt.
// file_search output with graphrag_enabled: the usual "results" chunks,
// plus a "facts" array the model can chain across documents.
{
"results": [ /* the nearest chunks, as always */ ],
"facts": [
{ "subject": "Greenfield platform", "predicate": "DEPENDS_ON", "object": "Component K9" },
{ "subject": "Component K9", "predicate": "SUPPLIED_BY", "object": "Helios Dynamics" },
{ "subject": "Helios Dynamics", "predicate": "HEADQUARTERED_IN","object": "Lisbon" }
]
}Turning it on
It is one field. Set graphrag_enabled: true when you create the store (or PATCH it on later). Ingest then builds the graph as well as the vector index, and file_search starts returning the facts array next to the chunk citations. Your calling code does not change; if it ignores facts it just gets normal vector results.
If a query has nothing for the graph to add, the facts array comes back empty and you pay nothing extra for it. The graph only bills storage when it is holding something, with the first 1 GB-day per store per day free, same as the vector index.
When it earns its keep, and when it does not
Reach for GraphRAG when answers depend on connecting things across documents.
The honest failure mode is the extraction step. A graph is only as good as the entities pulled out of your text, and documents that refer to the same company four different ways will produce four nodes that never join up. Corpora with consistent naming (part numbers, ticket ids, account names, legal entities) build clean graphs. Free-form prose about loosely named things builds a messy one, and a messy graph adds facts the model then has to ignore.
- ·
Good fit: "how does X relate to Y", supply chains, org structures, case files that reference each other, anything where the knowledge is spread thin across many files.
- ·
Overkill: a single FAQ or handbook where each answer sits in one passage. Plain vector search is faster and the graph adds nothing.
- ·
Rule of thumb: if you would have to read two or three documents and join them in your head to answer, the graph helps; if one paragraph answers it, leave it off.
It composes with the rest
GraphRAG works on encrypted stores too: with sealing on, the entity names and relationships are encrypted at rest under your key and only the facts a query returns are decrypted. The structure of the graph (which nodes connect) stays visible at rest; the names do not. The encryption page covers exactly what that means.