← MindRouter Documentation

MindRouter Architecture

Mirrored from docs/architecture.md in the MindRouter repository. Example hostnames are placeholders — substitute your own deployment.


Overview

MindRouter is a production-ready LLM inference load balancer designed to front heterogeneous backend clusters of Ollama and vLLM inference nodes. It provides a unified API surface compatible with OpenAI, Ollama, and Anthropic clients while implementing fair-share scheduling, quota management, and comprehensive audit logging.


System Components

1. API Gateway

The API Gateway is the entry point for all client requests.

Key Responsibilities: - Request authentication via API keys - Request validation and normalization - Protocol translation (OpenAI ↔ Ollama ↔ Anthropic ↔ vLLM) - Response streaming with low latency - Error handling and retry logic

Endpoints: - /v1/chat/completions - OpenAI-compatible chat - /v1/responses - OpenAI Responses API (inbound-only; typed input items and SSE events) - /v1/completions - OpenAI-compatible text completions - /v1/embeddings - OpenAI-compatible embeddings - /v1/rerank - Reranking - /v1/score - Scoring - /v1/models - List available models - /api/chat - Ollama-compatible chat - /api/generate - Ollama-compatible generation - /api/tags - Ollama-compatible model list - /anthropic/v1/messages - Anthropic Messages API compatible (inbound-only)

2. Translation Layer

The translation layer converts between different API formats.

┌─────────────────┐
│ Client Request  │
└────────┬────────┘
         │
    ┌────▼────┐  ┌─────────┐  ┌────────────┐
    │OpenAI In│  │Ollama In│  │Anthropic In│
    └────┬────┘  └────┬────┘  └──────┬─────┘
         │            │              │
         └────────────┼──────────────┘
                      │
              ┌───────▼───────┐
              │   Canonical   │
              │    Schema     │
              └───────┬───────┘
                      │
              ┌───────┴────────┐
              │                │
         ┌────▼────┐      ┌────▼─────┐
         │vLLM Out │      │Ollama Out│
         └────┬────┘      └────┬─────┘
              │                │
              └───────┬────────┘
                      │
         ┌────────────▼────────────┐
         │     Backend Request     │
         └─────────────────────────┘

Note: The Anthropic translator is inbound-only. Responses from backends (in OpenAI/Ollama format) are converted back to Anthropic Messages format by AnthropicInTranslator.format_response() and format_stream_event().

Canonical Schemas: - CanonicalChatRequest - Unified chat format (messages, tools, tool_choice, response_format, etc.) - CanonicalMessage - Message with role, content, tool_calls, tool_call_id - CanonicalToolCall / CanonicalToolDefinition - Tool calling primitives (arguments stored as JSON strings) - CanonicalEmbeddingRequest - Unified embedding format - CanonicalStreamChunk - Unified streaming format (including tool call deltas)

3. Fair-Share Scheduler

Implements Weighted Deficit Round Robin (WDRR) for fair resource allocation.

Key Concepts: - Share Weights: Per-group (e.g. faculty=3, staff=2, student=1, admin=10), configured in /admin/groups - Deficit Counters: Track service debt per user - Burst Credits: Allow full cluster use when idle - Deprioritization: Reduce priority for heavy users

Scheduling Flow: 1. Job arrives, compute initial priority 2. Add to per-user queue 3. When backend available: - Select user with highest (deficit + burst_credits) / weight - Score eligible backends - Route to best backend 4. On completion, update deficit counter

4. Backend Registry

Manages backend discovery, health, and telemetry. The registry operates on a Node/Backend separation: a Node represents a physical GPU server running a sidecar agent, while a Backend is an inference endpoint running on a node.

Node/Backend Model: - Node: Physical server with a sidecar agent, owns GPU devices - Backend: Inference endpoint (Ollama/vLLM) running on a node, assigned specific GPUs via gpu_indices - One sidecar poll per node (deduplicated across backends) - Per-backend GPU aggregation uses only assigned GPU subset

