How to Use Semantic Vector Search for Code Retrieval in Code-Graph-RAG

Code-Graph-RAG enables intent-based code retrieval by embedding natural language queries using UniXcoder, performing nearest-neighbor search against a vector store (Qdrant or Milvus), and resolving matches to full function metadata via Cypher queries.

The vitali87/code-graph-rag repository implements a semantic vector search pipeline that retrieves code based on meaning rather than exact keywords. This approach converts both user queries and codebase elements into dense vector embeddings, allowing developers to find functions and classes using natural language descriptions.

How Semantic Vector Search Works in Code-Graph-RAG

The semantic search pipeline operates through three integrated stages defined in the source code.

Stage 1: Embedding Natural Language Queries

The process begins in codebase_rag/embedder.py, where the embed_code() function converts text queries into dense vectors. By default, the system uses the UniXcoder model, though any OpenAI-compatible provider can be configured. The function caches embeddings for reuse (lines 80-89), ensuring efficient repeated queries against the same codebase.

Stage 2: Vector Store Retrieval

The embedded query passes to codebase_rag/vector_store.py, where search_embeddings() (lines 90-95) abstracts the underlying vector database. The system supports Qdrant by default, with optional Milvus support. If a project filter is provided, the helper _filter_by_project() (lines 23-32) narrows results to specific repository prefixes, ensuring cross-project isolation.

Stage 3: Resolving Matches to Metadata

Vector store returns contain only node IDs and similarity scores. The system converts these to full metadata through build_nodes_by_ids_query in codebase_rag/cypher_queries.py. The ingestor—a QueryProtocol implementation—executes this Cypher query against the graph database (Memgraph), returning qualified names, types, and attributes. Finally, semantic_code_search() in codebase_rag/tools/semantic_search.py (lines 30-85) wraps these as SemanticSearchResult objects.

Prerequisites and Dependency Gating

Semantic search requires the semantic extra package set. The guard function has_semantic_dependencies() in codebase_rag/utils/dependencies.py checks for torch, transformers, and a vector-store client at runtime. If dependencies are missing, semantic_code_search() logs warning ex.SEMANTIC_EXTRA and returns an empty list (lines 36-39) rather than failing.

Implementation Examples

Direct API Usage

from codebase_rag.tools.semantic_search import semantic_code_search
from codebase_rag.services import QueryProtocol

results = semantic_code_search(
    ingestor=ingestor,  # QueryProtocol implementation

    query="function that parses JSON",
    top_k=5,
    project="my_python_project"
)

for r in results:
    print(f"{r['qualified_name']} (type: {r['type']}, score: {r['score']})")

The function returns a list of dictionaries containing node_id, qualified_name, name, type, and score.

Command-Line Interface


# Start interactive mode

cgr start --repo-path /path/to/repo

# Inside the REPL

> semantic search "read a configuration file"

The CLI creates the tool via create_semantic_search_tool() (lines 58-86) and forwards queries through the same pipeline.

SDK Integration

from cgr import embed_code, semantic_search

# Debug embedding generation

embedding = embed_code("def load_config(path): ...")

# Search against running daemon

matches = semantic_search("load configuration file")

Summary

  • Three-stage pipeline: Query embedding (embed_code), vector retrieval (search_embeddings), and metadata resolution (build_nodes_by_ids_query)
  • Configurable backends: Supports UniXcoder embeddings with Qdrant or Milvus vector stores
  • Project isolation: Optional _filter_by_project ensures repository-scoped results
  • Dependency gating: has_semantic_dependencies() prevents runtime errors when optional packages are missing
  • Multiple interfaces: Available via direct Python API, CLI REPL, or high-level SDK

Frequently Asked Questions

By default, the system uses the UniXcoder model through the embed_code() function in codebase_rag/embedder.py. The architecture supports OpenAI-compatible providers, allowing you to configure alternative embedding models by adjusting the provider settings in the embedder configuration.

When you pass the project parameter to semantic_code_search(), it propagates through to _filter_by_project() in codebase_rag/vector_store.py. This helper applies a prefix filter to node IDs, ensuring the vector store only returns results belonging to the specified repository, which is critical for multi-project deployments.

Can I use a different vector store backend with Code-Graph-RAG?

Yes. While Qdrant is the default, the search_embeddings() interface in codebase_rag/vector_store.py abstracts the backend implementation. You can configure Milvus by setting the appropriate environment variables or configuration flags, and the generic interface will route calls accordingly.

What happens if semantic dependencies are not installed?

The system calls has_semantic_dependencies() from codebase_rag/utils/dependencies.py at runtime. If torch, transformers, or the vector client are missing, semantic_code_search() logs warning code ex.SEMANTIC_EXTRA and returns an empty list rather than raising an exception, allowing the system to degrade gracefully.

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 →