Files
Hy-Memory/docs/pro_graph_design.md
T
2026-10-16 16:26:27 +08:00

8.5 KiB

Graph Memory Architecture and Operations

This document describes the Graph features implemented by the current SDK. It is intended for operators enabling Graph and maintainers working on pipelines/_graph, reader_base.py, or a GraphStore backend.

Graph is an optional, fail-open enhancement. Vector retrieval remains the source of truth: if Graph is unavailable, incomplete, or disabled, normal memory search must continue to work.

1. Enabling Graph

Graph availability depends on the processing mode:

Mode Graph behavior
lite Disabled
pro Controlled by MEMORY_ENABLE_GRAPH, default false
ultra Enabled

The default backend is embedded Kuzu. Neo4j is available through the graph optional dependency.

# Embedded, single-process deployment
MEMORY_MODE=pro
MEMORY_ENABLE_GRAPH=true
MEMORY_GRAPH_PROVIDER=kuzu
MEMORY_GRAPH_DB_PATH=/data/hy-memory/kuzu

# Multi-process or remote deployment
MEMORY_GRAPH_PROVIDER=neo4j
NEO4J_URL=bolt://localhost:7687
NEO4J_USERNAME=neo4j
NEO4J_PASSWORD=secret
NEO4J_DATABASE=neo4j

Kuzu permits only one process to open a database path. Use Neo4j when several workers must share the same Graph.

2. Write-side projection

When Graph and MEMORY_GRAPH_WRITE are enabled, persisted L2 facts are projected into Graph asynchronously. Projection failures are logged and do not roll back the VDB write.

2.1 Node model

An L2 fact is represented as Memory(layer="l2_fact"), not as VdbRef. This allows the node to participate in Topic, Entity, relation, and temporal edges. VdbRef remains the lightweight target used by L6 DERIVED_FROM evidence links.

Graph projection does not replace the VDB. Content, vectors, event time, and normal retrieval remain VDB-owned.

2.2 Edge sources

Current relation sources are:

Relation Source Additional LLM call
co_occurs L2 facts created in one write batch No
semantic_neighbor Reconcile candidates above MEMORY_GRAPH_EDGE_MIN_SCORE No
causes Reconcile related output No additional call
elaborates Reconcile related output No additional call
contrasts Reconcile related output No additional call
same_series Reconcile related output No additional call
TAGGED_WITH Memory tags projected to Topic nodes No new memory LLM call
MENTIONS NER entities projected to Entity nodes No
TEMPORAL_NEXT Optional event-time ordering No

co_occurs is bounded by MEMORY_GRAPH_CO_OCCURS_MAX_BATCH to prevent an O(n²) edge explosion. semantic_neighbor is inexpensive but mostly repeats information already present in vector similarity; typed and co-occurrence relations usually carry more structural information.

2.3 Lifecycle synchronization

Graph state follows memory lifecycle changes:

  • ADD projects the new active fact and its edges.
  • UPDATE refreshes the projected node.
  • SUPERSEDE and SHADOW retire the old projection from active retrieval.
  • Search filters inactive or shadowed nodes even if stale edges remain.

Projection code lives in hy_memory/pipelines/_graph/projector.py and is scheduled from hy_memory/pipelines/writer.py.

3. Read-side Graph usage

legacy and hybrid readers share the same Graph post-processing. The readers differ only in candidate recall: legacy uses dense vectors; hybrid adds the keyword/BM25 channel.

Enable Graph post-processing with:

MEMORY_GRAPH_RERANK_ENABLED=true

All Graph operations are fail-open. Exceptions return the pre-Graph candidate order unless a test explicitly requests strict behavior.

3.1 A — Support propagation

Support propagation reranks candidates already present in the expanded recall pool. It never adds a new candidate.

For candidate v, the implementation computes bounded support from recalled neighbors and applies a small score adjustment:

support(v) = sum(edge_prior(u,v) * score(u)) / sqrt(pool_degree(v))
score'(v)  = score(v) + beta * min(support(v), support_cap)

Relevant settings:

MEMORY_GRAPH_PROPAGATE_BETA=0.15
MEMORY_GRAPH_PROPAGATE_ITERS=1
MEMORY_GRAPH_SUPPORT_CAP=1.0

3.2 B — Bounded relation expansion

