Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

57 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

SecureCorp AI

HybridRAG + Reranking

πŸ” An enterprise knowledge assistant with authorization-aware retrieval, citation validation, and offline evaluation.

SecureCorp AI

πŸ“Š At a Glance

Metric Value
Documents 275 (from 260 Markdown files)
Chunks 450
Body Tokens 124,472 (MiniLM tokenizer)
Vector Store ChromaDB β€’ 450 vectors β€’ 384 dims
Backend Tests 211 passed
Quality Gates βœ… ruff β€’ βœ… mypy β€’ βœ… format (348 files)
Embedding Model sentence-transformers/all-MiniLM-L6-v2
Reranker cross-encoder/ms-marco-MiniLM-L6-v2
BM25 k1=1.5, b=0.75 (library defaults)

πŸ§ͺ Evaluation

The offline evaluation harness measures retrieval and generation quality. Metrics are computed over the golden dev/holdout sets β€” never tuned on holdout data.

Retrieval Metrics (per strategy)

Strategy Recall@5 Recall@10 Hit@5 MRR@10 nDCG@10
Dense-only measured* measured* measured* measured* measured*
BM25-only measured* measured* measured* measured* measured*
Hybrid (BM25+Dense RRF) measured* measured* measured* measured* measured*
Hybrid + Cross-Encoder Rerank measured* measured* measured* measured* measured*

*Actual values computed by uv run run_retrieval_eval.py β€” see evaluation/ for per-category breakdowns.

Generation Metrics (RAGAS)

Metric Description
Faithfulness Answer supported by retrieved evidence
Answer Relevancy LLM answer addresses the query
Context Precision Retrieved chunks relevant to answers
Context Recall Retrieved chunks cover answer scope

Citation Metrics

Metric Value
Citation Validity Rate validated server-side
Unsupported Citation Rate rejected/invalid IDs removed
Citation Coverage % of answers with β‰₯1 valid citation

Security Metrics

Metric Invariant
Unauthorized chunks reaching LLM 0 (enforced)
Cross-user cache leakage blocked by scope-hashed keys
Cross-role cache leakage blocked by RBAC in cache keys

Never tune on the holdout set. Development data (development.jsonl: 283 items) is separate from final reporting data (holdout.jsonl: 71 items).


πŸ—οΈ Architecture

USER β†’ AUTH β†’ AUTHORIZATION β†’ QUERY ROUTER
                                      β”‚
         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
         β–Ό                        β–Ό                       β–Ό
   DOCUMENT RAG          STRUCTURED SQL          REFUSE
   (Hybrid: BM25+Dense,     (PostgreSQL, authz)    (safe refusal)
    RRF, Reranker)          (query results)           response
                                      β”‚
                                      β–Ό
                           GENERATION (Groq LLM)
                                      β”‚
                                      β–Ό
                       CITATION VALIDATION
                                      β”‚
                                      β–Ό
                          FINAL RESPONSE

Key invariants: RRF on chunk_id not document_id; authorization before evidence; cache scope includes auth context; LLM never decides authorization.


πŸš€ Core Capabilities

  1. Heterogeneous ingestion β€” Markdown-aware hierarchical chunking (atoms + packing)
  2. Hybrid retrieval β€” BM25 sparse + dense vector β†’ RRF fusion
  3. Cross-encoder reranking β€” Bounded candidate set (top 20–50), ms-marco-MiniLM-L6-v2
  4. RBAC + ABAC β€” Roles employee|manager|hr|finance|it|admin + attributes (tenant_id, department, owner_user_id)
  5. Secure cache β€” L1 exact + L2 semantic, scope-hashed keys, RBAC-aware, TTL invalidation
  6. Structured SQL β€” PostgreSQL via psycopg[binary], template-based query path (not free-form SQL)
  7. Citation-validated generation β€” Server-side evidence validation; unknown citation IDs rejected
  8. Offline evaluation β€” RAGAS + deterministic retrieval metrics + ablation studies
  9. Vector-store adapter β€” Provider-agnostic (ChromaDB default, Pinecone migratable)
  10. Full CI readiness β€” formatting/lint/typecheck/tests on every PR

πŸ“ Repository Structure

