text2cypher
Generate validated Cypher queries from natural language text with LLMs Ask a question in plain language and get back a read-only Cypher query that has been checked against your FalkorDB graph.
text2cypher asks an LLM to write the query, checks it against the real graph with cypher-guardrail, and sends what is wrong back to the LLM until the query passes or the attempts run out. A query that fails the checks is never handed back as if it were fine.
- Grounded in your graph: the prompt carries the schema read from the graph itself (labels, relationship types, properties with their value types, the paths that exist, and the indexes), cut down to what the question is about.
- Validated before it is returned: syntax, schema (labels, relationship types, paths and their direction) and property checks. A query that could write to the graph is never valid.
- Self-correcting: the problems found are written back to the LLM. If the cut-down schema does not get there, the loop moves to the full one.
- Honest outcomes:
valid,unanswerable(the LLM declined) orfailed(the corrections ran out), with every attempt, its issues, the schema it used and its token usage. - Example values: the schema shows up to three values of each property, so the LLM writes values the way your graph does. They are real data sent to the LLM provider:
Config(example_values=0)sends none. - Typos fixed without the LLM (optional): a misspelled label, relationship type or property that is a likely typo of exactly one name in your graph is replaced and the query validated again, at no cost in LLM calls.
- Optional execution: run the query read-only, with a timeout, and get the rows; a query that FalkorDB fails at run time is sent back to the LLM like any other problem.
- Bring your own LLM: a small protocol,
chat(the conversation as turns) or justcomplete, with an OpenAI client included. Async throughout.
Installation
Python 3.12 or later.
uv add text2cypher # or: pip install text2cypher
You need a FalkorDB graph that has data, reachable with the async client (falkordb.asyncio), and a model. The included client uses OpenAI's API and reads OPENAI_API_KEY.
Quickstart
import asyncio
from falkordb.asyncio import FalkorDB
from text2cypher import OpenAIClient, Text2Cypher
async def main() -> None:
client = FalkorDB(host="localhost", port=6379) # one client per event loop
agent = Text2Cypher(client, OpenAIClient("your-model"))
result = await agent.run("Which actors appeared in The Matrix?", graph="movies")
print(result.status) # "valid", "unanswerable" or "failed"
print(
result.query
) # MATCH (p:Person)-[:ACTED_IN]->(m:Movie {title: 'The Matrix'}) RETURN p.name
await client.aclose()
asyncio.run(main())
Always look at result.status. valid means the query passed the checks, not that it means what you meant (see below).
There is also a quickstart that needs no model and no server: it starts an embedded FalkorDB and answers with a scripted LLM, including one correction.
What is and is not checked
- Checked: the query is valid Cypher for FalkorDB, it cannot write, its parameters are provided (the prompt asks for values written in the query, so a
$nameis a problem), the labels, relationship types and paths exist in the direction used, and every property read exists on the label or relationship type it is read from. - Not checked: that the query means what the question meant. A query can be valid and still answer another question, for example by using a property with a similar name. Look at the query, or at the rows, before you rely on them.
- Known limits: the prompts, the loop and the schema filter have been tried with Claude Haiku on two small test graphs (6 and 36 labels); the filter was measured offline on the larger one. How well they do on your data, on a large schema or with other models is not measured yet, so check the queries and the rows on your own questions (the
evals/harness is there for that). Prompts and the filter's matching can change in a minor version; the public names (text2cypher.__all__,text2cypher.llmandtext2cypher.schema) follow semantic versioning.
Documentation
The full documentation is at text2cypher.readthedocs.io:
- Using text2cypher: the result, the configuration, running the query, errors
- How it works: the loop, the escalation and what it costs
- The schema and its filter: what the LLM is shown, your own filter, keeping the schema between runs
- When a question fails: what to look at, and what to try, for each outcome
- LLM clients: your own client, other OpenAI-compatible models,
FakeLLMfor tests - What is and is not checked and the API reference
For contributors: how it is built, and why, and a harness that replays questions through the real pipeline with replies written by a model or a person.
Development
uv sync # create the environment (Python >= 3.12 also installs FalkorDBLite for the tests)
uv run pytest # the tests, on an embedded FalkorDB
uv run pytest -m "not db" # only the tests that need no database (under ten seconds)
uv run ruff check . && uv run ruff format --check . && uv run ty check && uv run lint-imports
uv run coverage run -m pytest && uv run coverage report
Contributions are welcome: please open an issue or a pull request.
License
Apache License 2.0: see LICENSE.
Metadata
Release files for text2cypher 1.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| text2cypher-1.2.0.tar.gz | 43.0 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| text2cypher-1.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 94.0 kB
Release files / text2cypher-1.2.0.tar.gz
| Download URL | text2cypher-1.2.0.tar.gz |
|---|---|
| Size | 43.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
96ecae5c1d18366a6da9b837181514cd2815815b7a4096dcc368f784e9a40a22
|
|
BLAKE2b-256 checksum How to use checksums |
af29cd495097b9931a1379a12b29211494b182207e42f1054dcbcb3eea5b5632
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / text2cypher-1.2.0-py3-none-any.whl
| Download URL | text2cypher-1.2.0-py3-none-any.whl |
|---|---|
| Size | 51.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cef808e2d1de5ab7024a00cf96f0a7383e8a92121ef89a048c6a188ea6ebf8ee
|
|
BLAKE2b-256 checksum How to use checksums |
5521a7ef2a93f2ebddbdc2e978ad3acad9be70dbd491a9168a87e4c991e865b2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for text2cypher 1.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.