Aarya2004
Deploy: sync hosted Space to local app (chat, document capture, Modal backends, pages, mobile/QR)
47b2a99 | """Modal deployment of the Quillwright Best-Stack brain (ADR-0009). | |
| ADR-0005: the hosted HF Space has no GPU, so real models reach it via an outbound | |
| HTTPS call to Modal. ADR-0009 locks the **Best Stack** brain as **Nemotron 3 Nano | |
| 30B-A3B** (31.6B total / 3.2B active, MoE) — genuinely better than the local 4B and | |
| too big for local Ollama, which is exactly why it lives on Modal. | |
| Served with **vLLM** using NVIDIA's documented FP8 + tool-calling recipe | |
| (https://docs.vllm.ai/projects/recipes/en/latest/NVIDIA/Nemotron-3-Nano-30B-A3B.html). | |
| vLLM exposes an OpenAI-compatible API, so the client (`backends/modal.py`) talks | |
| /v1/chat/completions and adapts the tool_calls shape back to our contract. | |
| De-risk scope (ADR-0005): the BRAIN only. Vision (Omni) + multilingual copy this | |
| pattern once it's proven. | |
| Deploy (you run these — they touch your Modal account + credits): | |
| modal setup # one-time auth | |
| modal deploy quillwright/backends/modal_app.py | |
| Then point the app at the printed URL: | |
| export FF_BACKEND=modal | |
| export FF_MODAL_BRAIN_URL="https://<...>.modal.run" | |
| """ | |
| import modal | |
| MODEL = "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-FP8" # ADR-0009 Best-Stack brain, FP8 (~32GB). | |
| VLLM_PORT = 8000 | |
| image = ( | |
| # CUDA *devel* base (includes nvcc): FlashInfer's FP8 MoE kernel JIT-compiles at | |
| # runtime, so debian_slim (no nvcc) crashes engine init. This matches torch's cu12. | |
| modal.Image.from_registry("nvidia/cuda:12.8.1-devel-ubuntu22.04", add_python="3.12") | |
| .pip_install("vllm==0.12.0", "huggingface_hub", "flashinfer-python") | |
| # Fetch NVIDIA's custom reasoning-parser plugin via huggingface_hub. | |
| .run_commands( | |
| 'python -c "' | |
| "from huggingface_hub import hf_hub_download; import shutil; " | |
| "p = hf_hub_download(" | |
| "repo_id='nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16', " | |
| "filename='nano_v3_reasoning_parser.py'); " | |
| "shutil.copy(p, '/root/nano_v3_reasoning_parser.py')\"" | |
| ) | |
| .env( | |
| { | |
| # FP8 MoE acceleration (FP8 variant only), per NVIDIA's recipe. | |
| "VLLM_USE_FLASHINFER_MOE_FP8": "1", | |
| "VLLM_FLASHINFER_MOE_BACKEND": "throughput", | |
| # Download weights into the mounted cache volume (NOT ~/.cache, which the | |
| # build populates — Modal refuses to mount a volume over a non-empty dir). | |
| "HF_HOME": "/cache", | |
| } | |
| ) | |
| ) | |
| # Cache the downloaded weights across cold starts (pull once, not every boot). | |
| hf_cache = modal.Volume.from_name("quillwright-hf-cache", create_if_missing=True) | |
| app = modal.App("quillwright-brain") | |
| def serve(): | |
| """Launch vLLM's OpenAI-compatible server with NVIDIA's tool-calling recipe.""" | |
| import subprocess | |
| cmd = [ | |
| "vllm", | |
| "serve", | |
| MODEL, | |
| "--trust-remote-code", | |
| "--async-scheduling", | |
| "--kv-cache-dtype", | |
| "fp8", | |
| "--tensor-parallel-size", | |
| "1", | |
| "--enable-auto-tool-choice", | |
| "--tool-call-parser", | |
| "qwen3_coder", # the parser NVIDIA specifies for this model. | |
| "--reasoning-parser-plugin", | |
| "/root/nano_v3_reasoning_parser.py", | |
| "--reasoning-parser", | |
| "nano_v3", | |
| "--max-model-len", | |
| "262144", | |
| "--max-num-seqs", | |
| "8", | |
| "--port", | |
| str(VLLM_PORT), | |
| "--host", | |
| "0.0.0.0", | |
| ] | |
| subprocess.Popen(" ".join(cmd), shell=True) | |