Relation expansion may nominate nodes outside the initial pool. Admission is bounded by all of the following:

  • traversal hop limit;
  • seed score floor;
  • prefilter and expansion limits;
  • relation-type quota;
  • semantic hard gate sim(candidate) >= sim(seed) - delta;
  • final multi-channel scoring.

Admitted items are merged into a seed by default, so they do not consume an extra top-k slot.

Core settings and current defaults:

MEMORY_GRAPH_RELAX_GAMMA=0.3
MEMORY_GRAPH_SEED_FLOOR=0.5
MEMORY_GRAPH_MAX_EXPAND=20
MEMORY_GRAPH_EXPAND_HOPS=2
MEMORY_GRAPH_EXPAND_PREFILTER_TOP_N=50
MEMORY_GRAPH_SEED_SIM_DELTA=0.2
MEMORY_GRAPH_EXPAND_MERGE_SEED=true

Set MEMORY_GRAPH_RELAX_GAMMA=0 to disable relation expansion while retaining support propagation and relation paths.

3.3 C — Relation paths

Relation paths preserve connection semantics that would be lost in a flat memory list. The shared reader stores them independently from normal memories in its diagnostic ReadResponse.extra["related_paths"] field:

read_response.extra["related_paths"]

Each path contains the ordered nodes and relation types. Temporal edges also include direction (earlier -> later).

MEMORY_GRAPH_PATH_ENABLED=true
MEMORY_GRAPH_PATH_HIGH_FLOOR=0.5

3.4 Relation-type priors

The reader weights an edge by both its stored weight and a relation-type prior. Current priors are defined in pipelines/_graph/rerank.py:

Relation Prior
causes 0.90
elaborates 0.90
same_series 0.85
contrasts 0.70
temporal_next 0.70
co_occurs 0.55
episode 0.55
untyped related 0.50
semantic_neighbor 0.35

Higher priors are reserved for relations that provide information not already encoded by vector similarity. The degree normalization and support cap prevent high-degree nodes from dominating ranking.

4. Temporal edges and episodes

MEMORY_GRAPH_TEMPORAL_SPINE=true creates directed TEMPORAL_NEXT edges using VDB memory_at values. Graph nodes do not own canonical event time; projection resolves timestamps from VDB before building the spine.

Episodes are separate from Graph. episode_id groups memories belonging to one discussion and can provide bounded candidate support even when Graph is off.

MEMORY_EPISODE_RECALL_ENABLED=false
MEMORY_EPISODE_RECALL_WEIGHT=0.7
MEMORY_EPISODE_SUMMARY_ENABLED=false

Detailed Episode and summary settings are listed in docs/env_reference.md.

5. Backfill and rebuild

Existing VDB facts can be projected with:

client.build_memory_graph(
    user_id="u1",
    agent_id=None,      # None means all agents for the user
    clear_first=False,
)

Backfill can reconstruct:

  • L2 Memory nodes;
  • Topic and Entity projections;
  • semantic_neighbor edges from stored vectors;
  • optional TEMPORAL_NEXT edges.

Backfill cannot reconstruct batch co_occurs edges or LLM typed relations, because the original write-batch and reconcile decisions are not recoverable.

Use clear_first=True after changing projection rules. It clears the selected L2 projection and orphaned Topic/Entity nodes without deleting System 2 L6 schemas.

6. Observability

The shared reader records internal diagnostics in:

read_response.extra["graph_rerank"]   # edge, propagation, and admission stats
read_response.extra["related_paths"]  # decorated relation paths

HyMemoryClient.search() does not currently forward these two internal fields. For public operational visibility, use pipeline traces: read-side Graph work is recorded as READ_GRAPH_RERANK, while write projection reports GRAPH_PROJECT statistics and errors.

7. Implementation map

Responsibility Module
Projection and lifecycle synchronization hy_memory/pipelines/_graph/projector.py
Support, expansion, paths, priors hy_memory/pipelines/_graph/rerank.py
Reader integration hy_memory/pipelines/reader_base.py
Write scheduling hy_memory/pipelines/writer.py
Relation output parsing hy_memory/agent/reconciler.py
GraphStore interface hy_memory/data/graph_store_base.py
Kuzu backend hy_memory/data/graph_store_kuzu.py
Neo4j backend hy_memory/data/graph_store_neo4j.py
Graph backfill API HyMemoryClient.build_memory_graph()

Tests covering these contracts live primarily in tests/test_memory_graph.py, tests/test_graph_edge_idempotency.py, and tests/test_profile_evidence.py.