securecorp-ai-hybridrag/
β”œβ”€β”€ AGENTS.md  CLAUDE.md  README.md  LICENSE
β”œβ”€β”€ pyproject.toml  uv.lock  .env.example  .gitignore
β”œβ”€β”€ docs/company_bible.md
β”‚
β”œβ”€β”€ evaluation/
β”‚   β”œβ”€β”€ golden_set/{qa_pairs,qa_pairs_hard}.json
β”‚   β”œβ”€β”€ retrieval_eval/{retrieval_queries,expected_chunks}.json
β”‚   └── security_eval/{rbac_queries,forbidden_queries}.json
β”‚
β”œβ”€β”€ data/
β”‚   β”œβ”€β”€ raw/                           275 documents in 260 Markdown files
β”‚   β”œβ”€β”€ processed/{registry,registry_issues,chunks}.jsonl
β”‚   β”œβ”€β”€ golden/                        Phase 8 golden set (JSONL)
β”‚   β”‚   β”œβ”€β”€ development.jsonl          283 items, 9 categories
β”‚   β”‚   └── holdout.jsonl              71 items, 9 categories
β”‚   β”œβ”€β”€ sweep/                         chunking-sweep artifacts
β”‚   └── chroma_db/                     dense index (gitignored)
β”‚
β”œβ”€β”€ scripts/
β”‚   β”œβ”€β”€ build_registry.py              raw corpus β†’ registry.jsonl
β”‚   β”œβ”€β”€ build_chunks.py                registry   β†’ chunks.jsonl
β”‚   β”œβ”€β”€ build_index.py                 chunks.jsonl β†’ ChromaDB
β”‚   β”œβ”€β”€ build_golden.py                Phase 8: bootstrap+hand-fill
β”‚   β”œβ”€β”€ audit_golden.py                Phase 8: validate golden set schema
β”‚   β”œβ”€β”€ seed_db.py                     PostgreSQL synthetic seeding
β”‚   β”œβ”€β”€ run_retrieval_eval.py          overall 4-arm metrics
β”‚   β”œβ”€β”€ run_ablation.py                Phase 8: 4-arm Γ— per-category
β”‚   β”œβ”€β”€ run_ragas.py                   Phase 8: RAGAS adapter
β”‚   β”œβ”€β”€ run_chunking_sweep.py          Phase 8: 4-cell sweep
β”‚   β”œβ”€β”€ run_cache_experiments.py       Phase 8: hit rate + isolation
β”‚   └── run_phase8_eval.py             Phase 8: orchestrator + HTML report
β”‚
β”œβ”€β”€ src/hybridrag/
β”‚   β”œβ”€β”€ config.py                      Settings (env prefix HYBRIDRAG_)
β”‚   β”œβ”€β”€ domain/models.py               Document, Chunk, RankedChunk, enums
β”‚   β”œβ”€β”€ ingestion/                     frontmatter, loaders, registry,
β”‚   β”‚                                  structure, tokenization, chunking
β”‚   β”œβ”€β”€ indexing/                      embeddings, vector_store, chroma_store,
β”‚   β”‚                                  chunk_metadata, bm25_store, pipeline
β”‚   β”œβ”€β”€ retrieval/                     fusion, reranker, hybrid
β”‚   β”œβ”€β”€ generation/                    provider, formatter, generator
β”‚   β”œβ”€β”€ authorization/                 models, engine
β”‚   β”œβ”€β”€ routing/                       router
β”‚   β”œβ”€β”€ structured/                    db, query_path
β”‚   β”œβ”€β”€ caching/                       redis_cache, history
β”‚   β”œβ”€β”€ evaluation/                    retrieval_eval, citation_metrics,
β”‚   β”‚                                  ragas_adapter, ragas_runner,
β”‚   β”‚                                  redis_cache_eval, html_report
β”‚   β”œβ”€β”€ assistant.py                   end-to-end orchestration
β”‚   └── api/                           FastAPI routes + schemas
β”‚
└── tests/
    β”œβ”€β”€ unit/                          test_config, test_domain_models,
    β”‚                                  test_frontmatter, test_loaders,
    β”‚                                  test_registry, test_structure,
    β”‚                                  test_chunking, test_indexing, test_bm25
    β”œβ”€β”€ integration/test_chroma_store.py   real Chroma, fake vectors
    β”œβ”€β”€ test_structured.py             test_cache.py  test_abstention.py
    β”œβ”€β”€ security/                      (stub)
    └── evaluation/                    test_retrieval_eval_metrics,
                                       test_citation_metrics,
                                       test_ragas_adapter,
                                       test_redis_cache_eval,
                                       test_html_report,
                                       test_phase8_smoke

