Semantic retrieval depends on an index that keeps source text, metadata, and embeddings aligned before any answer-generation layer is added. A VectorStoreIndex provides that boundary in LlamaIndex by turning Document objects into embedded nodes that a retriever can search.
The direct build path uses VectorStoreIndex.from_documents(). LlamaIndex applies its configured transformations, embeds the resulting nodes, and stores them in an in-memory vector store unless a different StorageContext is supplied.
The deterministic BaseEmbedding subclass maps eight support-domain terms to vector positions, keeping the first construction check independent of hosted services. Its narrow vocabulary is not a production embedding model; indexing and retrieval in the application must share the same real model.
from llama_index.core import Document, VectorStoreIndex from llama_index.core.embeddings import BaseEmbedding class SupportKeywordEmbedding(BaseEmbedding): @classmethod def class_name(cls) -> str: return "SupportKeywordEmbedding" def _vector(self, text: str) -> list[float]: terms = [ "billing", "refund", "escalation", "support", "inventory", "warehouse", "restart", "sync", ] lowered = text.lower() return [1.0 if term in lowered else 0.0 for term in terms] def _get_text_embedding(self, text: str) -> list[float]: return self._vector(text) def _get_query_embedding(self, query: str) -> list[float]: return self._vector(query) async def _aget_query_embedding(self, query: str) -> list[float]: return self._vector(query)
The embedding maps support and inventory terms to separate vector positions. Production indexing and retrieval must use the same application embedding model.
documents = [ Document( text=( "Billing support runbook: refund ticket 7421 belongs to Maya. " "Escalate refund questions to the docs-review queue." ), metadata={"source": "billing-support-runbook"}, ), Document( text=( "Inventory runbook: warehouse sync ticket 8804 belongs to Arun. " "Restart the sync worker before opening an incident." ), metadata={"source": "inventory-runbook"}, ), ]
Metadata remains attached to the nodes created from each document, so retrieved results can identify their source.
Related: How to load local files with SimpleDirectoryReader in LlamaIndex
embed_model = SupportKeywordEmbedding() index = VectorStoreIndex.from_documents( documents, embed_model=embed_model, insert_batch_size=2, )
insert_batch_size=2 makes the two-document smoke-test batch explicit. Larger values favor local throughput, while smaller values reduce the request size sent to a remote vector store.
Related: How to persist and load an index in LlamaIndex
retriever = index.as_retriever(similarity_top_k=1) nodes = retriever.retrieve("Which runbook covers refund escalation?") print(f"index_type={type(index).__name__}") print(f"indexed_ref_docs={len(index.ref_doc_info)}") print(f"retriever_results={len(nodes)}") print(f"top_source={nodes[0].node.metadata['source']}")
Checking retrieval proves that the built index can compare a query embedding with its stored document embeddings.
Related: How to create a retriever in LlamaIndex
Related: How to run a query engine in LlamaIndex
$ python vector_store_index_build.py index_type=VectorStoreIndex indexed_ref_docs=2 retriever_results=1 top_source=billing-support-runbook
indexed_ref_docs=2 confirms that both source documents reached the index. top_source=billing-support-runbook confirms that retrieval selected the source containing the refund escalation terms.