ASDRP · Agentic RAG Track · Module 02
Turn text into numbers a computer can compare — then prove that semantically similar sentences actually land close together.
What we'll cover
Track 1 · Text → Vectors
"gold" and "bullion" share zero characters — but mean the same thing. A search that matches characters will miss it.
Once text is a point in space we can measure how close two points are — and "close" becomes "semantically similar."
Module 1 asked "retrieve the relevant passages." Embeddings are how relevance is measured.
Track 1 · Text → Vectors
all-MiniLM-L6-v2from sentence_transformers import SentenceTransformer
# Downloads the model the first time (~90 MB), then cached
model = SentenceTransformer("all-MiniLM-L6-v2")
# Encode a single sentence → numpy array shape (384,)
vec = model.encode("Gold is a safe-haven asset.")
print(vec.shape) # (384,)
print(vec[:5]) # [ 0.12, -0.83, 0.41, ...]
The model is downloaded from HuggingFace Hub on first call, then cached in ~/.cache/huggingface/. Subsequent runs are instant.
Track 1 · Text → Vectors
sentences = [
"Gold is a safe-haven asset.", # metals → safety
"Silver is used in solar panels.", # metals → industry
"Platinum is rarer than gold.", # metals → comparison
"The weather is nice today.", # off-topic
"Investors buy gold during recessions.", # semantically close to sentence 0
]
# Encode all at once — returns a (5, 384) numpy matrix
embeddings = model.encode(sentences)
print(embeddings.shape) # (5, 384)
# Each row is one sentence's vector
for sent, vec in zip(sentences, embeddings):
print(f"{sent[:35]!r:38s} norm={np.linalg.norm(vec):.4f}")
Track 2 · Embedding Space
Every sentence becomes a point in a 384-dimensional space. We can't draw 384 axes, but the geometry is the same as 2D or 3D:
Track 2 · Embedding Space
The dot product divided by the product of magnitudes. Because MiniLM outputs unit-norm vectors, the denominator is always 1 — cosine similarity reduces to a plain dot product.
| Value | Interpretation |
|---|---|
| ≈ 1.0 | Nearly identical meaning |
| ≈ 0.7 | Related topic |
| ≈ 0.3 | Loosely related |
| ≈ 0.0 | Unrelated |
| < 0 | Opposite sentiment (rare) |
import numpy as np
def cosine(a: np.ndarray, b: np.ndarray) -> float:
"""Cosine similarity between two 1-D vectors."""
a, b = np.asarray(a, float), np.asarray(b, float)
return float(a @ b / (np.linalg.norm(a) * np.linalg.norm(b)))
# Pair-wise examples
gold_vec = model.encode("Gold is a safe-haven asset.")
invest_vec = model.encode("Investors buy gold in recessions.")
weather_vec= model.encode("The weather is nice today.")
print(cosine(gold_vec, invest_vec)) # e.g. 0.74 (related)
print(cosine(gold_vec, weather_vec)) # e.g. 0.13 (unrelated)
Track 3 · Hands-on
sentences = [
"Gold is a safe-haven asset.",
"Investors buy gold during recessions.",
"Silver is used in solar panels.",
"Platinum group metals are catalysts.",
"The weather is nice today.",
]
embeddings = model.encode(sentences)
# Build a 5×5 similarity matrix
n = len(sentences)
sim = np.zeros((n, n))
for i in range(n):
for j in range(n):
sim[i, j] = cosine(embeddings[i], embeddings[j])
# Pretty-print
import pandas as pd
labels = [s[:28] + "…" for s in sentences]
df = pd.DataFrame(sim, index=labels, columns=labels).round(2)
print(df.to_string())
Track 3 · Hands-on
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
# Compress 384 dims → 2 for plotting
pca = PCA(n_components=2)
pts = pca.fit_transform(embeddings)
fig, ax = plt.subplots(figsize=(5, 4))
colors = ["#2563eb","#2563eb","#7c3aed",
"#7c3aed","#dc2626"]
for i, (x, y) in enumerate(pts):
ax.scatter(x, y, color=colors[i], s=80, zorder=3)
ax.annotate(labels[i], (x, y),
fontsize=7, textcoords="offset points",
xytext=(5, 3))
ax.set_title("PCA of sentence embeddings (2D)")
ax.set_xlabel("PC 1"); ax.set_ylabel("PC 2")
plt.tight_layout(); plt.show()
The two "gold" sentences should appear close together. Metals sentences cluster away from the weather sentence. PCA loses most variance — the real clusters are sharper in 384D.
Two points that look far apart in 2D might actually be close in the full 384-dim space. Always measure cosine similarity in the original space, not on the plot.
Track 3 · Cautions
all-MiniLM-L6-v2 was fine-tuned on general-web text. It works well for metals market prose, but specialist jargon (e.g. derivatives notation) may embed poorly compared to a domain-fine-tuned model.
Module 02 recap
SentenceTransformer.encode() maps any string to 384 floatsRun the notebook: 02_embeddings.ipynb · Next: Module 03 — Similarity & Vector Search (top-k retrieval with Qdrant)