Skip to main content

RAG system for querying Obsidian notes using LangGraph and local LLMs

Project description

ObsidianRAG Backend

Python backend providing RAG (Retrieval-Augmented Generation) capabilities for Obsidian vaults.

PyPI Python Tests


๐Ÿš€ Installation

As End User

# With pip
pip install obsidianrag

# With pipx (recommended - isolated environment)
pipx install obsidianrag

# With uv (fastest)
uv tool install obsidianrag

As Developer

git clone https://github.com/Vasallo94/ObsidianRAG.git
cd ObsidianRAG/backend
uv sync

๐Ÿ“– Usage

CLI Commands

Start Server

# Serve with auto-detected vault
obsidianrag serve --vault /path/to/vault

# Custom port and model
obsidianrag serve --vault ~/notes --port 9000 --model qwen2.5

# LM Studio
obsidianrag serve --vault ~/notes --provider lmstudio --model my-model

# Custom OpenAI-compatible server
obsidianrag serve --vault ~/notes --provider custom \
  --base-url http://my-server:8080/v1 \
  --api-format chat-completions \
  --api-key my-key

Index Vault

# Full rebuild
obsidianrag index --vault /path/to/vault --force

# Incremental (only changed notes)
obsidianrag index --vault /path/to/vault

Check Status

obsidianrag status --vault /path/to/vault

Ask Question (CLI)

obsidianrag ask --vault /path/to/vault "What notes do I have about Python?"

๐Ÿ”Œ API

Start Server

from obsidianrag.api.server import run_server

run_server(vault_path="/path/to/vault", host="0.0.0.0", port=8000)

Endpoints

POST /ask

Ask a question about your notes.

Request:

{
  "text": "What notes do I have about Python?",
  "session_id": "optional-session-id"
}

Response:

{
  "question": "What notes do I have about Python?",
  "result": "According to your notes...",
  "sources": [
    {
      "source": "Programming/Python.md",
      "score": 0.92,
      "retrieval_type": "retrieved"
    }
  ],
  "text_blocks": ["..."],
  "process_time": 2.5,
  "session_id": "abc123"
}

POST /ask/stream

Same as /ask but streams response via Server-Sent Events (SSE).

Events:

  • start - Request started
  • status - Progress update
  • retrieve_complete - Documents retrieved
  • token - LLM token (streamed)
  • answer - Final answer
  • done - Stream complete
  • error - Error occurred

GET /health

Check server status.

Response:

{
  "status": "ok",
  "model": "gemma3",
  "embedding_provider": "huggingface",
  "embedding_model": "sentence-transformers/paraphrase-multilingual-mpnet-base-v2",
  "db_ready": true
}

GET /stats

Get vault statistics.

Response:

{
  "total_notes": 150,
  "total_chunks": 450,
  "total_words": 25000,
  "total_chars": 150000,
  "avg_words_per_chunk": 55,
  "folders": 12,
  "internal_links": 350,
  "vault_path": "MyVault"
}

POST /rebuild_db

Force full database rebuild.


โš™๏ธ Configuration

Environment Variables

Create ~/.config/obsidianrag/.env:

# LLM
LLM_MODEL=gemma3
OLLAMA_BASE_URL=http://localhost:11434

# Embeddings
EMBEDDING_PROVIDER=huggingface  # or 'ollama'
EMBEDDING_MODEL=sentence-transformers/paraphrase-multilingual-mpnet-base-v2
OLLAMA_EMBEDDING_MODEL=nomic-embed-text

# Reranker
USE_RERANKER=true
RERANKER_MODEL=BAAI/bge-reranker-v2-m3
RERANKER_TOP_N=6

# Retrieval
CHUNK_SIZE=1500
CHUNK_OVERLAP=300
RETRIEVAL_K=12
BM25_K=5
BM25_WEIGHT=0.4
VECTOR_WEIGHT=0.6

# API
API_HOST=127.0.0.1
API_PORT=8000
CORS_ORIGINS=["http://localhost:3000", "app://obsidian.md"]

Programmatic Configuration

from obsidianrag.config import Settings, configure_from_vault

# Auto-configure from vault
configure_from_vault("/path/to/vault")

# Manual configuration
settings = Settings(
    obsidian_path="/path/to/vault",
    llm_model="qwen2.5",
    use_reranker=True,
    retrieval_k=15
)

๐Ÿ—๏ธ Architecture

Core Components

obsidianrag/
โ”œโ”€โ”€ api/
โ”‚   โ””โ”€โ”€ server.py         # FastAPI server
โ”œโ”€โ”€ cli/
โ”‚   โ””โ”€โ”€ main.py           # CLI commands (Typer)
โ”œโ”€โ”€ core/
โ”‚   โ”œโ”€โ”€ qa_agent.py       # LangGraph RAG agent
โ”‚   โ”œโ”€โ”€ qa_service.py     # Hybrid retriever + reranker
โ”‚   โ”œโ”€โ”€ db_service.py     # ChromaDB + indexing
โ”‚   โ””โ”€โ”€ metadata_tracker.py  # Change detection
โ”œโ”€โ”€ config/
โ”‚   โ””โ”€โ”€ __init__.py       # Pydantic settings
โ””โ”€โ”€ utils/
    โ””โ”€โ”€ logger.py         # Logging

RAG Pipeline

LangGraph Agent (qa_agent.py):

# Two-node graph: retrieve โ†’ generate
graph = StateGraph(AgentState)
graph.add_node("retrieve", retrieve_node)
graph.add_node("generate", generate_node)
graph.add_edge("retrieve", "generate")

Hybrid Retriever (qa_service.py):

  1. Vector search (ChromaDB)
  2. BM25 search
  3. Ensemble (weighted 0.6/0.4)
  4. CrossEncoder reranking
  5. GraphRAG link expansion

Database Service (db_service.py):

  • ChromaDB persistence
  • Incremental indexing (only changed notes)
  • Metadata tracking
  • Link extraction from [[wikilinks]]

๐Ÿงช Testing

# All tests
uv run pytest

# Unit tests only (no integration, no slow)
uv run pytest -m "not integration and not slow"

# With coverage
uv run pytest --cov=obsidianrag --cov-report=html

Test Structure:

  • tests/test_cli.py - CLI commands (14 tests)
  • tests/test_server.py - API endpoints (14 tests)
  • tests/test_qa_agent.py - LangGraph agent (17 tests)
  • tests/test_db_service.py - Database (16 tests)
  • tests/test_integration.py - E2E flows (16 tests)

Total: 88 tests


๐Ÿ”ง Development

Setup

# Clone repo
git clone https://github.com/Vasallo94/ObsidianRAG.git
cd ObsidianRAG/backend

# Install with dev dependencies
uv sync

# Run tests
uv run pytest

# Lint and format
uv run ruff check obsidianrag/ tests/
uv run ruff format obsidianrag/ tests/

Project Structure

backend/
โ”œโ”€โ”€ obsidianrag/          # Main package
โ”œโ”€โ”€ tests/                # Tests
โ”œโ”€โ”€ pyproject.toml        # Package metadata + dependencies
โ”œโ”€โ”€ uv.lock               # Lock file
โ””โ”€โ”€ pytest.ini            # Pytest configuration

๐Ÿ“„ License

MIT License - see LICENSE


๐Ÿค Contributing

See CONTRIBUTING.md

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

obsidianrag-3.0.3.tar.gz (30.0 kB view details)

Uploaded Source

Built Distribution

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

obsidianrag-3.0.3-py3-none-any.whl (35.4 kB view details)

Uploaded Python 3

File details

Details for the file obsidianrag-3.0.3.tar.gz.

File metadata

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

File hashes

Hashes for obsidianrag-3.0.3.tar.gz
Algorithm Hash digest
SHA256 610085c6514e92a6e8ba995060a88b4b59d58a875b8f4c7e2c01d633a4883ce5
MD5 58254e8b6cf726b512352d246f7dc1b4
BLAKE2b-256 d8232cc4160d8287aac9924fa2e2775a57217c4a67b2dd507576a9a69f7d5445

See more details on using hashes here.

Provenance

The following attestation bundles were made for obsidianrag-3.0.3.tar.gz:

Publisher: release-backend.yml on Vasallo94/ObsidianRAG

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

File details

Details for the file obsidianrag-3.0.3-py3-none-any.whl.

File metadata

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

File hashes

Hashes for obsidianrag-3.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 e6a4471d5a4906678364265d32a51e91140ee365af14b67e6836c6ce2c40b91f
MD5 257f02e82119703ac98fb5a60f0c8eae
BLAKE2b-256 0b9180bcb3b4ef86ed85c47bdbf8e7d3b8e5ed39138393a9fd9cab6ee99b22eb

See more details on using hashes here.

Provenance

The following attestation bundles were made for obsidianrag-3.0.3-py3-none-any.whl:

Publisher: release-backend.yml on Vasallo94/ObsidianRAG

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