Skip to main content

Reasoning-first document intelligence system

Project description

Querdex

PyPI version Downloads Python versions CI License: MIT

Reasoning-first document intelligence system.

Querdex indexes any document into a hierarchical tree, then uses a two-tier LLM search to answer questions with cited sources. It works without an LLM (keyword heuristics), and optionally plugs in Anthropic or OpenAI for higher-quality results.


Table of Contents


How it works

Document
   │
   ▼
Ingestion ──► parse into pages/sections (Section[])
   │
   ▼
Indexing ───► build hierarchical tree (TreeNode) + entity map + knowledge graph
   │
   ▼
Storage ────► persist to SQLite (sections, tree, entities, graph, query cache)
   │
   ▼
Query
  ├─ Tier 1: LLM (or keyword) batch-prune of tree nodes
  ├─ Tier 2: LLM (or heuristic) per-node relevance scoring
  ├─ Retrieval: pull section text for selected nodes
  └─ Answer: LLM synthesizes answer with source citations
   │
   ▼
Adaptive ───► update node summaries based on query feedback (runs in background)

Three query routes are selected automatically:

  • single_doc — standard hierarchical search on one document
  • multi_doc — virtual super-tree across up to 3 documents
  • graph — entity-seeded graph walk for relationship queries ("how does X relate to Y?")

Installation

Base install (no LLM, uses keyword heuristics):

pip install querdex

With Anthropic (Claude):

pip install querdex[anthropic]

With OpenAI (GPT):

pip install querdex[openai]

Development:

git clone <repo>
cd querdex
uv sync --extra dev
# or with an LLM provider:
uv sync --extra dev --extra anthropic
uv sync --extra dev --extra openai

Requirements: Python 3.11+


Quick Start (CLI)

1. Index a document

querdex index ./report.pdf --doc-id annual-report

Output:

Indexed doc_id=annual-report version=1
Nodes=12 max_depth=3

2. Query it

querdex query --doc-id annual-report --query "What was the Q3 revenue?"

Output:

Query ID: 3f8a1c...
Intent: single_doc | Cache hit: False
Q3 revenue was $1.2B, up 8% year-over-year (Revenue Analysis, pages 4-6).

3. Multi-turn conversation (session)

# First turn
querdex query --doc-id annual-report \
  --query "What were the risk factors?" \
  --session-id session_001

# Second turn — context from first turn is carried over
querdex query --doc-id annual-report \
  --query "Which of those risks materialised?" \
  --session-id session_001

4. Re-index an updated document

When the document changes, Querdex only rebuilds the affected parts:

querdex index ./report_v2.pdf --doc-id annual-report

5. Delete a document

querdex delete --doc-id annual-report

Custom database path

By default the database is stored at ./index_store/querdex.db. To change it:

querdex --db /path/to/my.db index ./report.pdf --doc-id demo
querdex --db /path/to/my.db query --doc-id demo --query "summary?"

LLM Setup

Without any LLM configured, Querdex falls back to keyword/heuristic matching — it always produces an answer, just less precise.

Anthropic (Claude)

export QUERDEX_LLM_PROVIDER=anthropic
export QUERDEX_LLM_API_KEY=sk-ant-...

# Optional: override model defaults
export QUERDEX_LLM_TIER1_MODEL=claude-haiku-4-5-20251001   # fast, cheap (batch prune)
export QUERDEX_LLM_TIER2_MODEL=claude-sonnet-4-6            # powerful (deep reasoning + answers)

OpenAI (GPT)

export QUERDEX_LLM_PROVIDER=openai
export QUERDEX_LLM_API_KEY=sk-...

# Optional: override model defaults
export QUERDEX_LLM_TIER1_MODEL=gpt-4o-mini   # fast, cheap
export QUERDEX_LLM_TIER2_MODEL=gpt-4o         # powerful

How the two tiers are used:

Tier Model Purpose
Tier 1 cheap/fast Single batched call to prune all tree nodes to the relevant few
Tier 2 powerful Per-node deep reasoning to confirm relevance + score confidence
Answer powerful Synthesise a cited answer from the retrieved section text

