Turns disconnected industrial documents into a single, queryable source of operational truth.
About β’ Features β’ Architecture β’ User Flow β’ Evaluation β’ Stack β’ Setup β’ Demo
LML is an industrial knowledge intelligence platform built for Indian process plants β refineries, chemical plants, manufacturing units β where critical operational knowledge is scattered across 7 to 12 disconnected systems and 25% of the engineers who hold it retire this decade.
A plant engineer today spends 35% of their working hours searching for information that already exists somewhere. The SOP is in one folder, the inspection report that contradicted it is in another, the P&ID showing which valve controls which vessel is in a cabinet in the control room. When something goes wrong at 2am, they get two different answers from two documents β and nothing tells them the answers conflict, let alone which one to trust.
18β22% of unplanned downtime events trace back to this fragmentation. Not equipment failure. Information failure.
LML ingests everything β PDFs, P&ID drawings, inspection reports, Excel logs, email archives β and builds a temporal knowledge graph that understands what changed, what contradicts what, which equipment connects to which, and what's at risk of disappearing when the engineer who knows the startup sequence for Compressor C-03 retires in March.
| Before LML | After LML |
|---|---|
| Engineer searches 4 systems and calls 2 people | Single query returns answer with source citations in < 3 seconds |
| Two documents make conflicting claims, nobody knows | Conflict detected, resolved by authority hierarchy, explained in plain English |
| "Which processes are affected if PT-204 fails?" takes hours | Graph traversal answers it in milliseconds from the P&ID topology |
| Expert retires, knowledge retires with them | Daily gap scan identifies at-risk knowledge, generates targeted interview questions |
| "Confidence: 87%" β opaque and useless | Three-component calibrated score explaining why the system is or isn't confident |
Every extracted fact is versioned. Equipment nodes, operating parameters, procedures, regulatory references β each carries valid_from and superseded_at timestamps in Neo4j. When a new document contradicts an existing node and is more authoritative, the old node gets superseded_at = now() and a SUPERSEDES edge links the new node to the historical one.
The history is never deleted. Engineers need to know what used to be true and exactly when it changed. Every current-state query filters WHERE n.superseded_at IS NULL. Audit queries walk the SUPERSEDES chain to reconstruct the knowledge state at any point in time.
Detection pipeline:
- Pairwise cosine similarity computed between new chunks and existing chunks from different documents
- Pairs above 0.85 similarity go to a local NLI cross-encoder (
cross-encoder/nli-deberta-v3-small) for contradiction scoring - Contradiction probability above 0.70 triggers resolution
Authority hierarchy (1 = highest):
Regulatory β OEM Manual β Internal SOP β Inspection Report β Field Note β Email
Resolution output is always a complete English sentence β never a score:
"The 2022 inspection report (IR-0291) supersedes the internal SOP (SOP-R02-v3) because inspection reports carry higher authority than internal SOPs for operating parameter limits, and it is more recent."
ConflictRecord objects are stored and returned in every QueryResponse, surfaced as a side-by-side comparison in the Conflict Explorer with the resolution clearly explained.
P&IDs are the most information-dense documents in any plant. LML sends them to a vision LLM (GPT-4o by default, or Gemini 1.5 Flash β configurable) with a structured vision prompt. The model returns equipment-instrument-pipe triples:
{
"nodes": [{"id": "P-201", "type": "pump"}, {"id": "PT-204", "type": "pressure_transmitter"}],
"edges": [{"from": "P-201", "to": "PT-204", "relationship": "CONNECTED_TO", "pipe_id": "L-104"}]
}Each triple becomes a directed edge in Neo4j. The graph enables topological queries impossible with text search:
"If PT-204 fails, which downstream processes are affected?"
Returns a BFS traversal up to 5 hops: PT-204 β HE-101 β R-02 β V-101. The path highlights in the React Flow graph visualization in real time.
Every answer carries three components, not one opaque percentage.
| Component | Weight | How it's computed |
|---|---|---|
| Source coverage | 40% | Retrieved chunks above 0.70 threshold Γ· estimated relevant chunks |
| Cross-doc consistency | 35% | 1 β (detected conflicts Γ· total source pairs) |
| Temporal freshness | 25% | Decay on age of most relevant source β full score under 1 year, 0.1/year decay, floor 0.2 |
Composite = (0.40 Γ coverage) + (0.35 Γ consistency) + (0.25 Γ freshness)
- > 0.75 β π’ High confidence β act on this
- 0.50 β 0.75 β π‘ Verify recommended
- < 0.50 β π΄ Do not act without manual verification
Computed post-retrieval, before the LLM generates an answer. Reflects evidence quality β the LLM never generates its own confidence score.
A daily background task (Celery beat, 02:00 UTC) scans the knowledge graph for nodes that are:
- Linked to zero source documents, or
- Fewer than 2 cross-links to other nodes, or
- Queried > 5 times in 30 days with average uncertainty < 0.50
Risk score: base_risk = criticality Γ (0.6 Γ source_scarcity + 0.4 Γ link_isolation) plus a query boost when the node is frequently queried with low confidence.
Above the threshold, GPT-4o-mini generates 4β6 targeted interview questions using the node's equipment context. Not "tell us about Compressor C-03" β but:
"What steps do you follow to restart C-03 after an emergency trip, specifically after the suction pressure alarm clears?"
Expert responses are ingested through the same pipeline as any other document, tagged source_type = "expert_capture". They become first-class knowledge with embeddings and graph links. The gap is marked resolved when the node's uncertainty composite exceeds 0.70.
graph LR
Upload[π Document Upload] --> Queue[Celery Task Queue]
Queue --> Adapter{Format Adapter}
Adapter -->|PDF / Scanned Form| pypdf[pypdf Parser]
Adapter -->|P&ID Image| Gemini[Gemini 1.5 Flash Vision]
Adapter -->|Excel| Unstructured[unstructured.io]
Adapter -->|Email| Unstructured
Adapter -->|Expert Capture| Text[Text Adapter]
pypdf --> Chunker[Semantic Chunker]
Gemini --> Chunker
Unstructured --> Chunker
Text --> Chunker
Chunker --> Embedder[text-embedding-3-small]
Embedder --> NER[spaCy NER + Regex]
NER --> Qdrant[(Qdrant\nVector Store)]
NER --> Neo4j[(Neo4j\nKnowledge Graph)]
style Qdrant fill:#4f46e5,color:#fff
style Neo4j fill:#00a651,color:#fff
style Gemini fill:#4285f4,color:#fff
graph TB
Engineer[π· Plant Engineer] -->|Natural language query| Copilot
subgraph "π§ LangGraph Copilot Agent"
Copilot[Query Input] --> Embed[Embed Query]
Embed --> Retrieve[Retrieve from Qdrant\nthreshold 0.60]
Retrieve --> NLI[NLI Conflict Detection\ncross-encoder/nli-deberta-v3-small]
NLI --> Generate[Generate Answer\nGroq llama-3.3-70b β OpenAI fallback]
Generate --> Score[Uncertainty Scoring\n3-component weighted]
end
Score --> Response[QueryResponse]
Response --> Answer[π Answer]
Response --> Sources[π Source Citations]
Response --> Uncertainty[π Uncertainty Gauge]
Response --> Conflicts[β οΈ Conflict Explorer]
Response --> Graph[πΈοΈ Graph Highlights]
style Engineer fill:#f59e0b,color:#000
style NLI fill:#7c3aed,color:#fff
style Score fill:#059669,color:#fff
Industrial NER combining spaCy (en_core_web_sm) with domain-specific regex covering:
- Equipment tags:
P-201,HE-304,C-03 - Instrument tags:
PT-204,FCV-12,RV-301 - Process parameters with SI units:
12 bar,180Β°C,120 mΒ³/h - Regulation references:
OISD-118,PESO,IS-2825,ISO-55001 - Procedure IDs:
SOP-R02-v4,MR-2847,IR-0291
Target: >85% F1 on equipment tags, parameters, and regulation references across held-out industrial PDFs.
The LLM is constrained to cite specific document names and explicitly state "I could not find relevant information" rather than hallucinate. The 0.70 retrieval threshold is intentional β a borderline chunk pushing uncertainty to amber is preferable to a confident wrong answer.
Measurement: Source faithfulness (citations accurate?), relevance (answer addresses the question?), completeness (all relevant sources surfaced?).
Does a query about Reactor R-02 surface links to its operating SOP, its 2022 inspection report, its upstream compressor, and the OISD regulation governing it? Cross-document linking is the primary differentiator from standard RAG.
Target: Each equipment node linked to β₯2 cross-document sources within 48 hours of initial document batch upload.
Groq inference: ~800β1200ms. Retrieval + NLI conflict detection + uncertainty scoring: ~400ms.
Target P95: under 3 seconds for knowledge bases with 50+ documents.
Given a regulation reference (OISD-118, PESO, Factory Act), the compliance agent retrieves relevant regulatory chunks, cross-references plant documentation, and returns severity-tagged gaps:
- π΄ Critical β safety parameter missing or directly contradicted
- π‘ Major β requirement addressed but incompletely
- π’ Minor β present with documentation gaps
Measurement: Precision and recall on a test plant with 18 known compliance gaps.
Benchmark case: Query "If PT-204 fails, which downstream processes are affected?" and verify the returned traversal matches actual P&ID topology β PT-204 β HE-101 β R-02 β V-101. A standard keyword or vector search returns nothing useful. The graph traversal returns the exact chain in under a second.
| Tool | Role |
|---|---|
| LangGraph | Stateful multi-step copilot agent β embed β retrieve β conflict detect β generate |
| Groq llama-3.3-70b-versatile | Primary copilot LLM (free tier, fastest inference) |
| GPT-4o-mini | Contradiction reasoning, compliance analysis, expert question generation |
| GPT-4o / Gemini 1.5 Flash | P&ID vision parsing β provider configurable via VISION_LLM_PROVIDER env var |
| text-embedding-3-small | 1536-dim embeddings, batched at 100, truncated at 8k chars |
| cross-encoder/nli-deberta-v3-small | Local NLI for conflict detection β graceful heuristic fallback if torch unavailable |
| spaCy en_core_web_sm | Industrial NER β runs locally |
| Tool | Role |
|---|---|
| FastAPI 0.110+ | Async API framework, Pydantic v2 native |
| Python 3.11 | Runtime |
| Celery 5 + Redis | Async ingestion tasks, daily beat scan |
| unstructured.io + pypdf | PDF, Excel, email, scanned form parsing |
| Pydantic v2 | All inputs/outputs runtime-validated |
| Store | Role |
|---|---|
| Qdrant | Vector store β every search filters plant_id + org_id as payload filters |
| Neo4j AuraDB | Knowledge graph β all Cypher queries filter plant_id, current queries add superseded_at IS NULL |
| Supabase (Postgres) | Auth, document metadata, audit logs β service role key, never anon |
| MinIO / S3 | Raw document storage β paths prefixed {org_id}/{plant_id}/ |
| Tool | Role |
|---|---|
| Next.js 15 App Router | SSR + file-based routing |
| TypeScript 5.9 strict | No any, every interface mirrors a Pydantic model |
| Tailwind CSS v4 | Utility-first, mobile-first (field technicians on phones) |
| shadcn/ui | Components owned in codebase β not a runtime npm dependency |
| React Flow | Interactive knowledge graph with traversal highlighting |
| React Query v5 | Adaptive polling β fast while documents process, slow when idle |
- Node.js 20+, Python 3.11+
- API keys: OpenAI (required), Groq (required), Google/Gemini (optional β used for P&ID vision if configured)
- Running: Qdrant, Neo4j, Redis, MinIO (or use Docker Compose)
git clone https://github.com/Leela0o5/LML.git
# Backend
cd backend && pip install -e .
python -m spacy download en_core_web_sm
cp .env.example .env # fill in API keys
uvicorn app.main:app --reload --port 8000
# Frontend
cd frontend && npm install
cp .env.local.example .env.local
npm run dev
# Or spin up everything at once
docker-compose upOPENAI_API_KEY= # embeddings + GPT-4o-mini reasoning + P&ID vision (default)
GROQ_API_KEY= # primary copilot (free tier)
GOOGLE_API_KEY= # optional β Gemini 1.5 Flash P&ID vision if VISION_LLM_PROVIDER=google
QDRANT_URL=http://localhost:6333
NEO4J_URI=bolt://localhost:7687
NEO4J_PASSWORD=
SUPABASE_URL=
SUPABASE_SERVICE_ROLE_KEY=
REDIS_URL=redis://localhost:6379
MINIO_ENDPOINT=localhost:9000
MINIO_ACCESS_KEY=
MINIO_SECRET_KEY=| Issue | Solution |
|---|---|
| "Qdrant search returned no results" | Check plant_id and org_id headers are being sent. Every search requires both. |
| "Contradiction not detected" | Chunk similarity may be below 0.85 threshold. Try more specific, overlapping claims. |
| "Graph traversal returned empty" | The P&ID document may not have been ingested. Check the document list for pid_image doc type. |
| "Daily gap scan not running" | Confirm Celery beat is running separately: celery beat -A app.tasks.celery_app |
βΆ Watch the full demo on YouTube
Leela β github.com/Leela0o5
Report Bug β’ Request Feature
Built for Indian industrial plants losing institutional knowledge faster than they can document it.




