# Entity Filtering When Querying the Zep Graph Memory: A Complete Technical Guide

> Master entity filtering in Zep graph memory. Learn to extract domain-specific nodes for cleaner data pipelines. A complete technical guide for efficient querying.

- Repository: [BaiFu/mirofish](https://github.com/666ghj/mirofish)
- Tags: how-to-guide
- Published: 2026-02-23

---

**Entity filtering in the Zep graph memory extracts only domain-specific nodes by stripping generic labels and optionally applying type whitelists to produce a clean entity collection for downstream processing.**

The mirofish repository implements a sophisticated filtering pipeline within its Zep integration layer to prepare simulation data. This process ensures that only meaningful, user-defined entities—rather than structural placeholders—are passed to agent workflows. Understanding this **entity filtering when querying the Zep graph memory** is essential for developers customizing knowledge graph simulations or extending the backend's memory management capabilities.

## The Filtering Architecture in ZepEntityReader

The core logic resides in [`backend/app/services/zep_entity_reader.py`](https://github.com/666ghj/mirofish/blob/main/backend/app/services/zep_entity_reader.py), specifically within the `ZepEntityReader` class. This service acts as the boundary between the mirofish simulation engine and the Zep knowledge graph API, handling connection management, retry logic, and entity sanitation.

### Connecting to Zep and Retrieving Raw Graph Data

The process begins with client initialization and bulk data retrieval. The reader instantiates a `Zep` client using the `ZEP_API_KEY` from the global configuration, then fetches the complete graph topology.

```python

# From backend/app/services/zep_entity_reader.py

reader = ZepEntityReader()  # Lines 80-86: Configures client with API key

nodes = reader.get_all_nodes(graph_id)   # Lines 26-36: Retry-enabled node fetch

edges = reader.get_all_edges(graph_id)   # Lines 57-68: Optional edge retrieval

```

The system stores retrieved nodes in a dictionary keyed by UUID to enable O(1) lookups during edge traversal (lines 52-54). This lookup table becomes critical when enriching entities with relationship context later in the pipeline.

### The Core Filtering Logic

The `filter_defined_entities` method applies a three-stage validation to determine which nodes represent "real" entities versus structural artifacts:

**1. Default-Label Removal**
Every node in Zep carries generic labels `"Entity"` or `"Node"`. The filter strips these universal markers to reveal domain-specific classifications underneath.

**2. Custom-Label Detection**
A node is retained only if it possesses at least one label that is **not** `"Entity"` or `"Node"`. This signals that the node represents a domain-specific concept (such as "Person" or "Organization") rather than a graph placeholder (lines 61-66).

**3. Optional Whitelist Intersection**
If the caller provides the `defined_entity_types` parameter, the method performs a set intersection between the node's custom labels and the whitelist. Nodes failing this check are discarded (lines 69-74).

The first surviving custom label becomes the node's resolved `entity_type`, used for statistics aggregation and prompt generation downstream (lines 75-78).

### Edge Enrichment and Relationship Mapping

When `enrich_with_edges=True`, the system augments filtered entities with their graph context. For each retained node, the method:

- Traverses all edges to find connections originating from or terminating at the current node, capturing directionality, edge names, facts, and opposite node UUIDs (lines 89-107)
- Resolves neighbor node details using the UUID lookup table, attaching minimal snapshots (UUID, name, labels, summary) to the `EntityNode` instance (lines 108-124)

This enrichment transforms flat entity lists into contextual subgraphs, enabling agents to understand relationship topology during simulation steps.

## Integration with the Simulation Workflow

The filtered entities feed directly into the simulation preparation stage. In [`backend/app/services/simulation_manager.py`](https://github.com/666ghj/mirofish/blob/main/backend/app/services/simulation_manager.py), the `prepare_simulation` method invokes `filter_defined_entities` during Stage 1 (lines 71-85), obtaining the canonical entity list that drives:

- Profile generation for simulation agents
- Configuration creation for scenario parameters
- Subsequent graph-memory updates via `ZepGraphMemoryUpdater`

This integration ensures that only validated, domain-relevant entities influence the simulation state, preventing placeholder nodes from corrupting agent reasoning.

## Practical Implementation Example

The following pattern demonstrates how to query and filter entities with optional type constraints and relationship enrichment:

```python
from backend.app.services.zep_entity_reader import ZepEntityReader

# Initialize reader (automatically loads ZEP_API_KEY from config)

reader = ZepEntityReader()

# Execute filtering with whitelist and edge enrichment

filtered = reader.filter_defined_entities(
    graph_id="simulation-graph-uuid",
    defined_entity_types=["Person", "Organization", "Location"],  # Optional whitelist

    enrich_with_edges=True  # Include relationship context

)

# Process results

print(f"Retrieved {filtered.filtered_count} valid entities of types {filtered.entity_types}")
for entity in filtered.entities:
    print(f"\n{entity.name} ({entity.get_entity_type()})")
    for edge in entity.related_edges:
        print(f"  → {edge['direction']} via {edge['edge_name']} to {edge.get('target_node_uuid')}")

```

This code returns a `FilteredEntities` dataclass (lines 130-138) containing the sanitized entity list, discovered type taxonomy, and cardinality counts.

## Summary

- **Entity filtering** in mirofish removes generic Zep labels (`"Entity"`, `"Node"`) to isolate domain-specific nodes.
- The **`filter_defined_entities`** method in [`zep_entity_reader.py`](https://github.com/666ghj/mirofish/blob/main/zep_entity_reader.py) implements a whitelist-aware pipeline that validates nodes based on custom label presence.
- **Edge enrichment** optionally attaches relationship context by traversing the graph and resolving neighbor nodes via UUID lookup tables.
- The **`SimulationManager`** consumes filtered results during preparation stage 1 to ensure only meaningful entities drive agent simulations.
- All configuration relies on `ZEP_API_KEY` from the global config module, with retry logic wrapping all Zep API calls.

## Frequently Asked Questions

### What distinguishes a "custom label" from a default label in Zep entity filtering?

Default labels are the universal markers `"Entity"` and `"Node"` that Zep assigns to every node automatically. Custom labels are user-defined classifications (such as "Customer" or "Product") assigned during graph construction. The filtering pipeline explicitly strips default labels and checks for the existence of at least one custom label to determine if a node represents a domain-specific entity worth retaining.

### How does the `defined_entity_types` whitelist parameter function?

When provided, `defined_entity_types` acts as an allowlist that intersects with a node's custom labels. If the node possesses any label present in the whitelist, it passes validation; otherwise, it is discarded. If the parameter is omitted (None), the system retains all nodes possessing at least one custom label regardless of its specific value.

### When should developers enable `enrich_with_edges` during filtering?

Enable edge enrichment when the simulation logic requires relationship awareness—such as when agents need to understand connections between entities or when the scenario involves network traversal. This adds computational overhead due to edge walking and neighbor lookups (lines 89-124), so it should be disabled for simple entity counts or type validation tasks where topology is irrelevant.

### What data structure does `filter_defined_entities` return?

The method returns a `FilteredEntities` dataclass containing three fields: `entities` (a list of `EntityNode` objects with optional edge attachments), `entity_types` (a set of discovered custom label strings), and `filtered_count` (an integer tally of valid entities). This structure provides both the processed data and metadata necessary for downstream simulation configuration.