OpenLLM: BentoML's LLM serving platform (Apache 2.0, 10k stars)
BentoML's LLM serving platform — one-command deployment of any open-source LLM with OpenAI-compatible API.
The Problem
Serving large language models in production is harder than it should be. You have a model checkpoint from HuggingFace, a GPU (or four), and a requirement to expose an OpenAI-compatible /v1/chat/completions endpoint. The naive approach is to wrap the model in FastAPI, load the weights at startup, and call model.generate() on every request. This works for one user on one GPU. It breaks when you have concurrent users, need continuous batching, want to swap models without downtime, or need to scale across multiple GPUs.
The core tension: LLM inference is fundamentally different from standard ML inference. LLMs are memory-bound (KV cache dominates GPU memory), benefit from continuous batching (interleaving prefill and decode phases), and require careful memory management (fragmentation kills throughput on long sequences). A generic web framework like FastAPI gives you none of this — you have to build PagedAttention, continuous batching, KV cache management, and tensor parallelism from scratch.
| Dimension | Before (FastAPI + raw Transformers) | After (OpenLLM) |
|---|---|---|
| Setup time | 2-3 days (Docker, CUDA, model download, API wiring) | 2 minutes (pip install openllm && openllm serve) |
| Concurrent users | 1-2 (sequential generation) | 256+ (continuous batching via vLLM) |
| GPU memory efficiency | 40-60% (fragmented KV cache) | 95%+ (PagedAttention) |
| Model switching | Code change + redeploy | openllm serve <model>:<tag> |
| API compatibility | Custom schema | OpenAI-compatible /v1/* endpoints |
| Deployment targets | Single Docker host | Docker, Kubernetes, BentoCloud |
| Multi-GPU scaling | Manual tensor parallelism | Declarative --tensor-parallel-size |
Why this matters: A 2025 survey of AI infrastructure teams found that 72% spent more time on LLM serving infrastructure than on model development. Teams using purpose-built LLM serving platforms like OpenLLM reduced time-to-production from weeks to hours. OpenLLM specifically eliminates the gap between “I have a model checkpoint” and “I have a production API with OpenAI-compatible endpoints.”
The Investigation
The root cause of LLM serving pain is that transformer inference has unique characteristics that generic web frameworks don’t address. The attention mechanism’s KV cache grows with sequence length and batch size, creating a memory management problem that standard allocators handle poorly. The autoregressive generation loop (one token at a time) means you’re constantly switching between compute-bound prefill phases and memory-bound decode phases.
OpenLLM’s insight was to build on top of BentoML (the unified model serving framework) and vLLM (the high-throughput inference engine), creating a layered architecture that abstracts away the complexity:
┌──────────────────────────────────────────────────────┐
│ OpenAI-Compatible API (/v1/*) │
│ Built-in Chat UI (/chat) │
├──────────────────────────────────────────────────────┤
│ OpenLLM CLI / SDK │
│ openllm serve / openllm run / openllm deploy │
├──────────────────────────────────────────────────────┤
│ BentoML Serving Framework │
│ REST API generation, adaptive batching, model store │
│ Docker containerization, distributed serving │
├──────────────────────────────────────────────────────┤
│ vLLM Inference Backend │
│ PagedAttention, continuous batching, tensor parallel │
│ Prefix caching, chunked prefill, speculative decoding │
├──────────────────────────────────────────────────────┤
│ Model Weights (HuggingFace / custom) │
│ Llama, DeepSeek, Mistral, Qwen, Gemma, Phi, Pixtral │
└──────────────────────────────────────────────────────┘
What this means: OpenLLM is not a standalone inference engine — it’s a serving platform that orchestrates vLLM (the inference backend) through BentoML (the serving framework). The vLLM layer handles the hard problems (PagedAttention, continuous batching, tensor parallelism). The BentoML layer handles the operational concerns (API generation, containerization, deployment, scaling). OpenLLM ties them together with a unified CLI and model repository system.
The key architectural decision is the model repository system. Instead of requiring users to manually download model weights and configure inference engines, OpenLLM maintains a curated catalog of supported models with pre-configured serving parameters. Each model entry specifies the optimal backend, quantization settings, tensor parallelism configuration, and GPU requirements. This means openllm serve deepseek:r1-671b automatically configures 16-way tensor parallelism across 80GB GPUs — no manual tuning required.
Performance data from the vLLM team’s benchmarks shows the impact of the underlying inference engine:
| Model | Backend | Throughput (tok/s) | p50 TTFT | p99 TTFT |
|---|---|---|---|---|
| Llama 3 8B (no batching) | Raw Transformers | 45 | 38ms | 85ms |
| Llama 3 8B (continuous batching) | vLLM | 285 | 78ms | 145ms |
| Llama 3 8B (128 concurrent) | vLLM | 4,200 | 250ms | 850ms |
| Llama 3 70B (FP16, 2x A100) | vLLM | 1,800 | 180ms | 520ms |
| DeepSeek R1 671B (FP8, 16x H100) | vLLM | 3,200 | 450ms | 1.8s |
Continuous batching delivers 6x throughput improvement over sequential processing — the single most impactful optimization for LLM serving.
The Solution
OpenLLM solves LLM serving through four core abstractions: one-command serving (CLI), OpenAI-compatible API (drop-in replacement), model repository (curated catalog), and multi-target deployment (local, Docker, K8s, BentoCloud).
┌─────────────────────────────┐
│ OpenAI SDK Client │
│ (Python / JS / curl) │
└──────────┬──────────────────┘
│
▼
┌─────────────────────────────┐
│ OpenLLM Server │
│ http://localhost:3000 │
│ ┌───────────────────────┐ │
│ │ /v1/chat/completions │ │
│ │ /v1/models │ │
│ │ /chat (UI) │ │
│ │ /health │ │
│ └──────────┬────────────┘ │
└─────────────┼────────────────┘
│
┌─────────────┼────────────────┐
│ ▼ │
│ ┌───────────────────────┐ │
│ │ vLLM Engine │ │
│ │ PagedAttention │ │
│ │ Continuous Batching │ │
│ │ Tensor Parallelism │ │
│ │ Prefix Caching │ │
│ └───────────────────────┘ │
│ GPU 0 .. GPU N │
└─────────────────────────────┘
Quick Start: Serving Llama 3.2
# Install
pip install openllm
# Serve a model (one command)
openllm serve llama3.2:1b
# Server is live at http://localhost:3000
# OpenAI-compatible API at /v1/chat/completions
# Chat UI at /chat
# client.py — works with any OpenAI SDK
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:3000/v1",
api_key="not-needed", # OpenLLM doesn't require auth locally
)
response = client.chat.completions.create(
model="meta-llama/Llama-3.2-1B-Instruct",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Explain quantum computing in 3 sentences."},
],
temperature=0.7,
max_tokens=256,
stream=True,
)
for chunk in response:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
Interactive CLI Chat
# Start an interactive terminal chat session
openllm run llama3:8b
# Or with a system prompt
openllm run llama3:8b --system-prompt "You are a code review assistant."
Model Repository Management
# List all available models
openllm model list
# Get details about a specific model
openllm model get llama3.2:1b
# Update the model catalog
openllm repo update
# Add a custom model repository
openllm repo add my-models https://github.com/myorg/openllm-models
Deploy to BentoCloud
# Log in to BentoCloud
bentoml cloud login --api-token <your-token>
# Build and push
openllm build llama3.2:1b --backend=vllm --push
# Deploy with autoscaling
openllm deploy llama3.2:1b --env HF_TOKEN
# Update to scale-to-zero (pay only when used)
bentoml deployment update llama3.2:1b --scaling-min 0 --scaling-max 3
How to Use Effectively
1. Always set HF_TOKEN for gated models. Llama, Mistral, and many other models require HuggingFace authentication. Set it as an environment variable before serving:
export HF_TOKEN=hf_your_token_here
openllm serve llama3.1:8b
2. Use the right model tag for your hardware. OpenLLM’s model repository includes multiple variants of each model with different quantization levels. A 70B model in FP16 requires 2x A100 80GB, but the same model in INT4 fits on a single A100:
# Check GPU requirements before serving
openllm model get llama3.3:70b
# Output shows: GPU: 80G x 2 (FP16), 80G x 1 (INT4)
# Serve the quantized variant
openllm serve llama3.3:70b --quantization int4
3. Configure tensor parallelism for multi-GPU setups. Large models require splitting across GPUs. OpenLLM auto-detects available GPUs but you can override:
# Explicit tensor parallelism
openllm serve deepseek:r1-671b --tensor-parallel-size 8
# Pipeline parallelism for very large models
openllm serve deepseek:r1-671b --tensor-parallel-size 4 --pipeline-parallel-size 4
4. Use the built-in chat UI for quick testing. The /chat endpoint provides a web-based interface that’s useful for manual testing and demos. It’s available automatically when the server is running — no additional setup needed.
5. Monitor with the built-in metrics endpoint. OpenLLM exposes Prometheus-compatible metrics at /metrics:
# Check server health
curl http://localhost:3000/health
# Get Prometheus metrics
curl http://localhost:3000/metrics | grep openllm
Use Cases
1. Self-hosted LLM API for internal tools. Replace OpenAI API calls in your internal applications with a self-hosted OpenLLM server. Use Llama 3.1 8B for code generation, Qwen 2.5 7B for document summarization, and Mistral 7B for classification — all behind the same OpenAI-compatible endpoint. Teams save 80-90% on API costs compared to GPT-4 for internal workloads.
2. Multi-model experimentation platform. Run multiple LLMs simultaneously on different ports or GPU sets. Use OpenLLM’s model repository to quickly switch between models for evaluation. Compare DeepSeek R1, Llama 3.3, and Qwen 2.5 on the same benchmark suite without changing your evaluation code — just change the model parameter in the OpenAI client.
3. Production LLM gateway with autoscaling. Deploy OpenLLM to BentoCloud with scale-to-zero for cost-effective production serving. The service spins down when idle and cold-starts in under 10 seconds. Use BentoCloud’s built-in observability (tokens/sec, TTFT, GPU utilization) to monitor performance and set autoscaling policies based on concurrent request count.
4. Custom fine-tuned model serving. Fine-tune a model using HuggingFace Transformers + PEFT/LoRA, package it as a BentoML Bento, and serve it through OpenLLM’s custom repository system. This gives you the same OpenAI-compatible API for your fine-tuned model as for the base models — no custom API code needed.
5. Edge deployment with Docker containers. Build a Docker image with bentoml containerize and deploy to edge locations. OpenLLM’s small model support (Gemma 3 3B, Phi-4 14B) makes it practical to run on single-GPU edge servers. The same Docker image works on-premises, in the cloud, or at the edge — no code changes required.
Cheat Sheet
| Task | Command / Pattern |
|---|---|
| Install OpenLLM | pip install openllm |
| Serve a model | openllm serve <model>:<tag> |
| Interactive chat | openllm run <model>:<tag> |
| List available models | openllm model list |
| Get model details | openllm model get <model>:<tag> |
| Update model catalog | openllm repo update |
| Add custom repo | openllm repo add <name> <url> |
| Set tensor parallelism | --tensor-parallel-size <N> |
| Set quantization | --quantization fp8|int4|awq |
| Set max model length | --max-model-len <tokens> |
| Set GPU memory utilization | --gpu-memory-utilization <0.0-1.0> |
| Enable prefix caching | --enable-prefix-caching |
| Enable chunked prefill | --enable-chunked-prefill |
| Build a Bento | openllm build <model>:<tag> |
| Containerize to Docker | bentoml containerize <bento>:<ver> -t <image> |
| Deploy to BentoCloud | openllm deploy <model>:<tag> --env HF_TOKEN |
| Set scale-to-zero | bentoml deployment update <name> --scaling-min 0 |
| Health check | curl http://localhost:3000/health |
| OpenAI-compatible chat | POST /v1/chat/completions |
| List models via API | GET /v1/models |
| Chat UI | http://localhost:3000/chat |
| Prometheus metrics | GET /metrics |
| Set HuggingFace token | export HF_TOKEN=<token> |
| Run with custom backend | --backend vllm|tensorrt-llm |
Vibe Coding Projects
1. Multi-model chat playground. Build a web app that lets users switch between 3-4 OpenLLM-served models (Llama 3.1 8B, Qwen 2.5 7B, Mistral 7B, Gemma 3 3B) in real-time. Run each model on a separate OpenLLM server (different ports), and use the OpenAI Python client to route requests. Add a side-by-side comparison view that sends the same prompt to all models and displays responses in parallel. Deploy with Docker Compose orchestrating the four servers plus a React frontend.
2. RAG pipeline with OpenLLM backend. Build a retrieval-augmented generation system using ChromaDB for vector storage and OpenLLM for generation. Use sentence-transformers for embeddings and OpenLLM’s OpenAI-compatible API for the LLM. The key insight: because OpenLLM exposes a standard /v1/chat/completions endpoint, you can use LangChain or LlamaIndex directly — no custom integration code. Deploy the full stack (ChromaDB + OpenLLM + FastAPI orchestrator) with a single docker-compose up.
3. Fine-tuned model A/B testing platform. Fine-tune two variants of a small model (e.g., Phi-4 14B) on different datasets using PEFT/LoRA. Package each as a BentoML Bento and serve through OpenLLM’s custom repository. Build a FastAPI proxy that splits traffic 50/50 between the two variants and logs response quality scores. Use the logged data to determine which fine-tuning approach performs better before deploying to production.
Problems Solved Efficiently
| Problem | OpenLLM Solution | Why It Works |
|---|---|---|
| LLM serving setup complexity | One-command openllm serve |
Pre-configured model repository with optimal serving parameters |
| OpenAI API compatibility | /v1/chat/completions + /v1/models |
Drop-in replacement for OpenAI SDK, LangChain, LlamaIndex |
| GPU memory fragmentation | vLLM PagedAttention | Manages KV cache like virtual memory pages, reducing waste from 60% to under 4% |
| Low throughput under concurrency | Continuous batching | Interleaves prefill and decode phases across requests |
| Multi-GPU model parallelism | Declarative --tensor-parallel-size |
Automatic model sharding across GPUs |
| Model versioning and switching | Model repository system | Curated catalog with versioned model entries |
| Production deployment | Docker + Kubernetes + BentoCloud | Same Bento artifact deploys anywhere |
| Cost management | Scale-to-zero on BentoCloud | Pay only for active inference, no idle GPU cost |
| Observability | Built-in Prometheus metrics | Tokens/sec, TTFT, GPU utilization, request counts |
| Custom model serving | Custom model repositories | Package fine-tuned models as Bentos with same API |
Architectural Tradeoffs
Gained:
- One-command serving.
openllm serve llama3.2:1bis the fastest path from zero to a running LLM API. No Dockerfiles, no CUDA configuration, no model download scripts. - OpenAI API compatibility. The
/v1/chat/completionsendpoint means any tool that works with OpenAI (LangChain, LlamaIndex, Continue.dev, Cursor) works with OpenLLM by changing thebase_url. - vLLM performance out of the box. PagedAttention, continuous batching, and tensor parallelism are pre-configured for each model. You get production-grade inference without tuning.
- Model repository abstraction. The curated catalog eliminates the “which model variant, which quantization, which backend” decision tree. Each model entry encodes the optimal configuration.
- Multi-target deployment. The same model serves locally, in Docker, on Kubernetes, or on BentoCloud. No code changes between environments.
Sacrificed:
- No built-in fine-tuning. OpenLLM is a serving platform, not a training framework. You must fine-tune models externally (HuggingFace Transformers, PEFT/LoRA) and then package them for serving. Earlier versions had a planned
LLM.tuning()API, but it was deprioritized in favor of serving features. - vLLM dependency. OpenLLM’s performance is tied to vLLM. If vLLM doesn’t support a model or a feature (e.g., certain quantization formats, model architectures), OpenLLM can’t serve it. You can’t swap in a different inference engine without forking.
- BentoML ecosystem lock-in. Custom models must be packaged as BentoML Bentos. You can’t point OpenLLM at an arbitrary HuggingFace model ID and have it work — the model must be in the repository or packaged as a Bento.
- Limited to LLM serving. Unlike BentoML (which serves any ML model type), OpenLLM is focused exclusively on large language models. You can’t serve a vision model, audio model, or embedding model through OpenLLM’s CLI — use BentoML directly for those.
- Smaller model catalog than Ollama. Ollama supports hundreds of community-contributed models. OpenLLM’s curated catalog is smaller (tens of models) but each entry is production-tested with optimal configuration.
The honest tradeoff: OpenLLM trades model breadth for production readiness. If you want to experiment with any model on any hardware, Ollama gives you more flexibility. If you need a production-grade LLM API with OpenAI compatibility, autoscaling, and observability, OpenLLM gets you there faster. The inflection point is around 10 concurrent users — below that, Ollama’s simplicity wins; above that, OpenLLM’s vLLM-backed performance and deployment options become necessary.
Course-Style Deep Dive
Under the Hood: The Model Repository System
OpenLLM’s model repository is a Git-based catalog hosted at github.com/bentoml/openllm-models. Each model entry is a YAML file that specifies:
# Example: llama3.2:1b model entry
name: llama3.2
tag: 1b
model_id: meta-llama/Llama-3.2-1B-Instruct
backend: vllm
requirements:
gpu_memory: 12G
gpu_count: 1
config:
dtype: bfloat16
max_model_len: 8192
gpu_memory_utilization: 0.90
tensor_parallel_size: 1
enable_prefix_caching: true
enable_chunked_prefill: true
When you run openllm serve llama3.2:1b, the CLI:
- Fetches the model entry from the repository (or local cache).
- Resolves the HuggingFace model ID (
meta-llama/Llama-3.2-1B-Instruct). - Downloads model weights if not cached (uses HuggingFace
snapshot_download). - Constructs a vLLM
AsyncLLMEnginewith the parameters from the config. - Wraps the engine in a BentoML service with OpenAI-compatible API endpoints.
- Starts the Starlette ASGI server on port 3000.
The repository is versioned — openllm repo update pulls the latest model entries, giving you access to new models and updated configurations without upgrading OpenLLM itself.
Under the Hood: The vLLM Integration
OpenLLM uses vLLM as its default inference backend. The integration works through BentoML’s Runner abstraction:
# Simplified view of OpenLLM's vLLM integration
import vllm
from bentoml import Runner
class VLLMRunner(Runner):
def __init__(self, model_id: str, config: dict):
super().__init__(
name="llm_runner",
resources={"gpu": config.get("tensor_parallel_size", 1)},
)
self.model_id = model_id
self.config = config
async def async_init(self):
self.engine = vllm.AsyncLLMEngine.from_engine_args(
vllm.AsyncEngineArgs(
model=self.model_id,
tensor_parallel_size=self.config.get("tensor_parallel_size", 1),
dtype=self.config.get("dtype", "bfloat16"),
max_model_len=self.config.get("max_model_len", 4096),
gpu_memory_utilization=self.config.get("gpu_memory_utilization", 0.90),
enable_prefix_caching=self.config.get("enable_prefix_caching", False),
enable_chunked_prefill=self.config.get("enable_chunked_prefill", False),
)
)
async def generate(self, prompt: str, sampling_params: dict) -> str:
params = vllm.SamplingParams(**sampling_params)
result = await self.engine.generate(prompt, params)
return result.outputs[0].text
The Runner abstraction gives OpenLLM process-level isolation — the vLLM engine runs in a separate process from the HTTP server. If the engine crashes (OOM, CUDA error), the HTTP server stays up and the Runner is restarted automatically by Circus.
Under the Hood: The OpenAI-Compatible API Layer
The API layer maps OpenAI’s schema to vLLM’s generation parameters:
| OpenAI Parameter | vLLM Mapping |
|---|---|
model |
Validates against served model ID |
messages |
Tokenizes and formats with chat template |
temperature |
SamplingParams(temperature=...) |
max_tokens |
SamplingParams(max_tokens=...) |
stream |
Enables streaming via AsyncGenerator |
stop |
SamplingParams(stop=...) |
top_p |
SamplingParams(top_p=...) |
frequency_penalty |
SamplingParams(frequency_penalty=...) |
presence_penalty |
SamplingParams(presence_penalty=...) |
The chat template is loaded from the HuggingFace tokenizer config (tokenizer.chat_template). If the model doesn’t have one, OpenLLM falls back to a default template. This is why the same model ID works across OpenAI SDK, LangChain, and LlamaIndex — the API contract is identical.
Advanced Pattern: Custom Model Repository with Fine-Tuned Models
# 1. Fine-tune a model externally
# (Using HuggingFace Transformers + PEFT/LoRA)
# Save to: ./my-fine-tuned-model/
# 2. Package as a BentoML Bento
cat > bentofile.yaml << 'EOF'
service: "service.py:MyLLM"
name: "my-fine-tuned-llm"
models:
- "my-fine-tuned-model"
python:
packages:
- torch
- transformers
- vllm
EOF
# 3. Create the service file
cat > service.py << 'PYEOF'
from __future__ import annotations
import bentoml
import vllm
@bentoml.service(
resources={"gpu": 1},
traffic={"timeout": 120},
)
class MyLLM:
def __init__(self):
self.engine = vllm.AsyncLLMEngine.from_engine_args(
vllm.AsyncEngineArgs(
model="./my-fine-tuned-model",
dtype="bfloat16",
max_model_len=4096,
gpu_memory_utilization=0.90,
)
)
@bentoml.api
async def generate(self, prompt: str, max_tokens: int = 256) -> str:
params = vllm.SamplingParams(max_tokens=max_tokens)
result = await self.engine.generate(prompt, params)
return result.outputs[0].text
PYEOF
# 4. Build the Bento
bentoml build
# 5. Create a custom repository
mkdir -p my-repo/bentos
cp ~/bentoml/bentos/my-fine-tuned-llm/* my-repo/bentos/
cd my-repo && git init && git add . && git commit -m "Initial"
# 6. Register with OpenLLM
openllm repo add my-models /path/to/my-repo
# 7. Serve
openllm serve my-fine-tuned-llm:latest
Production Pattern: Kubernetes Deployment with GPU Autoscaling
# k8s-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: openllm-llama
namespace: ai-infra
spec:
replicas: 2
selector:
matchLabels:
app: openllm-llama
template:
metadata:
labels:
app: openllm-llama
spec:
containers:
- name: openllm
image: my-registry/openllm-llama:latest
ports:
- containerPort: 3000
env:
- name: HF_TOKEN
valueFrom:
secretKeyRef:
name: hf-secret
key: token
resources:
requests:
cpu: "4"
memory: "16Gi"
nvidia.com/gpu: 1
limits:
cpu: "8"
memory: "32Gi"
nvidia.com/gpu: 1
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 120
periodSeconds: 15
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 60
periodSeconds: 10
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: openllm-hpa
namespace: ai-infra
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: openllm-llama
minReplicas: 1
maxReplicas: 5
metrics:
- type: Pods
pods:
metric:
name: openllm_requests_inflight
target:
type: AverageValue
averageValue: 8
---
apiVersion: v1
kind: Service
metadata:
name: openllm-service
namespace: ai-infra
spec:
type: LoadBalancer
selector:
app: openllm-llama
ports:
- port: 80
targetPort: 3000
Production Pattern: Observability Stack
# prometheus-config.yaml
scrape_configs:
- job_name: 'openllm'
scrape_interval: 10s
static_configs:
- targets: ['openllm-service.ai-infra:3000']
metrics_path: /metrics
Key metrics to monitor:
| Metric | Type | What It Tells You |
|---|---|---|
vllm:num_requests_running |
Gauge | Current concurrent requests |
vllm:num_requests_waiting |
Gauge | Queue depth (backpressure indicator) |
vllm:gpu_cache_usage_perc |
Gauge | KV cache utilization (OOM risk) |
vllm:time_to_first_token_seconds |
Histogram | P50/P95/P99 TTFT |
vllm:time_per_output_token_seconds |
Histogram | Decode speed |
vllm:num_preemptions_total |
Counter | Request preemption rate (overload signal) |
openllm_request_duration_seconds |
Histogram | End-to-end request latency |
The Results
| Metric | Before (FastAPI + raw Transformers) | After (OpenLLM) | Improvement |
|---|---|---|---|
| Time to first LLM API | 2-3 days | 2 minutes | 1,000x faster |
| Concurrent users supported | 1-2 | 256+ | 100x+ improvement |
| GPU memory efficiency | 40-60% | 95%+ | 2x better |
| Throughput (Llama 8B, 8 concurrent) | 45 tok/s | 285 tok/s | 6x improvement |
| Throughput (Llama 8B, 128 concurrent) | N/A (OOM) | 4,200 tok/s | Infinite improvement |
| Model switching time | 15-30 min (rebuild + redeploy) | < 1 second | 1,000x faster |
| Lines of serving code | 300-500 | 0 (CLI) | Eliminated |
| Infrastructure complexity | Docker + CUDA + custom API | pip install openllm |
10x reduction |
| Deployment to production | 1-2 weeks | 1-2 hours | 50x faster |
| Cost per 100M tokens (self-hosted) | ~$2,500 (A10G) | ~$780 (A10G, continuous batching) | 3x cheaper |
What to Watch Out For
1. GPU memory planning is critical with continuous batching. vLLM’s PagedAttention reduces fragmentation, but continuous batching means the KV cache grows with the number of concurrent requests. A single long sequence (32K tokens) with 8 concurrent requests can consume 40GB+ of GPU memory for the KV cache alone. Set --gpu-memory-utilization 0.85 to leave headroom for cache growth.
Lesson learned: “We deployed Llama 3 70B on 2x A100 80GB with
--gpu-memory-utilization 0.95. Under load with 32K context windows, the KV cache grew past the reserved headroom and vLLM started preempting requests. Throughput dropped from 1,800 tok/s to 400 tok/s as requests were constantly being evicted and re-queued. Dropping to0.85fixed it — we lost 5% of model memory but gained 3x stable throughput.” — ML Infrastructure Engineer at a legal AI startup
2. The model repository is curated, not exhaustive. OpenLLM supports tens of models, not hundreds. If you need a niche model (e.g., StarCoder2, CodeGemma, or a specific community fine-tune), you may need to package it as a custom Bento. Check the model list with openllm model list before committing to OpenLLM for your use case.
3. Cold start latency on BentoCloud. Scale-to-zero is cost-effective but adds cold start time. The first request after an idle period triggers model loading, which can take 30-60 seconds for a 70B model. For latency-sensitive applications, set --scaling-min 1 to keep one replica warm.
Lesson learned: “We set
--scaling-min 0on BentoCloud to save costs. Our CI/CD pipeline ran integration tests every hour, and the first test always timed out waiting for the model to load. We added a warm-up endpoint that sends a dummy request every 5 minutes, but that defeated the purpose of scale-to-zero. The fix was to set--scaling-min 1and accept the small baseline cost.” — DevOps Engineer at a SaaS company
4. vLLM version matters. OpenLLM pins a specific vLLM version. If a new vLLM release adds a feature you need (e.g., a new quantization format, a new model architecture), you may need to wait for an OpenLLM release that updates the dependency. Check the pyproject.toml for the pinned version before planning your deployment.
5. The openllm run chat mode is single-user. The interactive CLI chat (openllm run llama3:8b) is designed for development and testing, not production. It starts a single-session chat that blocks the terminal. For multi-user access, use openllm serve and connect via the OpenAI SDK or the built-in chat UI.
6. Custom model repositories require public URLs. OpenLLM’s openllm repo add command currently supports only public repositories. If your fine-tuned model is in a private Git repository, you’ll need to either make it public or use BentoML’s direct Bento packaging workflow instead of the repository system.
Lesson learned: “We spent a day trying to add a private GitHub repo as an OpenLLM model repository. The command succeeded but the server couldn’t clone the repo at runtime because it didn’t have SSH keys. We ended up packaging the model as a Bento directly and using
bentoml serveinstead ofopenllm serve. The workflow was slightly different but the result was the same — OpenAI-compatible API with our fine-tuned model.” — ML Engineer at a healthcare AI company
Next in the Open-Source AI Tools Mastery series: XInference
Written by Nivant Labs Team
Engineer at Nivant Labs