157 lines
5.2 KiB
Markdown
157 lines
5.2 KiB
Markdown
# haiku.rag Docker Compose Example
|
|
|
|
Run haiku.rag with docling-serve for remote document processing, continuous ingestion via `haiku-ingester`, and a read-only MCP server.
|
|
|
|
## Architecture
|
|
|
|
LanceDB allows exactly one writer + N readers per database URI, so the
|
|
example runs the ingester and the MCP server as **two separate containers**
|
|
sharing the same data volume:
|
|
|
|
- **docling-serve-1** / **docling-serve-2** - Two replicas of the
|
|
document conversion + chunking service. The ingester round-robins
|
|
jobs across them; running two means convert work overlaps and one
|
|
container restarting (e.g. for memory recycling) doesn't stall
|
|
ingest. Bumping to N replicas is the same pattern — duplicate the
|
|
service block and add the URL to `providers.docling_serve.base_url`.
|
|
- **haiku-ingester** - Long-lived writer. Watches `/docs`, ingests new and
|
|
changed files, queues retries, exposes the control plane on port 8765.
|
|
- **haiku-rag** - Read-only MCP server on port 8001 for AI assistant
|
|
integration. Cannot write to the database — the ingester owns writes.
|
|
|
|
Both haiku.* services share the same slim image (built once) and the same
|
|
config file; docker-compose overrides the image's default command to give
|
|
each container its role.
|
|
|
|
This setup showcases the minimal haiku.rag-slim image combined with external document processing, ideal for production deployments.
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
# Create required directories
|
|
mkdir -p data docs
|
|
|
|
# Create config file from example (required)
|
|
cp haiku.rag.yaml.example haiku.rag.yaml
|
|
|
|
# Start services (pulls ghcr.io/ggozad/haiku.rag-slim:latest)
|
|
docker compose up -d
|
|
```
|
|
|
|
Place documents in `docs/` for automatic indexing.
|
|
|
|
### Building locally for development
|
|
|
|
The example pulls the published image. To run a local build of
|
|
`haiku.rag-slim` instead — typical when iterating on the codebase — drop
|
|
a `docker-compose.override.yml` next to `docker-compose.yml` (the file
|
|
is auto-loaded by Compose and not checked in):
|
|
|
|
```yaml
|
|
services:
|
|
haiku-ingester:
|
|
build:
|
|
context: ../..
|
|
dockerfile: docker/Dockerfile.slim
|
|
haiku-rag:
|
|
build:
|
|
context: ../..
|
|
dockerfile: docker/Dockerfile.slim
|
|
```
|
|
|
|
Then:
|
|
|
|
```bash
|
|
docker compose build # builds & tags as ghcr.io/ggozad/haiku.rag-slim:latest
|
|
docker compose up -d # uses the local image
|
|
docker compose pull # back to the published image when done
|
|
```
|
|
|
|
## Volume Mounts
|
|
|
|
| Host Path | Container Path | Mounted on | Purpose |
|
|
|-----------|----------------|------------|---------|
|
|
| `./data` | `/data` | both haiku containers | Persistent LanceDB + ingester queue |
|
|
| `./docs` | `/docs` | `haiku-ingester` only | Documents to ingest (watched by the FS source) |
|
|
| `./haiku.rag.yaml` | `/app/haiku.rag.yaml` | both haiku containers | Configuration file |
|
|
|
|
**Important:** The `haiku.rag.yaml` config file must exist before running `docker compose up`. Copy it from the example:
|
|
|
|
```bash
|
|
cp haiku.rag.yaml.example haiku.rag.yaml
|
|
```
|
|
|
|
The example config sets `ingester.sources[0].root: /docs` - this is the **container path**, not your host path. Documents placed in `./docs` on your host will appear at `/docs` inside the container.
|
|
|
|
## Usage
|
|
|
|
Add documents by dropping files into `./docs/` on the host — the ingester
|
|
picks them up automatically (watchfiles + periodic sweep).
|
|
|
|
The `haiku-rag` container runs in read-only mode, so use it for queries:
|
|
|
|
```bash
|
|
# List documents
|
|
docker compose exec haiku-rag haiku-rag list
|
|
|
|
# Search
|
|
docker compose exec haiku-rag haiku-rag search "your query"
|
|
|
|
# Ask questions
|
|
docker compose exec haiku-rag haiku-rag ask "What is haiku.rag?"
|
|
```
|
|
|
|
Check ingester progress via its control plane:
|
|
|
|
```bash
|
|
curl http://localhost:8765/health
|
|
curl http://localhost:8765/jobs?status=queued
|
|
curl http://localhost:8765/dlq
|
|
```
|
|
|
|
## Ports
|
|
|
|
- `5001` - docling-serve replica 1 API (with UI enabled, debug only)
|
|
- `5002` - docling-serve replica 2 API (host port; container still listens on 5001)
|
|
- `8001` - MCP server (read-only)
|
|
- `8765` - ingester control plane (`/health`, `/jobs`, `/sources`, `/dlq`)
|
|
|
|
## Configuration
|
|
|
|
The setup uses `haiku.rag-slim` image configured to use docling-serve for document processing:
|
|
|
|
```yaml
|
|
processing:
|
|
converter: docling-serve
|
|
chunker: docling-serve
|
|
|
|
providers:
|
|
docling_serve:
|
|
base_url: http://docling-serve:5001
|
|
```
|
|
|
|
Edit `haiku.rag.yaml` to configure providers, embeddings, and other settings. See the [Configuration documentation](https://ggozad.github.io/haiku.rag/configuration/) for all options.
|
|
|
|
For API keys (OpenAI, Anthropic, etc.), set them as environment variables:
|
|
|
|
```bash
|
|
export OPENAI_API_KEY=your-key-here
|
|
export ANTHROPIC_API_KEY=your-key-here
|
|
docker compose up -d
|
|
```
|
|
|
|
The ingester container binds the control plane to `0.0.0.0` so the host
|
|
port-mapping works. The example config requires a bearer token via
|
|
`INGESTER_TOKEN`; set it in `.env` (gitignored) alongside the API keys
|
|
before bringing the stack up:
|
|
|
|
```bash
|
|
echo "INGESTER_TOKEN=$(openssl rand -hex 32)" >> .env
|
|
```
|
|
|
|
## Documentation
|
|
|
|
- [Remote Processing](https://ggozad.github.io/haiku.rag/remote-processing/)
|
|
- [Configuration](https://ggozad.github.io/haiku.rag/configuration/)
|
|
- [CLI Commands](https://ggozad.github.io/haiku.rag/cli/)
|
|
- [MCP Server](https://ggozad.github.io/haiku.rag/mcp/)
|