Skip to content
AI Engineering
Build Projects

Project: ask questions about your documents

Build a retrieval-augmented chatbot over a folder of documents. It teaches embeddings, chunking, vector search and how to measure retrieval.

Chapter 13: Build ProjectsLesson 2 of 5Level: StarterAbout 360 min
Words on this page (13)
embedding
: A list of numbers that represents the meaning of a piece of text or an image, so similar things sit close together.
chunk
: A small piece of a document, sized for indexing and retrieval.
vector
: An ordered list of numbers. Embeddings and model activations are vectors.
retrieval
: Finding the most relevant pieces of text for a query.
token
: A piece of text the model reads and writes, usually a word or part of a word. About 4 characters of English on average.
metadata
: Extra labels stored with a document or chunk, such as its title, date or country, which let you filter results.
vector database
: A database that stores embeddings and finds the nearest ones quickly.
prompt
: The input text you give a model, including instructions, examples and data.
recall
: Of the truly positive cases, the share the system found.
reranker
: A second model that rescores a short list of search results by reading query and passage together.
API
: Application programming interface: a way for one program to call another, usually over HTTP.
dot product
: Multiply matching entries of two vectors and add them up. Large when they point the same way.
cosine similarity
: A score from -1 to 1 for how much two vectors point the same way, ignoring their length.

The brief

Pick a small set of documents you know well, such as a product manual or your own notes. The user asks a question and gets an answer with citations to the passages used.

Steps

  1. Split the documents into of about 300 with overlap and keep the source and heading as .
  2. Embed each chunk and store it in a database (pgvector, Chroma or Supabase).
  3. Embed a question and fetch the top five chunks.
  4. the model to answer only from the chunks, cite them and say when the answer is not there.
  5. Print the retrieved chunks next to every answer so failures are easy to see.

Measure it

Write twenty questions with the document that answers each. Compute at five. Try one change at a time: chunk size, adding keyword search, adding a . Keep the changes that improve the number.

Done when

You have 20 questions, each with the passage that answers it written down. You measured how often the right passage is in the top 5 results and wrote the number down. Every answer shows its source chunk. A question the documents do not cover gets "I could not find that" instead of an invention. You can name two questions it still gets wrong and why.

Stretch

Add metadata filters, such as only documents from a chosen year. Add a question you know the documents cannot answer and check that the bot says so.

Starter

Python again. This starter chunks one text file, embeds the chunks locally (no key needed) and finds the closest ones for a question. Install with pip install sentence-transformers numpy.

import numpy as np
from sentence_transformers import SentenceTransformer

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

def chunks(text, size=200, overlap=40):
    words = text.split()
    step = size - overlap
    return [" ".join(words[i:i + size]) for i in range(0, max(len(words) - overlap, 1), step)]

docs = chunks(open("notes.txt").read())
vectors = model.encode(docs, normalize_embeddings=True)  # unit length, so a dot product is cosine similarity

def top(question, k=5):
    q = model.encode([question], normalize_embeddings=True)[0]
    best = np.argsort(vectors @ q)[::-1][:k]
    return [(float(vectors[i] @ q), docs[i]) for i in best]

for score, chunk in top("What is the refund window?"):
    print(f"{score:.2f}  {chunk[:100]}")

Print the scores next to the chunks, as step 5 says. Then add the model call that answers from them, using the pattern in the Calling a model lesson. Swap the in-memory list for pgvector or Chroma once it works.

Check yourself

A wrong answer appears. What do you inspect first?

What should the bot do with an unanswerable question?

Your recall at 5 is 0.6. Which one change should you try first?

Go deeper

  • Repo
    RAG TechniquesRepo★ 30k

    Nir Diamant · Notebooks for each improvement to try.

  • Docs

    Supabase · Store and query embeddings with Postgres.

  • Repo
    RagasRepo★ 16k

    Exploding Gradients · Metrics to score retrieval and answers.

Spotted a mistake or something unclear? Report it on GitHub.

On this page