Structured Extraction

Pull structured facts out of any indexed document — with source grounding: every extraction carries the exact section, page, and character span it came from, so nothing is silently hallucinated.

The schema is defined by example, not by code. Describe what you want and (optionally) show one or two examples:

querdex extract --doc-id demo \
  --prompt "Extract revenue figures and executive names" \
  --examples examples.json \
  --html review.html

examples.json:

[
  {
    "text": "Alice Chen reported revenue of $5M in Q1.",
    "extractions": [
      {"extraction_class": "metric", "extraction_text": "revenue of $5M", "attributes": {"period": "Q1"}},
      {"extraction_class": "person", "extraction_text": "Alice Chen"}
    ]
  }
]

The classes and attribute keys in your examples define the output schema. Every result is aligned back to the source text (exact → fuzzy matching); model output that cannot be located is kept but flagged unaligned so you can review it instead of trusting it.

--html writes a self-contained review page: the full document with color-coded highlights per extraction class, toggleable legend, attribute tooltips, and a click-to-jump list of all extractions.

Long documents are chunked and processed in parallel; use --passes 2 to trade extra LLM calls for higher recall. Without an LLM configured, extraction degrades to literal matching of your example texts.

Python API:

from querdex.extraction import ExtractionTask, ExtractionExample, ExampleExtraction

task = ExtractionTask(
    description="Extract revenue figures and executive names",
    examples=[...],
)
run = engine.extract_document("demo", task, passes=1)
for e in run.extractions:
    print(e.extraction_class, repr(e.extraction_text), e.section_id, e.char_start, e.alignment)

CLI Reference

querdex [--db PATH] <command> [options]
Command Description
index <file> Index a document. Auto-detects format from extension.
query Query an indexed document.
extract Run schema-by-example structured extraction over an indexed document.
delete Remove a document and all its data from the store.

index

querdex index <file_path> [--doc-id ID]
Argument Default Description
file_path required Path to the document to index
--doc-id auto-generated from filename+hash Stable identifier for this document

query

querdex query --doc-id ID --query TEXT [--session-id ID]
Argument Default Description
--doc-id required Document to query
--query required Natural language question
--session-id none Enables multi-turn context (pass same ID across turns)

extract

querdex extract --doc-id ID --prompt TEXT [--examples FILE] [--passes N] [--html FILE]
Argument Default Description
--doc-id required Document to extract from
--prompt required Natural language description of what to extract
--examples none JSON file with few-shot examples (defines the output schema)
--passes 1 Extraction passes; more passes improve recall
--html none Write an interactive HTML review page to this path

delete

querdex delete --doc-id ID

Python API

For integration into your own application:

import asyncio
from querdex.services import build_engine

# build_engine reads QUERDEX_LLM_* env vars automatically
engine = build_engine("./index_store/querdex.db")

# Index a document
doc = asyncio.run(engine.index_document("./report.pdf", doc_id="annual-report"))
print(f"Indexed: {doc.doc_id} | nodes={doc.stats.total_nodes}")

# Query
result = engine.query_document("annual-report", "What was Q3 revenue?")
print(result.answer)
print(f"Confidence: {result.confidence:.0%}")
for source in result.source_nodes:
    print(f"  Source: {source.title}, pages {source.pages}")

# Multi-turn query
result2 = engine.query_document(
    "annual-report",
    "What caused that increase?",
    session_id="my-session-001",
)

# Re-index after the document changes
doc_v2 = asyncio.run(engine.reindex_document("./report_v2.pdf", doc_id="annual-report"))

# Delete
engine.store.delete_document("annual-report")

# Always close when done
engine.store.close()

Passing an LLM client directly

from querdex.llm.anthropic_client import AnthropicLLMClient
from querdex.services.engine import QuerdexEngine
from querdex.storage import SQLiteStore

llm = AnthropicLLMClient(
    api_key="sk-ant-...",
    tier1_model="claude-haiku-4-5-20251001",
    tier2_model="claude-sonnet-4-6",
)
store = SQLiteStore("./querdex.db")
engine = QuerdexEngine(store, llm_client=llm)

Using the FakeLLMClient in tests