πŸ› οΈ Development Workflow

# Install
uv sync

# Quality gates (all pass)
uv run pytest              # 211 passed, 1 skipped (PHASE8_RUN smoke)
uv run ruff check .        # clean
uv run ruff format --check .  # clean (348 files formatted)
uv run mypy src            # clean (44 source files, no issues)

# Run the backend
uv run uvicorn src.hybridrag.api.main:app --reload

# Run the frontend
cd web && npm install && npm run dev  # localhost:3000

πŸš€ Deployment

Topology: Next.js frontend on Vercel, FastAPI backend on Railway, with Railway managed Postgres + Redis and Chroma Cloud for the dense index. The backend builds from the root Dockerfile (see railway.toml); the frontend builds from web/Dockerfile / Vercel's native Next.js build.

1. Railway β€” backend + data services

  1. Create a project and add two plugins: Postgres and Redis.

  2. Add your repo as a service (Railway auto-detects the Dockerfile).

  3. Set the service variables (Variables tab β†’ RAW editor). The app reads Railway's native DATABASE_URL / REDIS_URL directly, or the prefixed overrides β€” set whichever you prefer:

    # Data services β€” reference the plugins (names must match your services)
    HYBRIDRAG_DATABASE_URL=${{Postgres.DATABASE_URL}}
    HYBRIDRAG_REDIS_URL=${{Redis.REDIS_URL}}
    
    # Secrets / providers
    HYBRIDRAG_JWT_SECRET=<a long random secret>
    HYBRIDRAG_GROQ_API_KEY=<groq key>
    
    # Chroma Cloud (dense index)
    HYBRIDRAG_CHROMA_CLOUD=true
    HYBRIDRAG_CHROMA_API_KEY=<key>
    HYBRIDRAG_CHROMA_TENANT=<tenant-uuid>
    HYBRIDRAG_CHROMA_DATABASE=securecorp
    HYBRIDRAG_CHROMA_SERVER_URL=api.trychroma.com
    
    # Split-domain auth cookie (frontend and API are on different origins)
    HYBRIDRAG_CORS_ORIGINS=["https://<your-app>.vercel.app"]
    HYBRIDRAG_AUTH_COOKIE_DOMAIN=
    HYBRIDRAG_AUTH_COOKIE_SAMESITE=none
    HYBRIDRAG_AUTH_COOKIE_SECURE=true

    The preDeployCommand (python scripts/seed_db.py) creates the schema and seeds synthetic records on each deploy β€” idempotent (IF NOT EXISTS + ON CONFLICT DO NOTHING). If Postgres isn't wired yet it logs a warning and skips (exit 0) so the deploy still succeeds in document-RAG-only mode.

2. Vercel β€” frontend

  1. Import the repo, set the project root directory to web/.

  2. Set the production env var so the browser calls your Railway API:

    NEXT_PUBLIC_API_BASE=https://<your-backend>.up.railway.app

    NEXT_PUBLIC_* is inlined at build time, so a change requires a redeploy β€” not just a restart.

3. Verify

curl https://<your-backend>.up.railway.app/api/health
# {"status":"ok","retriever_wired":true,"redis_ok":true,"database_ok":true}

Then open the Vercel URL, log in with a demo user, and run a query β€” the cross-site session cookie is sent because the API sets SameSite=None; Secure.


πŸ“œ License

MIT β€” see LICENSE for details.


πŸ“¬ Contact

  • Project: SecureCorp AI β€” HybridRAG + Reranking
  • Repository: securecorp-ai-hybridrag
  • Purpose: Enterprise GenAI/RAG portfolio project


Releases

Packages

Contributors

Languages