VectorStoreIndex over QdrantVectorStore
WorkedIn this worked example, you will replicate the core logic of build_index_from_nodes from the repository. This function builds a VectorStoreIndex that stores nodes and their pre‑computed embeddings in a Qdrant collection, making Qdrant the single source of truth (the payload holds the chunk text and metadata, so no separate docstore is needed).
Why this wiring?
- Qdrant as docstore: By setting
index_doc_id=Trueandtext_key="text", each Qdrant point stores the full node text and metadata. Retrieval hydrates nodes straight from the payload. - No re‑embedding: Nodes already have
.embeddingset byembed_nodes_cached; the index uses them exactly as given. - Deterministic node IDs:
_stable_node_idsgives each node a UUID5 based on namespace and content, so re‑runs upsert the same points instead of duplicating. - Collection naming:
_collection_namebuilds a unique name from the namespace and a fingerprint of sorted node IDs, preventing cross‑lane contamination.
Your task
Study the code below and understand how each part fits together. The build_index_from_nodes function is already fully written; here we distill its essential steps into a standalone implementation that you will examine. Pay attention to:
- Creating the Qdrant client via
_get_qdrant_client(). - Making node IDs deterministic with
_stable_node_ids. - Deriving the collection name with
_collection_name. - Configuring
QdrantVectorStorewith the correct parameters. - Setting up a
StorageContextthat points to this vector store. - Returning a
VectorStoreIndexbuilt from the pre‑embedded nodes.
The starter_code below gives you the skeleton. The solution_code is the full reference. Read the reasoning in the comments.
Starter code
import os
from llama_index.core import StorageContext, VectorStoreIndex
from llama_index.vector_stores.qdrant import QdrantVectorStore
# Assume these helper functions are available from the repository:
# _get_qdrant_client, _stable_node_ids, _collection_name, vector_store_backend, qdrant_location
def build_index_from_nodes(nodes, embed_model, *, namespace: str = "", verbose: bool = True):
# Your implementation goes here
pass
Solution code
import os
from llama_index.core import StorageContext, VectorStoreIndex
from llama_index.vector_stores.qdrant import QdrantVectorStore
# Assume these are imported from the repository:
# from .memory_common import _get_qdrant_client, _stable_node_ids, _collection_name, vector_store_backend, qdrant_location
def build_index_from_nodes(nodes, embed_model, *, namespace: str = "", verbose: bool = True):
"""Build a VectorStoreIndex over Qdrant, using pre‑embedded nodes."""
# 1. Determine backend: default is qdrant, opt out with VECTOR_STORE=memory
from .memory_common import vector_store_backend, qdrant_location
if vector_store_backend() != "qdrant":
# Fallback to plain in‑memory index (no Qdrant)
return VectorStoreIndex(nodes, embed_model=embed_model)
# 2. Get the process‑wide Qdrant client (or None if unavailable)
from .memory_common import _get_qdrant_client
client = _get_qdrant_client()
if client is None:
# Qdrant unavailable – fallback to memory
return VectorStoreIndex(nodes, embed_model=embed_model)
# 3. Assign deterministic node IDs (re‑run ⇒ upsert, no duplicates)
from .memory_common import _stable_node_ids
_stable_node_ids(nodes, namespace=namespace)
# 4. Compute a stable collection name from namespace + corpus fingerprint
from .memory_common import _collection_name
collection = _collection_name(nodes, namespace=namespace)
if verbose:
print(f"[vector-store] qdrant collection {collection} "
f"({len(nodes)} node(s)) at {qdrant_location()}")
# 5. Create the QdrantVectorStore with the contract that makes Qdrant the docstore
vector_store = QdrantVectorStore(
client=client,
collection_name=collection,
index_doc_id=True, # store node.id_ as doc_id for direct access
text_key="text", # payload key holding the chunk text
)
# 6. Build a StorageContext that uses this Qdrant store (no in‑memory docstore)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
# 7. Create the index; LlamaIndex will not re‑embed because nodes already have embeddings
return VectorStoreIndex(
nodes,
storage_context=storage_context,
embed_model=embed_model,
)
Key takeaways
- The
QdrantVectorStoreparametersindex_doc_id=Trueandtext_key="text"are essential for Qdrant to act as the single source of truth. - Deterministic node IDs via
_stable_node_idsprevent duplicate points on re‑runs. - The collection name derived by
_collection_nameensures each (namespace, corpus) pair gets its own collection. - If Qdrant is unavailable, the code gracefully falls back to an in‑memory index.
Now review the rubric below to confirm you understand the critical details.
- roadmap-kg/kg/memory_common.py:931-972
- roadmap-kg/kg/memory_common.py:975-990
- roadmap-kg/kg/memory_common.py:836-872