from querdex.llm.fake_client import FakeLLMClient
from querdex.query.answering import AnswerGenerator

fake = FakeLLMClient(
    default='{"answer": "Revenue was $1.2B.", "confidence": 0.9}'
)
gen = AnswerGenerator(llm_client=fake)
answer, confidence, sources = gen.generate("What was revenue?", chunks)

Supported File Types

Extension Parser Notes
.txt TextParser Plain text, split by paragraphs
.md, .markdown MarkdownParser Heading-aware section splitting
.html, .htm HTMLParser Strips tags, extracts text blocks
.docx DOCXParser Microsoft Word, paragraph-level
.pdf PDFParser Page-level; OCR optional (see below)
.py PythonCodeParser Function/class level chunking
.js, .ts, .jsx, .tsx JSCodeParser Function-level chunking
.csv CSVParser Row-batched sections
.db, .sqlite SQLiteParser Table-level sections
.mp3, .wav, .m4a, .mp4, .mov AudioVideoParser Transcript-based (requires Whisper or similar)
.url URLParser Fetches and parses the web page at that URL
URL string URLParser Pass a URL string directly as the file path

PDF OCR

For scanned PDFs, enable OCR via environment variables:

# Tesseract (local)
export QUERDEX_OCR_ENABLED=true
export QUERDEX_OCR_PROVIDER=tesseract         # default when OCR enabled
export QUERDEX_TESSERACT_CMD=tesseract        # path to tesseract binary

# Cloud OCR (custom endpoint)
export QUERDEX_OCR_ENABLED=true
export QUERDEX_OCR_PROVIDER=cloud
export QUERDEX_OCR_ENDPOINT=https://your-ocr-api.com/v1/ocr
export QUERDEX_OCR_API_KEY=your-key

Environment Variables

Variable Default Description
QUERDEX_LLM_PROVIDER (none) anthropic or openai. If unset, heuristic mode is used.
QUERDEX_LLM_API_KEY (none) API key for the selected provider
QUERDEX_LLM_TIER1_MODEL claude-haiku-4-5-20251001 / gpt-4o-mini Fast model for batch node pruning
QUERDEX_LLM_TIER2_MODEL claude-sonnet-4-6 / gpt-4o Powerful model for deep reasoning and answers
QUERDEX_OCR_ENABLED false Enable OCR for scanned PDFs
QUERDEX_OCR_PROVIDER tesseract tesseract or cloud
QUERDEX_TESSERACT_CMD tesseract Path to Tesseract binary
QUERDEX_OCR_ENDPOINT (none) Endpoint URL for cloud OCR provider
QUERDEX_OCR_API_KEY (none) API key for cloud OCR provider

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

querdex-0.2.0.tar.gz (114.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

querdex-0.2.0-py3-none-any.whl (78.1 kB view details)

Uploaded Python 3

File details

Details for the file querdex-0.2.0.tar.gz.

File metadata

  • Download URL: querdex-0.2.0.tar.gz
  • Upload date:
  • Size: 114.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for querdex-0.2.0.tar.gz
Algorithm Hash digest
SHA256 fd9c10846cccea157355c34e5427fd1e47f3caa991ccc5c8f5bbb94a31d67bc6
MD5 13c9fa567e3f053c457eb47f29a85076
BLAKE2b-256 9c66758cfdd42f10f6935e6a98cab3eb14eece81685cc77fa264c8b896868455

See more details on using hashes here.

Provenance

The following attestation bundles were made for querdex-0.2.0.tar.gz:

Publisher: publish.yml on its-animay/querdex

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file querdex-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: querdex-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 78.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for querdex-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 389380684daf1a8000a16228bd0e8d38e7981b57292b93f10212771f54d5b856
MD5 99792c670262ea4ed080f31568eca12c
BLAKE2b-256 6a631b55dd8e1d038742b3e4e8cb3c16eca3eecc1c3ea5820c3f81c05192a34b

See more details on using hashes here.

Provenance

The following attestation bundles were made for querdex-0.2.0-py3-none-any.whl:

Publisher: publish.yml on its-animay/querdex

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page