Skip to content

Commit c859c62

Browse files
authored
Merge pull request #101 from vectorlessflow/dev
Dev
2 parents 2a9f258 + 3a760af commit c859c62

46 files changed

Lines changed: 3964 additions & 1720 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/docs/rfc/roadmap.md

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
---
2+
sidebar_position: 2
3+
---
4+
5+
# Roadmap: The Ultimate Document Retrieval Tool
6+
7+
> Focus: structured document retrieval — precise, reliable, indispensable.
8+
> The "jq of document retrieval".
9+
10+
## Scope
11+
12+
Focus on the document retrieval vertical — no code retrieval, no general knowledge platform. Build a complete Python developer experience layer on top of the Rust core engine, with broader format support and finer-grained parsing.
13+
14+
## Phase Overview
15+
16+
| Phase | Focus | Language |
17+
|-------|-------|----------|
18+
| A1 | Router Layer — support 1000+ document workspaces | Rust |
19+
| A2 | Document Formats — HTML, DOCX, LaTeX | Rust |
20+
| A3 | Parsing Precision — tables, figures, footnotes | Rust |
21+
| A4 | Python Ecosystem — CLI, Pythonic API, framework integration | Python |
22+
| A5 | Domain Optimization — legal, financial, technical documents | Rust |
23+
| A6 | Performance & Reliability — lazy loading, caching, concurrency | Rust |
24+
25+
Dependencies:
26+
27+
```
28+
A1 (Router) ────→ A6 (Lazy Loading) ────→ A2 (Formats)
29+
30+
A3 (Precision)
31+
32+
A4 (Python, can run in parallel)
33+
34+
A5 (Domain)
35+
```
36+
37+
---
38+
39+
## A1: Router Layer
40+
41+
**Goal:** Support retrieval across 1000+ document workspaces.
42+
43+
Full design: [RFC: Document Router](./router.md)
44+
45+
Key ideas:
46+
47+
- Insert a Router between `Engine.query()` and the Orchestrator
48+
- Use compile-stage artifacts (DocCard + ReasoningIndex + DocumentGraph) for coarse filtering
49+
- BM25 + keyword overlap + graph boost — three-signal scoring fusion
50+
- Optional LLM-assisted routing (LLM ranks top-M candidates when scores are ambiguous)
51+
- Only activates when document count exceeds a configurable threshold
52+
53+
Module structure:
54+
55+
```
56+
rust/src/router/
57+
├── mod.rs # DocumentRouter, RouteResult, ScoredCandidate
58+
├── scorer.rs # BM25 + keyword + graph fusion scoring
59+
└── config.rs # RouterConfig, RouteMode
60+
```
61+
62+
Estimated: ~600 lines Rust, no new dependencies.
63+
64+
---
65+
66+
## A2: Document Format Support
67+
68+
**Goal:** Support HTML, DOCX, LaTeX in addition to PDF and Markdown.
69+
70+
### HTML Parsing
71+
72+
```
73+
HTML DOM → hierarchical tree structure
74+
<h1>–<h6> → depth-mapped nodes
75+
<p>, <li>, <td> → content nodes
76+
<table> → special handling (text + structure)
77+
<code>, <pre> → preserve formatting
78+
```
79+
80+
Challenge: HTML documents often have deep nesting (`div > div > div`) that doesn't represent semantic structure. Need heuristics to skip decorative containers.
81+
82+
### DOCX Parsing
83+
84+
```
85+
DOCX = ZIP archive
86+
word/document.xml → paragraph extraction
87+
<w:pStyle w:val="Heading1"/> → heading level
88+
<w:p> → paragraph content
89+
Style inheritance → heading/body classification
90+
```
91+
92+
### LaTeX Parsing
93+
94+
```
95+
Regex-based extraction:
96+
\section{...} → depth-0 node
97+
\subsection{...} → depth-1 node
98+
\begin{...} environments → content blocks
99+
```
100+
101+
### Tasks
102+
103+
| # | Task | File |
104+
|---|------|------|
105+
| 1 | HTML parser | `rust/src/index/parse/html.rs` |
106+
| 2 | DOCX parser | `rust/src/index/parse/docx.rs` |
107+
| 3 | LaTeX parser | `rust/src/index/parse/latex.rs` |
108+
| 4 | Format detection | extend `detect_format_from_path()` |
109+
| 5 | IndexMode extension | `rust/src/index/pipeline.rs` |
110+
111+
New dependencies: `scraper = "0.22"`, `zip = "2"`
112+
113+
Estimated: ~800 lines Rust.
114+
115+
---
116+
117+
## A3: Parsing Precision
118+
119+
**Goal:** Fine-grained extraction of tables, figures, and footnotes.
120+
121+
### Current Limitations
122+
123+
`pdf-extract` produces flat text. Tables lose structure, figures are invisible, footnotes mix into body text.
124+
125+
### Table Extraction (PDF)
126+
127+
Use `lopdf` low-level access to detect text blocks with (x, y) coordinates, group by row and column, output as Markdown table strings. Insert as dedicated TreeNodes with `{type: "table"}` metadata.
128+
129+
### Figure Description (PDF)
130+
131+
Extract image streams via `lopdf`, send to LLM (vision-capable model), insert description as TreeNode with `{type: "figure"}` metadata. The only new LLM call in indexing — justified because figures often contain critical information invisible to text extraction.
132+
133+
### Cross-Reference Resolution
134+
135+
Resolve "see Section 3.2", "refer to Figure 4", "as noted in Table 2" to target TreeNodes. Enhances NavigationIndex with cross-reference edges for Worker navigation.
136+
137+
### Tasks
138+
139+
| # | Task | File |
140+
|---|------|------|
141+
| 1 | PDF table extraction | `rust/src/index/parse/pdf_table.rs` |
142+
| 2 | PDF figure description | `rust/src/index/parse/pdf_figure.rs` |
143+
| 3 | PDF footnote handling | `rust/src/index/parse/pdf_footnote.rs` |
144+
| 4 | Markdown table parsing | `rust/src/index/parse/md_table.rs` |
145+
| 5 | Cross-reference resolution | extend `rust/src/document/reference.rs` |
146+
147+
New dependency: `image = "0.25"`
148+
149+
Estimated: ~1000 lines Rust.
150+
151+
---
152+
153+
## A4: Python Ecosystem
154+
155+
**Goal:** Complete Python developer experience.
156+
157+
See the [Python ecosystem expansion plan](https://github.com/vectorlessflow/vectorless/blob/main/.claude/plans/shimmying-tumbling-hare.md) for full details.
158+
159+
| Phase | Content | Deliverable |
160+
|-------|---------|-------------|
161+
| 1 | CLI | `vectorless init/add/query/list/remove/ask/tree/stats/config` |
162+
| 2 | Pythonic API | `errors.py`, `_engine.py`, `_query.py`, type stubs |
163+
| 3 | High-level abstractions | `BatchIndexer`, `DocumentWatcher` |
164+
| 4 | Framework integration | LangChain `BaseRetriever`, LlamaIndex adapter |
165+
| 5 | Testing | Unit → Mock → E2E |
166+
167+
A4 runs in parallel with A1–A3 — the Python layer doesn't depend on new Rust features.
168+
169+
---
170+
171+
## A5: Domain Optimization
172+
173+
**Goal:** Domain-specific optimizations for legal, financial, and technical documents.
174+
175+
### Domain Template System
176+
177+
```rust
178+
pub trait DomainTemplate: Send + Sync {
179+
fn name(&self) -> &str;
180+
fn detect(&self, tree: &DocumentTree, card: &DocCard) -> bool;
181+
fn enhance(&self, tree: &mut DocumentTree, card: &mut DocCard);
182+
fn domain_tags(&self, tree: &DocumentTree) -> Vec<String>;
183+
}
184+
```
185+
186+
| Domain | Optimizations |
187+
|--------|--------------|
188+
| **Legal** | Contract clause identification, article reference resolution, defined term tracking |
189+
| **Financial** | KPI extraction from tables, reporting period detection, currency normalization |
190+
| **Technical** | Code block extraction with language tags, API endpoint identification, version-aware sectioning |
191+
192+
Templates hook into the compile pipeline after the Enhance stage.
193+
194+
Estimated: ~500 lines Rust (framework + 2–3 built-in templates).
195+
196+
---
197+
198+
## A6: Performance & Reliability
199+
200+
**Goal:** Optimize memory, latency, and observability.
201+
202+
### Lazy Document Loading
203+
204+
Defer tree loading until Worker dispatch. Router + Orchestrator.analyze only need DocCards (lightweight). Each DocumentTree is 10–100x larger than its DocCard.
205+
206+
### Caching
207+
208+
- **Router cache**: Cache routing results keyed by `(query_hash, doc_ids_hash)`. Invalidate on document add/remove.
209+
- **Query cache**: Same query + same documents = cached result. Useful for interactive mode.
210+
211+
### Subtree-Level Incremental Updates
212+
213+
Current incremental update detects file-level changes. Refine to diff affected subtrees and only re-compile changed portions. Can reduce re-indexing LLM calls by 50–80%.
214+
215+
### Metrics
216+
217+
| Metric | Source | Use Case |
218+
|--------|--------|----------|
219+
| Router latency | `router.route()` | Monitor routing overhead |
220+
| Router cache hit rate | Router cache | Tune cache size |
221+
| Lazy load count | Worker dispatch | Verify memory savings |
222+
223+
---
224+
225+
## Success Metrics
226+
227+
| Metric | Current | Target |
228+
|--------|---------|--------|
229+
| Max practical workspace size | ~100 docs | 10,000+ docs |
230+
| Index time per doc (PDF, 50 pages) | ~30s | ~20s |
231+
| Query latency (100 docs) | ~10s | ~8s |
232+
| Query latency (1000 docs) | N/A | ~12s |
233+
| Python install-to-query | Manual setup | < 5 minutes |
234+
| Format support | PDF, Markdown | + HTML, DOCX, LaTeX |
235+
236+
---
237+
238+
## Execution Priority
239+
240+
```
241+
Sprint 1: A1 (Router) + A4 Phase 1 (CLI)
242+
Sprint 2: A6 (Lazy Loading) + A4 Phase 2 (Pythonic API)
243+
Sprint 3: A2 (HTML, DOCX, LaTeX)
244+
Sprint 4: A3 (Table, Figure, Footnote)
245+
Sprint 5: A5 (Domain Templates) + A4 Phase 4 (Framework Integration)
246+
```
247+
248+
A1 is the most critical enabler — without it, large-scale scenarios are not viable. A4 (Python) runs in parallel throughout.

0 commit comments

Comments
 (0)