Skip to main content

Graph Schema Overview

Graphiti’s knowledge graph is composed of nodes (entities, episodes, communities, sagas) and edges (relationships between nodes). Understanding this schema is essential for working with Graphiti effectively.

Node Types

EntityNode

Represents real-world entities extracted from episodes—people, organizations, concepts, events, etc.
class EntityNode(Node):
    uuid: str                          # Unique identifier
    name: str                          # Entity name
    name_embedding: list[float] | None # Vector embedding of the name
    summary: str                       # Aggregated summary from relationships
    labels: list[str]                  # Entity types (e.g., ["Person", "Employee"])
    attributes: dict[str, Any]         # Custom attributes
    group_id: str                      # Partition identifier
    created_at: datetime               # When first added to graph

Example

EntityNode(
    uuid="550e8400-e29b-41d4-a716-446655440000",
    name="Kamala Harris",
    labels=["Person", "Politician"],
    summary="Kamala Harris served as Attorney General of California from 2011-2017 and became Vice President in 2021.",
    attributes={
        "birth_year": 1964,
        "education": "Howard University, UC Hastings"
    },
    group_id="default",
    created_at=datetime(2024, 3, 15, tzinfo=timezone.utc)
)

Key Fields

name: The canonical name of the entity
  • Graphiti deduplicates entities by name similarity
  • Used for entity resolution across episodes
name_embedding: Vector representation for semantic search
  • Generated by your configured embedder (e.g., OpenAI, Voyage)
  • Enables similarity-based entity retrieval
# Generate embedding
await entity_node.generate_name_embedding(embedder)
summary: Automatically generated from connected edges
  • Aggregates facts from all EntityEdges connected to this node
  • Updated as new information is added
  • Useful for quick entity context
labels: Entity types for classification
  • Can be a single type: ["Person"]
  • Or multiple types: ["Person", "Executive", "Founder"]
  • Used with custom entity types (see Custom Entity Types guide)
attributes: Flexible key-value properties
  • Store domain-specific data
  • Defined by custom entity type schemas
  • Extracted by LLM during processing
# Custom entity type with attributes
from pydantic import BaseModel, Field

class Employee(BaseModel):
    department: str = Field(description="Department name")
    start_date: str = Field(description="Employment start date")
    role: str = Field(description="Job title")

entity_types = {"Employee": Employee}

Working with EntityNodes

# Get by UUID
node = await EntityNode.get_by_uuid(driver, uuid="...")

# Get by group IDs
nodes = await EntityNode.get_by_group_ids(
    driver,
    group_ids=["user_123"],
    limit=100
)

# Save a node
await node.save(driver)

# Delete a node (and connected edges)
await node.delete(driver)

EpisodicNode

Stores raw input episodes with temporal metadata. See Episodes for detailed information.
class EpisodicNode(Node):
    uuid: str
    name: str
    content: str                   # Raw episode data
    source: EpisodeType           # message | json | text
    source_description: str        # Metadata about the source
    valid_at: datetime            # When content occurred
    created_at: datetime          # When ingested
    entity_edges: list[str]       # UUIDs of extracted EntityEdges
    group_id: str

Example

EpisodicNode(
    uuid="660e8400-e29b-41d4-a716-446655440001",
    name="Customer Support Chat 2024-03-15",
    content="user: My order is delayed\nassistant: Let me check that",
    source=EpisodeType.message,
    source_description="support_ticket_5678",
    valid_at=datetime(2024, 3, 15, 10, 30, tzinfo=timezone.utc),
    created_at=datetime(2024, 3, 15, 10, 35, tzinfo=timezone.utc),
    entity_edges=["edge-uuid-1", "edge-uuid-2"],
    group_id="customer_123"
)

CommunityNode

Represents clusters of related entities discovered through graph analysis. See Communities for details.
class CommunityNode(Node):
    uuid: str
    name: str                         # Auto-generated description
    name_embedding: list[float] | None
    summary: str                      # Aggregate summary of member entities
    group_id: str
    created_at: datetime

