When you ask a standard AI chatbot questions like "What caused the decline of the Indus Valley Civilization?" or "How was the Library of Alexandria destroyed?", you almost always get speculative, flat, and frequently hallucinated prose.

Standard LLMs suffer from a critical epistemological flaw in history: they invent citations, confuse dates across centuries, and homogenize complex, multi-century academic debates into simplistic, monocausal stories (e.g., asserting that the Indus Valley was destroyed solely by an invasion, ignoring 60 years of hydro-climatic paleochannel research).

Ancient history is not a flat list of dates. It is a multi-dimensional tension between physical archaeological strata (pollen cores, burn horizons, isotopic speleothem data) and contemporary epigraphic records vs. later dynastic myths.

I was inspired to build Histograph to eliminate this problem entirely. I wanted to create an Agentic Graph-RAG research engine that replaces speculative LLM guessing with a deterministic, forensic investigation: pulling live evidence from 10+ open archives, auditing every claim with 100% verified verbatim quotes, and assembling an in-memory knowledge graph to distinguish rock-solid consensus from competing hypotheses.

What It Does & How I Built It

As a solo developer, I engineered Histograph from the ground up as a zero-database, full-stack application:

Multi-Agent Research Pipeline (Python & FastAPI): Planner Agent: Deconstructs broad questions into targeted sub-queries targeting physical stratigraphy, primary chronicles, and modern scholarly consensus. Multi-Source Ingestion Engine: Fans out concurrently across 10+ open repositories without paid search APIs—including Internet Archive OCR text scans, Library of Congress manuscripts, OpenAlex, CrossRef, Semantic Scholar, CORE open-access papers, Wikipedia, and YouTube transcripts. Extractor Agent: Powered by NVIDIA Nemotron 70B, it extracts empirical claims, historical entities (Persons, Places, Events, Theories), and mandatory verbatim quotes ( ≥ 20 ≥20 characters) found directly in the cited texts. In-Memory NetworkX Knowledge Graph: Requires no heavy external databases (no Neo4j or Postgres). Everything runs in memory per session with sub-millisecond graph operations, linking claims, sources, and entities via semantic edges (CITES, SUPPORTS, CONTRADICTS, PRECEDES). The Laya Policy Engine (5-Tier Verification): Audits every claim against 5 strict rules: Citation existence, verbatim quote verification (exact & fuzzy matching ≥ 0.85 ≥0.85), date consistency, source independence (3-shingle overlap < 0.60 <0.60), and source tier hierarchy (Primary → → Peer-Reviewed → → Encyclopedia → → Web → → Social Lead). Dual Historiographical Reconstructions: Output 1 (Evidence-Based): Strict chronological progression of verified ACCEPT claims with verbatim quotes, citations, and counterevidence notes. Output 2 (Full-Picture 4-Level Architecture): Level 1 (Consensus), Level 2 (Competing Theories & Debates), Level 3 (Minority Perspectives), and Level 4 (Master Synthesis: Bedrock Points, Pivot Points, and Interlocking Factors). Modern Frontend & Academic PDF Export: Built with React 19, Tailwind CSS v4, and Vite, featuring live NDJSON streaming terminal logs, interactive Cytoscape.js graph exploration, chronological vertical timelines with conflict alerts, and a ReportLab academic PDF generator. Challenges I Faced The Syndicated Scraper Trap (Sybil Attack): On the open web, dozens of scraper blogs mirror the same unverified article. A naive RAG system would treat 10 scraper URLs as "10 independent corroborating sources". I solved this by implementing a 3-shingle Jaccard overlap algorithm ( < 0.60 <0.60) that identifies textual clones and collapses them into a single evidentiary instance. Prompt Injection in Raw Historical Archives: Ingesting digitized OCR full-texts from public archives meant untrusted text could contain adversarial directives. I engineered an XML sandboxing defense where all external text is isolated inside tags, instructing the model to treat enclosed text strictly as passive data. BCE/CE Chronological Mathematics: Standard LLMs struggle with negative date arithmetic (e.g., recognizing that 2500 BCE is older than 1900 BCE, or parsing circa expressions like c. 1900-1300 BCE). I built a dedicated deterministic integer timeline parser (app/agents/timeline.py) that normalizes dates and automatically flags date conflicts whenever competing sources diverge by

150 150 years. Solo Development & Onboarding Roadblocks: Building the backend, frontend, graph visualizer, and 28 passing unit tests completely alone was an intense sprint. When I hit international card verification roadblocks on the cloud portal, I adapted by engineering a clean, pluggable OpenAI-compatible API interface that allowed me to develop and validate the pipeline seamlessly. What I Learned Agentic Graph-RAG Outperforms Flat Vector RAG for Complex Domains: Flat vector search returns isolated text snippets that miss the big picture. Mapping evidence into a directed knowledge graph with CONTRADICTS and CITES edges allowed me to track competing schools of thought and detect historiographical debates that standard RAG misses completely. The Power of Negative Constraints with Nemotron: Working with NVIDIA Nemotron 70B showed me that state-of-the-art models excel at following strict negative instructions ("Never invent quotes; reject if verbatim text is missing") when paired with structured JSON schema enforcement. Epistemic Honesty in AI: Users don't want an AI that pretends to have 100% certainty on disputed history. Separating verified bedrock facts from competing theories and working hypotheses creates a far more trustworthy, academic-grade research experience.

Built With

Share this project:

Updates

Submission history