Two-Phase Telemetry Collection: 1. Phase A — Per-node sidecar poll: Calls each node's sidecar once, upserts GPU device records, stores GPU telemetry, updates node hardware info 2. Phase B — Per-backend health poll: Calls each backend's inference API for health/model/request metrics, computes per-backend GPU utilization from cached node data filtered by gpu_indices

Backend Adapters: - OllamaAdapter - Polls /api/tags, /api/ps, /api/version - VLLMAdapter - Polls /v1/models, /health, /metrics - SidecarClient - Polls node's /gpu-info for GPU hardware metrics

4a. GPU Sidecar Agent

A lightweight FastAPI service (sidecar/gpu_agent.py) that runs on each physical GPU server. Uses NVIDIA Management Library (pynvml) to expose per-GPU metrics.

Endpoints: - GET /health - Liveness check, returns GPU count - GET /gpu-info - Full GPU metrics (utilization, memory, temperature, power, clocks, processes)

Deployment: Runs as a Docker container with --gpus all or directly via Python on each GPU node. Exposes port 8007 by default.

5. Backend Scorer

Multi-factor scoring for backend selection.

Hard Constraints (must pass): - Model availability - Modality support (multimodal, embeddings) - Memory fit - Capacity available

Soft Scores (higher = better): - Model already loaded: +100 - Low GPU utilization: +50 - Low latency: +40 - Short queue: +30 - High throughput: +20 (recent tokens/second) - Priority: +N×10 (admin-configured backend preference)

6. Quota Management

Token-based quota system with group-based defaults.

Features: - Monthly token budgets - Requests per minute (RPM) limits - Max concurrent requests - Automatic quota reset

7. Audit Logging

Complete request/response logging for compliance.

Logged Data: - Full request content (prompts, messages) - Full response content - Token usage (actual or estimated) - Timing metrics (queue delay, processing time) - Scheduling decisions


Data Model

┌─────────────┐     ┌─────────────┐
│    User     │────<│   ApiKey    │
└──────┬──────┘     └─────────────┘
       │
       │     ┌─────────────┐
       ├────<│    Quota    │
       │     └─────────────┘
       │
       │     ┌─────────────┐     ┌─────────────┐
       └────<│   Request   │────<│  Response   │
             └──────┬──────┘     └─────────────┘
                    │
                    │     ┌─────────────┐
                    ├────<│  Artifact   │
                    │     └─────────────┘
                    │
                    │     ┌─────────────┐
                    └────<│ Scheduler   │
                          │  Decision   │
                          └─────────────┘

┌─────────────┐     ┌─────────────┐
│    Node     │────<│  GPUDevice  │
└──────┬──────┘     └──────┬──────┘
       │                   │
       │     ┌─────────────┤
       │     │  GPUDevice   │
       │     │  Telemetry   │
       │     └─────────────┘
       │
┌──────┴──────┐     ┌─────────────┐
│   Backend   │────<│    Model    │
└──────┬──────┘     └─────────────┘
       │
       │     ┌─────────────┐
       └────<│  Telemetry  │
             └─────────────┘

Node → Backend: one-to-many (a node can host multiple backends)
Backend.gpu_indices: JSON list of GPU device indices assigned to this backend
GPUDevice belongs to Node (not Backend)

Request Flow

Client Request
       │
       ▼
┌─────────────────┐
│  Authentication │
│   (API Key)     │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ Quota Check     │
│ Rate Limit      │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  Translation    │
│  (→ Canonical)  │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  Create Job     │
│  Compute Priority│
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  Route to       │
│  Backend        │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  Proxy Request  │
│  (Stream if     │
│   applicable)   │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  Record Audit   │
│  Update Usage   │
└────────┬────────┘
         │
         ▼
    Response

Deployment

Development

docker compose up --build

Production Considerations

  • Use external MariaDB cluster
  • Configure Redis for distributed rate limiting
  • Mount persistent volume for artifacts
  • Set up monitoring (Prometheus/Grafana)
  • Configure TLS termination
  • Set secure SECRET_KEY