RAG-SyntecIN PROGRESS
Question answering over the Syntec collective agreement: 172 documents split into 8,447 chunks, dense retrieval on Chroma, and a distance threshold that refuses off-topic questions before calling the LLM.
- ROLE
- Solo · Personal project, started from a technical-test skeleton
- STACK
- Python · LangChain · Chroma · FastAPI · Ollama · OpenAI API · Docker Compose · pytest
- RESULT
- Threshold calibration only: in-topic questions stayed below a distance of 0.701, off-topic ones above 0.780; the threshold sits at 0.74.
- LINKS
- Code ↗
- READING TIME
- 1 min read
1
Data
The Syntec collective agreement (IDCC 1486) from Légifrance: 172 documents split into 8,447 chunks, versioned in a hashed manifest.
2
What I built
Solo
- Ingestion and chunking: 500-character chunks with 100 characters of overlap.
- A Chroma index with top-3 dense retrieval, embeddings from a local model (Ollama) or OpenAI.
- Generation with a local model or gpt-4o-mini behind the same interface.
- A FastAPI /query endpoint, Docker Compose and 30 pytest tests.
- A labelled set of 55 questions in four classes, plus 20 held out, and the recall@k, precision@k, MRR and false-refusal metrics.
3
Key choices
- Refuse before generating
- If the nearest chunk is farther than a calibrated distance, the API refuses without calling the LLM.
- Versioned corpus
- A hashed manifest ties every chunk to a document version.
- Local or hosted models
- The same pipeline runs on Ollama or on OpenAI.
4
Results
Threshold calibration only: in-topic questions stayed below a distance of 0.701, off-topic ones above 0.780; the threshold sits at 0.74.
5
Limits
- No retrieval evaluation has run yet: the question set and the metrics exist, the runner does not.
- Dense retrieval only: hybrid search and reranking are planned, not built.
- The refusal threshold rests on six questions.
Questions about this project? → Email me