Skip to main content
← Back to knowledge-graphs

Creating Interactive Knowledge Graphs for AI Applications

Knowledge graphs have emerged as a powerful tool for enhancing AI applications, particularly in retrieval-augmented generation (RAG) systems. Unlike traditional vector databases that focus on semantic similarity, knowledge graphs capture the structural relationships between entities, enabling more accurate and explainable AI responses.

This guide explores how to create interactive knowledge graphs specifically designed for AI applications, focusing on practical implementation strategies that improve retrieval accuracy and user experience.

Why Knowledge Graphs for AI?

Knowledge graphs complement vector databases in several key ways:

FeatureVector DatabaseKnowledge Graph
Data ModelUnstructured embeddingsStructured entities and relationships
Query TypeSemantic similarityPattern matching and reasoning
ExplainabilityLowHigh (explicit relationships)
Multi-hop QueriesLimitedExcellent
Entity ResolutionDifficultBuilt-in
Schema AwarenessNoneFull support

For AI applications, knowledge graphs provide:

  • Better Context Understanding: Capture explicit relationships between concepts
  • Improved Retrieval: Find relevant information through graph traversal
  • Explainable Results: Show exactly how the AI arrived at its answer
  • Reduced Hallucinations: Ground responses in verified knowledge
  • Multi-hop Reasoning: Connect distant concepts through intermediate nodes

Knowledge Graph Architecture

A typical knowledge graph for AI applications consists of three layers:

┌─────────────────────────────────────────────────────────┐
│                    Application Layer                     │
│  (AI Agents, RAG Systems, Chatbots, Recommendation Engines)│
└─────────────────────────────────────────────────────────┘
                           ▲
                           │
┌─────────────────────────────────────────────────────────┐
│                    Query Layer                           │
│  (Cypher, GraphQL, SPARQL, REST APIs)                    │
└─────────────────────────────────────────────────────────┘
                           ▲
                           │
┌─────────────────────────────────────────────────────────┐
│                  Graph Database Layer                    │
│  (Neo4j, ArangoDB, Amazon Neptune, TigerGraph)           │
└─────────────────────────────────────────────────────────┘

Choosing the Right Graph Database

Several graph databases support AI applications:

DatabaseStrengthsBest For
Neo4jMature, excellent ecosystem, ACID complianceEnterprise applications
ArangoDBMulti-model, flexible schemaHybrid graph-document workloads
Amazon NeptuneServerless, AWS integrationCloud-native applications
TigerGraphHigh performance, GSQL languageLarge-scale analytics
NebulaGraphOpen source, distributedSelf-hosted deployments

For most AI applications, Neo4j offers the best balance of features, documentation, and community support.

Implementing a Knowledge Graph for AI

Step 1: Define Your Schema

Start by identifying the entities and relationships relevant to your AI application:

// Define node labels and properties
CREATE (n:Entity {
  id: $id,
  name: $name,
  type: $type,
  description: $description,
  created_at: datetime(),
  updated_at: datetime()
})

CREATE (n:Concept {
  id: $id,
  name: $name,
  definition: $definition,
  category: $category
})

CREATE (n:Document {
  id: $id,
  title: $title,
  url: $url,
  published_date: date(),
  source: $source
})

CREATE (n:Question {
  id: $id,
  text: $text,
  category: $category,
  difficulty: $difficulty
})

CREATE (n:Answer {
  id: $id,
  text: $text,
  confidence: $confidence,
  sources: $sources
})

Step 2: Create Relationships

Define how entities connect:

// Entity relationships
(:Entity)-[:HAS_PROPERTY]->(:Property)
(:Entity)-[:BELONGS_TO]->(:Category)
(:Entity)-[:RELATED_TO]->(:Entity)

// Document relationships
(:Document)-[:CONTAINS]->(:Entity)
(:Document)-[:ANSWERS]->(:Question)
(:Document)-[:REFERENCES]->(:Document)

// Question-answer relationships
(:Question)-[:HAS_ANSWER]->(:Answer)
(:Answer)-[:SUPPORTED_BY]->(:Document)
(:Answer)-[:USES_CONCEPT]->(:Concept)

Step 3: Load Data

Populate your graph with relevant data:

import neo4j from 'neo4j-driver'

const driver = neo4j.driver(
  'neo4j://localhost:7687',
  neo4j.auth.basic('neo4j', 'password')
)

