Vector DB Indexer
Prerequisites & Dependencies
- Python 3.10+
- Packages:
pip install qdrant-client sentence-transformers tiktoken (swap in openai for API embeddings; Chroma/pgvector equivalents follow the same flow)
- Environment:
EMBEDDING_MODEL (e.g., sentence-transformers/all-MiniLM-L6-v2); QDRANT_URL and QDRANT_API_KEY when using managed Qdrant Cloud
Execution Steps
- Load source documents and normalize text: strip headers/footers, collapse whitespace, and extract metadata (source path, section title, timestamp).
- Chunk with a token-bounded splitter (256-512 tokens) and 10-15% overlap so boundary context is preserved.
- Generate embeddings in batches; ensure query-time embedding uses the exact same model and version.
- Create the collection with matching vector size and distance metric (cosine for normalized embeddings) and add a payload index for metadata filtering.
- Upsert points with deterministic UUIDs (hash of source path + chunk index) for idempotent re-indexing, storing chunk text and metadata as payload.
- Verify: run semantic test queries, inspect top-k hits for relevance, and compare collection point count against expected chunk count.
import hashlib, uuid
from qdrant_client import QdrantClient, models
from sentence_transformers import SentenceTransformer
CHUNK, OVERLAP = 400, 60 # words; tune to your embedding model
model = SentenceTransformer("all-MiniLM-L6-v2")
client = QdrantClient(url="http://localhost:6333")
client.create_collection(
"docs",
vectors_config=models.VectorParams(size=384, distance=models.Distance.COSINE),
)
def chunk_text(text: str) -> list[str]:
words = text.split()
return [" ".join(words[i:i + CHUNK]) for i in range(0, len(words), CHUNK - OVERLAP)]
points = []
for doc in documents: # [{"path": str, "text": str}]
for i, chunk in enumerate(chunk_text(doc["text"])):
pid = uuid.UUID(hashlib.md5(f"{doc['path']}:{i}".encode()).hexdigest())
points.append(models.PointStruct(
id=str(pid),
vector=model.encode(chunk).tolist(),
payload={"text": chunk, "source": doc["path"], "chunk": i},
))
client.upsert("docs", points=points, wait=True)
1---2name: vector-db-indexer3description: Chunk documents and store vector embeddings into a Vector DB.4metadata:5 source: skills/vector-db-indexer/vector-db-indexer.md6---78# Vector DB Indexer910## Prerequisites & Dependencies11- Python 3.10+12- Packages: `pip install qdrant-client sentence-transformers tiktoken` (swap in `openai` for API embeddings; Chroma/pgvector equivalents follow the same flow)13- Environment: `EMBEDDING_MODEL` (e.g., `sentence-transformers/all-MiniLM-L6-v2`); `QDRANT_URL` and `QDRANT_API_KEY` when using managed Qdrant Cloud1415## Execution Steps161. Load source documents and normalize text: strip headers/footers, collapse whitespace, and extract metadata (source path, section title, timestamp).172. Chunk with a token-bounded splitter (256-512 tokens) and 10-15% overlap so boundary context is preserved.183. Generate embeddings in batches; ensure query-time embedding uses the exact same model and version.194. Create the collection with matching vector size and distance metric (cosine for normalized embeddings) and add a payload index for metadata filtering.205. Upsert points with deterministic UUIDs (hash of source path + chunk index) for idempotent re-indexing, storing chunk text and metadata as payload.216. Verify: run semantic test queries, inspect top-k hits for relevance, and compare collection point count against expected chunk count.2223```python24import hashlib, uuid25from qdrant_client import QdrantClient, models26from sentence_transformers import SentenceTransformer2728CHUNK, OVERLAP = 400, 60 # words; tune to your embedding model29model = SentenceTransformer("all-MiniLM-L6-v2")30client = QdrantClient(url="http://localhost:6333")31client.create_collection(32 "docs",33 vectors_config=models.VectorParams(size=384, distance=models.Distance.COSINE),34)3536def chunk_text(text: str) -> list[str]:37 words = text.split()38 return [" ".join(words[i:i + CHUNK]) for i in range(0, len(words), CHUNK - OVERLAP)]3940points = []41for doc in documents: # [{"path": str, "text": str}]42 for i, chunk in enumerate(chunk_text(doc["text"])):43 pid = uuid.UUID(hashlib.md5(f"{doc['path']}:{i}".encode()).hexdigest())44 points.append(models.PointStruct(45 id=str(pid),46 vector=model.encode(chunk).tolist(),47 payload={"text": chunk, "source": doc["path"], "chunk": i},48 ))49client.upsert("docs", points=points, wait=True)50```51