RAGCourse

RAG, vector DBs & enterprise search

Lessons10modules
Total105mfull study
Quick7mtrailer
Projects8docker labs

hello-rag · pgvector + OpenAI starter

Pgvector + text-embedding-3-large @ 1024 + a Markdown FAQ corpus. The first end-to-end RAG.

snap/rag-vector:helloRepo · rag-vector-hello
$git clonehttps://github.com/snap-dev/rag-vector-hello.git
docker-compose.yml
services:
  pgvector:
    image: pgvector/pgvector:pg16
    environment: { POSTGRES_PASSWORD: rag, POSTGRES_DB: rag }
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 2s
      retries: 10
    volumes: ["pg:/var/lib/postgresql/data"]

  api:
    image: python:3.11-slim
    working_dir: /app
    depends_on:
      pgvector: { condition: service_healthy }
    volumes: ["./src:/app/src:ro", "./corpus:/app/corpus:ro", "./requirements.txt:/app/requirements.txt:ro"]
    environment:
      OPENAI_API_KEY: ${OPENAI_API_KEY:?}
      PG_URL: postgresql://postgres:rag@pgvector:5432/rag
      EMBED_MODEL: text-embedding-3-large
      EMBED_DIM: "1024"
      MODEL_VERSION: "v1"
    ports: ["8000:8000"]
    command: >-
      bash -c "pip install -q -r requirements.txt && python -m src.ingest /app/corpus && uvicorn src.api:app --host 0.0.0.0 --port 8000"

volumes: { pg: {} }
Run
~/rag-vector-hello · zsh
$ docker compose up --abort-on-container-exit
[ingest] N chunks @ model=text-embedding-3-large dim=1024 v1 · GET /search?q=... → top-3 chunks + cosines
What you'll observe
Pgvector reaches healthy state before API starts
Ingester loads ./corpus/*.md, splits, embeds, inserts (text, embedding, model_version)
GET /search?q=... returns 3 chunks with cosine scores; top result > 0.7 on the canonical Q
model_version='v1' stamped on every row; re-runs are idempotent
API exits cleanly on SIGTERM; pg volume survives a docker compose down
Lift this to your work

Drop your team's Markdown / Confluence / Notion export into ./corpus, add an auth layer, point any chat UI at GET /search. Promote the pg container to your existing managed Postgres with one `CREATE EXTENSION vector`. Stamp model_version='v2' before re-embedding to a new model — never re-embed in place. Snap's first internal docs-search shipped with this exact compose; the day-1 cost was an afternoon.