Embeddings and RAG
How embeddings capture meaning, and how retrieval-augmented generation lets a model answer from your own project documents.
The problem RAG solves
Your specs, IMG notes and tickets are unknown to the model and far too big to paste into every prompt. Retrieval-augmented generation (RAG) first retrieves the few most relevant passages, then generates an answer from only those, with citations. The model's job shifts from remembering to reading, which it does well.
Embeddings: meaning as numbers
An embedding is a vector of numbers that an embedding model produces from text. Similar meanings get vectors pointing in similar directions: 'supplier blocked for payment' lands near 'vendor payment block'. Cosine similarity (-1 to 1) measures that closeness; near 1 means same topic. It measures meaning, not correctness.
Keyword versus semantic search
SAP content is full of exact codes, so production systems often combine both (hybrid search).
Offline: indexing your documents
Online: following one question
Try it: build the pipeline
Put the full RAG pipeline in order, from raw documents to a cited answer.
- 1Embed each chunk
- 2Store vectors with metadata
- 3Split specs and tickets into chunks
- 4Embed the user's question with the same model
- 5Retrieve the top-k most similar chunks
- 6Put the chunks and question into the prompt
- 7Generate an answer that cites its sources
Chunking and metadata decide quality
Chunks must be small enough to retrieve precisely, big enough to make sense alone. Split along the document's own structure, with a small overlap so rules are not cut in half. Tag each chunk with metadata (doc ID, section, object, release, status) to filter and cite.
When RAG answers badly
Check the retrieved chunks first. If the right passage is missing, it is a retrieval problem: fix chunking, search or metadata. If it was retrieved and the answer is still wrong, it is a generation problem: tighten the prompt, require citations, or use a stronger model.
import numpy as np
def cosine(a, b):
a, b = np.array(a), np.array(b)
return float(a @ b / (np.linalg.norm(a) * np.linalg.norm(b)))
# embed() = your platform's embedding API; chunks are embedded once, offline
chunks = [
{"id": "FS-BP-017 4.2", "text": "Payment block for suppliers is set via CR type ZSUP_BLK ..."},
{"id": "TCK-2231", "text": "Supplier posting block not replicated to ECC via DRF ..."},
]
for c in chunks:
c["vec"] = embed(c["text"])
q = embed("How do we block a supplier for payment?")
top = sorted(chunks, key=lambda c: cosine(q, c["vec"]), reverse=True)[:2]Real systems use a vector database, but the logic is the same.
Try it: retrieval or generation?
A RAG assistant gave a bad answer. Where is the problem?
Try it: the outdated answer
Your spec assistant confidently quotes the 2023 rule for supplier group ZINT payment terms. The 2025 spec changed it, and both versions are in the index. What do you do?
Remember
- RAG = retrieve relevant passages from your documents, then answer from them with citations.
- Embeddings capture meaning; chunking, metadata and hybrid search decide retrieval quality.
- Debug retrieval first, generation second, and filter by access rights.