runpod: warn loudly before a 150 GB model is put on a rented card

Everything around pods is tuned for images of ~10 GB and models of a few. The
native MoE engines are a different shape: DeepSeek-V4 is ~154 GB and they go
well past that, so a pod spends one to two hours filling its disk before it
answers anything — on EVERY cold start, since a pod is disposable storage.

The warning names the model, the size, and the fix: attach a network volume so
the weights are fetched once and every later pod attaches to them instead. It
appears at provision time, boxed so it cannot be missed in a log, and in the
test run — which is where someone looks BEFORE committing to a configuration,
while at provision time the money is already being spent.

It says nothing when a volume is attached, and nothing for ordinary models.
Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
parent 1460b575
......@@ -339,6 +339,9 @@ async def test_model(req: ModelTestRequest, request: Request,
# a failure means reading engine logs to find the pod URL and asking it by
# hand — which is how the last three failures were diagnosed.
out["pods"] = _pod_diagnostics()
warn = _weight_warning(req.model, entry)
if warn:
out["warning"] = warn
if out["ok"]:
out["sample"] = _sample(raw, capability)
empty = _empty_result(raw, capability)
......@@ -468,6 +471,24 @@ def _no_remote_reason(model: str, entry: dict, capability: str) -> str:
f"its {capability} capability")
def _weight_warning(model: str, entry: dict) -> str:
"""The 'this downloads 150 GB every cold boot' warning, if it applies.
Said here as well as at provision time: by the time a pod is booting the
money is already being spent, and a test run is where someone looks BEFORE
committing to a configuration.
"""
try:
from codai.api.runpod_worker import (weight_transfer_warning,
parse_model_runpod)
block = (entry or {}).get("runpod")
if not isinstance(block, dict):
return ""
return weight_transfer_warning(entry, parse_model_runpod(block))
except Exception:
return ""
def _pod_diagnostics() -> list:
"""Live pods and what each is serving, for the answer to stand on its own."""
try:
......
......@@ -487,6 +487,40 @@ def _add_staging(plan: dict, mcfg: "RunpodModelConfig", entry: dict, engine: str
print(f"[runpod] pod will download before serving: {names}", flush=True)
#: Engines that serve frontier-size mixture-of-experts models. Their weights are
#: not "large" in the way a diffusion model is large — DeepSeek-V4 is ~154 GB and
#: they go well past that — so a pod that downloads them pays an hour or two of
#: rental before it answers anything, every cold start.
_HUGE_WEIGHT_ENGINES = ("colibri", "ds4", "k3", "ktransformers")
def weight_transfer_warning(entry: dict, mcfg: "RunpodModelConfig",
account=None) -> str:
"""A warning to show prominently, or '' when there is nothing to warn about.
The cost of these models is the DOWNLOAD, not the GPU: the machinery around
it (price ranking, idle reaping, spend caps) is tuned for images of ~10 GB
and models of a few. Renting a card and then spending ninety minutes filling
its disk is a different shape of expensive, and it should never be a
surprise — so it is said at configuration time, at provision time, and in
the test run.
"""
engine = str(getattr(mcfg, "engine", "") or "").strip().lower()
backend = str((entry or {}).get("backend") or "").strip().lower()
if engine not in _HUGE_WEIGHT_ENGINES and backend not in _HUGE_WEIGHT_ENGINES:
return ""
vol, _mount = volume_for(mcfg, account)
if vol:
return ""
name = str((entry or {}).get("path") or "this model")
return (f"{name} runs on a {engine or backend} engine, whose models are "
f"100 GB and up — DeepSeek-V4 alone is ~154 GB. With no network "
f"volume configured, EVERY cold pod downloads all of it before it "
f"can answer, which is typically one to two hours of rental per "
f"boot. Attach a network volume (network_volume_id) so the weights "
f"are fetched once and every later pod attaches to them instead.")
def volume_for(mcfg: "RunpodModelConfig", account) -> tuple:
"""(volume_id, mount_path) for this pool, or ('', '')."""
vol = (getattr(mcfg, "network_volume_id", "") or "").strip() \
......@@ -1499,6 +1533,13 @@ class RunpodPodPool:
# …and from every SIBLING engine's reaper, which cannot see the set
# above: each engine has its own pools and its own reaper.
register_pod(pod_id, str(self.model_key), api_key=self.api_key) # url once ready
_warn = weight_transfer_warning(entry, self.mcfg, self.account)
if _warn:
print("[runpod] " + "!" * 68, flush=True)
for _line in _warn.split(". "):
if _line.strip():
print(f"[runpod] !! {_line.strip().rstrip('.')}.", flush=True)
print("[runpod] " + "!" * 68, flush=True)
print(f"[runpod] pod {pod_id} created for {self.model_key!r} "
f"({sel['display_name']} {sel['cloud_type']}) — booting; logs: {console}",
flush=True)
......
......@@ -678,3 +678,25 @@ def test_a_pod_is_told_where_its_baked_venvs_are():
env = pod_plan(mcfg, "ocr", entry={"path": "surya",
"model_type": "ocr_models"})["env"]
assert env["CODERAI_OCR_SURYA_VENV"] == "/usr/local"
def test_a_150gb_model_warns_before_anyone_rents_a_card():
"""The machinery around pods is tuned for ~10 GB images and models of a
few. A frontier MoE model is 100 GB and up — DeepSeek-V4 alone is ~154 GB —
so a pod spends an hour or two filling its disk before it answers anything,
on every cold start. That must never be a surprise."""
from codai.api.runpod_worker import weight_transfer_warning, parse_model_runpod
for engine in ("colibri", "ds4", "k3", "ktransformers"):
warn = weight_transfer_warning({"path": "big/model"},
parse_model_runpod({"engine": engine}))
assert "network volume" in warn and "cold pod" in warn, engine
# A volume is the fix, so the warning goes away when one is attached.
assert weight_transfer_warning(
{"path": "big/model"},
parse_model_runpod({"engine": "ds4", "network_volume_id": "vol-1"})) == ""
# And an ordinary capability model says nothing at all.
assert weight_transfer_warning(
{"path": "bge-m3"}, parse_model_runpod({"engine": "coderai"})) == ""
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment