Skip to main content

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.

CI Documentation Python Status License

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) or failed (the corrections ran out), with every attempt, its issues, the schema it used and its token usage.
  • Optional execution: run the final query read-only, with a timeout, and get the rows.
  • Bring your own LLM: a one-method protocol, 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 $name is 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.
  • Early days: the prompts and the loop have been tried with small models and small graphs, and the filter has not been measured on a real large schema. Expect them to need work.

Documentation

The full documentation is at text2cypher.readthedocs.io:

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 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for text2cypher 0.1.0
File Size Uploaded Provenance
text2cypher-0.1.0.tar.gz 30.3 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for text2cypher 0.1.0
File Interpreter ABI Platform
text2cypher-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 66.4 kB

Release files / text2cypher-0.1.0.tar.gz

Download URL text2cypher-0.1.0.tar.gz
Size 30.3 kB
Tags Source
SHA-256 checksum
How to use checksums
8b6629bce3802e4a54fef404155e9864d8f345a4931b4371b00e53704e57a605
BLAKE2b-256 checksum
How to use checksums
3c2f2c8fd1dde51fa8e24b3135637c8961f0afd7eab09be743db45e3859fd970
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.3 {"installer":{"name":"uv","version":"0.13.3","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-0.1.0-py3-none-any.whl

Download URL text2cypher-0.1.0-py3-none-any.whl
Size 36.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9b4eb067599dacee9f35fe78e9631e1342056248bc872feb9ab1374846c291d2
BLAKE2b-256 checksum
How to use checksums
a487d81bb3b3c2dba200e2cc086693f1912dfa0f210c8af8effe42ed6bfad075
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.3 {"installer":{"name":"uv","version":"0.13.3","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 0.1.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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page