A Retrieval-Augmented Generation (RAG) system for question-answering over the 430-page report "Basta Ya: Colombia, Memorias de Guerra y Dignidad" by Colombia's Truth Commission, combining BGE-M3 multilingual embeddings, FAISS vector search, and OpenAI's GPT for grounded answer generation.
The "Basta Ya" report is a foundational document of Colombia's transitional justice process, covering decades of armed conflict across more than 400 pages. Its length and density make it difficult to navigate: anyone trying to understand a specific event, actor, or period typically has to either fragment their reading across many sources or get lost in the volume of the document itself.
This project builds a semantic search and question-answering system over the report, so that a single grounded answer can be retrieved for any specific question about the historical period — using the report itself as the source of truth.
Why it matters: Reducing fragmentation of historical memory by giving consistent, citable answers grounded in an authoritative source.
PDF document
│
▼
[1] Text extraction (pypdf, page-by-page)
│
▼
[2] Chunking (1200 chars, 200 char overlap, with metadata)
│
▼
[3] Embeddings (BGE-M3, multilingual, normalized)
│
▼
[4] Vector index (FAISS IndexFlatL2)
│
▼
[5] Query → top-K retrieval → grounded prompt → GPT answer
| Stage | Component | Choice rationale |
|---|---|---|
| Extraction | pypdf |
Lightweight, handles malformed pages gracefully |
| Chunking | 1200 chars / 200 overlap | Balances context preservation with embedding quality |
| Metadata | page, chunk_id, char range, position | Enables source attribution per answer |
| Embeddings | BGE-M3 (multilingual) | Strong Spanish performance, 1024-dim dense vectors |
| Index | FAISS IndexFlatL2 | Exact (non-approximate) search; corpus size doesn't require ANN |
| Generator | OpenAI GPT API | Uses retrieved chunks as grounded context |
- BGE-M3 over OpenAI embeddings: stronger multilingual performance for Spanish-language source material, and runs locally without per-query API cost during retrieval.
- L2 exact search over HNSW/IVF: with a corpus of this size (~1,000 chunks), exact search is fast enough and avoids approximation errors that would reduce recall on niche queries.
- Overlap of 200 chars: ensures that facts spanning chunk boundaries (names, dates, causal links) aren't split across non-retrieved fragments.
- Page + position metadata: every retrieved chunk can be traced back to its exact location in the original report — critical for a domain where citation matters.
.
├── src/
│ └── rag_search.py # Main pipeline: extraction, chunking, search loop
├── data/
│ └── README.md # Instructions to obtain the source PDF
├── examples/
│ └── sample_queries.md # Example questions and retrieved answers
├── requirements.txt
├── .gitignore
├── LICENSE
└── README.md
- Python 3.10+
- OpenAI API key (for the generation step)
- The "Basta Ya" PDF placed in
data/(seedata/README.mdfor source)
# Clone the repository
git clone https://github.com/YOUR-USERNAME/truth-commission-rag.git
cd truth-commission-rag
# Create a virtual environment
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Set your OpenAI API key
export OPENAI_API_KEY="sk-..." # Windows: set OPENAI_API_KEY=sk-...
# Run the interactive search
python src/rag_search.pyPregunta: ¿Cuál fue el rol de los grupos paramilitares en el desplazamiento forzado?
[Top-K results retrieved with page references and relevance scores]
[Grounded answer generated by GPT using retrieved context]
See examples/sample_queries.md for more illustrative queries.
- Language: Python 3.10+
- PDF parsing: pypdf
- Embeddings: sentence-transformers (BGE-M3)
- Vector search: FAISS
- Generation: OpenAI API (GPT-3.5 / GPT-4)
- Data: NumPy
- Chunk size and overlap are the most underrated knobs: small adjustments meaningfully changed retrieval quality on long-form Spanish prose.
- Multilingual embeddings ≠ English embeddings: BGE-M3 retrieved more relevant chunks than English-first models on Spanish queries, even when the queries were short.
- Source attribution is part of the product, not metadata: in a domain like historical memory, an answer without a page reference is worse than no answer.
- Exact search beats ANN at small scale: defaulting to FAISS HNSW would have introduced approximation errors with no latency benefit at this corpus size.
- No evaluation suite yet: retrieval quality is qualitatively strong but not benchmarked. A held-out QA set with human-graded answers is the next step.
- No reranking: a cross-encoder reranker on the top-K candidates would likely improve precision on ambiguous queries.
- Single-document scope: the architecture generalizes, but the system is currently tied to one PDF.
"Basta Ya: Colombia, Memorias de Guerra y Dignidad" — Centro Nacional de Memoria Histórica / Comisión de la Verdad. Used here as a research source for educational and analytical purposes, with full attribution to the original authors and institutions.
MIT — see LICENSE. The source document itself retains its original copyright; this repository licenses only the code and analysis tooling.
Originally developed as a group coursework project by:
- Jacobo Camargo — GitHub · LinkedIn
- Godwin Zuluaga
- Nicolás Torres (original repository)
- Santiago Cobos
This fork is maintained by Jacobo Camargo for portfolio purposes.