async function loadKnowledgeGraph() {
  const session = driver.session()

  try {
    // Load entities
    await session.run(`
      CREATE (n:Entity {
        id: 'ai-agents',
        name: 'AI Agents',
        type: 'concept',
        description: 'Autonomous AI systems that can perform tasks'
      })
    `)

    // Load relationships
    await session.run(`
      MATCH (a:Entity {name: 'AI Agents'})
      MATCH (b:Entity {name: 'LLMs'})
      MERGE (a)-[:USES]->(b)
    `)

    console.log('Knowledge graph loaded successfully')
  } catch (error) {
    console.error('Error loading knowledge graph:', error)
  } finally {
    await session.close()
  }
}

Building an Interactive Graph Interface

Create a React component that visualizes your knowledge graph:

'use client'

import { useState, useEffect } from 'react'
import * as vis from 'vis-network'

interface GraphData {
  nodes: Array<{
    id: string
    label: string
    group: string
    title?: string
    value?: number
  }>
  edges: Array<{
    from: string
    to: string
    label?: string
    arrows?: string
    color?: string
  }>
}

interface KnowledgeGraphProps {
  query?: string
}

export default function KnowledgeGraph({ query }: KnowledgeGraphProps) {
  const containerRef = useRef<HTMLDivElement>(null)
  const networkRef = useRef<vis.Network | null>(null)
  const [selectedNode, setSelectedNode] = useState<string | null>(null)

  const options: vis.Options = {
    nodes: {
      shape: 'dot',
      size: 25,
      font: { size: 16, color: '#ffffff' },
      borderWidth: 2,
      shadow: true
    },
    edges: {
      width: 2,
      color: { color: '#999999', highlight: '#ffffff', hover: '#ffffff' },
      arrows: { to: { enabled: true, scaleFactor: 0.5 } },
      smooth: { type: 'continuous' }
    },
    physics: {
      stabilization: true,
      barnesHut: {
        gravitationalConstant: -2000,
        springConstant: 0.04,
        springLength: 100
      }
    },
    interaction: {
      hover: true,
      tooltipDelay: 200,
      selectConnectedEdges: true
    }
  }

  useEffect(() => {
    if (!containerRef.current) return

    // Load graph data from Neo4j
    const loadGraphData = async () => {
      const session = driver.session()
      try {
        const result = await session.run(`
          MATCH (n)-[r]->(m)
          WHERE n.id CONTAINS $query OR m.id CONTAINS $query
          RETURN n.id as fromId, n.name as fromLabel, n.type as fromGroup,
                 m.id as toId, m.name as toLabel, m.type as toGroup,
                 type(r) as relType
          LIMIT 100
        `, { query: query || '' })

        const nodes = new Map<string, any>()
        const edges: any[] = []

        result.records.forEach(record => {
          const fromId = record.get('fromId')
          const fromLabel = record.get('fromLabel')
          const fromGroup = record.get('fromGroup') || 'default'
          const toId = record.get('toId')
          const toLabel = record.get('toLabel')
          const toGroup = record.get('toGroup') || 'default'
          const relType = record.get('relType')

          // Add nodes
          if (!nodes.has(fromId)) {
            nodes.set(fromId, {
              id: fromId,
              label: fromLabel,
              group: fromGroup,
              title: fromLabel
            })
          }

          if (!nodes.has(toId)) {
            nodes.set(toId, {
              id: toId,
              label: toLabel,
              group: toGroup,
              title: toLabel
            })
          }

          // Add edges
          edges.push({
            from: fromId,
            to: toId,
            label: relType,
            arrows: 'to'
          })
        })

        const graphData = {
          nodes: Array.from(nodes.values()),
          edges
        }

        return graphData
      } catch (error) {
        console.error('Error loading graph data:', error)
        return null
      } finally {
        await session.close()
      }
    }

    loadGraphData().then(data => {
      if (data && containerRef.current) {
        const network = new vis.Network(containerRef.current, data, options)
        networkRef.current = network

        network.on('click', (params) => {
          if (params.nodes.length > 0) {
            setSelectedNode(params.nodes[0])
          } else {
            setSelectedNode(null)
          }
        })
      }
    })

    return () => {
      if (networkRef.current) {
        networkRef.current.destroy()
      }
    }
  }, [query, options])

  return (
    <div style={{ width: '100%', height: '600px', border: '1px solid #e0e0e0', borderRadius: '8px' }}>
      <div ref={containerRef} />
      {selectedNode && (
        <div style={{
          position: 'absolute',
          top: '10px',
          right: '10px',
          background: 'white',
          padding: '16px',
          borderRadius: '8px',
          boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
          maxWidth: '300px'
        }}>
          <h3 style={{ margin: '0 0 8px 0' }}>Selected Node</h3>
          <p style={{ margin: '0 0 4px 0' }}>{selectedNode}</p>
          <p style={{ margin: '0', fontSize: '12px', color: '#666' }}>
            Click to view details
          </p>
        </div>
      )}
    </div>
  )
}

