Files
xserv/docs/12-13-serving.md
Gahow Wang da043554ba phase 12+13: HTTP API server with OpenAI-compatible endpoint (Milestone ③)
New crate: xserv-server
- Engine thread: loads Qwen3-8B, processes requests sequentially
- axum HTTP server: /health, /v1/models, /v1/chat/completions
- tokio::sync::mpsc channel between API and engine threads
- Non-streaming JSON response (streaming SSE to be added later)

API is OpenAI-compatible:
  POST /v1/chat/completions {"messages": [...], "max_tokens": N}
  → {"choices": [{"message": {"content": "..."}}]}

Verified: "Hi" → ", I'm" (3 tokens), model runs correctly via HTTP.

Key learnings:
- std::sync::mpsc::SyncSender is Send but NOT Sync → wrap in Mutex for Arc<AppState>
- MutexGuard must not live across await points (scope carefully)
- axum 0.8 Extension<Arc<T>> requires T: Send + Sync

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-22 12:55:19 +08:00

99 lines
2.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Phase 12+13: Continuous Batching + HTTP API — Design Document (Milestone ③)
## Goal
实现 HTTP serving 层接收请求、调度执行、streaming 返回结果。OpenAI 兼容 API。
由于当前是单请求引擎(无 multi-GPU、无并发Phase 12 (continuous batching) 和 Phase 13 (HTTP API) 合并实现:先实现单请求 servingscheduler 作为 placeholder 留待后续扩展。
## Architecture
```
Client (curl / OpenAI SDK)
▼ HTTP POST /v1/chat/completions
┌─────────────────────────────────────┐
│ xserv-api (axum) │
│ - Parse request │
│ - Apply chat template │
│ - Submit to engine via channel │
│ - Stream SSE chunks from channel │
└────────────┬────────────────────────┘
│ InferenceRequest → mpsc channel
┌─────────────────────────────────────┐
│ xserv-engine (dedicated thread) │
│ - Receive requests │
│ - Run model forward (prefill+decode)│
│ - Send tokens back via channel │
└─────────────────────────────────────┘
```
## Crates
- `xserv-engine`: inference orchestration (model + cache + generate loop)
- `xserv-api`: HTTP server with axum
Both in one binary: `xserv-server`
## API Endpoints
```
POST /v1/chat/completions # main endpoint
GET /v1/models # list models
GET /health # health check
```
## Request/Response (OpenAI compatible)
Request:
```json
{
"model": "qwen3-8b",
"messages": [{"role": "user", "content": "Hello"}],
"stream": true,
"max_tokens": 256,
"temperature": 1.0
}
```
SSE Response:
```
data: {"id":"...","choices":[{"delta":{"content":"Hi"},"index":0}]}
data: {"id":"...","choices":[{"delta":{},"finish_reason":"stop"}]}
data: [DONE]
```
## Engine Design
```rust
pub struct Engine {
model: Qwen3,
config: ModelConfig,
tokenizer: Tokenizer,
}
impl Engine {
pub fn generate(&self, prompt_tokens: &[u32], params: &SamplingParams,
sender: mpsc::Sender<Token>) { ... }
}
```
Engine runs on a dedicated OS thread (avoids async/GPU conflicts).
API handlers communicate via `tokio::sync::mpsc` channels.
## Sampling
For this phase: greedy only (temperature=0 or 1 with argmax).
Top-k/top-p sampling added later.
## Test Plan
- [ ] curl streaming request → get SSE chunks
- [ ] Python OpenAI SDK client works
- [ ] /v1/models returns model info
- [ ] /health returns 200
- [ ] Multiple sequential requests work