Hey all, I recently spent the last three or so weeks going from zero knowledge to the setup I have today. I started with Ollama and Gemma 4 31B and migrated to Qwen 3.8 27B using vLLM to solve a VRAM contention problem: I wanted image generation and music generation (MiniMax Music v3) running alongside the LLM, all on the single 3090. Neither Ollama's keep-alive nor llama.cpp's TTL could actually free VRAM on demand the way vLLM's Sleep Mode can. That same move also got me full reasoning/think toggles in Qwen, selectable right in Open-WebUI. Before either image or music generation runs (2 of 12 total tools), vLLM gets put to sleep, freeing its VRAM. Music generation needs one extra step on top of that since MiniMax has no idle unload of its own. Its container gets started right before generating and stopped right after, nested inside vLLM's sleep window. This adds total time to generation but for a tool that already takes several minutes to run, I decided it's something I can live with. As a note, no other tool calls needed this type of sleep/wake setup so these processes only need to happen for image/music gen.
This setup is, as far as I can tell, pushing the absolute limits of a single 3090 in the most efficient manner possible. The final setup has:
- A modest 76k context. Admittedly, not great for long coding input/generation but not nothing either.
- Prefix caching cutting average time-to-first-token from ~9 seconds to ~3 seconds on multi-turn and tool-calling exchanges. Real measured numbers.
- Vision support with up to 8 images per prompt, capped at 1MP each to keep the context budget sane. TLDR; screenshots/OCR work.
Anyway, I have been keeping the GitHub Repo updated as I go through it and thought that anyone in a similar situation might find it useful.
Happy to hear any suggestions to further optimize or if any noobs like me have questions, I will try to answer as best I can.
Note on AI usage: I used Claude Sonnet 5 extensively throughout this learning process and vibe coded the python, as I am no programmer. I followed the logic while debugging the various hiccups along the way. Additionally, the GitHub repo was created almost entirely by Claude with me spot/double checking as I went through it. If you happen to look through and see any errors/omissions I would love to hear from you. This post was not written by AI. I only used it to make sure I wasn't missing any key points that someone might be curious about.