Knowledge GraphsEnterprise AI

Branching Memory: Persistent Conversational Context in GraphRAG

Barnyard stores conversation turns as a persistent graph in Neo4j, enabling durable context, branching threads, and provenance tracking that survives session restarts.

Dawson Bauer

Overview

Traditional chatbots maintain conversation history in a flat list of messages that disappears when the session ends. Barnyard's branching memory system stores conversation turns as a persistent graph structure in Neo4j, enabling:

  • Durable context that survives session restarts and server reboots
  • Branching conversations where a single turn can spawn independent continuations without overwriting the original path
  • Provenance tracking — each memory node is anchored to the entities and documents it referenced during retrieval

Architecture

MemoryNode

Each conversational turn is stored as a MemoryNode in Neo4j with:

FieldTypeDescription
idUUIDGlobally unique identifier returned to the caller
querystrThe user's original question
answerstrThe model's generated response
grounding_contextstrText snapshot of the retrieved KG context at answer time
timestampdatetimeWhen this turn occurred
user_idstrWhich user owns this memory node

Graph Structure

Turns are chained together with NEXT_TURN edges — turn A to turn B to turn C — and each turn also carries provenance links: an ABOUT edge to the entities it discussed (such as Apple Inc.) and a SOURCED_FROM edge to the documents it drew on (such as a Q3 report).

Relationship types:

  • NEXT_TURN — links consecutive turns in the same conversation thread
  • ABOUT — links a memory to the Entity nodes it discussed (survives entity merges)
  • SOURCED_FROM — links a memory to the TextNode(s) used as retrieval context (survives re-ingestion)

Branching Conversations

The key innovation is the spawn_child flag. Without it, each new turn extends the current chain linearly:

Without it, each new turn simply extends the current chain in a straight line — root, then turn one, turn two, turn three.

With spawn_child=True, a new branch is created from the current node without mutating it:

With branching enabled, a new turn forks off the current node without changing it: the original branch (root → turn one → turn two) stays intact, while an alternate follow-up grows alongside it as a separate path.

This is useful for:

  • Exploring alternative hypotheses without losing the original reasoning path
  • Parallel investigation threads on the same document set
  • A/B comparing different follow-up questions against the same context

Retrieval Enrichment

When answering a question, generate_answer_node injects the last N turns from the memory chain as conversation history. This means:

  1. The user doesn't need to resend prior turns — they're fetched directly from Neo4j
  2. Multi-turn coherence is maintained even across separate API sessions
  3. The grounding context from prior turns can be referenced if the current retrieval returns sparse results

Provenance and Robustness

ABOUT and SOURCED_FROM edges use stable identifiers:

  • ABOUT → Entity id (deterministic MD5 of name+type — survives entity re-extraction)
  • SOURCED_FROM → TextNode id (UUID4 — survives re-ingestion of the same document)

When a TextNode is deleted, SOURCED_FROM edges are removed but the MemoryNode itself is preserved with its grounding_context snapshot — the conversation history remains coherent even after source documents are removed.