Ingest & search the graph
Ingest graph knowledge into Tier 4 and query it with hybrid search.
Build the knowledge graph two ways — LLM extraction from text, or asserting facts verbatim — then query it with hybrid search. This is the Tier 4 surface you use for cross-session recall outside a live session (evaluation, batch ingestion, direct lookups).
Prerequisites
- An
embedderandllmwired intoPgMem— see Connect a model provider. - A
group_idfor the tenant you're writing to.
Steps
Ingest by extraction
add_episode runs the LLM over content, extracts entities and edges, dedupes
them against the graph, and resolves contradictions bi-temporally:
result = await mem.add_episode(
content="Acme upgraded to Enterprise on a 2-year term, closed by Dana.",
group_id="acme",
)
print(result.nodes, result.edges) # what was created or matchedAssert facts verbatim (no extraction)
For facts you already trust — a webhook, a validated tool result — skip the LLM and write them directly with provenance. This never mints state edges by accident:
from pgmem import Authority, ExternalFact, ExternalReference
await mem.add_episode(
content=raw_payload, # kept for provenance; not re-extracted
group_id="acme",
external_facts=[
ExternalFact(
content="Acme's plan changed to Enterprise",
external_refs=[ExternalReference(system="billing", id="acme")],
source=Authority.application,
confidence=1.0,
),
],
)Search the graph
mem.search is hybrid — vector similarity, full-text, and graph traversal, fused
into one ranked result. Always scope by group_ids:
results = await mem.search("what plan is Acme on?", group_ids=["acme"])
for node in results.nodes:
print(node.name, node.summary)
for edge in results.edges:
print(edge.fact) # the relationship, with validity boundsPass config=SearchConfig(...) to force a recipe (the constants
COMBINED_HYBRID_RRF / COMBINED_HYBRID_MMR / COMBINED_HYBRID_CROSS_ENCODER
cover the common ones), or center_node_uuid= to bias toward a known entity.
(Optional) build communities
Cluster related entities into summarized communities for higher-level recall. It's a wipe-and-rebuild over the named groups, so run it periodically, not per-episode:
await mem.build_communities(group_ids=["acme"])Verify
await mem.add_episode(content="Acme signed a 2-year Enterprise contract.", group_id="acme")
results = await mem.search("enterprise contract", group_ids=["acme"])
assert results.nodes, "expected at least one matching entity"Gotchas
add_episode(content=...) is ungoverned extraction — feed it "the plan is
Enterprise" (current state) and it may create an edge that goes stale. Assert
events through external_facts, and keep current-state text out of content. See
Events vs state.
- Extraction is heavy (LLM + embeddings) — run it off the response path. For
many episodes at once use
add_episode_bulk(needspool.max_size >= 2). searchis raw graph retrieval. To build a turn's prompt usecompile_context, which folds the graph in with the other tiers under a budget.
Related
- The knowledge graph — the model behind this
- Connect a model provider — the required providers
- Tune retrieval — depths and budgets in a turn
- PgMem —
add_episode/search/build_communities