benroshan Claude Sonnet 4.6 commited on
Commit
04aa9e2
Β·
1 Parent(s): 6b88803

docs: update architecture and decisions for 2026-05-30 changes

Browse files

- architecture.md: TinyBERT-L-2-v2 reranker, RAGAS pre-computed JSON benchmark
- decisions.md: TinyBERT switch, RAGAS removal, 8B judge model, ground truth answers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files changed (2) hide show
  1. docs/architecture.md +5 -4
  2. docs/decisions.md +4 -2
docs/architecture.md CHANGED
@@ -13,14 +13,14 @@ Query β†’ hybrid retrieval (ChromaDB dense + BM25 sparse) β†’ weighted RRF fusio
13
  | Vector store | ChromaDB (persistent) | Dense embedding storage and retrieval |
14
  | Sparse retrieval | rank_bm25 (BM25Okapi) | Keyword-match retrieval for regulatory text |
15
  | Hybrid fusion | Weighted RRF (dense 0.7 + sparse 0.3) | Merge dense + sparse result lists |
16
- | Reranker | cross-encoder/ms-marco-MiniLM-L-6-v2 | Re-score top-20 β†’ return top-5 |
17
  | Embeddings | Euron API (text-embedding-3-small) | API-based; avoids OOM on Render free tier. Groq has no embeddings endpoint. |
18
  | LLM | Groq (llama-3.3-70b-versatile) via langchain-groq | Fast open-weight inference; OpenAI-compatible |
19
  | Chunking | LangChain ParentDocumentRetriever | Child 200-char indexed, parent 800-char sent to LLM |
20
  | Memory | ConversationBufferWindowMemory (k=10) | Last 10 conversation turns |
21
  | Chain | ConversationalRetrievalChain | LangChain orchestration |
22
- | Eval (primary) | RAGAS | faithfulness, answer_relevancy, context_precision, context_recall |
23
- | Eval (secondary) | Custom LLM-as-Judge | 1–5 faithfulness score per turn (retained from v1) |
24
  | Eval (retrieval) | Precision@K | Ground-truth chunk matching |
25
  | Observability | LangSmith | Traces all LLM + retrieval calls via LANGCHAIN_TRACING_V2=true |
26
  | Document parsing | LlamaParse (primary), pypdf (fallback) | PDF extraction |
@@ -52,7 +52,8 @@ Query β†’ hybrid retrieval (ChromaDB dense + BM25 sparse) β†’ weighted RRF fusio
52
  - **ParentDocumentRetriever**: small chunks improve retrieval precision; large parent chunks improve answer faithfulness
53
  - **Cross-encoder reranker**: bi-encoder (ChromaDB) is fast but approximate; cross-encoder is slower but more accurate on top-20 pool
54
  - **BM25 weight 0.3**: regulatory text has exact keyword matches (section numbers); sparse retrieval catches what dense misses
55
- - **RAGAS as primary eval**: 4 named metrics that interviewers recognise; custom scorer retained as supplementary
 
56
 
57
  ## Known limitations
58
  - InMemoryStore for parent chunks: does not survive server restart (re-ingest required)
 
13
  | Vector store | ChromaDB (persistent) | Dense embedding storage and retrieval |
14
  | Sparse retrieval | rank_bm25 (BM25Okapi) | Keyword-match retrieval for regulatory text |
15
  | Hybrid fusion | Weighted RRF (dense 0.7 + sparse 0.3) | Merge dense + sparse result lists |
16
+ | Reranker | cross-encoder/ms-marco-TinyBERT-L-2-v2 | Re-score top-10 β†’ return top-5 (~17MB vs 85MB; OOM prevention on 512MB Render) |
17
  | Embeddings | Euron API (text-embedding-3-small) | API-based; avoids OOM on Render free tier. Groq has no embeddings endpoint. |
18
  | LLM | Groq (llama-3.3-70b-versatile) via langchain-groq | Fast open-weight inference; OpenAI-compatible |
19
  | Chunking | LangChain ParentDocumentRetriever | Child 200-char indexed, parent 800-char sent to LLM |
20
  | Memory | ConversationBufferWindowMemory (k=10) | Last 10 conversation turns |
21
  | Chain | ConversationalRetrievalChain | LangChain orchestration |
22
+ | Eval (primary) | RAGAS benchmark (pre-computed, JSON) | faithfulness 1.0, answer_relevancy 0.90 β€” run locally via `scripts/run_ragas_local.py`, committed to `frontend/src/data/ragas_benchmark.json` |
23
+ | Eval (secondary) | Custom LLM-as-Judge | 1–5 faithfulness score per turn (per-message badge in UI) |
24
  | Eval (retrieval) | Precision@K | Ground-truth chunk matching |
25
  | Observability | LangSmith | Traces all LLM + retrieval calls via LANGCHAIN_TRACING_V2=true |
26
  | Document parsing | LlamaParse (primary), pypdf (fallback) | PDF extraction |
 
52
  - **ParentDocumentRetriever**: small chunks improve retrieval precision; large parent chunks improve answer faithfulness
