How vitali87/code-graph-rag Generates Cypher Queries from Natural Language

code-graph-rag translates plain English questions into executable Cypher queries through a five-step pipeline that combines few-shot prompting, LLM inference, and post-processing validation.

The open-source code-graph-rag project provides a retrieval-augmented generation (RAG) system for codebases stored in graph databases. At its core lies a natural language to Cypher translation mechanism that lets developers query their code's knowledge graph using everyday English rather than graph query syntax.

The 5-Step Query Generation Pipeline

1. Capture the Request via CLI or SDK

User input enters the system through either the command-line interface or programmatic SDK. In codebase_rag/cli.py, the CLI receives raw text such as "Show me all functions that call UserService.create_user" and forwards it to the translation layer.


# Example usage pattern from the SDK documentation

from cgr import CypherGenerator

generator = CypherGenerator()
cypher = generator.generate(
    "Find all functions that call UserService.create_user"
)

2. Build a Few-Shot Prompt

The CypherGenerator class relies on PromptBuilder (defined in codebase_rag/prompts.py) to assemble a structured chat prompt containing:

  • System instruction: Explains the NL→Cypher translation task
  • Few-shot examples: Concrete question/query pairs from CYPHER_EXAMPLE_PAIRS in codebase_rag/cypher_queries.py
  • User question: The actual natural language input

These examples anchor the LLM to the project's specific graph schema and query patterns.

3. Invoke the LLM

The prompt passes to the generic LLM abstraction exposed in cgr/__init__.py. The default implementation calls self.llm.chat_completion() with the constructed messages, routing to whichever provider is configured (OpenAI, Anthropic, etc.).


# Simplified structure from the implementation

class CypherGenerator:
    def __init__(self, llm=None):
        self.llm = llm or DefaultLLM()
        self.prompt_builder = PromptBuilder()

    def generate(self, natural_language: str) -> str:
        prompt = self.prompt_builder.build(
            user_question=natural_language,
            examples=CYPHER_EXAMPLE_PAIRS  # few-shot anchors

        )
        response = self.llm.chat_completion(messages=prompt)
        return self._post_process(response.content)

4. Post-Process and Validate

Raw LLM output undergoes sanitization in codebase_rag/cypher_queries.py:

  • Markdown fences (cypher ... ) are stripped
  • Output is validated against whitelisted Cypher patterns defined in constants like CYPHER_FIND_BY_QUALIFIED_NAME
  • Optional formatting (line-break normalization) is applied

This validation layer prevents malformed or potentially unsafe queries from reaching the database.

5. Execute Against Memgraph

The validated Cypher query ships to codebase_rag/services/graph_service.py, which interfaces with the Memgraph backend. Results return to the user as structured code intelligence.

Core Implementation Files

File Responsibility
codebase_rag/cypher_queries.py Cypher templates, example pairs (CYPHER_EXAMPLE_PAIRS), and validation logic
codebase_rag/prompts.py Prompt assembly templates and instruction formatting
cgr/__init__.py Public API exposing CypherGenerator and LLM abstraction
codebase_rag/cli.py CLI entry point for natural language input
codebase_rag/services/graph_service.py Query execution against Memgraph

Why Few-Shot Examples Matter

The CYPHER_EXAMPLE_PAIRS constant is the project's secret sauce. By embedding concrete English→Cypher mappings directly into each prompt, code-graph-rag achieves schema-constrained generation without fine-tuning. The LLM sees patterns like:


# Conceptual example from cypher_queries.py structure

CYPHER_EXAMPLE_PAIRS = [
    {
        "question": "Find all functions that call UserService.create_user",
        "cypher": "MATCH (c:Function)-[:CALLS]->(t:Function {name: 'create_user', class: 'UserService'}) RETURN c"
    },
    # ... additional domain-specific examples

]

This approach outperforms zero-shot prompting on specialized graph schemas while remaining portable across LLM providers.

Summary

  • CypherGenerator is the primary interface for natural language to Cypher translation
  • The pipeline follows capture → prompt → LLM → validate → execute stages
  • Few-shot examples from codebase_rag/cypher_queries.py ground the LLM in the codebase's graph schema
  • Post-processing validation ensures only safe, pattern-matched queries reach Memgraph
  • The architecture abstracts LLM providers through cgr/__init__.py for flexibility

Frequently Asked Questions

What LLM providers does code-graph-rag support?

The project uses a generic LLM abstraction layer in cgr/__init__.py that can wrap any provider implementing the chat_completion interface. OpenAI and Anthropic Claude are commonly configured, though the exact supported list depends on your installation's dependencies.

How does the system prevent invalid Cypher queries?

Generated queries pass through a whitelist validator defined in codebase_rag/cypher_queries.py. The system checks against allowed patterns (such as CYPHER_FIND_BY_QUALIFIED_NAME) and strips extraneous formatting before execution. Queries failing validation are rejected before reaching the Memgraph backend.

Can I customize the few-shot examples for my codebase?

Yes. The CYPHER_EXAMPLE_PAIRS constant in codebase_rag/cypher_queries.py is the designated extension point. Adding question→query pairs specific to your graph's node labels, relationship types, and property conventions improves translation accuracy without modifying core logic.

Where is the Cypher query actually executed?

Execution happens in codebase_rag/services/graph_service.py, which manages connections to Memgraph. This service receives the validated Cypher string, runs it against the knowledge graph, and formats results for the CLI or calling application.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →