diff --git a/README.md b/README.md index 8997d87b..4ad49d15 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,20 @@ # Haiku RAG -Opinionated agentic RAG powered by LanceDB, Pydantic AI, and Docling. - -`haiku.rag` is an opinionated agentic RAG system that uses LanceDB for vector storage, Pydantic AI for multi-agent workflows, and Docling for document processing. It supports hybrid search (vector + full-text) with Reciprocal Rank Fusion, multiple embedding providers (Ollama, LM Studio, vLLM, OpenAI, VoyageAI), and includes research agents that plan, search, evaluate, and synthesize answers. +Agentic RAG built on [LanceDB](https://lancedb.com/), [Pydantic AI](https://ai.pydantic.dev/), and [Docling](https://docling-project.github.io/docling/). ## Features -- **Local LanceDB**: No external servers required, supports also LanceDB cloud storage, S3, Google Cloud & Azure -- **Multiple embedding providers**: Ollama, LM Studio, VoyageAI, OpenAI, vLLM -- **Multiple QA providers**: Any provider/model supported by Pydantic AI (Ollama, LM Studio, OpenAI, Anthropic, etc.) -- **Native hybrid search**: Vector + full-text search with native LanceDB RRF reranking -- **Reranking**: Default search result reranking with MixedBread AI, Cohere, Zero Entropy, or vLLM -- **Question answering**: Built-in QA agents on your documents -- **Research graph (multi‑agent)**: Plan → Search → Evaluate → Synthesize with agentic AI -- **File monitoring**: Auto-index files when run as server -- **CLI & Python API**: Use from command line or Python -- **MCP server**: Expose as tools for AI assistants -- **Flexible document processing**: Local (docling) or remote (docling-serve) processing +- **Hybrid search** — Vector + full-text with Reciprocal Rank Fusion +- **Reranking** — MxBAI, Cohere, Zero Entropy, or vLLM +- **Question answering** — QA agents with citations (page numbers, section headings) +- **Research agents** — Multi-agent workflows via pydantic-graph: plan, search, evaluate, synthesize +- **Document structure** — Stores full [DoclingDocument](https://docling-project.github.io/docling/concepts/docling_document/), enabling structure-aware context expansion and visual grounding +- **Multiple providers** — Embeddings: Ollama, OpenAI, VoyageAI, LM Studio, vLLM. QA/Research: any model supported by Pydantic AI +- **Local-first** — Embedded LanceDB, no servers required. Also supports S3, GCS, Azure, and LanceDB Cloud +- **MCP server** — Expose as tools for AI assistants (Claude Desktop, etc.) +- **File monitoring** — Watch directories and auto-index on changes +- **Inspector** — TUI for browsing documents, chunks, and search results +- **CLI & Python API** — Full functionality from command line or code ## Installation @@ -41,104 +39,51 @@ Install only the extras you need. See the [Installation](https://ggozad.github.i ## Quick Start ```bash -# Add documents -haiku-rag add "Your content here" -haiku-rag add "Your content here" --meta author=alice --meta topic=notes -haiku-rag add-src document.pdf --meta source=manual +# Index a PDF +haiku-rag add-src paper.pdf # Search -haiku-rag search "query" - -# Search with filters -haiku-rag search "query" --filter "uri LIKE '%.pdf' AND title LIKE '%paper%'" - -# Ask questions -haiku-rag ask "Who is the author of haiku.rag?" +haiku-rag search "attention mechanism" # Ask questions with citations -haiku-rag ask "Who is the author of haiku.rag?" --cite +haiku-rag ask "What datasets were used for evaluation?" --cite -# Deep QA (multi-agent question decomposition) -haiku-rag ask "Who is the author of haiku.rag?" --deep --cite +# Deep QA — decomposes complex questions into sub-queries +haiku-rag ask "How does the proposed method compare to the baseline on MMLU?" --deep -# Deep QA with verbose output -haiku-rag ask "Who is the author of haiku.rag?" --deep --verbose +# Research mode — iterative planning and search +haiku-rag research "What are the limitations of the approach?" --verbose -# Multi‑agent research (iterative plan/search/evaluate) -haiku-rag research \ - "What are the main drivers and trends of global temperature anomalies since 1990?" \ - --max-iterations 2 \ - --confidence-threshold 0.8 \ - --max-concurrency 3 \ - --verbose - -# Rebuild database (re-chunk and re-embed all documents) -haiku-rag rebuild - -# Start server with file monitoring +# Watch a directory for changes haiku-rag serve --monitor ``` -To customize settings, create a `haiku.rag.yaml` config file (see [Configuration](https://ggozad.github.io/haiku.rag/configuration/)). +See [Configuration](https://ggozad.github.io/haiku.rag/configuration/) for customization options. -## Python Usage +## Python API ```python from haiku.rag.client import HaikuRAG -from haiku.rag.config import Config -from haiku.rag.graph.agui import stream_graph -from haiku.rag.graph.research import ( - ResearchContext, - ResearchDeps, - ResearchState, - build_research_graph, -) -async with HaikuRAG("database.lancedb") as client: - # Add document - doc = await client.create_document("Your content") +async with HaikuRAG("research.lancedb", create=True) as rag: + # Index documents + await rag.create_document_from_source("paper.pdf") + await rag.create_document_from_source("https://arxiv.org/pdf/1706.03762") - # Search (reranking enabled by default) - results = await client.search("query") - for chunk, score in results: - print(f"{score:.3f}: {chunk.content}") + # Search — returns chunks with provenance + results = await rag.search("self-attention") + for result in results: + print(f"{result.score:.2f} | p.{result.page_numbers} | {result.content[:100]}") - # Ask questions - answer = await client.ask("Who is the author of haiku.rag?") + # QA with citations + answer, citations = await rag.ask("What is the complexity of self-attention?") print(answer) - - # Ask questions with citations - answer = await client.ask("Who is the author of haiku.rag?", cite=True) - print(answer) - - # Multi‑agent research pipeline (Plan → Search → Evaluate → Synthesize) - # Graph settings (provider, model, max_iterations, etc.) come from config - graph = build_research_graph(config=Config) - question = ( - "What are the main drivers and trends of global temperature " - "anomalies since 1990?" - ) - context = ResearchContext(original_question=question) - state = ResearchState.from_config(context=context, config=Config) - deps = ResearchDeps(client=client) - - # Blocking run (final result only) - report = await graph.run(state=state, deps=deps) - print(report.title) - - # Streaming progress (AG-UI events) - async for event in stream_graph(graph, state, deps): - if event["type"] == "STEP_STARTED": - print(f"Starting step: {event['stepName']}") - elif event["type"] == "ACTIVITY_SNAPSHOT": - print(f" {event['content']}") - elif event["type"] == "RUN_FINISHED": - print("\nResearch complete!\n") - result = event["result"] - print(result["title"]) - print(result["executive_summary"]) + for cite in citations: + print(f" [{cite.chunk_id}] p.{cite.page_numbers}: {cite.content[:80]}") ``` +For research agents and streaming with [AG-UI](https://docs.ag-ui.com/), see the [Agents docs](https://ggozad.github.io/haiku.rag/agents/). + ## MCP Server Use with AI assistants like Claude Desktop: diff --git a/docs/configuration/storage.md b/docs/configuration/storage.md index 42d76dcc..0dec6fa1 100644 --- a/docs/configuration/storage.md +++ b/docs/configuration/storage.md @@ -53,14 +53,33 @@ Authentication is handled through standard cloud provider credentials (AWS CLI, **Note:** Table optimization is automatically handled by LanceDB Cloud (`db://` URIs) and is disabled for better performance. For object storage backends (S3, Azure, GCS), optimization is still performed locally. -## Database Auto-creation +## Database Creation -haiku.rag intelligently handles database creation based on operation type: +Databases must be explicitly created before use: -- **Write operations** (add, add-src, delete, rebuild): Automatically create the database and required tables if they don't exist -- **Read operations** (list, get, search, ask, research): Fail with a clear error if the database doesn't exist +**CLI:** +```bash +# Create in default location (see Configuration File Locations below) +haiku-rag init -This prevents the common mistake where a search query accidentally creates an empty database. To initialize your database, simply add your first document using `haiku-rag add` or `haiku-rag add-src`. +# Create at custom path +haiku-rag init --db /path/to/database.lancedb +``` + +**Python:** +```python +# Create at custom path +async with HaikuRAG("/path/to/database.lancedb", create=True) as client: + ... + +# Create in default location +async with HaikuRAG(create=True) as client: + ... +``` + +The [default location](index.md#configuration-file-locations) is platform-specific (e.g., `~/Library/Application Support/haiku.rag/` on macOS). + +Operations on non-existent databases raise `FileNotFoundError`. This prevents accidental database creation from typos or misconfigured paths. ## Vector Indexing diff --git a/docs/index.md b/docs/index.md index 5a28099e..542de5ea 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,21 +1,20 @@ # haiku.rag -`haiku.rag` is an opinionated agentic RAG system that uses LanceDB for vector storage, Pydantic AI for multi-agent workflows, and Docling for document processing. It supports hybrid search (vector + full-text) with Reciprocal Rank Fusion, multiple embedding providers (Ollama, LM Studio, vLLM, OpenAI, VoyageAI), and includes research agents that plan, search, evaluate, and synthesize answers. +Agentic RAG built on [LanceDB](https://lancedb.com/), [Pydantic AI](https://ai.pydantic.dev/), and [Docling](https://docling-project.github.io/docling/). ## Features -- **Local LanceDB**: No external servers required, supports also LanceDB cloud storage, S3, Google Cloud & Azure -- **Multiple embedding providers**: Ollama, LM Studio, VoyageAI, OpenAI, vLLM -- **Multiple QA providers**: Any provider/model supported by Pydantic AI (Ollama, LM Studio, OpenAI, Anthropic, etc.) -- **Native hybrid search**: Vector + full-text search with native LanceDB RRF reranking -- **Reranking**: Optional result reranking with MixedBread AI, Cohere, Zero Entropy, or vLLM -- **Question answering**: Built-in QA agents on your documents -- **Research graph (multi‑agent)**: Plan → Search → Evaluate → Synthesize with agentic AI -- **File monitoring**: Auto-index files when run as server -- **Extended file format support**: Parse PDF, DOCX, HTML, Markdown, images, code files and more -- **Flexible document processing**: Local processing with docling or remote with [docling-serve](remote-processing.md) -- **MCP server**: Expose as tools for AI assistants -- **CLI & Python API**: Use from command line or Python +- **Hybrid search** — Vector + full-text with Reciprocal Rank Fusion +- **Reranking** — MxBAI, Cohere, Zero Entropy, or vLLM +- **Question answering** — QA agents with citations (page numbers, section headings) +- **Research agents** — Multi-agent workflows via pydantic-graph: plan, search, evaluate, synthesize +- **Document structure** — Stores full [DoclingDocument](https://docling-project.github.io/docling/concepts/docling_document/), enabling structure-aware context expansion and visual grounding +- **Multiple providers** — Embeddings: Ollama, OpenAI, VoyageAI, LM Studio, vLLM. QA/Research: any model supported by Pydantic AI +- **Local-first** — Embedded LanceDB, no servers required. Also supports S3, GCS, Azure, and LanceDB Cloud +- **MCP server** — Expose as tools for AI assistants (Claude Desktop, etc.) +- **File monitoring** — Watch directories and auto-index on changes +- **Inspector** — TUI for browsing documents, chunks, and search results +- **CLI & Python API** — Full functionality from command line or code ## Quick Start @@ -30,15 +29,15 @@ Use from Python: ```python from haiku.rag.client import HaikuRAG -async with HaikuRAG("database.lancedb") as client: +async with HaikuRAG("database.lancedb", create=True) as client: # Add a document doc = await client.create_document("Your content here") # Search documents results = await client.search("query") - # Ask questions - answer = await client.ask("Who is the author of haiku.rag?") + # Ask questions (returns answer and citations) + answer, citations = await client.ask("Who is the author of haiku.rag?") ``` Or use the CLI: diff --git a/docs/python.md b/docs/python.md index c8ff0412..12e2048b 100644 --- a/docs/python.md +++ b/docs/python.md @@ -342,15 +342,10 @@ Context expansion uses your configuration settings: Ask questions about your documents: ```python -answer = await client.ask("Who is the author of haiku.rag?") -print(answer) -``` - -Ask questions with citations showing source documents: - -```python -answer = await client.ask("Who is the author of haiku.rag?", cite=True) +answer, citations = await client.ask("Who is the author of haiku.rag?") print(answer) +for cite in citations: + print(f" [{cite.chunk_id}] {cite.document_title or cite.document_uri}") ``` Customize the QA agent's behavior with a custom system prompt: @@ -360,13 +355,13 @@ custom_prompt = """You are a technical support expert for WIX. Answer questions based on the knowledge base documents provided. Be concise and helpful.""" -answer = await client.ask( +answer, citations = await client.ask( "How do I create a blog?", system_prompt=custom_prompt ) ``` -The QA agent will search your documents for relevant information and use the configured LLM to generate a comprehensive answer. With `cite=True`, responses include citations showing which documents were used as sources. Citations prefer the document title when present, otherwise they use the URI. +The QA agent searches your documents for relevant information and uses the configured LLM to generate an answer. The method returns a tuple of `(answer_text, list[Citation])`. Citations include page numbers, section headings, and document references. The QA provider and model are configured in `haiku.rag.yaml` or can be passed directly to the client (see [Configuration](configuration/index.md)). diff --git a/docs/remote-processing.md b/docs/remote-processing.md index 823b692e..9b92beae 100644 --- a/docs/remote-processing.md +++ b/docs/remote-processing.md @@ -70,7 +70,7 @@ from haiku.rag.client import HaikuRAG async with HaikuRAG() as client: # PDF is processed by docling-serve - doc = await client.create_document_from_file("complex.pdf") + doc = await client.create_document_from_source("complex.pdf") ``` ### Remote Chunking diff --git a/docs/tutorial.md b/docs/tutorial.md index 65c81ee8..b920b018 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -74,9 +74,9 @@ haiku-rag add "JavaScript is a popular programming language, but has a lot of wa haiku-rag add "PHP is a bad programming language, because of spotted security history, horrible syntax and declining popularity" ``` -What will happen +What will happen: -- The piece of text is send to OpenAI `/embeddings` API service +- The piece of text is sent to OpenAI `/embeddings` API service - OpenAI translates the free form text to RAG embedding vectors needed for the retrieval - The vector values will be stored in a local database @@ -86,19 +86,19 @@ Now you can view your [LanceDB](https://lancedb.com/) database, and the embeddin haiku-rag info ``` -You should get the back the information: +You should see output like: ``` haiku.rag database info path: /Users/moo/Library/Application Support/haiku.rag/haiku.rag.lancedb - haiku.rag version (db): 0.13.3 + haiku.rag version (db): 0.20.0 embeddings: openai/text-embedding-3-small (dim: 1536) - documents: 3 - versions (documents): 3 - versions (chunks): 3 + documents: 3 (storage: 48.0 KB) + chunks: 3 (storage: 52.0 KB) + vector index: not created ────────────────────────────────────────────────────────────────────────────────── Versions - haiku.rag: 0.13.3 + haiku.rag: 0.20.0 lancedb: 0.25.2 docling: 2.58.0 ``` @@ -127,52 +127,27 @@ According to the document, Python is considered the best programming language in ## Programmatic interaction in Python -You can interact with Haiku RAG from Python in a similar manner as you can from the command line. Here we use Haiku RAG with the interactive Python command prompt (REPL). - -First we need to install `ipython`, as built-in Python REPL does not support async blocks. +You can interact with haiku.rag from Python. Since the API is async, we'll use IPython which supports async/await directly. ```bash uv pip install ipython -``` - -Run IPython: - -```bash ipython ``` -Then copy paste in the snippet (you can use [%cpaste](https://ipythonbook.com/magic/cpaste.html) command): +Then run: ```python -import sys -import logging from haiku.rag.client import HaikuRAG -# Increase logging verbosity so we see what happens behind the scenes, -# and check that the logger works -logging.basicConfig( - stream=sys.stdout, - level=logging.DEBUG, - format="%(name)s - %(levelname)s - %(message)s", -) -logger = logging.getLogger() -logger.setLevel(logging.DEBUG) -logger.debug("AGI here we come") - -# Uses LanceDB database from default storage location -# (database must be initialized first with 'haiku-rag init' or create=True) +# Uses database from default location (must be initialized first) async with HaikuRAG() as client: - answer = await client.ask("What is the best programming language in the world?") + answer, citations = await client.ask("What is the best programming language in the world?") print(answer) - ``` You should see: ``` -2025-10-18 17:05:49,611 - DEBUG - HTTP Response: POST https://api.openai.com/v1/chat/completions "200 OK" Headers({'date': 'Sat, 18 Oct 2025 14:05:49 GMT', 'content-type': 'application/json', 'transfer-encoding': 'chunked', 'connection': 'keep-alive', 'access-control-expose-headers': 'X-Request-ID', 'openai-organization': 'xxx', 'openai-processing-ms': '788', 'openai-project': 'xxx', 'openai-version': '2020-10-01', 'x-envoy-upstream-service-time': '1050', 'x-ratelimit-limit-requests': '10000', 'x-ratelimit-limit-tokens': '200000', 'x-ratelimit-remaining-requests': '9998', 'x-ratelimit-remaining-tokens': '199603', 'x-ratelimit-reset-requests': '14.981s', 'x-ratelimit-reset-tokens': '119ms', 'x-request-id': 'req_9651a3691a144dd388e97066ad67a49c', 'x-openai-proxy-wasm': 'v0.1', 'cf-cache-status': 'DYNAMIC', 'strict-transport-security': 'max-age=31536000; includeSubDomains; preload', 'x-content-type-options': 'nosniff', 'server': 'cloudflare', 'cf-ray': '990897b6f8d270d7-ARN', 'content-encoding': 'gzip', 'alt-svc': 'h3=":443"; ma=86400'}) -2025-10-18 17:05:49,611 - DEBUG - request_id: req_9651a3691a144dd388e97066ad67a49c - According to the document, Python is considered the best programming language in the world due to its flexibility, robust ecosystem, open-source licensing, and support from thousands of contributors. ```