Skip to content

Architecture

KaaS uses a three-layer architecture: a React Web UI, a Go backend, and a Python AI engine. A single Docker image bundles all three — no sidecar containers needed.

Overview

KaaS Architecture

LayerTechPurpose
Web UIReact 19 + Vite + shadcn/uiChat, Submit, Wiki, Status
BackendGo (net/http + go-zero/conf)REST API, Worker Pool, Task Queue, MCP endpoint
AI EnginePython (kb-ai daemon)LLM Compile Pipeline, Retrieval, Chat
StorageSQLite (default)Job queue, compile state

Web UI Layer

The frontend is a single-page application built with React 19, Vite, and shadcn/ui. It provides four pages:

  • Chat — SSE streaming conversation with source citations pointing back to wiki articles
  • Submit — Upload content (paste text, drag files, or enter URLs)
  • Wiki — Browse compiled wiki articles with Markdown rendering
  • Status — Monitor compilation progress in real time

The UI includes built-in i18n (English / Chinese) and light/dark theme support. It connects directly to the Go backend REST API — no authentication layer (designed for local/intranet deployment).

Go Backend Layer

The Go backend is the orchestration hub. It uses the standard library net/http (not go-zero's rest.Server) to avoid write-timeout conflicts with SSE streaming.

Key components:

  • REST API — Handles /api/submit, /api/tasks, /api/wiki, /api/chat, and serves the embedded Web UI at /
  • Worker Pool — Dispatcher + Extract workers + Pipeline workers for concurrent compilation
  • Circuit Breaker — Automatically halts LLM calls after consecutive failures (configurable threshold + cooldown)
  • Lease Recovery — Heartbeat-based lease renewal; orphaned tasks are automatically recovered on restart
  • MCP Endpoint — Reverse proxies /mcp to the Python MCP server for remote agent access
  • SQLite Store — Persists task queue, compile state, and job metadata

Python AI Engine

The Python AI engine (kb-ai) handles all LLM interactions:

  • Compile Pipeline — Extract → Classify → Write → Index (4-phase Markdown generation)
  • Retrieval — LLM-iterative approach: reads master-index → LLM selects pages → fetches full article text (no embeddings)
  • Chat — Streaming conversation with prompt caching and citation sourcing
  • MCP Server — Exposes an ask tool via stdio or streamable-http transport

The Go backend spawns the Python engine as a long-running daemon process, communicating via a multiplexed stdin/stdout JSON protocol (see below).

Go-Python Communication

Go-Python Communication Protocol

KaaS uses a custom multiplexed protocol over the daemon's stdin/stdout pipes. This avoids HTTP overhead and cold-start latency while supporting concurrent requests.

Protocol Format

Request (Go → Python via stdin, one JSON per line):

json
{"id": "3", "cmd": "chat", "payload": {"query": "...", "kb_dir": "./data"}}

Response (Python → Go via stdout, one JSON per line):

json
{"id": "3", "ok": true, "data": {"extraction": {...}, "cost": {...}}}

Streaming response (multiple lines for the same id):

json
{"id": "3", "stream": true, "event": {"type": "delta", "text": "..."}}
{"id": "3", "stream": true, "event": {"type": "done"}, "final": true}

Key Design Elements

ElementDescription
id fieldEvery request carries a unique id. The Go readLoop dispatches responses by matching id back to the waiting goroutine.
ConcurrencyGo uses a semaphore to limit in-flight requests. Python dispatches commands to a ThreadPoolExecutor.
StreamingStreaming commands (chat, pipeline-stream) emit multiple {"stream": true} events until "final": true.
CancellationGo sends {"cmd": "cancel", "payload": {"target_id": "3"}} to abort a running stream. Python uses a per-request cancel_registry to signal threads.
ReadinessPython prints __READY__ to stderr after initialization. Go waits for this before sending any commands.
Thread safetyPython's _write_response acquires a lock before writing to stdout to prevent interleaved JSON lines.

Lifecycle

  1. Go spawns kb-ai daemon as a subprocess (exec.Cmd)
  2. Python initializes, prints __READY__ to stderr
  3. Go sends init command with LLM credentials
  4. Normal operation: multiplexed request/response over stdin/stdout
  5. On shutdown: Go closes stdin → Python's readline loop exits gracefully
  6. On crash: Go supervisor detects exit, restarts daemon automatically (up to MaxRestarts)

Storage

KaaS uses SQLite by default for zero-dependency deployment:

  • Task queue — Job metadata, status, lease information
  • Compile state — Content hashes for incremental compilation

All wiki output is stored as plain Markdown files in the kb_dir directory (./data by default):

data/
├── wiki/          # Compiled wiki articles (Markdown)
├── raw/           # Original input content
├── index/         # master-index + topic-indexes
└── kaas.db        # SQLite database

Deployment

KaaS ships as a single Docker image that bundles:

  • Pre-built React UI (served as static files by Go)
  • Statically-linked Go binary
  • Python runtime + kb-ai package (via uv)
bash
docker run -d --name kaas \
  -p 8080:8080 \
  -v ./data:/app/data \
  -e LLM_API_KEY=sk-xxx \
  kaas

Only port 8080 is exposed. The Go backend handles all external traffic — REST API, embedded Web UI, and MCP endpoint. The Python daemon runs internally with no network surface.