klieo-memory-graph-rag 3.3.0

Graph-first RAG composer over KnowledgeGraph + LongTermMemory. Stable at 1.x per ADR-039.
Documentation

klieo-memory-graph-rag

Graph-first RAG composer over klieo-memory-graph::KnowledgeGraph + klieo-core::LongTermMemory.

Status: stable at 3.x. Trait freeze contract recorded in ADR-039.

Layers

  • klieo-core (Layer 0) — frozen at 3.2.0
  • klieo-memory-graph (Layer 1) — KnowledgeGraph trait
  • klieo-memory-graph-neo4j (Layer 2) — Neo4j backend
  • klieo-memory-qdrant (Layer 1) — vector store with FilterableLongTermMemory
  • klieo-memory-graph-rag (Layer 2) — this crate

What's in the crate

  • BuiltinExtractor (regex + caller-hint dedup)
  • FallbackExtractor (primary → secondary on empty)
  • LlmEntityExtractor (klieo-core::llm + JSON-array prompt)
  • NullProvenance stub (M4 replaces with a klieo-provenance bridge)
  • GraphAwareLongTerm — drop-in LongTermMemory impl
  • KnowledgeIngestionPipeline + ImportSource extension point

Quickstart — builder facade

GraphAwareLongTerm::builder() defaults the extractor (BuiltinExtractor) and the metrics counter (RecallMetrics::default()) so callers only supply the two mandatory backends — the authoritative vector store and the graph index:

use std::sync::Arc;
use klieo_memory_graph::{FilterableLongTermMemory, KnowledgeGraph};
use klieo_memory_graph_rag::GraphAwareLongTerm;

# fn run(vector: Arc<dyn FilterableLongTermMemory>, graph: Arc<dyn KnowledgeGraph>) {
let long_term = GraphAwareLongTerm::builder().build(vector, graph);
# let _ = long_term; }

Override defaults via the builder's setters:

use std::sync::Arc;
use klieo_memory_graph::RecallMetrics;
use klieo_memory_graph_rag::{
    FallbackExtractor, BuiltinExtractor, GraphAwareLongTerm, LlmEntityExtractor,
};

# fn run<V, G>(vector: Arc<V>, graph: Arc<G>, llm: Arc<dyn klieo_core::llm::LlmClient>)
# where
#     V: klieo_memory_graph::FilterableLongTermMemory + 'static,
#     G: klieo_memory_graph::KnowledgeGraph + 'static,
# {
let metrics = Arc::new(RecallMetrics::default());
let extractor = Arc::new(FallbackExtractor::new(
    BuiltinExtractor::default(),
    LlmEntityExtractor::new(llm),
));
let long_term = GraphAwareLongTerm::builder()
    .extractor(extractor)
    .metrics(Arc::clone(&metrics))
    .min_graph_hits(2)
    .build(vector, graph);
# let _ = long_term; let _ = metrics; }

Read metrics.snapshot() from an ops/metrics endpoint to see graph hit-rate vs vector-fallback rate.

Full M2 wiring

use std::sync::Arc;
use klieo_memory_graph_rag::GraphAwareLongTerm;
use klieo_memory_graph_neo4j::Neo4jKnowledgeGraph;
use klieo_memory_neo4j::MemoryNeo4j;
use klieo_memory_qdrant::MemoryQdrant;

# async fn run() -> Result<(), Box<dyn std::error::Error>> {
let qdrant = MemoryQdrant::connect("http://localhost:6334").await?;
let neo4j = MemoryNeo4j::connect("bolt://localhost:7687", "neo4j", "pw").await?;
let graph = Arc::new(Neo4jKnowledgeGraph::new(neo4j.neo4j_handle()));
let long_term = GraphAwareLongTerm::builder().build(qdrant.qdrant_long_term, graph);
// `long_term` is a drop-in `Arc<dyn LongTermMemory>`.
# let _ = long_term; Ok(()) }

Advanced wiring — direct constructor

GraphAwareLongTerm::new(vector, graph, extractor, metrics) stays available for callers that want explicit control over every component.

For ingest from external sources (Confluence pages, regulatory texts, …) implement ImportSource in your own crate and pass it to KnowledgeIngestionPipeline::new.

License

MIT.