{"id":50883946,"url":"https://github.com/headless-start/grounded-rag","last_synced_at":"2026-06-15T15:01:47.960Z","repository":{"id":362496206,"uuid":"1259323549","full_name":"headless-start/grounded-rag","owner":"headless-start","description":"Domain-specific ask-my-docs RAG: answers only from retrieved evidence, cites the source paragraph, and refuses when unsupported. Hybrid retrieval, re-ranking, and a CI eval gate.","archived":false,"fork":false,"pushed_at":"2026-06-04T12:24:43.000Z","size":134,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-04T14:11:34.245Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/headless-start.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-04T11:52:05.000Z","updated_at":"2026-06-04T12:24:48.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/headless-start/grounded-rag","commit_stats":null,"previous_names":["headless-start/grounded-rag"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/headless-start/grounded-rag","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/headless-start%2Fgrounded-rag","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/headless-start%2Fgrounded-rag/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/headless-start%2Fgrounded-rag/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/headless-start%2Fgrounded-rag/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/headless-start","download_url":"https://codeload.github.com/headless-start/grounded-rag/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/headless-start%2Fgrounded-rag/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34367696,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-15T02:00:07.085Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-15T15:01:46.700Z","updated_at":"2026-06-15T15:01:47.934Z","avatar_url":"https://github.com/headless-start.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# grounded-rag\n\nA domain-specific \"ask-my-docs\" system that answers **only** from retrieved evidence,\ncites the exact source paragraph, and **refuses** when the documents don't support an\nanswer. It ships with an automated evaluation harness that fails CI when answer quality\nregresses.\n\n\u003e Status: **Phase 1 complete** (cited answers end-to-end). Phase 2 (hybrid + rerank +\n\u003e refusal hardening) and Phase 3 (continuous eval + CI gate) to follow.\n\n## Architecture\n\n```mermaid\nflowchart LR\n    subgraph Ingest\n        D[PDF / Markdown] --\u003e C[token-aware chunker]\n        C --\u003e E[bge-small embeddings]\n        E --\u003e V[(Chroma)]\n    end\n    subgraph Query\n        Q[question] --\u003e R[dense retrieve top-k]\n        V --\u003e R\n        R --\u003e A[answer + citation enforcement]\n        A --\u003e|grounded| OUT[answer + citations + contexts]\n        A --\u003e|unsupported| REF[refusal]\n    end\n    A --\u003e LLM[OpenAI-compatible LLM]\n```\n\n\u003e Phase 2 adds BM25 + Reciprocal Rank Fusion and a cross-encoder re-ranker between\n\u003e `retrieve` and `answer`. The LLM is an OpenAI-compatible endpoint, so Project 2's local\n\u003e server plugs in via `GR_OPENAI_BASE_URL` with no code change.\n\n## Quickstart\n\n```bash\nmake setup                      # uv sync (Python 3.11 toolchain)\ncp .env.example .env            # set GR_OPENAI_API_KEY (or point GR_OPENAI_BASE_URL at a local server)\nmake ingest                     # load data/ -\u003e chunk -\u003e embed -\u003e Chroma\nmake ask Q=\"How much PTO do employees accrue per year?\"\nmake run                        # serve POST /ask, GET /health on :8000\n```\n\nAsk over HTTP:\n\n```bash\ncurl -s localhost:8000/ask -H 'content-type: application/json' \\\n  -d '{\"question\":\"How do I trigger an emergency stop on the Atlas arm?\"}' | jq\n```\n\n## How grounding works\n\n1. **Retrieve** the top contexts for the question.\n2. **Refuse early** if fewer than `GR_REFUSAL_MIN_CONTEXTS` contexts come back.\n3. **Generate** with a prompt (`prompts/answer_v1.md`, version pinned in `config.py`) that\n   requires every factual sentence to carry an inline citation like `[acme_handbook.md p1 ¶2]`.\n4. **Enforce**: after generation, every cited label is checked against the chunks actually\n   retrieved. Citations that don't match are dropped; if nothing real remains, the answer\n   is replaced with a structured refusal. No grounding → no answer.\n\n## Configuration\n\nAll knobs live in `src/grounded_rag/config.py`, sourced from env with the `GR_` prefix\n(see `.env.example`): chunk sizes, `top_k`/`top_n`, refusal threshold, model names, store\npaths, and the active prompt version.\n\n## Metrics\n\n_Populated in Phase 3 from a real `make eval` run — faithfulness, answer-relevancy,\ncontext-precision, and retrieval hit-rate@k, plus the dense-vs-hybrid-vs-rerank ablation.\nNo numbers are committed until they come from a real run on this machine._\n\n## Development\n\n```bash\nmake lint    # ruff + mypy\nmake test    # pytest\nmake fmt     # ruff format + autofix\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fheadless-start%2Fgrounded-rag","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fheadless-start%2Fgrounded-rag","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fheadless-start%2Fgrounded-rag/lists"}