Spaces:
Sleeping
Experiment Lab β LangChain RAG Implementation
This branch rewrites the core RAG pipeline using LangChain and its
supporting frameworks, replacing the custom implementations in master.
What Changed
| Component | master branch | experiment-lab branch |
|---|---|---|
| DOCX loading | python-docx + manual XML block extraction |
langchain_community Docx2txtLoader |
| PDF loading | pymupdf + font-size heading heuristics |
langchain_community PyMuPDFLoader |
| Text splitting | Custom recursive token splitter | langchain_text_splitters RecursiveCharacterTextSplitter (tiktoken) |
| Embeddings | Custom EmbeddingClient ABC + manual OpenAI/SentenceTransformer wrappers |
langchain_openai.OpenAIEmbeddings / langchain_huggingface.HuggingFaceEmbeddings |
| Vector store | Manual chromadb + FAISS with custom metadata filtering |
langchain_community.vectorstores.FAISS only β local, no Chroma |
| Retrieval | Manual query embedding β vs.search(vector, tenant_id) |
vs.search(text, tenant_id) β store embeds internally |
| LLM generation | Manual openai.OpenAI().chat.completions.create() |
LCEL chain: RICS_PROMPT | ChatOpenAI | StrOutputParser() |
| Retry logic | None | Built-in via ChatOpenAI(max_retries=3) |
What Stayed the Same
These components contain business logic specific to this system and were not replaced with LangChain equivalents:
app/api/β FastAPI endpoints, tenant middleware, upload/generate/statusapp/db/β SQLAlchemy ORM models and session managementapp/cache/section_cache.pyβ SHA-256 keyed JSON section cacheapp/generator/postprocess.pyβ[VERIFY]non-invention enforcementapp/generator/reranker.pyβ Custom Jaccard + numeric overlap rerankerapp/templates/rics_templates.pyβ RICS section skeleton templatesapp/models/schemas.pyβ Pydantic API schemasapp/config.pyβ Settings management
New Dependencies
langchain>=0.3.0
langchain-core>=0.3.0
langchain-openai>=0.2.0
langchain-community>=0.3.0
faiss-cpu>=1.8.0
langchain-huggingface>=0.1.0
langchain-text-splitters>=0.3.0
docx2txt>=0.8
Key Design Decisions
Why keep a custom reranker?
LangChain's built-in rerankers (FlashrankRerank, CrossEncoderReranker)
require additional model downloads or paid APIs. The custom Jaccard+numeric
reranker is lightweight, free, and tailored to RICS numeric fact verification.
Why keep [VERIFY] post-processing?
This is a domain-specific safety feature with no LangChain equivalent. It enforces the non-invention guarantee that is core to RICS report integrity.
LCEL Chain Structure
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
chain = RICS_PROMPT | ChatOpenAI(model="gpt-4o-mini", temperature=0.2) | StrOutputParser()
text = chain.invoke({"skeleton": ..., "bullets": ..., "examples": ...})
Vectorstore Pipeline
# Ingestion β store handles embedding internally
vectorstore.add_documents(langchain_docs)
# Retrieval β store embeds query internally
results = vectorstore.search(query_text, tenant_id=tenant_id, k=10)
Merged product features (AI transparency + tenant RAG)
The following were merged from the main-line feature work and are in addition to the LangChain stack above:
retrieve_for_report()β tenant-scoped retrieval with the reportβs source document prioritised.- Provenance enrichment β filenames, snippet previews, and section hints for citations in the API and UI.
compute_ai_transparency()β heuristic AI-involvement estimates stored in section metadata.- Frontend β aggregate AI involvement bar, per-section transparency, citation chips, and fixed proofread/enhance re-run handling.
- Generate mode uses LCEL (
RICS_PROMPT | ChatOpenAI | StrOutputParser) with the same richbuild_user_prompt/ style-profile content as before (singleuser_contentvariable in the chat template).
Proofread and enhance modes still use the OpenAI Chat Completions client for stable, predictable behaviour.
Running This Branch
git checkout experiment-lab
pip install -e ".[dev]"
cp .env.example .env # add OPENAI_API_KEY if available
uvicorn app.main:app --reload
Open http://localhost:8000 β the same UI as master.
Trade-offs vs Master Branch
| Aspect | Master (custom) | Experiment-lab (LangChain) |
|---|---|---|
| Code volume | ~800 lines of RAG pipeline code | ~400 lines (LangChain handles the rest) |
| Structural fidelity | Heading/list/table block types preserved | Plain text only (heading levels lost) |
| Debuggability | Full control, easy to step through | LangChain abstractions can obscure flow |
| Observability | Manual logging | LangSmith tracing available |
| Upgradability | Manual updates to each component | Single pip upgrade langchain |
| Vendor lock-in | None | LangChain API surface |