Enhancing AI with Graph-Aware Retrieval

GraphRAG Implementation

GraphRAG (Graph Retrieval-Augmented Generation) combines the strengths of graphs and vector databases:

async function graphRAGQuery(question: string) {
  const session = driver.session()

  try {
    // Step 1: Identify relevant entities using graph queries
    const entities = await session.run(`
      MATCH (n:Entity)
      WHERE n.name CONTAINS $question
      RETURN n LIMIT 5
    `, { question })

    // Step 2: Find related entities and relationships
    const related = await session.run(`
      MATCH (n:Entity)-[r]-(m:Entity)
      WHERE n.name IN $entityNames
      RETURN DISTINCT n.name as entity, m.name as related, type(r) as relation
    `, { entityNames: entities.records.map(r => r.get('n.name')) })

    // Step 3: Retrieve relevant documents
    const documents = await session.run(`
      MATCH (d:Document)-[:CONTAINS]->(e:Entity)
      WHERE e.name IN $entityNames
      RETURN d.title, d.url, d.summary
      LIMIT 5
    `, { entityNames: entities.records.map(r => r.get('n.name')) })

    // Step 4: Generate answer using retrieved information
    const answer = await generateAnswer({
      question,
      entities: entities.records.map(r => r.get('n')),
      relationships: related.records.map(r => ({
        entity: r.get('entity'),
        related: r.get('related'),
        relation: r.get('relation')
      })),
      documents: documents.records.map(r => ({
        title: r.get('title'),
        url: r.get('url'),
        summary: r.get('summary')
      }))
    })

    return answer
  } finally {
    await session.close()
  }
}

Multi-hop Query Processing

Knowledge graphs excel at multi-hop queries:

// Find all AI frameworks that use Neo4j
MATCH path = (n:Framework)-[:USES]->(d:Database)-[:USED_BY]->(a:Application)
WHERE n.name CONTAINS 'AI Framework'
RETURN DISTINCT n.name as framework, d.name as database, a.name as application

Interactive Features for AI Applications

Real-time Graph Exploration

const options: vis.Options = {
  interaction: {
    hover: true,
    tooltipDelay: 200,
    zoomView: true,
    dragView: true,
    selectConnectedEdges: true
  },
  physics: {
    stabilization: true,
    barnesHut: {
      gravitationalConstant: -2000,
      springConstant: 0.04,
      springLength: 100
    }
  }
}

Query-Driven Graph Views

const loadGraphByQuery = async (query: string) => {
  const session = driver.session()
  try {
    const result = await session.run(`
      MATCH (n)-[r]->(m)
      WHERE n.name CONTAINS $query OR m.name CONTAINS $query
      RETURN n.id as fromId, n.name as fromLabel, n.type as fromGroup,
             m.id as toId, m.name as toLabel, m.type as toGroup,
             type(r) as relType
      LIMIT 50
    `, { query })

    const nodes = new Map<string, any>()
    const edges: any[] = []

    result.records.forEach(record => {
      const fromId = record.get('fromId')
      const fromLabel = record.get('fromLabel')
      const fromGroup = record.get('fromGroup') || 'default'
      const toId = record.get('toId')
      const toLabel = record.get('toLabel')
      const toGroup = record.get('toGroup') || 'default'
      const relType = record.get('relType')

      if (!nodes.has(fromId)) {
        nodes.set(fromId, { id: fromId, label: fromLabel, group: fromGroup })
      }
      if (!nodes.has(toId)) {
        nodes.set(toId, { id: toId, label: toLabel, group: toGroup })
      }
      edges.push({ from: fromId, to: toId, label: relType })
    })

    return { nodes: Array.from(nodes.values()), edges }
  } finally {
    await session.close()
  }
}

Best Practices for AI Knowledge Graphs

  1. Start Small: Begin with a focused domain before scaling
  2. Quality Over Quantity: Focus on accurate, well-structured data
  3. Iterate: Continuously refine your schema based on use cases
  4. Hybrid Approach: Combine graphs with vector databases for best results
  5. User Feedback: Incorporate user interactions to improve the graph
  6. Performance: Optimize queries and use indexing for large graphs

Conclusion

Interactive knowledge graphs provide a powerful foundation for AI applications, offering:

  • Better Retrieval: Graph traversal finds relevant information through explicit relationships
  • Improved Explainability: Show exactly how the AI arrived at its answer
  • Enhanced Reasoning: Support multi-hop queries and complex relationships
  • Rich Interactions: Visual exploration of knowledge structures

By combining knowledge graphs with vector databases, you create a hybrid system that leverages the strengths of both approaches. This enables more accurate, explainable, and user-friendly AI applications that can handle complex queries while maintaining interpretability.

Further Reading