架构
KaaS 采用三层架构:React Web UI、Go 后端、Python AI 引擎。单个 Docker 镜像打包所有组件——无需 sidecar 容器。
概览
| 层 | 技术 | 职责 |
|---|---|---|
| Web UI | React 19 + Vite + shadcn/ui | Chat、Submit、Wiki、Status |
| 后端 | Go (net/http + go-zero/conf) | REST API、Worker Pool、任务队列、MCP 端点 |
| AI 引擎 | Python (kb-ai daemon) | LLM 编译流水线、检索、问答 |
| 存储 | SQLite(默认) | 任务队列、编译状态 |
Web UI 层
前端是基于 React 19、Vite 和 shadcn/ui 的单页应用,包含四个页面:
- Chat — SSE 流式对话,附带指向 wiki 文章的来源引用
- Submit — 提交内容(粘贴文本、拖入文件、输入 URL)
- Wiki — 浏览编译产出的 wiki 文章,Markdown 渲染
- Status — 实时监控编译进度
UI 内置中英文国际化和明暗主题切换。直连 Go 后端 REST API,无鉴权层(设计为本地/内网部署)。
Go 后端层
Go 后端是整个系统的编排中枢。使用标准库 net/http(而非 go-zero 的 rest.Server),以避免 SSE 流式传输与写超时的冲突。
核心组件:
- REST API — 处理
/api/submit、/api/tasks、/api/wiki、/api/chat,并在/提供内嵌 Web UI - Worker Pool — Dispatcher + Extract workers + Pipeline workers,并发编译加速
- Circuit Breaker — LLM 连续失败后自动熔断(可配置阈值 + 冷却时间)
- Lease Recovery — 基于心跳的租约续期;异常退出后自动恢复孤立任务
- MCP 端点 — 将
/mcp反向代理到 Python MCP server,供远程 agent 接入 - SQLite Store — 持久化任务队列、编译状态和任务元数据
Python AI 引擎
Python AI 引擎(kb-ai)负责所有 LLM 交互:
- 编译流水线 — Extract → Classify → Write → Index(4 阶段 Markdown 生成)
- 检索 — LLM 迭代式:读 master-index → LLM 选页 → 读取完整文章(无嵌入向量)
- 问答 — 流式对话,支持 prompt caching 和引用溯源
- MCP Server — 通过 stdio 或 streamable-http 暴露
ask工具
Go 后端将 Python 引擎作为常驻守护进程启动,通过多路复用的 stdin/stdout JSON 协议通信(见下文)。
Go-Python 通信
KaaS 使用自定义的多路复用协议,基于守护进程的 stdin/stdout 管道。相比 HTTP 方案,避免了网络开销和冷启动延迟,同时支持并发请求。
协议格式
请求(Go → Python,通过 stdin,每行一个 JSON):
json
{"id": "3", "cmd": "chat", "payload": {"query": "...", "kb_dir": "./data"}}响应(Python → Go,通过 stdout,每行一个 JSON):
json
{"id": "3", "ok": true, "data": {"extraction": {...}, "cost": {...}}}流式响应(同一 id 的多行输出):
json
{"id": "3", "stream": true, "event": {"type": "delta", "text": "..."}}
{"id": "3", "stream": true, "event": {"type": "done"}, "final": true}关键设计要素
| 要素 | 说明 |
|---|---|
id 字段 | 每个请求携带唯一 id。Go 端的 readLoop 根据 id 将响应分发到对应的等待 goroutine。 |
| 并发控制 | Go 使用信号量限制在途请求数。Python 将命令分发到 ThreadPoolExecutor 并发执行。 |
| 流式传输 | 流式命令(chat、pipeline-stream)发送多个 {"stream": true} 事件,直到 "final": true。 |
| 取消机制 | Go 发送 {"cmd": "cancel", "payload": {"target_id": "3"}} 中止正在执行的流。Python 使用每请求的 cancel_registry 通知线程。 |
| 就绪信号 | Python 初始化完成后向 stderr 输出 __READY__。Go 收到此信号后才开始发送命令。 |
| 线程安全 | Python 的 _write_response 写入 stdout 前获取锁,防止并发写入导致 JSON 行交错。 |
生命周期
- Go 通过
exec.Cmd启动kb-ai daemon子进程 - Python 初始化完毕,向 stderr 输出
__READY__ - Go 发送
init命令传递 LLM 凭证 - 正常运行:stdin/stdout 上的多路复用请求/响应
- 关闭时:Go 关闭 stdin → Python 的 readline 循环退出
- 崩溃时:Go supervisor 检测到进程退出,自动重启(最多
MaxRestarts次)
存储
KaaS 默认使用 SQLite,实现零依赖部署:
- 任务队列 — 任务元数据、状态、租约信息
- 编译状态 — 内容哈希,支持增量编译
所有 wiki 产出以纯 Markdown 文件形式存储在 kb_dir 目录(默认 ./data):
data/
├── wiki/ # 编译产出的 wiki 文章(Markdown)
├── raw/ # 原始输入内容
├── index/ # master-index + topic-index
└── kaas.db # SQLite 数据库部署
KaaS 以单个 Docker 镜像交付,包含:
- 预构建的 React UI(Go 作为静态文件服务)
- 静态链接的 Go 二进制
- Python 运行时 + kb-ai 包(通过 uv)
bash
docker run -d --name kaas \
-p 8080:8080 \
-v ./data:/app/data \
-e LLM_API_KEY=sk-xxx \
kaas仅暴露端口 8080。Go 后端处理所有外部流量——REST API、内嵌 Web UI 和 MCP 端点。Python 守护进程在内部运行,无网络暴露面。