Example

CommunityNode(
    uuid="770e8400-e29b-41d4-a716-446655440002",
    name="California Political Leadership",
    summary="Community of political figures who have served in California government positions including Governor, Attorney General, and Lieutenant Governor.",
    group_id="default",
    created_at=datetime(2024, 3, 15, tzinfo=timezone.utc)
)

SagaNode

Organizes sequences of related episodes (e.g., conversation threads, event timelines).
class SagaNode(Node):
    uuid: str
    name: str          # Saga identifier
    group_id: str
    created_at: datetime

Example

SagaNode(
    uuid="880e8400-e29b-41d4-a716-446655440003",
    name="customer_support_conversation_123",
    group_id="customer_456",
    created_at=datetime(2024, 3, 15, tzinfo=timezone.utc)
)

Edge Types

EntityEdge (RELATES_TO)

Represents semantic relationships between entities, with temporal validity tracking.
class EntityEdge(Edge):
    uuid: str
    source_node_uuid: str         # Source EntityNode UUID
    target_node_uuid: str         # Target EntityNode UUID
    name: str                     # Relationship name
    fact: str                     # Natural language fact
    fact_embedding: list[float] | None
    episodes: list[str]           # Episode UUIDs that mention this edge
    group_id: str
    
    # Temporal fields
    created_at: datetime          # When edge was first created
    expired_at: datetime | None   # When edge was invalidated by new info
    valid_at: datetime | None     # When the fact became true
    invalid_at: datetime | None   # When the fact stopped being true
    
    # Custom attributes
    attributes: dict[str, Any]

Example

EntityEdge(
    uuid="990e8400-e29b-41d4-a716-446655440004",
    source_node_uuid="kamala-harris-uuid",
    target_node_uuid="california-ag-uuid",
    name="held_position",
    fact="Kamala Harris served as Attorney General of California from January 2011 to January 2017.",
    fact_embedding=[0.123, -0.456, ...],  # 1536-dim vector
    episodes=["episode-uuid-1", "episode-uuid-2"],
    group_id="default",
    created_at=datetime(2024, 3, 15, tzinfo=timezone.utc),
    expired_at=None,  # Still current in the graph
    valid_at=datetime(2011, 1, 3, tzinfo=timezone.utc),
    invalid_at=datetime(2017, 1, 3, tzinfo=timezone.utc),
    attributes={"position_type": "elected_official"}
)

Key Fields

name: The relationship type
  • Examples: "works_at", "knows", "located_in", "married_to"
  • Can be customized with edge types (see Custom Edge Types guide)
fact: Human-readable description of the relationship
  • Used for search and retrieval
  • Embedded for semantic similarity
fact="Alice Chen joined Acme Corp as Senior Engineer in March 2024."
fact_embedding: Vector representation for semantic search
  • Generated from the fact text
  • Enables similarity-based edge retrieval
episodes: Provenance tracking
  • Lists all episodes that mentioned this relationship
  • Enables tracing back to original sources
# Find episodes that mention an edge
episode_uuids = edge.episodes
episodes = await EpisodicNode.get_by_uuids(driver, episode_uuids)
Temporal fields: See Temporal Model
  • valid_at: When the fact became true in the real world
  • invalid_at: When the fact stopped being true
  • created_at: When Graphiti learned about it
  • expired_at: When superseded by newer information

Working with EntityEdges

# Get by UUID
edge = await EntityEdge.get_by_uuid(driver, uuid="...")

# Get edges connected to a node
edges = await EntityEdge.get_by_node_uuid(driver, node_uuid="...")

# Get edges between two nodes
edges = await EntityEdge.get_between_nodes(
    driver,
    source_node_uuid="alice-uuid",
    target_node_uuid="acme-uuid"
)

