CloudCodeTree LogoCloudCodeTree
AI NewsTutorialsAbout
CloudCodeTree Logo
CloudCodeTree
  • AI News
  • Tutorials
  • About
← Back to AI News
Embeddings From Scratch: Your First Semantic Search App with sentence-transformers and all-MiniLM-L6-v2

Embeddings From Scratch: Your First Semantic Search App with sentence-transformers and all-MiniLM-L6-v2

Chris Harper

3 min read

Jul 29, 2026 · 04:08 UTC

AI
Tutorial
Embeddings
HuggingFace

Three pip installs and 8 lines of Python turn any text list into a searchable semantic index — this is the primitive that every RAG, hybrid search, and reranking tutorial in this series builds on.

What you'll be able to do after this:

  • Convert a list of sentences into 384-dimensional embedding vectors with a single .encode() call
  • Compute cosine similarity to find the nearest semantic match without a vector database
  • Understand why two sentences about different words can match better than two sentences sharing the same word

Install

pip install sentence-transformers torch

The 8 lines

from sentence_transformers import SentenceTransformer, util

model = SentenceTransformer("all-MiniLM-L6-v2")

docs = [
    "Claude Code can run multiple subagents in parallel.",
    "Embeddings capture semantic meaning as dense vectors.",
    "The weather in San Francisco is foggy.",
]

query = "How do I parallelize agent tasks?"
doc_embeddings = model.encode(docs, convert_to_tensor=True)
query_embedding  = model.encode(query, convert_to_tensor=True)

scores  = util.cos_sim(query_embedding, doc_embeddings)[0]
best    = scores.argmax().item()
print(f"Best match: {docs[best]} (score: {scores[best]:.3f})")
# → Best match: Claude Code can run multiple subagents in parallel. (score: 0.712)

The model runs locally — no API key, no network call after the first download.

What's actually happening

model.encode() passes each sentence through a transformer, then mean-pools the token representations into a single 384-dimensional vector. Each dimension is a float with no standalone meaning — the geometry of the full vector is what matters.

util.cos_sim() measures the angle between two vectors: 1.0 = same direction (identical meaning), 0.0 = unrelated. It normalizes for length so a short query and a long paragraph compare fairly.

The query and "subagents in parallel" share almost no words but point in the same region of semantic space. "Foggy weather" points elsewhere. That's the value.

Choosing a model

all-MiniLM-L6-v2 is the sensible default: 22M parameters, 384 dims, 5× faster than the larger all-mpnet-base-v2 with comparable quality on most short-text tasks. When you need higher retrieval quality, check the MTEB leaderboard — it ranks 200+ embedding models on standardized retrieval, clustering, and classification benchmarks. BAAI/bge-large-en-v1.5 is a common upgrade pick when you have more compute.

This is the foundation for every other tutorial in this series: the chunking post showed how to split documents; pgvector showed where to store vectors; hybrid search showed how to combine them with BM25. It all starts here.

Sources: sentence-transformers Quickstart — sbert.net · all-MiniLM-L6-v2 model card — HuggingFace · Video: Sentence Transformers — Embedding, Similarity and Semantic Search (YouTube)