53
  - **Cross-encoder reranker**: bi-encoder (ChromaDB) is fast but approximate; cross-encoder is slower but more accurate on top-20 pool
54
  - **BM25 weight 0.3**: regulatory text has exact keyword matches (section numbers); sparse retrieval catches what dense misses
55
+ - **RAGAS benchmark pre-computed locally**: `nest_asyncio` cannot patch `uvloop` (used by uvicorn on Render Linux), making live RAGAS eval impossible on prod. Run `scripts/run_ragas_local.py` locally, commit JSON results, Vercel builds dashboard from file.
56
+ - **TinyBERT-L-2-v2 reranker**: MiniLM-L-6-v2 (~85MB) + base memory (~250MB) + Tavily content + LLM call exceeded Render 512MB on web queries. TinyBERT-L-2-v2 is ~17MB β€” same ranking quality at demo corpus scale.
57
 
58
  ## Known limitations
59
  - InMemoryStore for parent chunks: does not survive server restart (re-ingest required)
docs/decisions.md CHANGED
@@ -6,11 +6,13 @@
6
  |------|----------|-----------|--------|
7
  | 2026-05 | Euron API for embeddings (not local sentence-transformers) | Local model ~400MB β†’ OOM on Render 512MB free tier | Active |
8
  | 2026-05-24 | Groq (llama-3.3-70b-versatile) for LLM; Euron retained for embeddings | Groq: faster inference, open-weight model. Euron kept for embeddings β€” Groq has no embeddings endpoint. | Active |
9
- | 2026-05 | Render (Docker) over Railway for backend | Free tier RAM fit confirmed: embeddings ~150MB + reranker ~85MB = ~250MB total | Active |
10
  | 2026-05 | ParentDocumentRetriever (child 200 / parent 800) | Better faithfulness: small chunks retrieved precisely, large chunks give LLM full context | Active |
11
  | 2026-05 | BM25 weight 0.3 in RRF fusion | Regulatory text has exact keyword matches; sparse recall is complementary, not dominant | Active |
12
- | 2026-05 | RAGAS as primary eval (custom scorer as secondary) | RAGAS provides 4 named metrics (faithfulness, answer_relevancy, context_precision, context_recall) that interviewers recognise; v1 custom scorer retained for per-turn display | Active |
 
13
  | 2026-05 | LangSmith tracing via env var (no code changes) | LangChain reads LANGCHAIN_TRACING_V2 automatically; zero instrumentation cost | Active |
 
14
  | 2026-05 | Cross-encoder reranker pre-downloaded at Docker build time | Avoids cold-start latency on first request in production | Active |
15
  | 2026-05 | Idempotent ingestion via md5(source+page+text) chunk IDs | Re-running ingest does not duplicate chunks in ChromaDB | Active |
16
 
 
6
  |------|----------|-----------|--------|
7
  | 2026-05 | Euron API for embeddings (not local sentence-transformers) | Local model ~400MB β†’ OOM on Render 512MB free tier | Active |
8
  | 2026-05-24 | Groq (llama-3.3-70b-versatile) for LLM; Euron retained for embeddings | Groq: faster inference, open-weight model. Euron kept for embeddings β€” Groq has no embeddings endpoint. | Active |
9
+ | 2026-05 | Render (Docker) over Railway for backend | Free tier RAM fit confirmed: embeddings ~150MB + reranker ~17MB = ~230MB total | Active |
10
  | 2026-05 | ParentDocumentRetriever (child 200 / parent 800) | Better faithfulness: small chunks retrieved precisely, large chunks give LLM full context | Active |
11
  | 2026-05 | BM25 weight 0.3 in RRF fusion | Regulatory text has exact keyword matches; sparse recall is complementary, not dominant | Active |
12
+ | 2026-05-30 | RAGAS pre-computed locally, dashboard JSON-driven | `nest_asyncio` cannot patch `uvloop` on Render β€” live eval endpoint always 500s. Run `scripts/run_ragas_local.py` (8B judge model) β†’ commit `ragas_benchmark.json` β†’ Vercel builds dashboard. | Active |
13
+ | 2026-05-30 | RAGAS judge uses `llama-3.1-8b-instant` not `llama-3.3-70b` | 70B model exhausts Groq free-tier 100k TPD in one eval run. 8B has 500k TPD and is sufficient for statement-level faithfulness checks. Answer generation still uses 70B. | Active |
14
  | 2026-05 | LangSmith tracing via env var (no code changes) | LangChain reads LANGCHAIN_TRACING_V2 automatically; zero instrumentation cost | Active |
15
+ | 2026-05-30 | Reranker switched to TinyBERT-L-2-v2 (~17MB) from MiniLM-L-6-v2 (~85MB) | MiniLM + base memory + Tavily content + LLM call exceeded 512MB on web queries; TinyBERT saves 68MB permanently with acceptable ranking quality at demo scale | Active |
16
  | 2026-05 | Cross-encoder reranker pre-downloaded at Docker build time | Avoids cold-start latency on first request in production | Active |
17
  | 2026-05 | Idempotent ingestion via md5(source+page+text) chunk IDs | Re-running ingest does not duplicate chunks in ChromaDB | Active |
18