# Save an edge
await edge.save(driver)

# Delete an edge
await edge.delete(driver)

EpisodicEdge (MENTIONS)

Links episodes to the entities they mention.
class EpisodicEdge(Edge):
    uuid: str
    source_node_uuid: str  # EpisodicNode UUID
    target_node_uuid: str  # EntityNode UUID
    group_id: str
    created_at: datetime

Purpose

EpisodicEdges provide provenance—you can always trace which episodes mentioned which entities.
# Find all episodes that mention "Alice"
episodes = await EpisodicNode.get_by_entity_node_uuid(
    driver,
    entity_node_uuid=alice.uuid
)

CommunityEdge (HAS_MEMBER)

Links communities to their member entities.
class CommunityEdge(Edge):
    uuid: str
    source_node_uuid: str  # CommunityNode UUID
    target_node_uuid: str  # EntityNode UUID
    group_id: str
    created_at: datetime

Usage

# Find all entities in a community
records, _, _ = await driver.execute_query("""
    MATCH (c:Community {uuid: $community_uuid})-[:HAS_MEMBER]->(e:Entity)
    RETURN e
""", community_uuid=community.uuid)

HasEpisodeEdge (HAS_EPISODE)

Links sagas to their episodes.
class HasEpisodeEdge(Edge):
    uuid: str
    source_node_uuid: str  # SagaNode UUID
    target_node_uuid: str  # EpisodicNode UUID
    group_id: str
    created_at: datetime

NextEpisodeEdge (NEXT_EPISODE)

Chains episodes in chronological order within a saga.
class NextEpisodeEdge(Edge):
    uuid: str
    source_node_uuid: str  # Earlier EpisodicNode UUID
    target_node_uuid: str  # Later EpisodicNode UUID
    group_id: str
    created_at: datetime

Usage

# Traverse a conversation thread
records, _, _ = await driver.execute_query("""
    MATCH path = (start:Episodic)-[:NEXT_EPISODE*]->(end:Episodic)
    WHERE start.uuid = $start_uuid
    RETURN path
""", start_uuid=first_episode.uuid)

Node and Edge Inheritance

All nodes and edges inherit from base classes:
class Node(BaseModel, ABC):
    uuid: str = Field(default_factory=lambda: str(uuid4()))
    name: str
    group_id: str
    labels: list[str] = Field(default_factory=list)
    created_at: datetime = Field(default_factory=lambda: utc_now())
    
    @abstractmethod
    async def save(self, driver: GraphDriver): ...
    async def delete(self, driver: GraphDriver): ...

class Edge(BaseModel, ABC):
    uuid: str = Field(default_factory=lambda: str(uuid4()))
    group_id: str
    source_node_uuid: str
    target_node_uuid: str
    created_at: datetime
    
    @abstractmethod
    async def save(self, driver: GraphDriver): ...
    async def delete(self, driver: GraphDriver): ...
This provides consistent interfaces for all graph elements.

Graph Queries

Finding Connected Information

# Get all relationships for an entity
edges = await EntityEdge.get_by_node_uuid(driver, node_uuid=alice.uuid)

# Find entities related to Alice
records, _, _ = await driver.execute_query("""
    MATCH (alice:Entity {uuid: $alice_uuid})-[:RELATES_TO]-(related:Entity)
    RETURN related
""", alice_uuid=alice.uuid)

Traversing Multi-Hop Relationships

# Find entities within 2 hops
records, _, _ = await driver.execute_query("""
    MATCH (start:Entity {uuid: $start_uuid})-[:RELATES_TO*1..2]-(connected:Entity)
    RETURN DISTINCT connected
""", start_uuid=start_node.uuid)

Temporal Queries

