Plain vector search answers the question “which articles are most similar to this ticket?” but it cannot answer “what other concepts, products, or people are closely connected to what the customer is asking about?” GraphRAG fills that gap by maintaining a knowledge graph of named entities extracted from every ticket and traversing the graph at query time to surface relationship context that flat embeddings cannot express.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/yocxy2/2a/llms.txt
Use this file to discover all available pages before exploring further.
Entity types
The system recognises five entity types. Every entity extracted by GPT-4o-mini is tagged with one of these:| Type | Examples |
|---|---|
| Person | customer names, agent names, account holders |
| Place | shipping addresses, warehouse locations, country names |
| Concept | refund policy, subscription plan, two-factor authentication |
| Product | SKU names, software features, hardware models |
| Organization | payment processors, courier companies, partner brands |
How GraphRAG works
Async job triggered after ticket creation
After a ticket is saved and the HTTP response is returned to the caller,
ticketController.ts adds a BullMQ job to the entity-extraction Redis queue with the ticketId and raw user_description text.Entity extraction via GPT-4o-mini
entityExtractionWorker picks up the job (concurrency: 5) and calls extractEntities(), which sends the ticket text to GPT-4o-mini with a structured prompt requesting JSON output of named entities.Entities stored with vector embeddings
For each extracted entity that doesn’t already exist in the database, the worker generates a 1536-dimension embedding of the entity name using
text-embedding-3-small and stores the entity in the entities table via raw SQL.Vector search finds similar entities
When the next ticket arrives,
getGraphContextForTicket() calls findSimilarEntities(), which embeds the new ticket description and queries pgvector for the top 3 nearest entity nodes:BFS graph traversal from the closest entity
traverseGraph() is called with the most similar entity as the starting node. BFS explores both outgoing and incoming EntityRelation edges up to maxDepth=2 and collects up to maxNodes=10 nodes.Graph traversal
traverseGraph() implements a breadth-first search starting from a named entity and expanding through both directions of every EntityRelation edge.
- The starting entity is looked up by exact name match in the
entitiestable. - A
visitedset prevents cycles — each entity ID is only processed once. - For each dequeued node, the worker queries both
fromId = entityId(outgoing) andtoId = entityId(incoming) relation rows via Prisma. - The BFS stops early when either the queue is empty,
depth >= maxDepth, ornodes.length >= maxNodes. - The function returns a
GraphContextcontaining the full node list, the edge list, andrelevantEntities— a flat array of every node’s name, ready to concatenate into a prompt.
traverseGraph returns an empty context { nodes: [], edges: [], relevantEntities: [] } without throwing.
GraphRAG context is appended to the AI response as
"Related entities: ..." only when at least one entity is found. If the entities table is empty (e.g. on a fresh install before any entity extraction jobs have run), this section is silently omitted from the response.Database schema
The knowledge graph is stored in two tables defined inprisma/schema.prisma.
related_to with a strength of 0.5. The strength field (range 0.0–1.0, default 1.0) is available for more sophisticated traversal weighting in future iterations.
GraphContext interface
The following interfaces fromsrc/services/graphRagService.ts describe all data returned by traverseGraph() and getGraphContextForTicket().