sasukeUchiha123 commited on
Commit
2e73062
Β·
verified Β·
1 Parent(s): fcc6866

Upload README.md with huggingface_hub

Browse files
Files changed (1) hide show
  1. README.md +516 -10
README.md CHANGED
@@ -1,20 +1,526 @@
1
  ---
2
- title: Gpu Goblin
3
- emoji: πŸš€
4
  colorFrom: red
5
  colorTo: red
6
  sdk: docker
7
- app_port: 8501
8
- tags:
9
- - streamlit
10
  pinned: false
11
- short_description: AI agent that hunts wasted compute on AMD MI300X
12
  license: mit
 
 
 
 
 
 
 
 
 
 
 
 
13
  ---
14
 
15
- # Welcome to Streamlit!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
- Edit `/src/streamlit_app.py` to customize this app to your heart's desire. :heart:
18
 
19
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
20
- forums](https://discuss.streamlit.io).
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: GPU Goblin
3
+ emoji: 🧌
4
  colorFrom: red
5
  colorTo: red
6
  sdk: docker
7
+ app_port: 7860
 
 
8
  pinned: false
 
9
  license: mit
10
+ short_description: Qwen agent that hunts wasted compute on AMD MI300X.
11
+ tags:
12
+ - amd
13
+ - amd-hackathon-2026
14
+ - mi300x
15
+ - rocm
16
+ - qwen
17
+ - vllm
18
+ - huggingface
19
+ - agent
20
+ - fine-tuning
21
+ - llm
22
  ---
23
 
24
+ # GPU Goblin
25
+
26
+ > An AI agent that hunts wasted compute on AMD MI300X. Powered by Qwen.
27
+
28
+ GPU Goblin profiles a fine-tuning run, diagnoses inefficiency against a
29
+ curated ROCm knowledge base, recommends MI300X-specific fixes, and
30
+ re-benchmarks to prove the speedup with real numbers. The agent itself runs
31
+ on a Qwen model via Hugging Face Inference Providers; the canonical demo
32
+ workload is `Qwen/Qwen2.5-7B-Instruct` LoRA fine-tuning on MI300X.
33
+
34
+ Submitted to the **AMD Developer Hackathon**, Track 1: AI Agents & Agentic
35
+ Workflows. Incorporates the Qwen Technology Partner challenge (Qwen as both
36
+ agent brain and audit target) and uses Hugging Face as the model hub +
37
+ deployment layer.
38
+
39
+ See [`brainstorming/idea.md`](brainstorming/idea.md),
40
+ [`brainstorming/architecture.md`](brainstorming/architecture.md), and
41
+ [`brainstorming/goals.md`](brainstorming/goals.md).
42
+
43
+ ## Quick Start
44
+
45
+ ```bash
46
+ pip install -e ".[dev]"
47
+
48
+ # Required for the live agent loop:
49
+ export HF_TOKEN=hf_... # Hugging Face Inference token
50
+
51
+ # Optional β€” override the default Qwen model / provider:
52
+ # export GOBLIN_QWEN_MODEL=Qwen/Qwen2.5-7B-Instruct
53
+ # export GOBLIN_QWEN_PROVIDER=auto # or together / fireworks-ai / nebius / ...
54
+
55
+ uvicorn agent.server:app --reload --port 8000
56
+ streamlit run ui/app.py
57
+ ```
58
+
59
+ The Streamlit UI works **without `HF_TOKEN`** in offline-replay mode β€” it
60
+ plays a cached audit trajectory (`tests/fixtures/cached_audit.json`) so
61
+ judges can see the canonical `142 β†’ 318 tok/s (2.24Γ—)` demo without our
62
+ backend or any live LLM.
63
+
64
+ ## Repo Layout
65
+
66
+ ```
67
+ agent/
68
+ schemas.py # Shared pydantic models (RunMetrics, WorkloadConfig, ...)
69
+ backends/ # Pluggable LLM driver (Qwen via HF Inference Providers)
70
+ tools/ # 6 tools the agent can call
71
+ loop.py # Provider-agnostic tool-use loop
72
+ server.py # FastAPI + SSE
73
+ runner/ # GPU runner (rocprofv3 wrapper) + FakeRunner fallback
74
+ kb/ # ROCm knowledge base (22 curated rules, the moat)
75
+ ui/ # Streamlit chat UI
76
+ workloads/ # Canonical Qwen demo + synthetic corpus
77
+ tests/ # Pytest suite + fixtures
78
+ brainstorming/ # Design docs (idea / architecture / goals)
79
+ ```
80
+
81
+ ## Development
82
+
83
+ The agent loop is testable on a laptop without an MI300X via the `FakeRunner`
84
+ and the synthetic corpus in `workloads/synthetic/`. Real benchmarks require
85
+ ROCm + MI300X (the `LiveRunner` auto-falls-back to `FakeRunner` when
86
+ `rocprofv3` / `amd-smi` / a render device are missing).
87
+
88
+ ```bash
89
+ python3 -m pytest tests/ -v # 86 tests, no GPU required
90
+ python3 -m agent workloads/train_qwen_lora.py # CLI driver, prints SSE events
91
+ ```
92
+
93
+ ## Running on AMD Developer Cloud (MI300X)
94
+
95
+ End-to-end recipe for the live demo path. Assumes you've got the $100 hackathon
96
+ credits. Plan on ~10-15 GPU-hours total (well under budget).
97
+
98
+ ### 1. Provision an MI300X instance
99
+
100
+ 1. Sign in to [AMD AI Developer Program](https://www.amd.com/en/developer/resources/developer-program.html)
101
+ and join the AMD Developer Cloud waitlist (instant approval for hackathon
102
+ participants).
103
+ 2. Spin up an **MI300X** instance. Pick the largest container disk you can
104
+ (the model weights cache is 15-30 GB).
105
+ 3. SSH in. You should land in a Linux shell with a `/dev/dri/renderD*`
106
+ device visible β€” confirm with `ls /dev/dri`.
107
+
108
+ ### 2. Pull the ROCm + PyTorch container
109
+
110
+ ```bash
111
+ docker pull rocm/pytorch:rocm6.1_ubuntu22.04_py3.10_pytorch_2.3
112
+ ```
113
+
114
+ Run it with the GPU exposed. The `--device` / `--group-add video` lines are
115
+ the only ones that matter for ROCm passthrough:
116
+
117
+ ```bash
118
+ docker run -it --rm \
119
+ --device=/dev/kfd --device=/dev/dri \
120
+ --group-add video --ipc=host --shm-size=16g \
121
+ -v $HOME:/workspace \
122
+ -e HF_TOKEN=$HF_TOKEN \
123
+ -e GOBLIN_QWEN_MODEL=Qwen/Qwen2.5-7B-Instruct \
124
+ -e ROCM_IMAGE_TAG=rocm6.1_pytorch2.3 \
125
+ -p 8000:8000 -p 8501:8501 \
126
+ rocm/pytorch:rocm6.1_ubuntu22.04_py3.10_pytorch_2.3 bash
127
+ ```
128
+
129
+ ### 3. Verify the GPU is visible inside the container
130
+
131
+ ```bash
132
+ amd-smi monitor # shows utilization, HBM, power per GPU
133
+ rocprofv3 --version # confirms the profiler is on PATH
134
+ python -c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))"
135
+ # β†’ True MI300X
136
+ ```
137
+
138
+ If any of these fail, `LiveRunner` will fall back to `FakeRunner` β€” the
139
+ agent loop still works, but you get cached metrics instead of a real
140
+ benchmark. Don't chase the bug; the demo lane is intact.
141
+
142
+ ### 4. Clone, install, run
143
+
144
+ ```bash
145
+ cd /workspace
146
+ git clone https://github.com/Manoj-Sri/amd-hackathon-rocm.git goblin
147
+ cd goblin
148
+
149
+ pip install -e ".[dev]"
150
+ python -m pytest tests/ -q # 86 tests pass without GPU; faster sanity check
151
+
152
+ # Live run on MI300X:
153
+ python -m agent workloads/train_qwen_lora.py
154
+ # Streams SSE events: thought, tool_call, tool_result, ..., final_report
155
+ ```
156
+
157
+ ### 5. Run the FastAPI server + UI
158
+
159
+ ```bash
160
+ # Terminal 1 (inside the container):
161
+ uvicorn agent.server:app --host 0.0.0.0 --port 8000
162
+
163
+ # Terminal 2:
164
+ streamlit run ui/app.py --server.port 8501 --server.address 0.0.0.0
165
+ ```
166
+
167
+ If the cloud instance gives you a public IP/URL, port-forward 8501 to your
168
+ laptop. If not, SSH-tunnel: `ssh -L 8501:localhost:8501 user@instance` β†’
169
+ open `http://localhost:8501` locally.
170
+
171
+ ### 6. Cost-control checklist
172
+
173
+ - Cache benchmark results (`bench_cache/` is content-addressed by config +
174
+ workload SHA + container tag, so identical configs are free).
175
+ - Day-1 baseline run is the only "must-burn-GPU" task; everything else can
176
+ use cached metrics or the FakeRunner.
177
+ - Stop the instance between work sessions. AMD Developer Cloud bills only
178
+ for running time.
179
+ - Public reference price: ~$1.99/GPU-hour for MI300X VMs. ~$8 of your $100
180
+ covers a full demo + dry-runs.
181
+
182
+ ## Integrating with HF Qwen
183
+
184
+ The agent runs on Qwen via Hugging Face **Inference Providers**, which
185
+ auto-routes your request to one of HF's serving partners (Together,
186
+ Fireworks-AI, Nebius, Replicate, ...). You do not run Qwen yourself β€” HF
187
+ does β€” and you authenticate with a single token.
188
+
189
+ ### 1. Get a Hugging Face token
190
+
191
+ 1. Sign up at [huggingface.co](https://huggingface.co/).
192
+ 2. Create a token at [Settings β†’ Access Tokens](https://huggingface.co/settings/tokens)
193
+ with **read** + **inference** scope.
194
+ 3. Export it:
195
+ ```bash
196
+ export HF_TOKEN=hf_yourtokenhere
197
+ ```
198
+
199
+ ### 2. Join the AMD Developer Hackathon HF Organization
200
+
201
+ The hackathon submission requires publishing your project as a Hugging Face
202
+ Space within the event organization. Click the "Join" link on the
203
+ [hackathon page](https://lablab.ai/ai-hackathons/amd-developer) (look for
204
+ "Join the AMD Developer Hackathon HF Organization") and accept the
205
+ invitation in your HF account.
206
+
207
+ ### 3. Confirm Qwen reachability
208
+
209
+ Before running the full agent, smoke-test the HF Inference connection:
210
+
211
+ ```bash
212
+ python - <<'PY'
213
+ import asyncio, os
214
+ from huggingface_hub import AsyncInferenceClient
215
+
216
+ async def go():
217
+ client = AsyncInferenceClient(token=os.environ["HF_TOKEN"])
218
+ resp = await client.chat_completion(
219
+ model="Qwen/Qwen2.5-7B-Instruct",
220
+ messages=[{"role": "user", "content": "Say hello in 5 words."}],
221
+ max_tokens=32,
222
+ )
223
+ print(resp.choices[0].message.content)
224
+
225
+ asyncio.run(go())
226
+ PY
227
+ ```
228
+
229
+ Expect a 1-line Qwen response. If you get an auth error, your token is
230
+ missing the `inference` scope. If you get a 404, the chosen model isn't
231
+ served by any active provider β€” try `Qwen/Qwen2.5-32B-Instruct` or set
232
+ `provider="together"` explicitly.
233
+
234
+ ### 4. Run the agent against Qwen
235
+
236
+ The agent picks Qwen automatically β€” no env var needed beyond `HF_TOKEN`:
237
+
238
+ ```bash
239
+ python -m agent workloads/train_qwen_lora.py
240
+ ```
241
+
242
+ You should see SSE events streaming: `thought` blocks from Qwen, `tool_call`
243
+ events as it picks tools, `tool_result` events, and finally a `final_report`
244
+ with the canonical `142 β†’ 318 tok/s (2.24Γ—)` line.
245
+
246
+ ### 5. Switching the model or provider
247
+
248
+ Qwen has many variants. Override at process start:
249
+
250
+ ```bash
251
+ # Bigger model, more reliable tool calls:
252
+ export GOBLIN_QWEN_MODEL=Qwen/Qwen2.5-32B-Instruct
253
+
254
+ # Pin to a specific provider (skip auto-routing):
255
+ export GOBLIN_QWEN_PROVIDER=together # or fireworks-ai / nebius / replicate
256
+ ```
257
+
258
+ `Qwen/Qwen2.5-7B-Instruct` (the default) is the sweet spot: ~14 GB at
259
+ bf16, fast, supports tool calls. Bump to `-32B-Instruct` if 7B starts
260
+ emitting malformed tool arguments mid-audit.
261
+
262
+ ### 6. Self-host Qwen on the same MI300X via vLLM (Path B)
263
+
264
+ The strongest "AMD-end-to-end" story: Qwen runs on the same MI300X that
265
+ GPU Goblin is auditing, served by vLLM behind an OpenAI-compatible
266
+ endpoint. Goblin already supports this β€” pick it with one env var. The
267
+ recipe below mirrors the [lablab vLLM-on-AMD-Developer-Cloud
268
+ tutorial](https://lablab.ai/ai-tutorials/amd-developer-cloud-host-llm-vllm).
269
+
270
+ #### 6a. Stand up vLLM on the MI300X
271
+
272
+ ```bash
273
+ # Inside your MI300X cloud instance (rocm/pytorch container or bare host).
274
+ # Pull AMD's official rocm/vllm image β€” has vLLM + ROCm + Qwen support baked in.
275
+ docker pull rocm/vllm:latest
276
+
277
+ # Run vLLM serving a Qwen tool-calling model. `--tool-call-parser hermes`
278
+ # is the critical flag β€” it tells vLLM to parse Qwen's Hermes-format
279
+ # <tool_call> tags into the OpenAI `tool_calls` shape the agent expects.
280
+ #
281
+ # Pick ONE of the model recipes below.
282
+
283
+ # (a) Qwen2.5-32B-Instruct β€” recommended for the AMD GPU path. ~64 GB at
284
+ # bf16 (well under MI300X's 192 GB). Tool calling is significantly
285
+ # more reliable than 7B and the 32K context fits any audit conversation
286
+ # comfortably. First run downloads ~64 GB, takes 5-10 minutes.
287
+ docker run -d --name qwen-vllm \
288
+ --device=/dev/kfd --device=/dev/dri --group-add video \
289
+ --ipc=host --shm-size=16g \
290
+ -p 8000:8000 \
291
+ -v $HOME/.cache/huggingface:/root/.cache/huggingface \
292
+ -e HF_TOKEN=$HF_TOKEN \
293
+ rocm/vllm:latest \
294
+ --model Qwen/Qwen2.5-32B-Instruct \
295
+ --dtype bfloat16 \
296
+ --max-model-len 32768 \
297
+ --gpu-memory-utilization 0.85 \
298
+ --enable-auto-tool-choice \
299
+ --tool-call-parser hermes
300
+
301
+ # (b) Qwen2.5-7B-Instruct β€” light/fast, fine for smoke tests, occasionally
302
+ # hallucinates rule ids on tool calls. Use --max-model-len 32768 (the
303
+ # model's native cap) to keep audits from exhausting context near the
304
+ # compare_runs step.
305
+ # docker run -d --name qwen-vllm \
306
+ # ...same flags as above except...
307
+ # --model Qwen/Qwen2.5-7B-Instruct \
308
+ # --max-model-len 32768 \
309
+ # ...
310
+
311
+ # Wait for "Application startup complete" in the logs, then verify:
312
+ docker logs -f qwen-vllm # ctrl-C once you see "Application startup complete"
313
+ curl http://localhost:8000/v1/models
314
+ # β†’ JSON listing the model id you served
315
+ ```
316
+
317
+ Sanity check tool calling end-to-end:
318
+ ```bash
319
+ curl -s http://localhost:8000/v1/chat/completions \
320
+ -H 'Content-Type: application/json' \
321
+ -d '{
322
+ "model": "Qwen/Qwen2.5-32B-Instruct",
323
+ "messages": [{"role": "user", "content": "Call get_weather for Paris."}],
324
+ "tools": [{"type":"function","function":{"name":"get_weather","description":"weather","parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}}],
325
+ "tool_choice": "auto"
326
+ }' | python3 -c "import sys,json;r=json.load(sys.stdin);print(r['choices'][0]['message'])"
327
+ ```
328
+ Expect a `tool_calls` array with `name=get_weather` and `arguments` mentioning Paris. If you get plain text instead, the `--tool-call-parser hermes` flag was dropped.
329
+
330
+ #### 6b. Point GPU Goblin at the local vLLM
331
+
332
+ ```bash
333
+ export GOBLIN_AGENT_BACKEND=qwen-vllm
334
+ export GOBLIN_QWEN_VLLM_URL=http://localhost:8000/v1
335
+ export GOBLIN_QWEN_VLLM_MODEL=Qwen/Qwen2.5-32B-Instruct # match the model you served
336
+ # Optional β€” only if you fronted vLLM with auth (default vLLM ignores the key):
337
+ # export GOBLIN_QWEN_VLLM_KEY=<your-token>
338
+
339
+ python -m agent workloads/train_qwen_lora.py
340
+ ```
341
+
342
+ Verify the agent picked up the right backend:
343
+ ```bash
344
+ curl http://localhost:8000/healthz # the Goblin server, not vLLM
345
+ # β†’ {"backend": "qwen-vllm", "vllm_url": "http://localhost:8000/v1", ...}
346
+ ```
347
+
348
+ That's it β€” the agent loop, the tools, the system prompt, the SSE
349
+ streaming, the offline-replay fallback all carry over unchanged. The
350
+ only thing that's different is which OpenAI-compatible endpoint
351
+ ``QwenVLLMBackend`` talks to.
352
+
353
+ #### 6c. Comparing the two backends
354
+
355
+ | Aspect | `qwen-hf` (default) | `qwen-vllm` |
356
+ |---|---|---|
357
+ | Auth | `HF_TOKEN` | none by default; optional `GOBLIN_QWEN_VLLM_KEY` |
358
+ | Compute | Together / Fireworks-AI / Nebius (HF routes) | Your MI300X |
359
+ | Latency | 200-500 ms / turn (network-bound) | 50-150 ms / turn (in-cluster) |
360
+ | Cost | HF Inference credits | Your AMD Developer Cloud GPU-hours |
361
+ | Demo story | "uses HF as the model hub" | "Qwen runs on the same MI300X it audits" |
362
+ | Setup time | 30 sec (just `HF_TOKEN`) | 2-3 min (model download + warmup) |
363
+ | Best for | HF Space deployment | Pitch demo on MI300X |
364
+
365
+ Run **both** during the hackathon: `qwen-hf` for the Space (judges who
366
+ click the URL get a real audit without an MI300X); `qwen-vllm` for the
367
+ live pitch demo (the strongest "all AMD" story the judging criterion
368
+ "How effectively the chosen model is integrated" rewards).
369
+
370
+ ## Deploying to Hugging Face Spaces
371
+
372
+ This repo is **already shaped to be a Hugging Face Space** β€” `README.md`
373
+ carries the YAML frontmatter HF needs, and `requirements.txt` at the root
374
+ is the deliberately-minimal Streamlit-only dependency set (no torch /
375
+ transformers / huggingface_hub at runtime). The deployed Space is the
376
+ **offline-replay lane**: judges interact with a Streamlit UI that streams
377
+ the canonical `142 β†’ 318 tok/s (2.24Γ—)` audit trajectory from
378
+ `tests/fixtures/cached_audit.json`, without a live LLM, without a backend,
379
+ and without our laptop. This is what satisfies the hackathon's "Demo
380
+ Application Platform + Application URL" submission fields.
381
+
382
+ ### One-time setup
383
+
384
+ 1. Create a Hugging Face account at [huggingface.co](https://huggingface.co/)
385
+ and join the **`lablab-ai-amd-developer-hackathon`** HF Organization
386
+ ([direct link](https://huggingface.co/lablab-ai-amd-developer-hackathon)).
387
+ The Space MUST live under that org for the hackathon Special Prize and
388
+ for the lablab submission to validate.
389
+ 2. Create a token at [Settings β†’ Access Tokens](https://huggingface.co/settings/tokens)
390
+ with **`write`** scope. Export it:
391
+ ```bash
392
+ export HF_TOKEN=hf_yourtokenhere
393
+ ```
394
+ 3. On the org's page, click **"New Space"**:
395
+ - **Owner:** `lablab-ai-amd-developer-hackathon`
396
+ - **Space name:** `gpu-goblin` (or your preferred slug)
397
+ - **License:** MIT
398
+ - **SDK:** **Streamlit**
399
+ - **Hardware:** **CPU basic** (free; the Space's offline-replay default
400
+ loads no GPU code path)
401
+ - **Visibility:** **Public** (required for the hackathon prize)
402
+ 4. Don't initialize the Space with anything β€” leave it empty so the first
403
+ push lands cleanly.
404
+
405
+ ### Deploy β€” Option A: scripted upload via `huggingface_hub` (recommended)
406
+
407
+ ```bash
408
+ export HF_TOKEN=hf_...
409
+ python scripts/deploy_to_hf_space.py --space-name gpu-goblin
410
+ ```
411
+
412
+ The script (`scripts/deploy_to_hf_space.py`) uses `HfApi.upload_file` to
413
+ push exactly the files the Space needs (README, requirements.txt, the
414
+ `agent/` package, `kb/`, `ui/`, the cached audit fixture, etc.) and
415
+ deliberately omits build artifacts like `bench_cache/` and
416
+ `__pycache__/` that would bloat the Space repo.
417
+
418
+ ### Deploy β€” Option B: git push (works but uploads everything tracked)
419
+
420
+ From the project root:
421
+
422
+ ```bash
423
+ # HTTPS remote β€” auth via your HF token (use the token as the password):
424
+ git remote add space https://huggingface.co/spaces/lablab-ai-amd-developer-hackathon/gpu-goblin
425
+
426
+ # HF Spaces use 'main' as the default branch:
427
+ git push space main
428
+ ```
429
+
430
+ You'll see a build log at
431
+ `https://huggingface.co/spaces/lablab-ai-amd-developer-hackathon/gpu-goblin`.
432
+ Cold-start takes 30-60 seconds (Streamlit + the pure-pydantic deps); once
433
+ up, the canonical demo trajectory replays in ~10 seconds when a judge
434
+ clicks **"Use sample workload"**.
435
+
436
+ ### What the Space looks like to judges
437
+
438
+ When a judge opens the Space URL:
439
+
440
+ 1. The lane toggle defaults to **Offline replay** β€” appropriate for the Space
441
+ since there's no MI300X behind it.
442
+ 2. They click **"Use sample workload"** (which references
443
+ `workloads/train_qwen_lora.py`).
444
+ 3. Streamlit attempts to reach `http://localhost:8000/audit`, fails with
445
+ `ConnectionError`, surfaces a one-line warning ("Backend unreachable β€”
446
+ running offline-replay demo from cached audit"), then plays the cached
447
+ audit trajectory event-by-event with `~0.4s` pauses between events.
448
+ 4. Final report renders: `Tokens/sec: 142 β†’ 318 (2.24Γ—)` with the
449
+ side-by-side metrics table, waste-budget bar chart, diff viewer, and
450
+ per-rule citations.
451
+
452
+ ### Updating the Space
453
+
454
+ After any change to the repo, redeploy with whichever flow you used initially:
455
+
456
+ ```bash
457
+ # Option A:
458
+ python scripts/deploy_to_hf_space.py --space-name gpu-goblin
459
+
460
+ # Option B:
461
+ git push space main
462
+ ```
463
+
464
+ HF rebuilds the Space automatically on every push/upload.
465
+
466
+ ### (Stretch) Live agent in the Space
467
+
468
+ The shipped Space defaults to offline-replay (no Space secrets needed).
469
+ For a live demo where judges drive a real Qwen agent, three options:
470
+
471
+ **Option 1 β€” In-process Qwen via HF Inference Providers (already wired)**
472
+
473
+ Set these as Space **Settings β†’ Variables and secrets**:
474
+
475
+ | Secret | Value |
476
+ |---|---|
477
+ | `HF_TOKEN` | Your HF token with `inference` scope |
478
+ | `GOBLIN_AGENT_BACKEND` | `qwen-hf` (default) |
479
+ | `GOBLIN_QWEN_MODEL` | `Qwen/Qwen2.5-7B-Instruct` (or any HF Qwen model id) |
480
+
481
+ After redeploying, the lane caption flips to `🟒 Live: agent runs Qwen
482
+ in-process via Hugging Face Inference Providers` and judges audit live.
483
+
484
+ **Option 2 β€” Connect to a self-hosted vLLM on your AMD droplet**
485
+
486
+ If you've followed the AMD Developer Cloud tutorial and have vLLM serving
487
+ Qwen on your MI300X at `http://YOUR_DROPLET_IP:8000/v1`, point the Space
488
+ at it via Space secrets:
489
+
490
+ | Secret | Value |
491
+ |---|---|
492
+ | `GOBLIN_AGENT_BACKEND` | `qwen-vllm` |
493
+ | `GOBLIN_QWEN_VLLM_URL` | `http://YOUR_DROPLET_IP:8000/v1` |
494
+ | `GOBLIN_QWEN_VLLM_MODEL` | The model ID vLLM advertises at `/v1/models` |
495
+
496
+ **Important:** the AMD Developer Cloud droplet blocks port 8000 by default.
497
+ SSH into the droplet and run `ufw allow 8000` (per the [lablab tutorial](https://lablab.ai/ai-tutorials/amd-huggingface-deployment-for-ai-hackathons))
498
+ before the Space can reach the endpoint. Verify from outside:
499
+ ```bash
500
+ curl -s http://YOUR_DROPLET_IP:8000/v1/models
501
+ ```
502
+
503
+ **Option 3 β€” Connect to a separate FastAPI backend**
504
+
505
+ If you've run `uvicorn agent.server:app` somewhere reachable (an MI300X on
506
+ AMD Developer Cloud, an HF Inference Endpoint, a small CPU box), set
507
+ `GOBLIN_BACKEND_URL` as a Space secret pointing at the `/audit` endpoint.
508
+ Streamlit will stream real SSE from that backend.
509
+
510
+ All three options are optional; the offline-replay Space is what
511
+ satisfies the submission requirement.
512
 
513
+ ## Configuration Reference
514
 
515
+ | Env var | Default | Purpose |
516
+ |---|---|---|
517
+ | `GOBLIN_AGENT_BACKEND` | `qwen-hf` | Pick the LLM backend: `qwen-hf` (HF Inference Providers) or `qwen-vllm` (self-hosted vLLM on MI300X). |
518
+ | `HF_TOKEN` | *(none)* | Required when `qwen-hf` is active. Hugging Face Inference token. |
519
+ | `GOBLIN_QWEN_MODEL` | `Qwen/Qwen2.5-7B-Instruct` | Model id used by the `qwen-hf` backend. |
520
+ | `GOBLIN_QWEN_PROVIDER` | `auto` | HF Inference Provider routing (`auto` / `together` / `fireworks-ai` / `nebius` / ...). |
521
+ | `GOBLIN_QWEN_VLLM_URL` | `http://localhost:8000/v1` | Base URL of the self-hosted vLLM endpoint (only used when `qwen-vllm` is active). |
522
+ | `GOBLIN_QWEN_VLLM_MODEL` | `Qwen/Qwen2.5-7B-Instruct` | Model id served by your local vLLM. |
523
+ | `GOBLIN_QWEN_VLLM_KEY` | `EMPTY` | Optional auth token if you front vLLM with nginx/Caddy + auth. |
524
+ | `GOBLIN_BACKEND_URL` | `http://localhost:8000/audit` | UI's backend endpoint. |
525
+ | `ROCM_IMAGE_TAG` | `unknown` | Container tag mixed into the benchmark cache key. |
526
+ | `GOBLIN_GPU_ID` | `0` | Which `/dev/dri/renderD*` to bind in `goblin_runner.sh`. |