You want an agent that answers questions about your material — handbooks, tickets, design notes, contracts. Not generic web knowledge. Your files.
Say you have thousands of documents.
Someone asks: “How do we reset a contractor’s laptop?”
Somewhere in that pile, the answer exists. Your agent must find it and reply in plain language.
You cannot send everything
A language model only sees what you put in this request.
If you paste all thousands of documents into every request:
| What goes wrong | Why |
|---|---|
| It won’t fit | Models have a size limit on the text they can read in one call |
| It costs too much | You pay for the text you send, every time |
| Answers get worse | Extra noise buries the few lines that matter |
So the job is not “give the model the whole library.”
The job is: find a few useful passages for this question, then ask the model.
thousands of documents
│
│ ✗ cannot all go in one request
│
▼
find a small set that
matches THIS question
│
▼
send those + the question
to the chat modelThat “find a small set” step is the heart of this story. This chapter teaches the idea that makes meaning-based find possible. The next chapter wires find → answer end to end.
First try: search by words
A simple approach: look for documents that share words with the question.
Question: “How do we reset a contractor’s laptop?”
A note says: “Procedure to wipe a loaner computer before return.”
Same idea. Different words. Keyword search often misses it.
| Approach | Compares | Risk |
|---|---|---|
| Keyword search | Shared spelling | Misses synonyms and paraphrase |
| Meaning search | How close the ideas are | Can still find “laptop” ↔ “loaner computer” |
People read meaning. Your program needs a way to score meaning too.
Embeddings: meaning as numbers
An embedding is a long list of numbers that stands for what a piece of text is about.
Another word for that list is vector. Same idea.
You do not invent the numbers. You send text to an embedding model — a specialized model whose only job is:
text in → list of numbers out
It is not your chat model. Chat models write replies. Embedding models place meaning on a map.
"Reset a contractor laptop"
→ [0.12, -0.04, 0.33, …]
"Wipe a loaner computer before return"
→ [0.11, -0.05, 0.31, …] ← nearby numbers
"Python is a programming language"
→ [-0.22, 0.41, -0.09, …] ← far away
Similar meaning → similar lists. Unrelated meaning → different lists.
Once every passage is a list of numbers, “find useful docs” becomes: embed the question, then keep the passages whose numbers sit closest.
A tiny map you can hold in your head
Real embeddings have hundreds or thousands of numbers. The math is the same with two, so we can draw it.
Pretend these toy vectors (made-up for teaching):
| Text | Toy vector (x, y) |
|---|---|
| “reset contractor laptop” | (4, 1) |
| “wipe loaner computer” | (3.6, 1.1) |
| “Python language” | (-2, 3) |
y
│ Python (-2, 3)
│
│
│ wipe loaner (3.6, 1.1)
│ reset laptop (4, 1)
│
└────────────────── xThe question and the IT note sit near each other. The Python line sits elsewhere. Your program can keep the near ones and ignore the far ones — even among thousands of points.
Similarity: a score for “how near”
Your program needs a number, not a drawing.
The usual score for text embeddings is cosine similarity. In plain words: do two lists point the same direction?
| Score (about) | Plain meaning |
|---|---|
| Near 1 | Same direction — very similar meaning |
| Near 0 | Unrelated |
| Near -1 | Opposite (rare for ordinary sentences) |
You almost never care about the exact digits. You care about order:
- related passages → higher score
- unrelated passages → lower score
Worked idea
Question: “How do we reset a contractor’s laptop?”
Stored passages (among thousands):
- “Wipe a loaner computer before return.”
- “Renew the Python license by Friday.”
Embed the question and both passages. Passage 1 scores high. Passage 2 scores low. Keep passage 1 for the model.
That is meaning search over a library you cannot paste whole.
What a call looks like
Same family as your other API calls: send text, get structured data back. Here the data is numbers, not a chat reply.
You send (idea):
{
"model": "an-embedding-model",
"texts": [
"How do we reset a contractor laptop?",
"Wipe a loaner computer before return."
]
}
You get (idea):
{
"embeddings": [
{ "values": [0.12, -0.04, 0.33, "…many more…"] },
{ "values": [0.11, -0.05, 0.31, "…many more…"] }
]
}
One list of numbers per input string, same order.
Then your code compares two lists with cosine similarity. That step is ordinary math on your machine. You do not need another model call just to score two vectors you already have.
In practice you embed documents once when you index them, store the numbers, and at question time you mostly embed the question and compare.
Where this sits in the agent story
You already know how to call a model and how to give it tools.
For a document agent, the missing piece is a smart lookup:
person asks about YOUR docs
│
▼
embed the question
│
▼
compare to stored passage embeddings
│
▼
keep the closest few passages
│
▼
send passages + question
to the chat model → answerThis chapter is the middle of that path: embed and compare.
Turning “closest passages + question → grounded answer,” including how you split long files into passages, is the next chapter: retrieval augmented generation (RAG).
Two chapters, one story:
| Chapter | Job in the story |
|---|---|
| Embeddings and Similarity (here) | Why you can’t send all docs; how meaning becomes numbers you can rank |
| RAG (next) | Split, store, retrieve the top passages, then generate the answer |
Rules that save pain
| Rule | Why |
|---|---|
| One embedding model per store | Model A and model B use different maps. Mixing them makes “near” meaningless. |
| Re-embed when text changes | Old numbers describe old words. |
| Embed when you index; compare locally | Indexing costs API calls. Scoring vectors you already have is cheap. |
| Keywords still matter sometimes | Exact IDs (ORDER-12345) often need exact match. Meaning search shines for paraphrase. |
When things go wrong
| Problem | What it usually means |
|---|---|
| Related texts score low | Different embedding models mixed, or text too short / noisy |
| Everything scores “kind of high” | Weak or near-duplicate passages; check your examples |
| Good match, wrong answer later | Lookup found the passage, but the chat step failed — that is the RAG chapter’s problem |
Words to keep
| Word | Meaning |
|---|---|
| Document agent | An agent that answers from your files, not only general knowledge |
| Embedding | A list of numbers that captures what text is about |
| Embedding model | The model that turns text into that list |
| Vector | Another name for the list of numbers |
| Similarity | A score for how close two embeddings are (often cosine) |
| Meaning search | Finding text by idea, not only by shared words |
| Question | What the person wants answered |
| Prompt | The full text you send the chat model (later: may include retrieved passages) |
See it in Code
The Code panel embeds a few short sentences and prints similarity scores. Related pairs should beat unrelated ones — the same ranking idea you would use across thousands of passages.