import modal from modal_backend.commentary import app model_volume = modal.Volume.from_name("f1-model-cache", create_if_missing=True) image = ( modal.Image.debian_slim(python_version="3.11") .pip_install( "torch==2.4.0", extra_index_url="https://download.pytorch.org/whl/cu121", ) .pip_install( "transformers==4.51.0", "accelerate>=0.30.0", "huggingface-hub>=0.22.0", "sentencepiece", ) .env({"HF_HOME": "/model-cache", "TRANSFORMERS_CACHE": "/model-cache"}) ) MODEL_ID = "nvidia/Llama-3.1-Nemotron-Nano-8B-v1" SYSTEM_PROMPT = """You are a senior F1 strategist with deep knowledge of historical races. The user will describe a real race and change one variable. Your task: 1. Briefly acknowledge the actual race outcome (1 sentence) 2. Reason through how the changed variable affects pit windows, undercut/overcut risk, tire deg, and track position (3–5 sentences) 3. Narrate the alternate outcome with specific lap numbers and position changes 4. Produce a plausible alternate final top-5 Be specific. Reference real team strategies and driver tendencies.""" def _load_model(): from transformers import AutoModelForCausalLM, AutoTokenizer import torch tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, trust_remote_code=True) model = AutoModelForCausalLM.from_pretrained( MODEL_ID, torch_dtype=torch.bfloat16, device_map="auto", trust_remote_code=True, ) model.eval() return model, tokenizer @app.function( image=image, gpu="A100", timeout=300, volumes={"/model-cache": model_volume}, secrets=[modal.Secret.from_name("hf-token")], ) def reason_strategy(prompt: str, warmup: bool = False) -> dict: import os import torch hf_token = os.environ.get("HF_TOKEN", "") if hf_token: from huggingface_hub import login login(token=hf_token) model, tokenizer = _load_model() if warmup: return {"status": "warm"} messages = [ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": prompt}, ] input_text = tokenizer.apply_chat_template( messages, tokenize=False, add_generation_prompt=True ) inputs = tokenizer(input_text, return_tensors="pt").to("cuda") with torch.no_grad(): output_ids = model.generate( **inputs, max_new_tokens=512, do_sample=True, temperature=0.7, top_p=0.9, pad_token_id=tokenizer.eos_token_id, ) new_tokens = output_ids[0][inputs["input_ids"].shape[-1]:] reasoning_chain = tokenizer.decode(new_tokens, skip_special_tokens=True).strip() return {"reasoning_chain": reasoning_chain} @app.local_entrypoint() def main(): sample_prompt = ( "Race: 2023 British Grand Prix\n" "Original outcome: Verstappen won from pole, Hamilton finished P4 after a late pit.\n" "User change: What if Hamilton had pitted 5 laps earlier on lap 30 for fresh mediums?" ) print("Running warmup...") result = reason_strategy.remote(prompt="", warmup=True) print(f"Warmup result: {result}") print("\nRunning strategy inference...") result = reason_strategy.remote(prompt=sample_prompt, warmup=False) reasoning = result.get("reasoning_chain", "") assert reasoning, "reasoning_chain is empty — inference failed" print(f"\nReasoning chain:\n{reasoning}")