Lightweight structural RAG library — index documents as trees, query without a vector DB.
Project description
treerag 🌳
A lightweight structural RAG library — index documents as hierarchical trees, query them without a vector database.
Works with any LangChain-compatible LLM: OpenAI, Anthropic, Gemini, Ollama.
Install
# Base
pip install treerag
# With OpenAI
pip install "treerag[openai]"
# With Anthropic
pip install "treerag[anthropic]"
# Everything
pip install "treerag[all]"
Quick Start
from treerag import index_document, make_summarizer, ask, make_retriever
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o")
# 1. Index
doc = index_document("my_doc.md", summarizer=make_summarizer(llm))
# 2. Ask — returns enriched LangChain AIMessage
result = ask("What does this cover?", doc, make_retriever(llm))
print(result.content) # answer text
print(result.references) # sections used
print(result.response_metadata) # token usage, model, etc
Supported Input Formats
# Files
doc = index_document("my_doc.md")
doc = index_document("report.pdf")
doc = index_document("document.docx")
doc = index_document("notes.txt")
# URLs
doc = index_document("https://docs.example.com")
Response Formats
# Default — raw LangChain AIMessage with .references attached
result = ask("What is this?", doc, retriever)
print(result.content) # answer text
print(result.references) # [{"node_id", "title", "path", "file_name"}, ...]
# Plain dict
result = ask("What is this?", doc, retriever, return_raw=False)
print(result["answer"])
print(result["references"])
# Streaming
for chunk in ask("What is this?", doc, retriever, stream=True):
if isinstance(chunk, dict):
print("\nRefs:", chunk["__references__"])
else:
print(chunk, end="", flush=True)
Async Support
from treerag import aask, make_async_retriever
retriever = make_async_retriever(llm)
result = await aask("What is this?", doc, retriever)
print(result.content)
# Async streaming
async for chunk in await aask("What is this?", doc, retriever, stream=True):
if isinstance(chunk, dict):
print(chunk["__references__"])
else:
print(chunk, end="", flush=True)
Multi-Document Q&A
from treerag import ask_multi
doc1 = get_document_by_id("uuid-1")
doc2 = get_document_by_id("uuid-2")
result = ask_multi("What is the budget cap?", [doc1, doc2], retriever)
print(result.content)
print(result.references) # shows which file each section came from
Registry Management
from treerag import list_documents, get_document_by_id, delete_document
# List all indexed docs
for doc in list_documents():
print(doc["name"], doc["doc_id"], doc["total_sections"])
# Load by UUID (fast, O(1))
doc = get_document_by_id("3f7a1c2d-9b4e-4f8a-b2d1-6e5c3a9f0e12")
# Load by file name
from treerag import get_document
doc = get_document("my_doc.md")
# Delete by UUID
delete_document("3f7a1c2d-9b4e-4f8a-b2d1-6e5c3a9f0e12")
Custom Prompts
# Domain-specific summarizer
summarizer = make_summarizer(
llm,
system_prompt="You are a legal expert. Summarize clauses, obligations, and key terms precisely."
)
# Domain-specific retriever
retriever = make_retriever(
llm,
answer_system_prompt=(
"You are a legal assistant. "
"Provide precise answers using ONLY the provided document context. "
"Avoid assumptions."
)
)
# Per-question extra context
result = ask(
"What are the key obligations and clauses defined in this document?",
doc,
retriever,
extra_context="This document is a legal agreement outlining terms, obligations, and conditions."
)
Provider Examples
from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_ollama import ChatOllama
# OpenAI — cost optimized: cheap model for search, smart model for answers
retriever = make_retriever(
llm=ChatOpenAI(model="gpt-4o"),
search_llm=ChatOpenAI(model="gpt-4o-mini"),
)
# Anthropic
retriever = make_retriever(ChatAnthropic(model="claude-haiku-4-5-20251001"))
# Gemini
retriever = make_retriever(ChatGoogleGenerativeAI(model="gemini-2.0-flash"))
# Ollama (local, free)
retriever = make_retriever(ChatOllama(model="llama3"))
Production Usage (no local storage)
# persist=False — returns dict, you handle storage
doc = index_document("my_doc.md", persist=False)
db.save(doc["doc_id"], doc) # PostgreSQL
redis.set(doc["doc_id"], json.dumps(doc)) # Redis
# Load from your storage and pass directly to ask()
doc = db.get("some-uuid")
result = ask("Your question?", doc, retriever)
How It Works
Indexing:
File / URL
↓ read_file() — read content
↓ parse_sections() — split by markdown headers
↓ make_summarizer(llm) — AI summaries per section
↓ build_hierarchy() — parent → child tree
↓ flatten_tree() — {node_id: content} lookup
↓ save_registry() — indexed_docs.json (UUID key)
Q&A:
Query
↓ tree search — LLM reads outline → picks node IDs
↓ fetch content — full text from flat_nodes
↓ answer gen — LLM reads sections → generates answer
↓ AIMessage with .references attached
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
treerag-0.1.0.tar.gz
(19.7 kB
view details)
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
treerag-0.1.0-py3-none-any.whl
(19.3 kB
view details)
File details
Details for the file treerag-0.1.0.tar.gz.
File metadata
- Download URL: treerag-0.1.0.tar.gz
- Upload date:
- Size: 19.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1d50c116b4edcf4267c9065a4e612915963b740807284e0a50b2195d70f17fa4
|
|
| MD5 |
c985bcc6024b825166890897f9e2af99
|
|
| BLAKE2b-256 |
925ed251f187b9eba3b89b7268b06a20b0c6478eae6c636ee762d4b66be834e1
|
File details
Details for the file treerag-0.1.0-py3-none-any.whl.
File metadata
- Download URL: treerag-0.1.0-py3-none-any.whl
- Upload date:
- Size: 19.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
33b6e51b58ed0cf2c0b636b8f5aaec4da237742cdb5c827adf02179114087264
|
|
| MD5 |
f5b08de112c1949c25d5f2124de7b347
|
|
| BLAKE2b-256 |
1c4c069ef6ef4077f1ffea533c8f61a606983df4fbbef8a40bb0dc34b4ba9cd4
|