Neo4j Agent
A single-agent pipeline combining Neo4j graph database with vector search. The agent creates knowledge nodes with Cypher, builds relationships between experts, creates a vector index on embeddings, performs vector similarity search via the index, evaluates graph context richness, and synthesizes an answer combining vector matches with relationship data. Demonstrates SDK primitives across real Neo4j graph + vector operations.
Environment variables
This example requires OPENAI_API_KEY, WAXELL_API_KEY, and WAXELL_API_URL. Requires Neo4j on localhost:7687 (auth: neo4j/demodemo). Use --dry-run to skip real API calls.
Architecture
Key Code
Graph Node and Relationship Creation with @tool
The agent creates Expert nodes with embeddings via Cypher and builds typed relationships between them.
@waxell.tool(tool_type="database", name="neo4j_create_nodes")
def create_knowledge_nodes(driver, experts: list[dict], embeddings) -> dict:
"""Create Expert nodes with embeddings via Cypher."""
with driver.session() as session:
session.run("MATCH (n:WaxellExpert) DETACH DELETE n")
for expert, emb in zip(experts, embeddings):
session.run(
"CREATE (n:WaxellExpert {name: $name, domain: $domain, "
"org: $org, embedding: $embedding})",
name=expert["name"], domain=expert["domain"],
org=expert["org"], embedding=emb.tolist(),
)
return {"nodes_created": len(experts)}
@waxell.tool(tool_type="database", name="neo4j_create_relationships")
def create_relationships(driver, relationships: list[tuple]) -> dict:
"""Create relationships between Expert nodes."""
with driver.session() as session:
for src, dst, rel_type in relationships:
session.run(
f"MATCH (a:WaxellExpert {{name: $src}}), (b:WaxellExpert {{name: $dst}}) "
f"CREATE (a)-[:{rel_type}]->(b)", src=src, dst=dst,
)
return {"relationships_created": len(relationships)}
Vector Index and Similarity Search
@waxell.tool(tool_type="vector_db", name="neo4j_create_vector_index")
def create_vector_index(driver, dim: int) -> dict:
"""Create a vector index on Expert embeddings."""
with driver.session() as session:
session.run(
f"CREATE VECTOR INDEX {VECTOR_INDEX} IF NOT EXISTS "
f"FOR (n:WaxellExpert) ON (n.embedding) "
f"OPTIONS {{indexConfig: {{`vector.dimensions`: {dim}, "
f"`vector.similarity_function`: 'cosine'}}}}"
)
return {"index": VECTOR_INDEX, "dimensions": dim}
@waxell.tool(tool_type="vector_db", name="neo4j_vector_search")
def vector_search(driver, query_embedding, k: int = 3) -> dict:
"""Vector similarity search using the vector index."""
with driver.session() as session:
result = session.run(
f"CALL db.index.vector.queryNodes('{VECTOR_INDEX}', $k, $embedding) "
"YIELD node, score "
"RETURN node.name AS name, node.domain AS domain, score",
k=k, embedding=query_embedding.tolist(),
)
return {"hits": [...], "total": len(hits)}
What this demonstrates
@waxell.observe-- single agent with full lifecycle tracing@waxell.tool(tool_type="database")-- Neo4j Cypher operations (CREATE nodes, CREATE relationships, DETACH DELETE) recorded as database tool spans@waxell.tool(tool_type="vector_db")-- Neo4j vector index creation and similarity search recorded as vector DB tool spans@waxell.retrieval(source="neo4j")-- graph search result extraction recorded with Neo4j as the source@waxell.decision-- query type selection (pure_vector, graph_traversal, hybrid)@waxell.reasoning_dec-- graph context quality assessment with relationship density analysiswaxell.score()-- graph relevance and answer quality scores attached to the tracewaxell.tag()/waxell.metadata()-- vector DB type, database host, and query type- Auto-instrumented LLM calls -- OpenAI synthesis with both vector matches and relationship context
- Graph + vector hybrid -- knowledge graph relationships combined with vector similarity search
Run it
# Dry-run mode (no API key needed)
cd dev/waxell-dev
python -m app.demos.neo4j_agent --dry-run
# Live mode (requires Neo4j on localhost:7687)
export OPENAI_API_KEY="sk-..."
python -m app.demos.neo4j_agent
# Custom query
python -m app.demos.neo4j_agent --dry-run --query "Find knowledge graph connections for AI governance"