A manufacturing plant deployed an AI assistant backed by a traditional vector RAG system to help technicians investigate, plan, and execute routine maintenance across their production lines.
Everything looked completely fine, and leadership was praising the whole deployment. What they did not realize was that the system had a fundamental flaw, one that could become a nightmare on the factory floor at any moment.
Consider how this failure mode unfolds on the factory floor.
A technician stands in front of a down machine, opens the internal AI assistant, and enters a specific query
How do I resolve Fault 414 on the CNC Lathe Model 800, and are the replacement parts in stock?
In a traditional vector-search RAG architecture, the system embeds the query, scans the document store for chunks with the highest cosine similarity, and feeds the top five matches to an LLM.
The system returns a detailed, step-by-step repair guide. It looks authoritative. It reads cleanly.
There is only one problem, the manual it pulled is for the CNC Lathe Model 600.
The Model 600 uses an older control board, a different hydraulic valve assembly, and different torque specifications. Follow that guide on a Model 800, and you strip a spindle drive or blow a pressure seal.
The vector search was not uncertain. The vector search returns a high cosine similarity score. To an embedding model, the text describing Fault 414 on a Model 600 and a Model 800 looks almost identical.
That is the vector trap. Vector search does not understand hardware. It understands vocabulary.
Why it failed?
The failure of vector search on industrial data comes down to two structural flaws
Semantic similarity scores linguistic closeness, not hardware compatibility.
An embedding model has no concept of non-interchangeable components. It only knows that the words describing the Model 600 manual and the Model 800 manual sound nearly identical.
Live inventory is a dynamic integer, not a static concept.
Warehouse stock sits inside an ERP database or inventory log, changing by the minute. It does not live inside a static PDF manual. Vector search either hallucinates a stock count or admits it cannot read the warehouse.
To answer operational questions on a factory floor, you cannot rely on linguistic closeness. You need structural truth.
How we have solved it?
To solve this, we replaced pure vector search with a Knowledge Graph mapped directly to the physical structure of the plant.
The schema separates the physical world (equipment, parts, faults, live logs) from the document world (manuals, chunks, blueprints), connecting them through explicit, typed relationships.
Schema
// Nodes
Equipment{id, model, installationDate, status} // Physical machines on the floor
Part{sku, name, material, lifecycleStatus} // Replaceable components
Supplier{supplierId, name, country, status} // Equipment and component suppliers
FaultCode{code, severity, description} // Standardized machine error states
Procedure{id, title, estimatedTime, safetyLevel} // Standard fixes
InventoryLog{transactionId, quantity, timestamp, location} // Real-time warehouse movement
Project{projectId, name, startDate, status} // Capital upgrades, maintenance work
Manual{documentId, version, language} // Top-level equipment documentation
ProjectDoc{docId, type, author} // Blueprints, compliance reports
Chunk{chunkId, text, embedding, pageNumber} // Vectorized text segments
// Relationships
(Equipment)-[:ASSEMBLED_WITH]->(Part) // Bill of materials
(Equipment)-[:TRIGGERS_ERROR]->(FaultCode) // Telemetry and failure history
(Supplier)-[:SUPPLIES]->(Part) // Vendor source for components
(FaultCode)-[:RESOLVED_BY]->(Procedure) // Problem to solution mapping
(Procedure)-[:REQUIRES_PART]->(Part) // Materials needed for a fix
(Procedure)-[:DETAILED_IN]->(Manual) // Grounds the fix in documentation
(InventoryLog)-[:TRACKS_STOCK]->(Part) // Current warehouse availability
(Project)-[:MODIFIES]->(Equipment) // Assets under active maintenance work
(ProjectDoc)-[:DOCUMENTS]->(Project) // Paperwork linked to an initiative
(Chunk)-[:EXTRACTED_FROM]->(Manual) // Document lineage
(Chunk)-[:EXTRACTED_FROM]->(ProjectDoc) // Document lineage
(Chunk)-[:MENTIONS_EQUIPMENT]->(Equipment) // NLP-extracted semantic link
(Chunk)-[:MENTIONS_PART]->(Part) // NLP-extracted semantic link
(Chunk)-[:MENTIONS_FAULT]->(FaultCode) // NLP-extracted semantic link
(Chunk)-[:MENTIONS_PROCEDURE]->(Procedure) // NLP-extracted semantic link
(Chunk)-[:MENTIONS_SUPPLIER]->(Supplier) // NLP-extracted semantic link
(Chunk)-[:NEXT_CHUNK]->(Chunk) // Sequential reading orderHybrid Retrieval Pattern
We have not abandoned vector search entirely while implementing the Graph RAG architecture. We have assigned Vector Search and Graph Traversals to two distinct Jobs.
Vector first with Graph expansion
When a query contains natural language without clear primary keys, vector search acts as an entry point to find candidate chunks, which are then expanded through graph edges to fetch grounded domain context.
CALL db.index.vector.queryNodes('chunk_vector_index', 5, $question_embedding)
YIELD node AS chunk, score
MATCH (chunk)-[:MENTIONS_EQUIPMENT]->(e:Equipment)
OPTIONAL MATCH (e)-[:ASSEMBLED_WITH]->(part:Part)
RETURN
chunk.text AS manual_text,
e.model AS model,
collect(part.name) AS components,
scoreEntity first deterministic traversal
When a query contains explicit identifiers, such as a specific machine model or a fault code, vector embeddings are bypassed entirely. The system anchors directly onto the target nodes and walks the explicit relationships.
MATCH (e:Equipment {id: $equipment_id})-[:TRIGGERS_ERROR]->(f:FaultCode {code: $fault_code})
MATCH (f)-[:RESOLVED_BY]->(p:Procedure)-[:REQUIRES_PART]->(part:Part)
OPTIONAL MATCH (part)<-[:TRACKS_STOCK]-(inv:InventoryLog)
MATCH (p)-[:DETAILED_IN]->(m:Manual)<-[:EXTRACTED_FROM]-(c:Chunk)
RETURN
p.title AS procedure,
part.sku AS required_part,
sum(inv.quantity) AS stock_level,
collect(c.text) AS documentationHow it helped?
So, now our schema and Retrieval patterns are set, let us return to the original question
How do I resolve Fault 414 on the CNC Lathe Model 800, and are the replacement parts in stock?
Instead of passing this text to a vector index and praying it does not pick the Model 600 manual, the system extracts the entities (model: 'CNC Lathe Model 800', fault: '414') and runs a single graph traversal
MATCH (e:Equipment {
model: 'CNC Lathe Model 800'
})-[:TRIGGERS_ERROR]->(f:FaultCode {code: '414'})
MATCH (f)-[:RESOLVED_BY]->(p:Procedure)
MATCH (p)-[:DETAILED_IN]->(m:Manual)<-[:EXTRACTED_FROM]-(c:Chunk)
OPTIONAL MATCH (p)-[:REQUIRES_PART]->(part:Part)
OPTIONAL MATCH (part)<-[:TRACKS_STOCK]-(inv:InventoryLog)
RETURN
e.model AS Equipment,
f.code AS Fault,
p.title AS ResolutionProcedure,
part.name AS PartNeeded,
coalesce(sum(inv.quantity), 0) AS StockAvailable,
collect(DISTINCT c.text) AS ManualChunksLook at what this traversal guarantees that vector search structurally cannot
Zero Path to Model 600
The traversal starts specifically at the Equipment node where model = 'CNC Lathe Model 800'. The Model 600 manual does not exist in this subgraph. There is no mathematical possibility of returning the wrong manual.
Real-Time Stock Calculation
The stock count is not pulled from a text chunk written three years ago. It executes a live sum() over active InventoryLog nodes attached to the required part.
Deterministic Prompt Context
The payload handed to the LLM contains explicit key-value parameters (exact procedure title, part SKU, current stock integer) alongside the verified manual chunks.
What it unlocks further?
Once the physical structure of a plant lives inside a graph, you can answer complex operational questions that vector search cannot even attempt.
Supplier Swaps and Downstream Impacts
If we swap the hydraulic pump from supplier A with supplier B on the main assembly line, what downstream procedures need rewriting, and do we have the required new safety manuals already indexed?
A vector search cannot solve this because “downstream impact” is a structural concept.
In Graph RAG, the query traverses Part (Supplier A) <-[:REQUIRES_PART]- Procedure -[:DETAILED_IN]-> Manual and compares it against Part (Supplier B) relationships across active Equipment nodes.
Preemptive Maintenance across Subassemblies
Find every active piece of equipment that shares a subassembly with the conveyor system that failed yesterday, and check if the warehouse has enough replacement belts to preemptively service all of them tonight.
This query spans four distinct domains, failure history, bill-of-materials, active asset status, and real-time inventory. Vector embeddings cannot calculate shared subassembly topologies across disparate equipment types.
A graph traversal handles it in a single pass.
The overall impact
After three months of monitoring the deployment, operational feedback showed a fundamental shift in how technical teams interacted with system documentation.
Before moving to Graph RAG, resolving a multi-domain technical question meant working across departmental silos. A technician had to check paper manuals or PDFs for repair steps, open an ERP terminal to check part inventory, and consult a maintenance log to verify equipment revisions, often taking hours or days of manual coordination for a single complex query.
After deploying the graph architecture, cross-domain queries resolved in a single traversal. Technicians received verified, model-accurate documentation alongside real-time inventory counts without jumping between systems.
Conclusion
Vector search is excellent for unstructured natural language search bars. It is dangerous when used as the primary lookup engine for physical, high-stakes infrastructure.
When a wrong answer means damaged hardware, line downtime, or safety hazards, you cannot rely on linguistic proximity. Connect your domain entities, map your relationships, and let the graph supply the truth.



