An agentic system that ingests PDF documents, extracts structured facts into a Neo4j knowledge graph, and answers questions via an LLM over graph-based retrieval.
The project focuses on end-to-end ingestion, explicit graph structure, and inspectable retrieval, rather than opaque vector-only RAG.
- Copy
.env.exampleto.envand fill values. - Install dependencies:
pip install -r requirements.txt. - Test Neo4j connection:
python scripts/test_neo4j_connection.py. - Ingest PDFs:
python scripts/ingest_folder.py --path "C:\\path\\to\\pdfs". - Run the agent:
python src/chatbot_framework.py.
Corpora are created from folder names. For example, data/Citigroup/ becomes corpus Citigroup.
Single corpus (ingest one folder):
python scripts/ingest_folder.py --path "C:\path\to\data\Citigroup"Multiple corpora (ingest the whole data/ tree):
python scripts/ingest_folder.py --path "C:\path\to\data"Add one new document to an existing corpus without duplicating old docs:
- Temporarily move already‑ingested PDFs out of the corpus folder.
- Run the ingest command on the corpus folder.
- Move the old PDFs back.
Reset Neo4j (destructive, use only if you want a clean rebuild):
MATCH (n) DETACH DELETE n;Below is a real terminal run from python src/chatbot_framework.py showing multiple questions answered against the Citigroup transcript in data/.
As of the latest ingest:
- Banks: 3
- Documents: 7
- Pages: 159
- Facts: 908
- Questions: 158
Environment variables live in .env at the repo root. Start from .env.example.
Required:
NEO4J_URINEO4J_PASSWORDOPENAI_API_KEY
Optional:
NEO4J_USERNAME(defaults toneo4j)NEO4J_DEBUG(set to1to enable Neo4j debug prints)
src/: core source codescripts/: small utilities (like connection tests)docs/: lightweight documentation- See
docs/GETTING_STARTED.mdfor beginner notes on repo conventions and setup.
- See
This project uses two kinds of models:
-
Chat model (agent)
- Default:
gpt-5-nano - Location:
src/chatbot_framework.py(build_agentcall) - Change by editing the
llm_modelargument
- Default:
-
Embedding model (retrieval + ingestion)
- Default:
text-embedding-3-small(cost-saving choice) - Locations:
src/process_graph.py,src/documentation_model.py,src/pdf_processor.py - Change to
text-embedding-3-largeif you want higher quality
- Default:
Show a sample of the corpus -> document -> page chain:
MATCH (c:CORPUS)-[:CONTAINS]->(d:DOCUMENT)-[:CONTAINS]->(p:PAGE)
RETURN c, d, p
LIMIT 25The ingestion pipeline in src/documentation_model.py is partially implemented.
Stubs are still in place for summaries and best representation detection.
See docs/DESIGN.md for a full gap list and ordered todo items.
Cost note: PRA PDFs in data/ are image-heavy and need OCR/vision to process; that adds cost.
For a low-cost start, prefer text-extractable PDFs and run a small pilot first.
- Image-heavy or protected PDFs require OCR/vision; text extraction alone will be sparse.
- Retrieval quality depends on FACT nodes existing; if fact extraction fails, answers will be weak.
- Neo4j validation is manual (see
docs/queries/ingestion_validation.cypheranddocs/ingestion_validation.md). - Index setup is not automated yet; performance is fine for small datasets only.
- PRA rulebooks are not used by the agent right now; the system prompt instructs the bot to skip PRA until OCR/vision is in place.
- Atomic fact: a minimal, standalone statement that can be verified from the page text without extra context.
- Two ingestion runs on
CitiGroup_2025_Q2_earnings_call_transcript.pdfeach used 20,658 tokens. - Working assumption: this personal project targets tens of pages, with headroom to scale later.