# Find facts valid at a specific time
records, _, _ = await driver.execute_query("""
    MATCH (n)-[e:RELATES_TO]->(m)
    WHERE e.valid_at <= $query_time
      AND (e.invalid_at > $query_time OR e.invalid_at IS NULL)
      AND e.expired_at IS NULL
    RETURN e
""", query_time=datetime(2023, 6, 1, tzinfo=timezone.utc))

Embeddings

Graphiti generates vector embeddings for semantic search:

Entity Name Embeddings

# Generate embedding for an entity
await entity_node.generate_name_embedding(embedder)
# Sets entity_node.name_embedding = [0.123, -0.456, ...]

# Batch generation for multiple entities
from graphiti_core.nodes import create_entity_node_embeddings

await create_entity_node_embeddings(embedder, entity_nodes)

Edge Fact Embeddings

# Generate embedding for an edge
await entity_edge.generate_embedding(embedder)
# Sets entity_edge.fact_embedding = [0.234, -0.567, ...]

# Batch generation for multiple edges
from graphiti_core.edges import create_entity_edge_embeddings

await create_entity_edge_embeddings(embedder, entity_edges)

Embedding Configuration

from graphiti_core.embedder.openai import OpenAIEmbedder, OpenAIEmbedderConfig

# Custom embedder
embedder = OpenAIEmbedder(
    config=OpenAIEmbedderConfig(
        embedding_model="text-embedding-3-large",
        embedding_dim=3072  # Dimension depends on model
    )
)

graphiti = Graphiti(uri, user, password, embedder=embedder)

Database Backend Differences

Graphiti supports multiple graph databases with minor schema variations:

Neo4j, FalkorDB, Neptune

-- EntityEdge as a relationship
MATCH (n:Entity)-[e:RELATES_TO]->(m:Entity)
RETURN e

Kuzu

-- EntityEdge as an intermediate node
MATCH (n:Entity)-[:RELATES_TO]->(e:RelatesToNode_)-[:RELATES_TO]->(m:Entity)
RETURN e
Graphiti’s driver abstraction handles these differences automatically. You don’t need to write different queries for different backends.

Custom Attributes

Both EntityNodes and EntityEdges support custom attributes:
from pydantic import BaseModel, Field

# Define a custom entity type
class Person(BaseModel):
    age: int = Field(description="Person's age")
    occupation: str = Field(description="Job title")
    city: str = Field(description="Current city")

# Define a custom edge type
class WorksAt(BaseModel):
    start_date: str = Field(description="Employment start date")
    department: str = Field(description="Department name")

# Use in add_episode
result = await graphiti.add_episode(
    name="HR Data",
    episode_body="Alice Chen, 32, works as a Software Engineer in the Platform team. She joined on 2024-01-15 in San Francisco.",
    source=EpisodeType.text,
    reference_time=datetime.now(timezone.utc),
    entity_types={"Person": Person},
    edge_types={"WorksAt": WorksAt}
)

# Extracted EntityNode will have:
# attributes = {"age": 32, "occupation": "Software Engineer", "city": "San Francisco"}

# Extracted EntityEdge will have:
# attributes = {"start_date": "2024-01-15", "department": "Platform"}

Group IDs and Multi-Tenancy

Every node and edge has a group_id field for partitioning:
# Add data to different groups
await graphiti.add_episode(
    name="User 1 Data",
    episode_body="Alice likes hiking.",
    group_id="user_1",
    reference_time=datetime.now(timezone.utc)
)

await graphiti.add_episode(
    name="User 2 Data",
    episode_body="Bob likes coding.",
    group_id="user_2",
    reference_time=datetime.now(timezone.utc)
)

# Search within a group
results = await graphiti.search(
    "What does the user like?",
    group_ids=["user_1"]  # Only searches user_1's data
)

Schema Visualization

Here’s the complete graph schema:

Next Steps

Communities

Learn about community detection and clustering

Custom Types

Define custom entity and edge types

Search

Query nodes and edges effectively

Temporal Model

Understand temporal aspects of nodes and edges

Build docs developers (and LLMs) love