Lightweight AI agent converting natural language to Neo4j Cypher.
The web-based UI
enables users to ask questions and receive Cypher scripts interactively via a browser. It supports multiple LLM providers: OpenAI GPT-5-mini, Google Gemini 2.5 Pro, and OpenAI Assistant.
The backend exposes /api/schema, returning the loaded Neo4j schema as JSON. The UI shows this in a side panel for quick reference. For more details, see the UI README.
# Clone and configure
git clone git@github.com:nickzren/text-to-cypher.git
cd text-to-cypher
cp .env.example .env
# Edit .env to add your API keys
# Run with Docker Compose
docker compose upOpen http://localhost:8000 for the UI and http://localhost:7474 for Neo4j Browser.
- Git
- Python 3.12+
- pip
- Clone the repository:
git clone git@github.com:nickzren/text-to-cypher.git cd text-to-cypher - Install dependencies:
pip install uv uv sync cd ui && npm install && cd ..
- Configure environment:
cp .env.example .env # Edit .env to add your OPENAI_API_KEY and other settings
CLI mode:
uv run python -m src.text2cypher_agent
You> Show compounds that treat both type 2 diabetes mellitus and hypertension.
MATCH (c1:Compound)-[:TREATS_CtD]->(d1:Disease {name: 'type 2 diabetes mellitus'}),
(c1)-[:TREATS_CtD]->(d2:Disease {name: 'hypertension'})
RETURN c1, d1, d2Web UI mode:
./scripts/run-dev.shThe file data/input/neo4j_schema.json contains a Neo4j schema. While the example uses the Hetionet Neo4j database, the export_neo4j_schema.py script can be used to export the schema from any Neo4j database.
To set up the Hetionet Neo4j Docker container locally, follow the instructions from this link.
If you need to export the schema from your own Neo4j instance, first update the .env file to set DB_URL and DB_NAME.
Then, run the following command to export the schema:
python src/export_neo4j_schema.py --output_dir data/input/You can also access the Neo4j Browser at http://localhost:7474 to run the Cypher queries generated by the text-to-cypher framework.
For any unclear schema elements, create data/input/schema_hints.json:
{
"relationships": {
"OBSCURE_AbC": "A does something to C"
}
}LLMs can only “see” the schema you expose, so a precise, self‑describing graph leads to dramatically better text‑to‑Cypher results.
| # | Guideline | Why it matters |
|---|---|---|
| 1 | One label = one entity (singular noun) – Disease, Drug, Gene, … |
Avoids synonym / over‑loaded labels, keeping queries unambiguous. oai_citation_attribution:0‡Neo4j |
| 2 | Relationship type = SOURCE_VERB_TARGET in UPPER_SNAKE_CASEUse verbs from the OBO Relation Ontology where possible (e.g. GENE_ASSOCIATED_WITH_DISEASE, DRUG_TREATS_DISEASE). |
Verbal, directional names read like English, helping both humans and models infer intent. oai_citation_attribution:1‡Neo4j Online Community oai_citation_attribution:2‡obofoundry.org |
| 3 | Properties in lowerCamelCase with clear semantics – approvalYear, uniprotId |
Consistent keys let the model project properties confidently. oai_citation_attribution:3‡Neo4j |
| 4 | Define constraints & indexes up‑front – CREATE CONSTRAINT ... IS UNIQUE on natural keys, composite indexes for frequent filters |
Prevents duplicates, speeds queries, and signals “canonical” identifiers to the LLM. oai_citation_attribution:4‡Neo4j |
| 5 | Ban “generic” nodes or relationships – no catch‑all Entity label or RELATED_TO relationship |
Specificity keeps generated Cypher terse and correct. |
| 6 | Document required vs optional properties (table or JSON) | Gives both humans and the model a ground truth for projection. |
| 7 | Be ruthlessly consistent – once you pick a style, never mix alternatives | Consistency is the strongest signal the LLM gets. oai_citation_attribution:5‡Neo4j |
Bottom line – if a new teammate can understand your graph without extra docs, an LLM probably can too.
