A Retrieval-Augmented Generation (RAG) application that answers questions about medical device regulations using your own PDF documents as the knowledge base. Powered by ChromaDB for vector storage and Claude (Anthropic) as the language model.
PDF documents
│
▼
[ingest.py] — load → split into chunks → embed → store in ChromaDB
│
▼
[question.py] — user query → retrieve top chunk → build prompt → Claude → answer
- Ingestion (
ingest.py) — reads all PDFs from thedata/folder, splits them into overlapping text chunks, and stores them in a local ChromaDB collection. - Querying (
question.py) — takes a user question, finds the most relevant chunk from ChromaDB, passes it to Claude as context, and prints the answer.
Claude is instructed to answer only from the retrieved data — it will not use its own training knowledge or make things up.
rag-nmi/
├── data/ # Place your PDF documents here
├── chroma_db/ # ChromaDB persistent storage (auto-created on first ingest)
├── ingest.py # Ingestion pipeline: PDF → chunks → ChromaDB
├── question.py # Query pipeline: user input → RAG → Claude → answer
├── requirements.txt # Python dependencies
├── .env # API key (not committed)
└── README.md
git clone <repo-url>
cd retrieval-augmented-generation
python -m venv venv
# Windows
venv\Scripts\activate
# macOS / Linux
source venv/bin/activatepip install -r requirements.txtWindows note: If you get a
DLL load failederror foronnxruntime, install the Microsoft Visual C++ Redistributable and then runpip install --force-reinstall onnxruntime.
Create a .env file in the project root:
ANTHROPIC_API_KEY=your-api-key-here
Get your key at console.anthropic.com.
Place PDF files containing medical device regulation content in the data/ folder.
Run this once (or whenever you add new PDFs):
python ingest.pyThis loads all PDFs, splits them into 300-character chunks with 100-character overlap, and stores them in chroma_db/.
python question.pyYou will be prompted to enter a question. The app retrieves the most relevant chunk and asks Claude to answer based only on that context.
What do you want to know about Medical device regulations?
What are MDR and IVDR?
---------------------
Based on the information provided, I can tell you that:
- **MDR** refers to the Medical Devices Regulation
- **IVDR** refers to the In Vitro Diagnostic (Medical Devices) Regulation
However, the data provided only mentions these terms in the context of guidance
documents being prepared by the European Commission and codes that match for
manufacturers of medical devices. It does not provide a detailed definition or
explanation of what these regulations specifically entail.
So beyond knowing what the abbreviations stand for, I don't have enough
information to give you more details about these regulations.
The answer is deliberately limited to what appears in the retrieved chunk. If the source PDFs contain more detail about MDR/IVDR, a broader retrieval (n_results > 1) would surface it.
| Variable | File | Description |
|---|---|---|
DATA_PATH |
ingest.py / question.py |
Folder containing source PDFs |
CHROMA_PATH |
ingest.py / question.py |
ChromaDB storage directory |
chunk_size |
ingest.py |
Characters per chunk (default: 300) |
chunk_overlap |
ingest.py |
Overlap between chunks (default: 100) |
n_results |
question.py |
Number of chunks retrieved per query (default: 1) |
model |
question.py |
Claude model used (default: claude-opus-4-8) |
max_tokens |
question.py |
Maximum tokens in Claude's response (default: 1024) |
| Package | Purpose |
|---|---|
anthropic |
Claude API client |
chromadb |
Local vector database for storing and retrieving chunks |
langchain_community |
PyPDFDirectoryLoader for reading PDFs |
langchain_text_splitters |
RecursiveCharacterTextSplitter for chunking |
pypdf |
PDF parsing backend used by LangChain |
python-dotenv |
Loads ANTHROPIC_API_KEY from .env |
onnxruntime |
Required by ChromaDB's default embedding model |
- Only the top 1 chunk is retrieved by default. For questions that span multiple sections of a document, increase
n_resultsinquestion.pyand update the prompt accordingly. - Chunk size (300 characters) is small. Larger chunks provide more context per retrieval but may dilute relevance. Tune
chunk_sizeandchunk_overlapiningest.pyto suit your documents. - The ChromaDB collection name is
medicinsk_regelverk. If you switch document sets, either drop and recreate the collection or change the name in both files. - Re-running
ingest.pyusesupsert, so existing IDs are overwritten rather than duplicated.