<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[CloudGPU Blog]]></title><description><![CDATA[CloudGPU Blog]]></description><link>https://cloudgpu.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Sat, 31 Oct 2026 23:14:43 GMT</lastBuildDate><atom:link href="https://cloudgpu.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Roo Code configuration profiles for DeepSeek, Kimi and MiniMax on one OpenAI-compatible endpoint]]></title><description><![CDATA[One base URL and one key, a profile per model ID, a profile per mode, and a tool-call check for each]]></description><link>https://cloudgpu.hashnode.dev/roo-code-profiles-deepseek-kimi-minimax</link><guid isPermaLink="true">https://cloudgpu.hashnode.dev/roo-code-profiles-deepseek-kimi-minimax</guid><category><![CDATA[Roo Code]]></category><category><![CDATA[vscode]]></category><category><![CDATA[Deepseek]]></category><category><![CDATA[AI coding]]></category><category><![CDATA[api]]></category><dc:creator><![CDATA[CloudGPU]]></dc:creator><pubDate>Thu, 29 Oct 2026 09:53:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adb44ed52ba0198ba45d101/fcddf9e5-e864-46fe-a4fe-140d6880b5c6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Adapted from our CloudGPU guide on using DeepSeek V4 Flash in Roo Code.</p>
<p><strong>Short answer:</strong> create one Roo Code configuration profile per model, all using the <strong>OpenAI Compatible</strong> provider with the same Base URL (<code>https://cloudgpu.app/v1</code>) and API key, and change only the Model field: <code>deepseek-v4.1-flash</code>, <code>kimi-k2.6</code>, <code>kimi-k3</code> or <code>minimax-m3</code>. Then link a profile to each Roo Code mode, and run one tool-call request per model ID before you trust it with a task.</p>
<p>Disclosure: I work on CloudGPU, and the endpoint below is ours. The Roo Code steps follow the official Roo Code docs (<a href="https://roocodeinc.github.io/Roo-Code/features/api-configuration-profiles/">API Configuration Profiles</a> and <a href="https://roocodeinc.github.io/Roo-Code/providers/openai-compatible/">Using OpenAI Compatible Providers</a>). We haven't run Roo Code end to end against this endpoint, so the checks below are for you to run, not results we measured.</p>
<h2>Why profiles</h2>
<p>According to the Roo Code docs, a configuration profile holds its own provider, API key, model selection, temperature, thinking budget and rate limit setting, and you can switch profiles from Settings or from the API Configuration dropdown in the chat. The docs also say you can link a profile to each mode, and that each task remembers the profile it started with, so a resumed task keeps its original model.</p>
<p>That fits a gateway well: the provider, URL and key never change, so each profile differs only in its model ID.</p>
<h2>What you need</h2>
<ul>
<li>An API key (<code>cgw-sk-...</code>) from the API console. It is shown once, so copy it right away. The quick start is on the <a href="https://cloudgpu.app/api/docs?utm_source=hashnode&amp;utm_medium=article&amp;utm_campaign=202611_seg04_codingagent&amp;utm_content=hashnode_roo_profiles">API docs page</a>.</li>
<li>Roo Code installed in VS Code.</li>
<li>The key in an environment variable for the checks below:</li>
</ul>
<pre><code class="language-bash">export CLOUDGPU_API_KEY="cgw-sk-your-key"
</code></pre>
<h2>Step 1: Pick the model IDs</h2>
<p>These chat model IDs are in the model table on the CloudGPU API page (checked 2026-10-28). IDs are case-sensitive.</p>
<table>
<thead>
<tr>
<th>Model ID</th>
<th>Model</th>
</tr>
</thead>
<tbody><tr>
<td><code>deepseek-v4.1-flash</code></td>
<td>DeepSeek V4.1 Flash</td>
</tr>
<tr>
<td><code>kimi-k2.6</code></td>
<td>Kimi K2.6</td>
</tr>
<tr>
<td><code>kimi-k3</code></td>
<td>Kimi K3</td>
</tr>
<tr>
<td><code>minimax-m3</code></td>
<td>MiniMax M3</td>
</tr>
</tbody></table>
<p><code>GET /v1/models</code> is public: it lists model IDs without a key. Other endpoints still need your key.</p>
<pre><code class="language-bash">curl -s https://cloudgpu.app/v1/models
</code></pre>
<h2>Step 2: Create one profile per model</h2>
<p>Following the Roo Code docs: open Settings (gear icon), go to <strong>Providers</strong>, click <strong>+</strong> next to the profile selector and name the profile, for example <code>cgw-deepseek</code>. Then fill in:</p>
<table>
<thead>
<tr>
<th>Roo Code field</th>
<th>Value</th>
</tr>
</thead>
<tbody><tr>
<td>API Provider</td>
<td>OpenAI Compatible</td>
</tr>
<tr>
<td>Base URL</td>
<td><code>https://cloudgpu.app/v1</code></td>
</tr>
<tr>
<td>API Key</td>
<td>your <code>cgw-sk-...</code> key</td>
</tr>
<tr>
<td>Model</td>
<td><code>deepseek-v4.1-flash</code></td>
</tr>
</tbody></table>
<p>Repeat for <code>cgw-kimi-k2.6</code>, <code>cgw-kimi-k3</code> and <code>cgw-minimax</code>, changing only the Model field.</p>
<p>The docs list a per-profile <strong>Rate Limit</strong> (minimum seconds between requests, default 0, meaning off). Leave it at 0 unless you hit <code>429 rate_limit_exceeded</code>; the API docs list 100 requests per minute per key and 10,000 requests per day per account. Every profile here uses the same key, so they share the per-key limit.</p>
<p><strong>Model Configuration</strong> (Max Output Tokens, Context Window and so on) is optional. We don't publish values for these models, so leave the defaults unless you know the limits you need.</p>
<h2>Step 3: Link profiles to modes</h2>
<p>The Roo Code docs say you can associate a profile with each mode in the Prompts tab, and Roo Code also remembers the last profile you used in each mode. Which model goes with which mode is your call; one way to try it is a Kimi profile for Architect and a DeepSeek profile for Code, then swap and compare on the same small task.</p>
<p>Orchestrator subtasks inherit the parent task's profile, according to the docs, so a subtask won't switch models on you mid-task.</p>
<h2>Step 4: Tool-call check for every profile</h2>
<p>The Roo Code docs say it "uses native tool calling exclusively" and that a model without native tool calling "cannot be used with Roo Code". We haven't confirmed tool calls for any of these four IDs inside Roo Code, so the way to verify is to run one request with a <code>tools</code> array for each model ID. This uses the <code>openai</code> Python package (<code>pip install openai</code>):</p>
<pre><code class="language-python">import os
from openai import OpenAI

client = OpenAI(
    base_url="https://cloudgpu.app/v1",
    api_key=os.environ["CLOUDGPU_API_KEY"],
)

tools = [{
    "type": "function",
    "function": {
        "name": "read_file",
        "description": "Read a file from the workspace",
        "parameters": {
            "type": "object",
            "properties": {"path": {"type": "string"}},
            "required": ["path"],
        },
    },
}]

for model in ["deepseek-v4.1-flash", "kimi-k2.6", "kimi-k3", "minimax-m3"]:
    try:
        resp = client.chat.completions.create(
            model=model,
            messages=[{"role": "user", "content": "Open README.md using the tool."}],
            tools=tools,
            max_tokens=2048,  # leave room: some models think before they answer
        )
    except Exception as e:
        print(f"{model}: error -&gt; {e}")
        continue
    msg = resp.choices[0].message
    if msg.tool_calls:
        call = msg.tool_calls[0].function
        print(f"{model}: tool call -&gt; {call.name}({call.arguments})")
    else:
        print(f"{model}: no tool call, text -&gt; {msg.content!r}")
</code></pre>
<p>How to read it:</p>
<ul>
<li><strong><code>tool_calls</code> present</strong> (a <code>read_file</code> call with <code>{"path": "README.md"}</code> or similar): try that profile in Roo Code on a small task.</li>
<li><strong>Plain text or an error</strong>: don't use that profile with Roo Code; try another ID.</li>
<li><strong>Empty <code>content</code> and no tool call</strong>: some models spend output tokens on thinking first. Raise <code>max_tokens</code> here (and Max Output Tokens in that profile's Model Configuration) and run it again before you decide.</li>
</ul>
<h2>Troubleshooting</h2>
<ul>
<li><strong>HTTP 401 <code>invalid_api_key</code></strong>: the key is wrong or revoked. Create a new one in the console and update it in every profile.</li>
<li><strong>HTTP 401 <code>missing_authorization</code></strong>: no <code>Authorization: Bearer</code> header was sent (<code>/v1/models</code> is public, but chat requests need the key). In a shell, check that <code>echo $CLOUDGPU_API_KEY</code> isn't empty.</li>
<li><strong>HTTP 400 <code>model_not_found</code></strong>: check the Model field against <code>/v1/models</code>; IDs are case-sensitive.</li>
<li><strong>Connection errors</strong>: the Base URL must be exactly <code>https://cloudgpu.app/v1</code>.</li>
<li><strong>HTTP 429 <code>rate_limit_exceeded</code></strong>: all profiles share the same key's limit; set a small per-profile Rate Limit or slow down parallel tasks.</li>
<li><strong>A resumed task uses the "wrong" model</strong>: per the docs, tasks keep the profile they started with. Start a new task to use another profile.</li>
</ul>
<h2>FAQ</h2>
<p><strong>Can Roo Code use several models through one OpenAI-compatible endpoint?</strong>
Yes. Create one configuration profile per model ID with the same Base URL and API key, and switch profiles from Settings or the chat dropdown.</p>
<p><strong>Can each Roo Code mode use a different model?</strong>
Yes. The Roo Code docs say you can link a configuration profile to each mode in the Prompts tab.</p>
<p><strong>Do deepseek-v4.1-flash, the Kimi IDs and minimax-m3 support the tool calling Roo Code needs?</strong>
We haven't confirmed tool calls on any of them inside Roo Code. Run the Step 4 Python check for each ID before you rely on it.</p>
<p><strong>Do all profiles share one rate limit?</strong>
They share the limits of the key they use: 100 requests per minute per key and 10,000 requests per day per account, per the API docs.</p>
<p><strong>Where are the rates?</strong>
Per-model rates are in the price table on the <a href="https://cloudgpu.app/api?utm_source=hashnode&amp;utm_medium=article&amp;utm_campaign=202611_seg04_codingagent&amp;utm_content=hashnode_roo_profiles_rates">CloudGPU API page</a>.</p>
<hr />
<p>Facts checked 2026-10-28.</p>
]]></content:encoded></item><item><title><![CDATA[Wan 2.2 A14B at 720p on a 24 GB GPU: why it runs out of memory and what to change]]></title><description><![CDATA[What a public InvokeAI bug report found, and which settings to change]]></description><link>https://cloudgpu.hashnode.dev/wan-2-2-a14b-720p-24gb-oom</link><guid isPermaLink="true">https://cloudgpu.hashnode.dev/wan-2-2-a14b-720p-24gb-oom</guid><category><![CDATA[AI]]></category><category><![CDATA[Machine Learning]]></category><category><![CDATA[GPU]]></category><category><![CDATA[video]]></category><dc:creator><![CDATA[CloudGPU]]></dc:creator><pubDate>Thu, 29 Oct 2026 08:38:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adb44ed52ba0198ba45d101/84755438-3e6f-43f2-ae60-75593f615b66.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you try Wan 2.2 T2V A14B at 1280×720 on a 24 GB card and get <code>torch.OutOfMemoryError</code>, you are not alone. A public bug report, reported in InvokeAI issue #9831 (2026-10-12) on an RTX 4090 24GB, lays out exactly when it fails, why, and which setting got it running. This post walks through that report and the official docs, step by step.</p>
<p>Everything below is quoted from the issue or from official documentation. We have not reproduced the runs ourselves.</p>
<h2>1. The symptom and the conditions it was reported under</h2>
<p>From <a href="https://github.com/invoke-ai/InvokeAI/issues/9831">InvokeAI issue #9831</a> (opened 2026-10-12, open, labelled bug, no comments when read on 2026-10-28):</p>
<ul>
<li><strong>Machine:</strong> Windows 10, RTX 4090 with 24 GB VRAM, manual development checkout of InvokeAI <code>main</code> at 8111b5067e (7.0.0-alpha.1), Python 3.12, torch 2.13.0+cu130.</li>
<li><strong>Model:</strong> Wan 2.2 T2V A14B, GGUF Q4_K_M, both experts (High Noise and Low Noise), plus the <code>Wan2.2-T2V-A14B-Diffusers</code> components and the Lightning 4-step LoRAs (V1.1, high and low).</li>
<li><strong>Job:</strong> 1280×720, 81 frames, 4 steps, guidance 1.0, default <code>invokeai.yaml</code>.</li>
<li><strong>Error:</strong> <code>torch.OutOfMemoryError</code> in <code>diffusers/models/transformers/transformer_wan.py:502</code>.</li>
</ul>
<p>The issue's results table (settings and outcome as reported; we list the memory outcome only):</p>
<table>
<thead>
<tr>
<th><code>enable_partial_loading</code></th>
<th><code>device_working_mem_gb</code></th>
<th>Attention</th>
<th>Memory outcome reported in #9831</th>
</tr>
</thead>
<tbody><tr>
<td>true (default)</td>
<td>3 (default)</td>
<td>PyTorch SDPA</td>
<td>OOM in the first transformer block, also at 832×480</td>
</tr>
<tr>
<td>false</td>
<td>3</td>
<td>PyTorch SDPA</td>
<td>Completed, but VRAM full; overflowed into shared system memory</td>
</tr>
<tr>
<td>true</td>
<td>10</td>
<td>PyTorch SDPA</td>
<td>Completed (the issue's workaround for 24 GB)</td>
</tr>
<tr>
<td>true</td>
<td>10</td>
<td>SageAttention</td>
<td>Completed, but overflowed (about 1.2 GB more held than SDPA)</td>
</tr>
<tr>
<td>false</td>
<td>3</td>
<td>SageAttention</td>
<td>Completed, but overflowed into shared system memory</td>
</tr>
</tbody></table>
<p>Two details matter when you compare this with your own machine:</p>
<ul>
<li>The run with partial loading off did not really "fit". The issue says the card still overflowed and Windows moved memory to shared system memory instead of raising an OOM.</li>
<li>This is a Windows machine on a 7.0.0 alpha development build. Linux, or a release build, may behave differently; the issue does not test them.</li>
</ul>
<p><strong>What to check</strong></p>
<ul>
<li>Your error matches: <code>torch.OutOfMemoryError</code> in the Wan transformer, at the first denoise block.</li>
<li>Your <code>invokeai.yaml</code> still has the defaults (<code>enable_partial_loading: true</code>, <code>device_working_mem_gb: 3</code>, or neither line set).</li>
<li>On Windows, watch "Shared GPU memory" in Task Manager. If it climbs during generation, you are in the spill case, not the OOM case.</li>
</ul>
<h2>2. Why 24 GB is not enough here</h2>
<p><strong>Two experts, one at a time.</strong> The official <a href="https://github.com/Wan-Video/Wan2.2">Wan2.2 README</a> (read 2026-10-28) describes the A14B models as a two-expert design: "a high-noise expert for the early stages, focusing on overall layout; and a low-noise expert for the later stages, refining video details. Each expert model has about 14B parameters, resulting in a total of 27B parameters but only 14B active parameters per step". So you download and load two diffusion models, but each denoise step uses one.</p>
<p><strong>The official script's own guidance.</strong> For its single-GPU 1280*720 A14B command (with <code>--offload_model True --convert_model_dtype</code>), the README says: "This command can run on a GPU with at least 80GB VRAM." That statement is about the Wan repo's <code>generate.py</code>, not about InvokeAI or GGUF weights, but it tells you 720p A14B is not a small job.</p>
<p><strong>What the issue found inside InvokeAI.</strong> According to #9831:</p>
<ul>
<li>Wan denoise has no working-memory estimate. <code>_get_wan_transformer_working_mem_bytes</code> returns <code>None</code> unless <code>wan_memory_optimization</code> is on, so the expert is loaded with the floor, <code>device_working_mem_gb</code> (3 GB), as its working memory.</li>
<li>At 720p with 81 frames the transformer sees 75,600 tokens, "and the activations need far more than 3 GB."</li>
<li>With partial loading on, the cache frees only 2,003 MB of the 10.8 GB UMT5 text encoder before loading the 9.2 GB expert, so the first block runs out of memory with 21.3 GiB allocated.</li>
</ul>
<p>In short: model weights plus text encoder plus the attention activations for 75,600 tokens do not fit in 24 GB, and InvokeAI reserves only 3 GB for the activations by default.</p>
<p><strong>What to check</strong></p>
<ul>
<li>The InvokeAI log around model loading: is the text encoder still partly in VRAM when the expert loads?</li>
<li>Your resolution and frame count. The 75,600-token figure is for 1280×720 with 81 frames only.</li>
</ul>
<h2>3. Local settings to change</h2>
<h3>3a. Raise the working memory</h3>
<p>InvokeAI's <a href="https://invoke.ai/configuration/low-vram-mode/">Low-VRAM mode docs</a> (read 2026-10-28): "Invoke reserves 3GB VRAM as working memory by default", and you can raise it in <code>invokeai.yaml</code> to prevent OOMs (the docs' example sets 4).</p>
<p>The issue's workaround for this exact case on 24 GB is 10:</p>
<pre><code class="language-yaml"># invokeai.yaml — workaround reported in InvokeAI issue #9831 for 24 GB
device_working_mem_gb: 10
</code></pre>
<p>With that, partial loading on and SDPA, the issue reports the 720p, 81-frame job completing. Invoke needs a restart after you edit the file.</p>
<p><strong>What to check</strong></p>
<ul>
<li>The OOM is gone and Task Manager's shared GPU memory stays flat during denoise.</li>
<li>If you also set <code>max_cache_vram_gb</code>, the docs say to keep it at or below your VRAM minus <code>device_working_mem_gb</code> minus <code>reserve_vram_gb</code>.</li>
</ul>
<h3>3b. Keep partial loading on, and turn off the Windows sysmem fallback</h3>
<p>The docs say Low-VRAM mode is enabled by default via <code>enable_partial_loading: true</code>. In the issue, turning it off did not prevent the overflow: the encoder was unloaded, but the run spilled into shared memory.</p>
<p>The same docs ask Windows users to disable the Nvidia sysmem fallback: NVIDIA Control Panel → 3D Settings → Manage 3D Settings → "CUDA - Sysmem Fallback Policy" → "Prefer No Sysmem Fallback". With it disabled, an overflow shows up as an OOM you can act on instead of silently spilling into shared system memory.</p>
<p><strong>What to check</strong></p>
<ul>
<li><code>enable_partial_loading</code> is <code>true</code> (or absent) in <code>invokeai.yaml</code>.</li>
<li>On Windows, the NVIDIA Control Panel setting reads "Prefer No Sysmem Fallback".</li>
</ul>
<h3>3c. Try <code>wan_memory_optimization</code> (opt-in)</h3>
<p>From the same docs page: setting <code>wan_memory_optimization: true</code> makes partial-load Wan transformer weights "target about 2 GiB resident and stream remaining layers from RAM". It "reduces peak VRAM during both denoise and decode, but generation can be substantially slower and requires enough system RAM for offloaded weights." The docs also note same-seed output may differ slightly from the baseline path.</p>
<p>The issue explains that this flag is also what turns on Wan's working-memory estimate. It does not report a run with the flag on, so we have no figures for it.</p>
<pre><code class="language-yaml">wan_memory_optimization: true
</code></pre>
<p><strong>What to check</strong></p>
<ul>
<li>Free system RAM during generation; the docs say offloaded weights need it.</li>
<li>Compare a short test clip against your baseline before committing to long runs.</li>
</ul>
<h3>3d. Lower the resolution, and treat frame count with care</h3>
<p>The issue's only other resolution is 832×480. With default settings it also ran out of memory. With partial loading on and <code>device_working_mem_gb: 10</code>, it fit with both attention backends.</p>
<p>The issue tests 81 frames only. Fewer frames means a shorter clip, but the issue gives no figures for it, so try it on your own setup rather than relying on a number from us.</p>
<p><strong>What to check</strong></p>
<ul>
<li>At 832×480, the default settings still fail in the issue. Raise <code>device_working_mem_gb</code> as well; do not rely on resolution alone.</li>
</ul>
<h3>3e. Quantization, and the official script's flags</h3>
<p>The issue already used GGUF Q4_K_M weights for both experts and still ran out of memory at default settings. Lower-bit weights alone did not fix it there; working memory did.</p>
<p>If you use the Wan repo's own <code>generate.py</code> instead of InvokeAI, the README says: "If you encounter OOM (Out-of-Memory) issues, you can use the <code>--offload_model True</code>, <code>--convert_model_dtype</code> and <code>--t5_cpu</code> options to reduce GPU memory usage."</p>
<p>On attention, these are figures reported in InvokeAI issue #9831 (one RTX 4090 24GB on Windows), not measured by us and not a claim about CloudGPU cards: the issue reports SageAttention held about 1.2 GB more than SDPA at 75,600 tokens, which pushed that card over the edge at 720p. At 832×480, the issue reports both backends fit.</p>
<p><strong>What to check</strong></p>
<ul>
<li>If you switched to SageAttention and shared GPU memory now climbs at 720p, switch back to SDPA and compare.</li>
<li>The Wan2.2 model weights are licensed Apache-2.0 (per the README and the <a href="https://huggingface.co/Wan-AI/Wan2.2-T2V-A14B">model card</a>); check the license of any community GGUF build you download separately.</li>
</ul>
<h2>4. If local settings are still not enough: run the same workflow on a card with more VRAM</h2>
<p>If the slower settings are not an option for you, the other route is more VRAM. On CloudGPU you can rent a card with more VRAM, billed per minute, and set up the same InvokeAI workflow on it. Cards listed on <a href="https://cloudgpu.app/pricing?utm_source=hashnode&amp;utm_medium=article&amp;utm_campaign=202611_seg01_comfyui&amp;utm_content=wan22_oom">/pricing</a> when we read it on 2026-10-28 include:</p>
<table>
<thead>
<tr>
<th>Card on /pricing</th>
<th>VRAM (as shown on /pricing)</th>
</tr>
</thead>
<tbody><tr>
<td>RTX 5090 32G</td>
<td>32 GB</td>
</tr>
<tr>
<td>RTX 4090 48G</td>
<td>48 GB</td>
</tr>
<tr>
<td>A100 80G</td>
<td>80 GB</td>
</tr>
</tbody></table>
<p>To be clear about what this does and does not mean:</p>
<ul>
<li>We have not tested Wan 2.2 A14B, InvokeAI or this workflow on any of these cards. The only difference we can state is more VRAM than a 24 GB card.</li>
<li>VRAM need depends on model, precision and workflow. See <a href="https://cloudgpu.app/guides/how-much-vram-do-i-need-to-run-an-llm">How much VRAM do I need to run an LLM?</a></li>
<li>Billing is per minute, rounded up, with a 1-minute minimum, and stops when you destroy the instance (<a href="https://cloudgpu.app/terms">terms</a>). Rates per card are on /pricing.</li>
</ul>
<p><strong>What to check</strong></p>
<ul>
<li>Before renting, compare the VRAM column above with what your settings needed locally (the InvokeAI log and Task Manager tell you where it ran out).</li>
<li>Destroy the instance when the job is done, so billing stops.</li>
</ul>
<h2>FAQ</h2>
<p><strong>Why does Wan 2.2 A14B run out of memory at 720p on a 24 GB GPU in InvokeAI?</strong> According to InvokeAI issue #9831, Wan denoise has no working-memory estimate unless <code>wan_memory_optimization</code> is on, so InvokeAI reserves only the default 3 GB for activations. At 1280×720 with 81 frames the transformer sees 75,600 tokens, and the activations need far more than that.</p>
<p><strong>What setting fixed it in the issue?</strong><code>device_working_mem_gb: 10</code> in <code>invokeai.yaml</code>, with partial loading left on. The issue reports the 720p, 81-frame job then completed on an RTX 4090 24GB (Windows 10, InvokeAI 7.0.0-alpha.1).</p>
<p><strong>Does turning off partial loading help?</strong> Not in the issue. With <code>enable_partial_loading: false</code> the card still overflowed, and Windows moved memory to shared system memory instead of raising an OOM.</p>
<p><strong>Does lowering the resolution to 832×480 avoid the OOM?</strong> Not on its own. The issue reports an OOM at 832×480 with default settings too; with <code>device_working_mem_gb: 10</code> it fit.</p>
<p><strong>What does the official Wan2.2 README say about VRAM for A14B at 720p?</strong> For its own single-GPU <code>generate.py</code> command at 1280*720, it says the command "can run on a GPU with at least 80GB VRAM", and suggests <code>--offload_model True</code>, <code>--convert_model_dtype</code> and <code>--t5_cpu</code> for OOM issues.</p>
<h2>Sources</h2>
<ul>
<li>InvokeAI issue #9831, <a href="https://github.com/invoke-ai/InvokeAI/issues/9831">https://github.com/invoke-ai/InvokeAI/issues/9831</a> (opened 2026-10-12; read 2026-10-28)</li>
<li>Wan2.2 README (GitHub), <a href="https://github.com/Wan-Video/Wan2.2">https://github.com/Wan-Video/Wan2.2</a> (read 2026-10-28)</li>
<li>Wan2.2-T2V-A14B model card, <a href="https://huggingface.co/Wan-AI/Wan2.2-T2V-A14B">https://huggingface.co/Wan-AI/Wan2.2-T2V-A14B</a> (read 2026-10-28)</li>
<li>InvokeAI docs, Low-VRAM mode, <a href="https://invoke.ai/configuration/low-vram-mode/">https://invoke.ai/configuration/low-vram-mode/</a> (read 2026-10-28)</li>
<li>CloudGPU /pricing and /terms (read 2026-10-28)</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Use Kimi K2.6 and K3 through an OpenAI-compatible API: curl, the OpenAI SDK, Cline and Aider]]></title><description><![CDATA[One base URL, one key, two Kimi model IDs, and the exact settings for your coding agent]]></description><link>https://cloudgpu.hashnode.dev/kimi-k2-6-k3-api-openai-compatible-cline-aider</link><guid isPermaLink="true">https://cloudgpu.hashnode.dev/kimi-k2-6-k3-api-openai-compatible-cline-aider</guid><category><![CDATA[AI coding]]></category><category><![CDATA[Kimi]]></category><category><![CDATA[llm]]></category><category><![CDATA[Python]]></category><category><![CDATA[api]]></category><dc:creator><![CDATA[CloudGPU]]></dc:creator><pubDate>Tue, 27 Oct 2026 04:22:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adb44ed52ba0198ba45d101/43655892-ef24-4c2f-b464-1c36c9dd5423.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Adapted from our CloudGPU blog post on Kimi K2.</p>
<p>If a tool already speaks the OpenAI-compatible chat format, switching it to Kimi comes down to three values: the base URL, the API key and the model ID. This post shows those values on the CloudGPU gateway, then the same setup in curl, the <code>openai</code> Python package, Cline and Aider.</p>
<p>Disclosure: I work on CloudGPU.</p>
<h2>The three values</h2>
<table>
<thead>
<tr>
<th>Setting</th>
<th>Value</th>
</tr>
</thead>
<tbody><tr>
<td>Base URL</td>
<td><code>https://cloudgpu.app/v1</code></td>
</tr>
<tr>
<td>API key</td>
<td>a <code>cgw-sk-...</code> key from the API console, kept in <code>$CGW_API_KEY</code></td>
</tr>
<tr>
<td>Model ID</td>
<td><code>kimi-k2.6</code> or <code>kimi-k3</code></td>
</tr>
</tbody></table>
<p>Both IDs are in the model table on the live API page (checked 2026-10-27), which also lists <code>kimi-k2.5</code>. The original post suggests <code>kimi-k2.6</code> for everyday coding agents and <code>kimi-k3</code> for harder reasoning tasks.</p>
<p>A team test on 2026-10-26 with an internal key found both IDs in <code>/v1/models</code>, a working chat request, and a single tool call (the <code>tools</code> parameter, returning <code>tool_calls</code>) for each.</p>
<h2>Step 1: Get a key</h2>
<ol>
<li>Sign up at cloudgpu.app with an email address or a Google account.</li>
<li>Top up the prepaid balance. Payment options are card or USDT.</li>
<li>In the API console, create a key. It starts with <code>cgw-sk-</code> and is shown only once, so copy it straight away.</li>
<li>Keep it in an environment variable:</li>
</ol>
<pre><code class="language-bash">export CGW_API_KEY="cgw-sk-..."
</code></pre>
<p>The same balance pays for the API per token and for rented GPUs by the minute.</p>
<h2>Step 2: Check the key with curl</h2>
<pre><code class="language-bash">curl https://cloudgpu.app/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $CGW_API_KEY" \
  -d '{
    "model": "kimi-k2.6",
    "messages": [{"role": "user", "content": "Refactor this function to use early returns."}]
  }'
</code></pre>
<p>If something is off, the error codes from the API docs tell you what:</p>
<ul>
<li><code>401 missing_authorization</code>: no <code>Authorization</code> header was sent.</li>
<li><code>401 invalid_api_key</code>: the key is unknown or revoked.</li>
<li><code>400 model_not_found</code>: the model ID is not in the catalog. Copy it from the model table.</li>
<li><code>429 rate_limit_exceeded</code>: you hit the per-minute or per-day limit. The public beta defaults are 100 requests per minute per key and 10,000 requests per day per account.</li>
</ul>
<h2>Step 3: The OpenAI Python SDK</h2>
<p>Only <code>base_url</code> and <code>api_key</code> change:</p>
<pre><code class="language-python">import os
from openai import OpenAI

client = OpenAI(
    base_url="https://cloudgpu.app/v1",
    api_key=os.environ["CGW_API_KEY"],
)

resp = client.chat.completions.create(
    model="kimi-k3",
    messages=[{"role": "user", "content": "Explain this stack trace in two sentences."}],
    max_tokens=2048,
)
print(resp.choices[0].message.content)
</code></pre>
<p>For streaming, pass <code>stream=True</code>. The API docs say the response is Server-Sent Events in OpenAI format and the SDK handles it for you.</p>
<p>If a reply comes back empty with <code>finish_reason</code> set to <code>"length"</code>, the model ran out of output budget. Raise <code>max_tokens</code> and try again.</p>
<h2>Step 4: Cline</h2>
<p>According to the official Cline docs ("OpenAI Compatible" provider page, read 2026-10-27), the settings are in the Cline settings panel (the gear icon):</p>
<ol>
<li>API Provider: select "OpenAI Compatible".</li>
<li>Base URL: <code>https://cloudgpu.app/v1</code></li>
<li>API Key: your <code>cgw-sk-...</code> key.</li>
<li>Model: enter <code>kimi-k2.6</code> (or <code>kimi-k3</code>).</li>
</ol>
<p>The same docs list the usual fixes: "Invalid API Key" means the key or provider is wrong, and "Model Not Found" means the model ID isn't available at that base URL.</p>
<h2>Step 5: Aider</h2>
<p>According to the official Aider docs ("OpenAI compatible APIs", read 2026-10-27), set two environment variables and prefix the model name with <code>openai/</code>:</p>
<pre><code class="language-bash">export OPENAI_API_BASE=https://cloudgpu.app/v1
export OPENAI_API_KEY=$CGW_API_KEY

aider --model openai/kimi-k2.6
</code></pre>
<p>On Windows the docs use <code>setx OPENAI_API_BASE ...</code> and <code>setx OPENAI_API_KEY ...</code>, then restart the shell.</p>
<h2>What the gateway does and doesn't do</h2>
<p>It speaks the OpenAI chat-completions format, streams tokens, and bills per token from a prepaid balance with no subscription. It doesn't store your prompts or train on them, and there is no automatic failover. Per-token rates for every model are listed on the API page and can change, so this post doesn't repeat them.</p>
<p>Model IDs, rates and the full docs: <a href="https://cloudgpu.app/api?utm_source=hashnode&amp;utm_medium=article&amp;utm_campaign=202611_seg04_codingagent&amp;utm_content=hashnode_kimi_api">cloudgpu.app/api</a></p>
<h2>FAQ</h2>
<p><strong>Which base URL do I use?</strong><code>https://cloudgpu.app/v1</code> for any OpenAI-compatible client.</p>
<p><strong>Which model ID should I start with?</strong> The original post suggests <code>kimi-k2.6</code> for everyday coding agents and <code>kimi-k3</code> for harder reasoning. Both are in the live model table.</p>
<p><strong>Does it work with the OpenAI SDK?</strong> Yes. Set <code>base_url</code> to <code>https://cloudgpu.app/v1</code> and pass your <code>cgw-sk-</code> key as <code>api_key</code>.</p>
<p><strong>How do I pay?</strong> From a prepaid balance, topped up by card or USDT.</p>
]]></content:encoded></item><item><title><![CDATA[How do you use DeepSeek V4.1 Flash and Kimi K3 in opencode through a custom OpenAI-compatible provider?]]></title><description><![CDATA[One provider block in opencode.json, four exact model IDs, a sanity check from the openai package, and the fixes for the errors you are likely to hit]]></description><link>https://cloudgpu.hashnode.dev/opencode-custom-provider-deepseek-kimi</link><guid isPermaLink="true">https://cloudgpu.hashnode.dev/opencode-custom-provider-deepseek-kimi</guid><category><![CDATA[opencode]]></category><category><![CDATA[llm]]></category><category><![CDATA[#ai-tools]]></category><category><![CDATA[devtools]]></category><category><![CDATA[api]]></category><dc:creator><![CDATA[CloudGPU]]></dc:creator><pubDate>Mon, 26 Oct 2026 19:44:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adb44ed52ba0198ba45d101/62b67b8e-3685-4562-9a0a-049a2d913c52.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Adapted from our opencode custom-provider tutorial <a href="https://dev.to/cloudgpu_app/use-deepseek-v41-flash-and-kimi-in-opencode-via-a-custom-openai-compatible-provider-5co4">on dev.to</a>.</p>
<h1>How do you use DeepSeek V4.1 Flash and Kimi K3 in opencode through a custom OpenAI-compatible provider?</h1>
<p>You add a <code>provider</code> block to <code>opencode.json</code> that uses the <code>@ai-sdk/openai-compatible</code> package, set its <code>baseURL</code> to <code>https://cloudgpu.app/v1</code>, read the key from <code>{env:CGW_API_KEY}</code>, and list <code>deepseek-v4.1-flash</code> and <code>kimi-k3</code> under <code>models</code>; opencode then offers them as <code>cloudgpu/deepseek-v4.1-flash</code> and <code>cloudgpu/kimi-k3</code>.</p>
<p>The rest of this post is the copy-paste version of that sentence, with each opencode behaviour traced to the opencode docs.</p>
<p>Disclosure: I work on CloudGPU.</p>
<h2>What this is based on</h2>
<p>We ran this provider block in opencode on 2026-10-26 and both headline models replied. Everything else below about opencode itself (the <code>/models</code> screen, <code>/connect</code>, the <code>limit</code> block, the default model) follows the opencode docs, so read "according to the opencode docs" literally.</p>
<h2>The four values at a glance</h2>
<table>
<thead>
<tr>
<th>What</th>
<th>Value</th>
</tr>
</thead>
<tbody><tr>
<td>npm package</td>
<td><code>@ai-sdk/openai-compatible</code></td>
</tr>
<tr>
<td>Base URL</td>
<td><code>https://cloudgpu.app/v1</code> (keep the <code>/v1</code>)</td>
</tr>
<tr>
<td>API key</td>
<td>a <code>cgw-sk-...</code> key, exported as <code>CGW_API_KEY</code></td>
</tr>
<tr>
<td>Model IDs</td>
<td><code>deepseek-v4.1-flash</code>, <code>kimi-k3</code>, <code>kimi-k2.6</code>, <code>glm-5.3-flash</code></td>
</tr>
</tbody></table>
<p>The model IDs were checked against the model table on the live API page on 2026-10-27.</p>
<h2>Step 1: Export the key</h2>
<p>According to the opencode docs, config files support <code>{env:VARIABLE_NAME}</code> substitution, so the key can stay out of the JSON file:</p>
<pre><code class="language-bash">export CGW_API_KEY="cgw-sk-..."   # put this in ~/.bashrc or ~/.zshrc to keep it
</code></pre>
<h2>Step 2: Add the custom provider to opencode.json</h2>
<p>Put this in <code>opencode.json</code> in your project root. According to the opencode docs, the global file lives at <code>~/.config/opencode/opencode.json</code>, the project file overrides it, and "configuration files are merged together, not replaced", so the same block also works globally.</p>
<pre><code class="language-json">{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "cloudgpu": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "CloudGPU",
      "options": {
        "baseURL": "https://cloudgpu.app/v1",
        "apiKey": "{env:CGW_API_KEY}"
      },
      "models": {
        "deepseek-v4.1-flash": { "name": "DeepSeek V4.1 Flash" },
        "kimi-k3": { "name": "Kimi K3" },
        "kimi-k2.6": { "name": "Kimi K2.6" },
        "glm-5.3-flash": { "name": "GLM-5.3 Flash" }
      }
    }
  }
}
</code></pre>
<p>Field guide, according to the opencode docs (Providers → Custom provider):</p>
<ul>
<li><strong><code>cloudgpu</code></strong> is the provider ID. You choose it, and it becomes the prefix in <code>cloudgpu/&lt;model&gt;</code>.</li>
<li><strong><code>npm</code></strong>: "<code>@ai-sdk/openai-compatible</code> for OpenAI-compatible providers (for <code>/v1/chat/completions</code>)".</li>
<li><strong><code>options.baseURL</code></strong> is the API endpoint; <strong><code>options.apiKey</code></strong> is optional "if not using auth".</li>
<li><strong><code>models</code></strong>: each key must be the exact ID the endpoint serves. <code>name</code> is only the label in the UI.</li>
</ul>
<p>Only want the two headline models? Delete the <code>kimi-k2.6</code> and <code>glm-5.3-flash</code> lines.</p>
<h3>Alternative: <code>/connect</code> instead of <code>apiKey</code></h3>
<p>According to the opencode docs, you can run <code>/connect</code>, scroll to <strong>Other</strong>, enter the provider ID (<code>cloudgpu</code>), and paste the key. The docs warn that this "only stores a credential", so you still need the <code>provider</code> block, just without the <code>apiKey</code> line.</p>
<h2>Step 3: Choose a model</h2>
<p>Check from the command line that opencode sees the provider. According to the opencode CLI docs, <code>opencode models [provider]</code> lists models in <code>provider/model</code> form:</p>
<pre><code class="language-bash">opencode models cloudgpu
</code></pre>
<p>The output should look like this (illustrative, not a captured run):</p>
<pre><code class="language-text">cloudgpu/deepseek-v4.1-flash
cloudgpu/glm-5.3-flash
cloudgpu/kimi-k2.6
cloudgpu/kimi-k3
</code></pre>
<p>Then pick one with <code>-m</code> in <code>provider/model</code> form. The dot in <code>v4.1</code> is part of the ID:</p>
<pre><code class="language-bash">opencode -m cloudgpu/deepseek-v4.1-flash
opencode run -m cloudgpu/kimi-k3 "Explain what this repo's main entry point does"
</code></pre>
<p>Inside the TUI, according to the opencode docs, you "run the <code>/models</code> command and your custom provider and models will appear in the selection list". To make one the default, the opencode models docs use a top-level <code>"model"</code> key in <code>provider_id/model_id</code> form, here <code>"model": "cloudgpu/deepseek-v4.1-flash"</code>.</p>
<p><strong>Which one for what?</strong> There are no benchmarks here, so try them on your own repo. All four are in the config, so comparing them takes one switch.</p>
<h2>Step 4: Sanity-check the endpoint outside opencode</h2>
<p>If opencode misbehaves, take it out of the loop. First, list the IDs your key can use:</p>
<pre><code class="language-bash">curl https://cloudgpu.app/v1/models \
  -H "Authorization: Bearer $CGW_API_KEY"
</code></pre>
<p>Without the header this returns <code>401</code> with <code>missing_authorization</code>, which is expected. The API docs list it as "No Authorization header." (As of 2026-10-27, see <a href="https://cloudgpu.app/api/docs">/api/docs</a>.)</p>
<p>Then send one chat request with the <code>openai</code> Python package:</p>
<pre><code class="language-python"># pip install openai
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://cloudgpu.app/v1",
    api_key=os.environ["CGW_API_KEY"],
)

for model in ["deepseek-v4.1-flash", "kimi-k3"]:
    resp = client.chat.completions.create(
        model=model,
        messages=[{"role": "user", "content": "Reply with: ok"}],
    )
    print(model, resp.choices[0].finish_reason, repr(resp.choices[0].message.content))
</code></pre>
<p>If a model comes back with empty or <code>None</code> content and <code>finish_reason</code> is <code>"length"</code>, the reply ran out of output tokens: leave <code>max_tokens</code> unset or set it higher.</p>
<h2>Troubleshooting</h2>
<p><strong>1. The model doesn't show up, or you get <code>400 model_not_found</code>.</strong> The keys under <code>models</code> must match the IDs from <code>GET /v1/models</code> character for character. Watch for short aliases (<code>deepseek-flash</code>), a missing version segment (<code>deepseek-v4-flash</code> vs <code>deepseek-v4.1-flash</code>) and capital letters. Also check that the provider ID is the same in all three places: the <code>provider</code> key, the ID typed into <code>/connect</code> (if you used it), and the <code>cloudgpu/</code> prefix. According to the opencode docs, <code>opencode auth list</code> shows which credentials are stored.</p>
<p><strong>2. The base URL is wrong.</strong> The AI SDK docs describe <code>baseURL</code> as the URL prefix for API calls, and their example sends chat requests to <code>&lt;baseURL&gt;/chat/completions</code>:</p>
<pre><code class="language-text">https://cloudgpu.app/v1                     correct
https://cloudgpu.app                        missing /v1
https://cloudgpu.app/v1/chat/completions    too specific
</code></pre>
<p><strong>3. An error asking for an <code>Authorization: Bearer</code> header.</strong> According to the opencode docs, an unset <code>{env:...}</code> variable "will be replaced with an empty string", so the request goes out without a key. Check the variable in the shell you launch opencode from:</p>
<pre><code class="language-bash">echo "${CGW_API_KEY:+set}"   # prints "set" if the variable is present
</code></pre>
<p>After editing <code>~/.bashrc</code> or <code>~/.zshrc</code>, open a new terminal or <code>source</code> the file. IDE terminals and desktop launchers may not read your shell profile.</p>
<p><strong>4. Empty replies.</strong> Check <code>finish_reason</code> as in Step 4. In opencode, the per-model knob the docs describe is the optional <code>limit</code> block (<code>limit.context</code> = "maximum input tokens the model accepts", <code>limit.output</code> = "maximum tokens the model can generate"). If you add it, use real values from the model provider's docs, not guesses.</p>
<p><strong>5. <code>401 invalid_api_key</code>, <code>402 insufficient_balance</code> or <code>429 rate_limit_exceeded</code>.</strong> The CloudGPU API docs describe them like this (As of 2026-10-27, see <a href="https://cloudgpu.app/api/docs">/api/docs</a>):</p>
<ul>
<li><code>401</code> <code>invalid_api_key</code>: "Key unknown or revoked."</li>
<li><code>402</code> <code>insufficient_balance</code>: "Top up."</li>
<li><code>429</code> <code>rate_limit_exceeded</code>: "Per-minute or per-day limit hit."</li>
</ul>
<p>The documented rate limits are "Per API key, per minute: 100 requests" and "Per account, per day: 10,000 requests", and the docs add: "These defaults exist to stop abuse during the public beta. Contact us if you need them raised — happy to do it for any genuine workload, just need to know the use case."</p>
<h2>Paying for it</h2>
<p>Usage is billed per token from a prepaid balance (card, Alipay, Google Pay, Apple Pay or USDT). Keys, the model table and per-model rates are on the <a href="https://cloudgpu.app/api?utm_source=hashnode&amp;utm_medium=article&amp;utm_campaign=202611_seg04_codingagent&amp;utm_content=hashnode_opencode">CloudGPU API page</a>.</p>
<h2>FAQ</h2>
<p><strong>Which npm package does an OpenAI-compatible custom provider use in opencode?</strong>
<code>@ai-sdk/openai-compatible</code>. According to the opencode docs, it's the package for providers that use <code>/v1/chat/completions</code>.</p>
<p><strong>What base URL goes in <code>options.baseURL</code>?</strong>
<code>https://cloudgpu.app/v1</code>, with <code>/v1</code> and nothing after it.</p>
<p><strong>Can the model ID contain a dot, like <code>deepseek-v4.1-flash</code>?</strong>
Yes. Use it exactly as listed, in <code>provider/model</code> form: <code>-m cloudgpu/deepseek-v4.1-flash</code>.</p>
<p><strong>Why does a model sometimes return an empty answer?</strong>
Check <code>finish_reason</code>. If it is <code>"length"</code>, the reply ran out of output tokens; raise <code>max_tokens</code> or leave it unset.</p>
<p><strong>Do I have to put the API key in <code>opencode.json</code>?</strong>
No. Use <code>"apiKey": "{env:CGW_API_KEY}"</code> so the file only holds a reference. According to the opencode docs, <code>/connect</code> can store the credential instead.</p>
<p><strong>Are there rate limits?</strong>
Yes. The API docs list "Per API key, per minute: 100 requests" and "Per account, per day: 10,000 requests", and say: "These defaults exist to stop abuse during the public beta. Contact us if you need them raised — happy to do it for any genuine workload, just need to know the use case." As of 2026-10-27, see <a href="https://cloudgpu.app/api/docs">/api/docs</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Use DeepSeek V4 in Cursor, Continue, Cline and aider through one OpenAI-compatible base URL]]></title><description><![CDATA[One key, one base URL, three DeepSeek model IDs, and the values to paste into each coding agent]]></description><link>https://cloudgpu.hashnode.dev/deepseek-v4-coding-agents-cursor-continue-cline-aider</link><guid isPermaLink="true">https://cloudgpu.hashnode.dev/deepseek-v4-coding-agents-cursor-continue-cline-aider</guid><category><![CDATA[Deepseek]]></category><category><![CDATA[llm]]></category><category><![CDATA[#ai-tools]]></category><category><![CDATA[Python]]></category><category><![CDATA[ vscode]]></category><dc:creator><![CDATA[CloudGPU]]></dc:creator><pubDate>Mon, 26 Oct 2026 19:42:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adb44ed52ba0198ba45d101/0258aa64-f6a4-4d9a-98bf-0ac4fd12f158.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Originally published on cloudgpu.app.</p>
<p>Most coding agents let you swap the model behind them by changing one setting: the OpenAI-compatible base URL. This post shows how to put DeepSeek V4 behind Cursor, Continue, Cline and aider using the CloudGPU gateway, paid from one prepaid balance. Switching back later is the same one-field change.</p>
<p>Disclosure: I work on CloudGPU.</p>
<h2>The three values every tool needs</h2>
<table>
<thead>
<tr>
<th>Setting</th>
<th>Value</th>
</tr>
</thead>
<tbody><tr>
<td>Base URL</td>
<td><code>https://cloudgpu.app/v1</code> (no trailing slash)</td>
</tr>
<tr>
<td>API key</td>
<td>a <code>cgw-sk-...</code> key from the API console, stored in <code>$CGW_API_KEY</code></td>
</tr>
<tr>
<td>Model ID</td>
<td><code>deepseek-v4-flash</code>, <code>deepseek-v4.1-flash</code> or <code>deepseek-v4-pro</code></td>
</tr>
</tbody></table>
<p>The model IDs are copied from the model table on the live API page (checked 2026-10-27). Type them exactly: a wrong case or a missing dot returns <code>400 model_not_found</code>.</p>
<h2>Step 1: Get a key</h2>
<ol>
<li>Sign up at cloudgpu.app with an email address or a Google account.</li>
<li>Open the API console, create a key (name it after the tool, e.g. <code>cursor</code>) and copy it. It starts with <code>cgw-sk-</code> and is shown only once, so keep it in a password manager.</li>
<li>Put it in an environment variable so it stays out of your code and dotfiles:</li>
</ol>
<pre><code class="language-bash">export CGW_API_KEY="cgw-sk-..."
</code></pre>
<h2>Step 2: Check the key with curl</h2>
<pre><code class="language-bash">curl https://cloudgpu.app/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $CGW_API_KEY" \
  -d '{"model":"deepseek-v4-flash","messages":[{"role":"user","content":"hello"}]}'
</code></pre>
<p>A JSON reply with <code>choices[0].message.content</code> means the key and balance work. To list the model IDs your key can use, call <code>GET https://cloudgpu.app/v1/models</code> with the same <code>Authorization</code> header. Without a key it returns <code>401</code> with <code>missing_authorization</code>, which is expected.</p>
<p>The same check from the <code>openai</code> Python package, if your agent framework is built on it:</p>
<pre><code class="language-python"># pip install openai
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://cloudgpu.app/v1",
    api_key=os.environ["CGW_API_KEY"],
)

resp = client.chat.completions.create(
    model="deepseek-v4-flash",
    messages=[{"role": "user", "content": "Explain what this regex matches: ^\\d{3}-\\d{4}$"}],
)
print(resp.choices[0].message.content)
</code></pre>
<h2>Step 3: Cursor</h2>
<p>Per Cursor's help page on using your own API key, open <strong>Cursor Settings &gt; Models</strong> and paste your <code>cgw-sk-...</code> key into the API key field. That page doesn't cover the base URL. As of 2026-10-27, per Cursor staff on the forum, using your own key through the base URL override "is an officially supported setup" (<a href="https://forum.cursor.com/t/custom-base-urls-for-each-custom-model/147219">forum thread</a>). Turn on the option to override the base URL and set it to <code>https://cloudgpu.app/v1</code>. Then add <code>deepseek-v4-flash</code> (or <code>deepseek-v4.1-flash</code> / <code>deepseek-v4-pro</code>) as a custom model and select it in Chat. Setting names change between Cursor versions, so follow what your build shows.</p>
<p>Two things to know, per Cursor: custom API keys only work with chat models, and Tab completion keeps using Cursor's built-in models. As of 2026-10-27, per Cursor staff on the forum (same thread), while the base URL override is on, requests for Cursor's own models go to the custom endpoint too, so turn the override off when you switch back to them.</p>
<h2>Step 4: Continue</h2>
<p>Per the Continue docs, the current config format is <code>config.yaml</code> (<code>~/.continue/config.yaml</code>; the older <code>config.json</code> is deprecated). It uses the <code>openai</code> provider for any OpenAI-compatible endpoint; you change <code>apiBase</code>.</p>
<p>The Continue docs say the VS Code and JetBrains extensions can't read variables exported in your shell, so put the key in <code>~/.continue/.env</code> (plain <code>NAME=value</code>, no quotes):</p>
<pre><code class="language-bash">CGW_API_KEY=cgw-sk-...
</code></pre>
<p>Then reference it from <code>config.yaml</code>:</p>
<pre><code class="language-yaml">name: CloudGPU
version: 0.0.1
schema: v1

models:
  - name: DeepSeek V4 Flash (CloudGPU)
    provider: openai
    model: deepseek-v4-flash
    apiBase: https://cloudgpu.app/v1
    apiKey: ${{ secrets.CGW_API_KEY }}
    roles: [chat, edit, apply]
</code></pre>
<p>If your <code>config.yaml</code> already has <code>name</code>, <code>version</code> and <code>schema</code>, add only the model entry. Restart the IDE after editing <code>.env</code>, and don't commit a <code>.env</code> file that contains the key. Swap the <code>model:</code> line for <code>deepseek-v4.1-flash</code> or <code>deepseek-v4-pro</code> to try the others.</p>
<h2>Step 5: Cline</h2>
<p>Per the Cline docs, open the Cline settings panel, set API Provider to "OpenAI Compatible" and fill in three fields: Base URL <code>https://cloudgpu.app/v1</code>, your API key, and model ID <code>deepseek-v4-flash</code>, <code>deepseek-v4.1-flash</code> or <code>deepseek-v4-pro</code>. Run a small task first to check the model handles your workflow before you hand it a long one.</p>
<h2>Step 6: aider</h2>
<p>The aider docs connect to any OpenAI-compatible endpoint through <code>OPENAI_API_BASE</code> and <code>OPENAI_API_KEY</code>, with the model name prefixed by <code>openai/</code>. Reuse the key you already exported:</p>
<pre><code class="language-bash">export OPENAI_API_KEY="$CGW_API_KEY"
export OPENAI_API_BASE=https://cloudgpu.app/v1
aider --model openai/deepseek-v4-flash
</code></pre>
<p>Any other framework that accepts an OpenAI-compatible base URL takes the same two values.</p>
<h2>Which DeepSeek ID to pick</h2>
<p>All three IDs are in the model table on the API page, each with its own rate. <code>deepseek-v4-flash</code> is the model used in the API docs examples, so start there. Then try <code>deepseek-v4.1-flash</code> or <code>deepseek-v4-pro</code> on a real task in your agent and keep the one that fits. Check DeepSeek's own docs for each model's context length and reasoning behaviour.</p>
<p>If a reply comes back with an empty <code>content</code> and <code>finish_reason="length"</code>, raise <code>max_tokens</code> or leave it unset.</p>
<h2>Paying for it</h2>
<p>Usage is paid per token from a prepaid balance; there's no subscription, and the balance doesn't expire. Top up on the billing page by card, Alipay, Google Pay, Apple Pay, or USDT on TRC-20. Rates change, so this post doesn't repeat them: the per-token rate for each model is in the table on the <a href="https://cloudgpu.app/api?utm_source=hashnode&amp;utm_medium=article&amp;utm_campaign=202611_seg04_codingagent&amp;utm_content=hashnode_deepseek_agents">CloudGPU API page</a>. GPU rental rates are on /pricing, and the same balance pays for both.</p>
<h2>Troubleshooting</h2>
<ul>
<li><strong>Cursor rejects the key:</strong> check the base URL is exactly <code>https://cloudgpu.app/v1</code> and the key has no leading or trailing spaces.</li>
<li><code>429 rate_limit_exceeded</code><strong>:</strong> the public-beta default is 100 requests per minute per API key and 10,000 requests per day per account. Use a second key for parallel agents, or email support to raise the limit.</li>
<li><code>402 insufficient_balance</code><strong>:</strong> top up on the billing page.</li>
<li><strong>Streaming stops mid-answer:</strong> check whether the tool has a request timeout setting and raise it.</li>
</ul>
<p>CloudGPU is in public beta with no SLA. If a model returns <code>503 upstream_not_configured</code>, the API docs say it is temporarily unavailable: retry later or use another model.</p>
<h2>FAQ</h2>
<p><strong>Which base URL do I use in Cursor, Continue or Cline?</strong><code>https://cloudgpu.app/v1</code>, with a cloudgpu.app API key that starts with <code>cgw-sk-</code>.</p>
<p><strong>Which DeepSeek model IDs can I use?</strong><code>deepseek-v4-flash</code>, <code>deepseek-v4.1-flash</code> and <code>deepseek-v4-pro</code>, as listed on the API page. Add the ID as a custom model in the tool and select it.</p>
<p><strong>Does this change Cursor tab completion?</strong> No. Per Cursor's docs, custom API keys only work with chat models, and Tab completion keeps using Cursor's built-in models.</p>
<p><strong>Are embeddings supported?</strong> Not yet, per the API docs. If your tool needs an embeddings model for codebase indexing, configure that separately.</p>
]]></content:encoded></item><item><title><![CDATA[Save Your Work Before You Destroy a Cloud GPU: Checkpoints, rsync and Hub Uploads (2026)]]></title><description><![CDATA[Destroying a rented GPU deletes its disk. Copy checkpoints, LoRA adapters and outputs off the machine with rsync, scp, Hugging Face or rclone.]]></description><link>https://cloudgpu.hashnode.dev/save-work-before-destroying-cloud-gpu-2026</link><guid isPermaLink="true">https://cloudgpu.hashnode.dev/save-work-before-destroying-cloud-gpu-2026</guid><category><![CDATA[GPU]]></category><category><![CDATA[Machine Learning]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[Devops]]></category><dc:creator><![CDATA[CloudGPU]]></dc:creator><pubDate>Mon, 26 Oct 2026 13:16:20 GMT</pubDate><content:encoded><![CDATA[<p><strong>On CloudGPU, destroying an instance deletes its disk, and there is no persistent storage across instances yet, so anything you want to keep — checkpoints, LoRA adapters, generated images, logs — must be copied off the machine before you destroy it.</strong> An instance is also destroyed automatically if your balance runs out. This post is the checklist and the commands we use.</p>
<h2>What happens to your files, and when</h2>
<table>
<thead>
<tr>
<th>Event</th>
<th>What happens to the disk</th>
</tr>
</thead>
<tbody><tr>
<td>You click Destroy</td>
<td>The instance stops, billing settles, the disk is deleted</td>
</tr>
<tr>
<td>Your balance cannot cover the next hour</td>
<td>The instance is destroyed and its disk deleted</td>
</tr>
<tr>
<td>You want to “pause” and resume tomorrow</td>
<td>Not available yet: stopping releases the GPU; you start a new instance next time</td>
</tr>
<tr>
<td>The JupyterLab tab or SSH session closes</td>
<td>Nothing — the instance keeps running (and billing) until destroyed</td>
</tr>
</tbody></table>
<p>Because billing is per minute, the economical pattern is: work, copy outputs off, destroy. The minutes spent copying are billed like any other minute, so plan the copy rather than leaving the instance up “just in case”.</p>
<h2>Pick a destination</h2>
<table>
<thead>
<tr>
<th>Destination</th>
<th>Good for</th>
<th>Command family</th>
</tr>
</thead>
<tbody><tr>
<td>Your own computer</td>
<td>Small to medium outputs, anything private</td>
<td><code>rsync</code> / <code>scp</code> over SSH</td>
</tr>
<tr>
<td>Hugging Face Hub (private repo)</td>
<td>LoRA adapters, merged models, datasets you will reuse</td>
<td><code>huggingface-cli upload</code></td>
</tr>
<tr>
<td>S3-compatible object storage (S3, R2, B2…)</td>
<td>Large checkpoints, image batches, logs</td>
<td><code>rclone copy</code></td>
</tr>
<tr>
<td>JupyterLab download button</td>
<td>A handful of small files</td>
<td>Browser</td>
</tr>
</tbody></table>
<p>Do <strong>not</strong> push large files through the instance’s public API endpoint: the tunnel is capped at 3 MB/s and is meant for API responses, not file transfer. Use SSH or an upload from the machine.</p>
<p>Outbound speed from the supplier data centre to a given destination varies. Test with a small file first and add the copy time to your budget.</p>
<h2>Commands</h2>
<h3>1. Pull with rsync from your laptop (resumable)</h3>
<pre><code class="language-bash"># run on your laptop; user, host and port are on the instance page
rsync -avP -e "ssh -p &lt;ssh-port&gt;" &lt;ssh-user&gt;@&lt;ssh-host&gt;:/workspace/out/ ./run-2026-10-23/
</code></pre>
<p><code>-P</code> shows progress and resumes partial files if the connection drops. Re-run the same command at the end; rsync only copies what changed.</p>
<h3>2. Keep pulling during a long run</h3>
<pre><code class="language-bash"># laptop: pull new checkpoints every 10 minutes while training runs
while true; do
  rsync -aP -e "ssh -p &lt;ssh-port&gt;" &lt;ssh-user&gt;@&lt;ssh-host&gt;:/workspace/out/ ./run/ &amp;&amp; date
  sleep 600
done
</code></pre>
<p>Pair it with frequent saves in your trainer (for LLaMA-Factory, <code>save_steps</code> in the YAML; for Hugging Face <code>Trainer</code>, <code>save_steps</code> and <code>save_total_limit</code>).</p>
<h3>3. Push a LoRA adapter to a private Hugging Face repo</h3>
<pre><code class="language-bash">pip install -U "huggingface_hub[cli]"
huggingface-cli login            # paste a fine-grained write token
huggingface-cli upload &lt;your-user&gt;/qwen3-8b-qlora-run1 /workspace/out/qwen3-8b-qlora . --private
</code></pre>
<p>Use a fine-grained token scoped to the one repo and revoke it after the run.</p>
<h3>4. Copy a large output folder to object storage</h3>
<pre><code class="language-bash">curl https://rclone.org/install.sh | bash          # you are root on the instance; or: apt-get install -y rclone
rclone config                                       # add your S3 / R2 / B2 remote
rclone copy /workspace/out remote:my-bucket/run1 --progress --transfers 8
</code></pre>
<h3>5. Tar first when there are many small files</h3>
<pre><code class="language-bash">tar -C /workspace -czf /workspace/outputs.tgz out/
</code></pre>
<p>Thousands of small PNGs or log files copy much faster as one archive.</p>
<h2>The pre-destroy checklist</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Check</th>
<th>Why</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>Training or batch has finished (or you saved a checkpoint)</td>
<td>Partial runs are lost on destroy</td>
</tr>
<tr>
<td>2</td>
<td>Outputs copied and <strong>verified</strong> (file count, sizes, or <code>sha256sum</code>)</td>
<td>A failed copy looks like a successful one until you need it</td>
</tr>
<tr>
<td>3</td>
<td>Configs, scripts and the exact command line saved</td>
<td>So you can reproduce the run on a fresh instance</td>
</tr>
<tr>
<td>4</td>
<td>Environment captured (<code>pip freeze &gt; requirements.txt</code>)</td>
<td>Next instance starts clean</td>
</tr>
<tr>
<td>5</td>
<td>Tokens you pasted on the machine revoked</td>
<td>Good hygiene, even though the disk is deleted</td>
</tr>
<tr>
<td>6</td>
<td>Click Destroy</td>
<td>Unused minutes of the pre-authorised hour return to your balance</td>
</tr>
</tbody></table>
<h2>Budget for the copy, and for the balance</h2>
<p>Two numbers keep long runs safe:</p>
<ul>
<li><strong>Balance buffer.</strong> An instance is destroyed when the balance runs out. For an 8-hour run on a card listed at $0.65/h (RTX 4090 48G, 2026-10-23 23:58 Beijing time), the run itself is $5.20; keep that plus a margin for setup and copying.</li>
<li><strong>Copy time.</strong> Estimate <code>size ÷ measured upload speed</code>, then add it to the job. On a card listed at $0.59/h, 10 extra minutes of copying cost about $0.10.</li>
</ul>
<p>Stock and prices change during the day; check the <a href="https://cloudgpu.app/deploy">Deploy page</a>. Billing rules are on <a href="https://cloudgpu.app/gpu-rental-per-minute-billing">per-minute billing</a>.</p>
<h2>A note on where your data goes</h2>
<p>If your data must not leave a particular jurisdiction, do not train on it here, and choose your copy destination with the same care.</p>
<h2>FAQ</h2>
<p><strong>What happens to my files when I destroy a cloud GPU instance on CloudGPU?</strong></p>
<p>The disk is deleted. Copy anything you need off the machine before you destroy it.</p>
<p><strong>Is there persistent storage between instances?</strong></p>
<p>Not yet. Stopping releases the GPU and the next session starts on a new instance, so keep checkpoints and outputs elsewhere.</p>
<p><strong>What if my balance runs out during training?</strong></p>
<p>The instance is destroyed and its disk deleted. Keep enough balance for the whole run plus a margin, and copy checkpoints off as you go.</p>
<p><strong>How do I download checkpoints from a rented GPU?</strong></p>
<p>Use rsync or scp over SSH, or upload from the machine to a model hub or object storage. Do not use the public API endpoint, which is capped at 3 MB/s.</p>
<p><strong>Am I billed while I copy files off?</strong></p>
<p>Yes. Billing runs per minute until you destroy the instance, so plan the copy and destroy promptly afterwards.</p>
<hr />
<p>If the checkpoints you are saving come from a fine-tune, the <a href="https://cloudgpu.app/rent-gpu-for-lora-fine-tuning">LoRA and QLoRA fine-tuning page</a> covers card choice and billing for those runs. <em>Originally published at <a href="https://cloudgpu.app/blog/save-work-before-destroying-cloud-gpu-2026">cloudgpu.app</a>.</em></p>
<blockquote>
<p>Prices are list prices read on 2026-10-23 23:58 Beijing time (UTC+8); current prices on <a href="https://cloudgpu.app/deploy">/deploy</a> take precedence.</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Self-Host an LLM on a Rented GPU or Pay per Token? A Break-Even Calculator (2026)]]></title><description><![CDATA[When does renting a GPU beat a per-token API? The break-even formula, a Qwen3 32B example on a 32 GB card, utilisation and a script.]]></description><link>https://cloudgpu.hashnode.dev/self-host-llm-vs-api-break-even-2026</link><guid isPermaLink="true">https://cloudgpu.hashnode.dev/self-host-llm-vs-api-break-even-2026</guid><category><![CDATA[llm]]></category><category><![CDATA[self-hosted]]></category><category><![CDATA[AI]]></category><category><![CDATA[GPU]]></category><category><![CDATA[Python]]></category><dc:creator><![CDATA[CloudGPU]]></dc:creator><pubDate>Sun, 25 Oct 2026 13:13:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adb44ed52ba0198ba45d101/3c49eb32-82d7-4de3-8db4-8b259b1ea822.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Self-hosting on a rented GPU is cheaper than a per-token API only when you keep the GPU busy: the break-even is the hourly GPU price divided by the API’s price per token, expressed as tokens you must actually generate and process every hour.</strong> Below that throughput the API wins; above it the GPU wins. This post gives the formula, a worked example with an open 32B model on a single 32 GB card, and a script to run with your own measurements.</p>
<h2>The formula</h2>
<pre><code class="language-text">api_cost_per_hour  = (input_tokens_per_hour × input_price + output_tokens_per_hour × output_price) / 1,000,000
gpu_cost_per_hour  = hourly_gpu_price                     # you pay it whether the GPU is busy or idle

break_even_tokens_per_hour = hourly_gpu_price / blended_price_per_token
blended_price_per_token    = (r × input_price + output_price) / ((r + 1) × 1,000,000)    # r = input:output ratio
</code></pre>
<p>Then correct for <strong>utilisation</strong>: if your GPU is busy only 40% of the hours you rent it, the throughput you need while busy is break-even ÷ 0.4.</p>
<h2>Worked example: Qwen3 32B (4-bit) on an RTX 5090 32G</h2>
<p>Qwen3 32B is an open-weight model (Apache-2.0) that is not offered on the CloudGPU API, so self-hosting is the way to run it here. We use the 4-bit AWQ build because it fits a 32 GB card.</p>
<p><strong>Model size (estimate).</strong> Hugging Face metadata for <code>Qwen/Qwen3-32B</code> lists 32,762,123,264 parameters. In <code>Qwen/Qwen3-32B-AWQ</code>, 31.21B of them are stored at 4 bits and 1.56B stay in BF16:</p>
<pre><code class="language-text">31.21B × 0.5 byte           ≈ 15.6 GB   (4-bit weights)
 1.56B × 2 bytes            ≈  3.1 GB   (BF16 embeddings, norms, output layer)
AWQ scales/zeros, group 128 ≈  0.6 GB
total                       ≈ 19.3 GB   (the repository's files add up to 19.33 GB)
</code></pre>
<p>The FP8 build (<code>Qwen/Qwen3-32B-FP8</code>, about 34.3 GB of files) does not fit in 32 GB of VRAM; it needs a 48 GB card such as the RTX 4090 48G. Figures read from the Hugging Face API on 2026-10-23 21:12 Beijing time; see also <a href="https://cloudgpu.app/run/qwen3-32b">Qwen3 32B VRAM</a>.</p>
<p><strong>Context headroom (estimate).</strong> With an FP16 KV cache, Qwen3 32B stores 2 × 64 layers × 8 KV heads × 128 × 2 bytes = 262,144 bytes (about 0.26 MB) per token: about 2.1 GB at 8k tokens and 8.6 GB at 32k. After about 19.3 GB of weights, a 32 GB card has roughly 12.7 GB for the KV cache and runtime overhead, so at most about 48k cached tokens shared by all concurrent requests, fewer once the overhead is counted.</p>
<p>Inputs (2026-10-23 21:13 Beijing time):</p>
<table>
<thead>
<tr>
<th>Item</th>
<th>Value</th>
<th>Source</th>
</tr>
</thead>
<tbody><tr>
<td>RTX 5090 32G list price</td>
<td>$0.59 per hour, billed per minute</td>
<td><a href="https://cloudgpu.app/gpu-prices.json">https://cloudgpu.app/gpu-prices.json</a></td>
</tr>
<tr>
<td>Per-token reference prices on the same balance</td>
<td>glm-5.3-flash $0.16 in / $0.55 out; gpt-oss-120b $0.135 / $0.54; deepseek-v4-flash $0.27 / $1.08 (per 1M tokens)</td>
<td><a href="https://cloudgpu.app/api">/api</a></td>
</tr>
</tbody></table>
<p><strong>What a self-hosted token costs.</strong> At a fixed $0.59 per hour, the cost per million tokens depends only on the throughput you sustain. The throughputs below are inputs to the arithmetic, not measurements:</p>
<table>
<thead>
<tr>
<th>Sustained throughput (all requests, input + output)</th>
<th>Tokens per hour</th>
<th>Cost per 1M tokens</th>
</tr>
</thead>
<tbody><tr>
<td>100 tokens/s</td>
<td>0.36M</td>
<td>≈ $1.64</td>
</tr>
<tr>
<td>250 tokens/s</td>
<td>0.90M</td>
<td>≈ $0.66</td>
</tr>
<tr>
<td>500 tokens/s</td>
<td>1.80M</td>
<td>≈ $0.33</td>
</tr>
<tr>
<td>1,000 tokens/s</td>
<td>3.60M</td>
<td>≈ $0.16</td>
</tr>
</tbody></table>
<p><strong>Break-even against per-token prices</strong> (3 input : 1 output):</p>
<table>
<thead>
<tr>
<th>Per-token reference</th>
<th>Blended price</th>
<th>Break-even per hour</th>
<th>Throughput needed at 100% / 50% utilisation</th>
</tr>
</thead>
<tbody><tr>
<td>glm-5.3-flash</td>
<td>$0.2575 / 1M</td>
<td>≈ 2.29M tokens/h</td>
<td>≈ 636 / 1,273 tokens/s</td>
</tr>
<tr>
<td>gpt-oss-120b</td>
<td>$0.236 / 1M</td>
<td>≈ 2.50M tokens/h</td>
<td>≈ 694 / 1,387 tokens/s</td>
</tr>
<tr>
<td>deepseek-v4-flash</td>
<td>$0.4725 / 1M</td>
<td>≈ 1.25M tokens/h</td>
<td>≈ 347 / 694 tokens/s</td>
</tr>
</tbody></table>
<p>These are different models from Qwen3 32B, so the table compares cost only: decide on quality first, then use the arithmetic. How to read it: on one card you would need to sustain several hundred tokens per second, aggregated across concurrent requests, for every hour you pay for. That needs batching and steady traffic, and you should verify it with a benchmark on the card. For spiky or low-volume traffic, a per-token API is usually the lower-cost choice.</p>
<p>We do not publish a measured tokens-per-second figure for this card here; measure your own with your prompt lengths and concurrency.</p>
<h2>When renting the GPU wins anyway</h2>
<p>Price per token is not the only reason to rent:</p>
<table>
<thead>
<tr>
<th>Situation</th>
<th>Why a GPU makes sense</th>
</tr>
</thead>
<tbody><tr>
<td>The model is not offered as an API (e.g. Qwen3 32B on CloudGPU, a community fine-tune, your own LoRA)</td>
<td>There is no per-token option to compare against</td>
</tr>
<tr>
<td>Large batch jobs with steady load (offline eval, synthetic data, embeddings, transcription batches)</td>
<td>Utilisation is high and the batch finishes; destroy the instance afterwards</td>
</tr>
<tr>
<td>You need custom serving: LoRA adapters, constrained decoding, specific quantisation</td>
<td>You control the stack</td>
</tr>
<tr>
<td>You need image pipelines with custom nodes (ComfyUI)</td>
<td>APIs expose fixed models only</td>
</tr>
</tbody></table>
<h2>When the API wins</h2>
<table>
<thead>
<tr>
<th>Situation</th>
<th>Why</th>
</tr>
</thead>
<tbody><tr>
<td>Traffic is spiky or low</td>
<td>You would pay for idle GPU hours</td>
</tr>
<tr>
<td>The model is too large for one rented card (e.g. DeepSeek V4, Kimi K3)</td>
<td>Self-hosting would need far more VRAM than one card has</td>
</tr>
<tr>
<td>You need the model now, without ops work</td>
<td>No boot, no downloads, no monitoring</td>
</tr>
<tr>
<td>You need a closed frontier model</td>
<td>Only available as an API</td>
</tr>
</tbody></table>
<p>For that last case, the same CloudGPU balance pays for the API. Our per-1M-token rate for each Claude model is shown next to the official list price on the <a href="https://cloudgpu.app/api">API page</a>; official list prices were checked 2026-10-24 on the official Claude pricing page and can change after that date. Rates for the other models are on the same page.</p>
<h2>What an always-on GPU costs</h2>
<p>If you keep a card running 24/7 to serve traffic, the bill is fixed regardless of tokens (list prices, 2026-10-23 21:13 Beijing time):</p>
<table>
<thead>
<tr>
<th>Card</th>
<th>Per day (24 h)</th>
<th>Per 30 days</th>
</tr>
</thead>
<tbody><tr>
<td>RTX 4090 24G ($0.33/h)</td>
<td>$7.92</td>
<td>$237.60</td>
</tr>
<tr>
<td>RTX 5090 32G ($0.59/h)</td>
<td>$14.16</td>
<td>$424.80</td>
</tr>
<tr>
<td>RTX 4090 48G ($0.65/h)</td>
<td>$15.60</td>
<td>$468.00</td>
</tr>
<tr>
<td>A800 80G ($1.09/h)</td>
<td>$26.16</td>
<td>$784.80</td>
</tr>
<tr>
<td>A100 80G ($1.49/h)</td>
<td>$35.76</td>
<td>$1,072.80</td>
</tr>
</tbody></table>
<p>“Fixed cost” does not mean unlimited output: the card’s throughput caps how many tokens you can serve. Also budget for restarts — destroying an instance deletes its disk, so a redeploy re-downloads weights. Stock changes during the day; check <a href="https://cloudgpu.app/deploy">Deploy</a>.</p>
<h2>A script for your own numbers</h2>
<pre><code class="language-python">def break_even(gpu_price_h, in_price_m, out_price_m, in_out_ratio=3.0, utilisation=1.0):
    blended = (in_out_ratio * in_price_m + out_price_m) / (in_out_ratio + 1) / 1e6   # $ per token
    tokens_per_hour = gpu_price_h / blended
    return tokens_per_hour, tokens_per_hour / 3600 / utilisation                       # tokens/h, tokens/s while busy

def monthly(gpu_price_h, hours_per_day=24, days=30):
    return gpu_price_h * hours_per_day * days

def cost_per_million(gpu_price_h, tokens_per_second):
    return gpu_price_h / (tokens_per_second * 3600 / 1e6)                              # $ per 1M tokens

# Qwen3 32B AWQ on an RTX 5090 32G at $0.59/h vs a $0.16 in / $0.55 out per-token reference (2026-10-23 21:13)
tph, tps = break_even(0.59, 0.16, 0.55, in_out_ratio=3, utilisation=0.5)
print(f"break-even: {tph/1e6:.2f}M tokens/h, {tps:.0f} tokens/s while busy")
print(f"self-hosted cost at 500 tokens/s: ${cost_per_million(0.59, 500):.2f} per 1M tokens")
print(f"always-on RTX 5090 32G for 30 days: ${monthly(0.59):.2f}")
</code></pre>
<p>Replace the prices with the live values from <a href="https://cloudgpu.app/pricing">/pricing</a> and <a href="https://cloudgpu.app/api">/api</a> on the day you decide, and replace utilisation and the input:output ratio with your logs.</p>
<h2>FAQ</h2>
<p><strong>Is self-hosting an LLM cheaper than using an API?</strong></p>
<p>Only if you keep the GPU busy enough. Divide the GPU’s hourly price by the API’s blended price per token; if your measured sustained throughput is above that number, self-hosting is cheaper.</p>
<p><strong>How do I calculate the break-even between GPU rental and API pricing?</strong></p>
<p>break-even tokens per hour = hourly GPU price ÷ blended API price per token, where the blended price weights input and output by your traffic ratio. Divide by utilisation to get the throughput you need while busy.</p>
<p><strong>What utilisation do I need for self-hosting to pay off?</strong></p>
<p>It depends on the model and card; compute break-even from the formula, then compare with the throughput you measure under realistic concurrency.</p>
<p><strong>Why rent a GPU if the API is cheaper per token?</strong></p>
<p>For models with no API, fine-tunes and LoRA adapters, custom serving stacks, ComfyUI pipelines, or steady batch jobs that keep the card busy.</p>
<p><strong>Can I use the same balance for GPUs and the API?</strong></p>
<p>Yes. One prepaid balance covers per-minute GPU rental and per-token API calls.</p>
<hr />
<p>If you want to check the hourly side of the formula, the <a href="https://cloudgpu.app/gpu-rental-per-minute-billing">per-minute GPU rental page</a> explains how a job is billed. <em>Originally published at</em> <a href="https://cloudgpu.app/blog/self-host-llm-vs-api-break-even-2026"><em>cloudgpu.app</em></a><em>.</em></p>
<blockquote>
<p>Break-even figures are arithmetic on list prices, not performance measurements. Prices were read on 2026-10-23 21:13 Beijing time (UTC+8); model sizes are estimates from Hugging Face metadata read at 21:12; current prices on <a href="https://cloudgpu.app/deploy">/deploy</a> and <a href="https://cloudgpu.app/api">/api</a> take precedence.</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[KV Cache VRAM Calculator: How Much Memory Does Context Length Need? (2026)]]></title><description><![CDATA[KV cache memory for any context length: the formula, per-token sizes for Qwen3, Llama 3 and Mistral from config.json, and what fits on 24–80 GB.]]></description><link>https://cloudgpu.hashnode.dev/kv-cache-vram-context-length-calculator-2026</link><guid isPermaLink="true">https://cloudgpu.hashnode.dev/kv-cache-vram-context-length-calculator-2026</guid><category><![CDATA[llm]]></category><category><![CDATA[GPU]]></category><category><![CDATA[Machine Learning]]></category><category><![CDATA[AI]]></category><category><![CDATA[Python]]></category><dc:creator><![CDATA[CloudGPU]]></dc:creator><pubDate>Sat, 24 Oct 2026 13:12:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adb44ed52ba0198ba45d101/8f5ec94d-945e-4165-8c2f-a07230b92ed6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>The KV cache is the memory a transformer uses to remember every token in the context, and its size grows linearly with context length:</strong> bytes per token = 2 × layers × KV heads × head dimension × bytes per value. For Qwen3 32B at FP16 that is 256 KiB per token, or about 8 GB for a 32k-token context, on top of the model weights. This is why a model that loads fine can still run out of memory when you raise the context.</p>
<p>This post gives the formula, the per-token numbers for popular models (read from their <code>config.json</code>), and how much context fits on 24, 32, 48 and 80 GB cards.</p>
<h2>The formula</h2>
<pre><code class="language-text">kv_bytes_per_token = 2 × num_hidden_layers × num_key_value_heads × head_dim × bytes_per_value
kv_total_bytes     = kv_bytes_per_token × context_tokens × concurrent_sequences
</code></pre>
<ul>
<li>The <strong>2</strong> is for keys and values.</li>
<li><code>num_key_value_heads</code> is smaller than the number of attention heads in models with grouped-query attention (GQA), which is why modern models have much smaller caches than older ones.</li>
<li><code>bytes_per_value</code> is 2 for FP16/BF16, 1 for 8-bit KV cache, about 0.5 for 4-bit.</li>
<li><strong>Concurrent sequences multiply the cache.</strong> If your server keeps four parallel slots, budget four times the context.</li>
</ul>
<h2>Per-token KV cache for popular models (FP16)</h2>
<p>Architecture values are from each model’s <code>config.json</code> on Hugging Face (read 2026-10-23). GB here means GiB (1024³ bytes).</p>
<table>
<thead>
<tr>
<th>Model</th>
<th>Layers</th>
<th>KV heads</th>
<th>head_dim</th>
<th>KV per token</th>
<th>8k ctx</th>
<th>32k ctx</th>
<th>128k ctx</th>
</tr>
</thead>
<tbody><tr>
<td>Llama 3.1 8B</td>
<td>32</td>
<td>8</td>
<td>128</td>
<td>128 KiB</td>
<td>1.0 GB</td>
<td>4.0 GB</td>
<td>16 GB</td>
</tr>
<tr>
<td>Qwen3 8B</td>
<td>36</td>
<td>8</td>
<td>128</td>
<td>144 KiB</td>
<td>1.1 GB</td>
<td>4.5 GB</td>
<td>18 GB*</td>
</tr>
<tr>
<td>Qwen3 14B</td>
<td>40</td>
<td>8</td>
<td>128</td>
<td>160 KiB</td>
<td>1.25 GB</td>
<td>5.0 GB</td>
<td>20 GB*</td>
</tr>
<tr>
<td>Mistral Small 3 24B</td>
<td>40</td>
<td>8</td>
<td>128</td>
<td>160 KiB</td>
<td>1.25 GB</td>
<td>5.0 GB</td>
<td>— (32k max)</td>
</tr>
<tr>
<td>Qwen3 32B</td>
<td>64</td>
<td>8</td>
<td>128</td>
<td>256 KiB</td>
<td>2.0 GB</td>
<td>8.0 GB</td>
<td>32 GB*</td>
</tr>
<tr>
<td>Llama 3.3 70B</td>
<td>80</td>
<td>8</td>
<td>128</td>
<td>320 KiB</td>
<td>2.5 GB</td>
<td>10 GB</td>
<td>40 GB</td>
</tr>
<tr>
<td>Qwen2.5 72B</td>
<td>80</td>
<td>8</td>
<td>128</td>
<td>320 KiB</td>
<td>2.5 GB</td>
<td>10 GB</td>
<td>40 GB*</td>
</tr>
</tbody></table>
<p>* Beyond the model’s native window. Qwen3 dense models are documented with a native 32,768-token context, extendable with YaRN rope scaling; check the model card before going past the native length.</p>
<p>The formula does not apply as-is to models with sliding-window layers (for example Gemma 3) or latent attention (DeepSeek V3-style MLA); their caches are smaller than this formula suggests.</p>
<h2>How much context fits on each card</h2>
<p>Total memory ≈ weights + KV cache + overhead. Weights are the Q4_K_M sizes on our <a href="https://cloudgpu.app/run">/run</a> pages; overhead is an <strong>assumed 1.5 GB</strong> for CUDA context, buffers and the runtime. The result is a ceiling for a single sequence; runtimes reserve extra buffers, so plan below it.</p>
<p><strong>Qwen3 32B at Q4_K_M (≈ 19.5 GB weights, 256 KiB/token):</strong></p>
<table>
<thead>
<tr>
<th>Card class</th>
<th>Left for KV after weights + 1.5 GB</th>
<th>Context ceiling (1 sequence)</th>
<th>Practical guidance</th>
</tr>
</thead>
<tbody><tr>
<td>24 GB (RTX 4090 / 3090)</td>
<td>≈ 3 GB</td>
<td>≈ 12k tokens</td>
<td>about 8k; tight</td>
</tr>
<tr>
<td>32 GB (RTX 5090)</td>
<td>≈ 11 GB</td>
<td>≈ 45k (native max 32k)</td>
<td>16k–32k comfortable</td>
</tr>
<tr>
<td>48 GB (RTX 4090 48G)</td>
<td>≈ 27 GB</td>
<td>≈ 110k</td>
<td>full native 32k, or several parallel slots</td>
</tr>
</tbody></table>
<p><strong>Llama 3.3 70B at Q4_K_M (≈ 41.5 GB weights, 320 KiB/token):</strong></p>
<table>
<thead>
<tr>
<th>Card class</th>
<th>Left for KV</th>
<th>Context ceiling (1 sequence)</th>
<th>Practical guidance</th>
</tr>
</thead>
<tbody><tr>
<td>48 GB (RTX 4090 48G / A6000)</td>
<td>≈ 5 GB</td>
<td>≈ 16k</td>
<td>about 8k; tight</td>
</tr>
<tr>
<td>80 GB (A100 / A800)</td>
<td>≈ 37 GB</td>
<td>≈ 121k</td>
<td>32k comfortable, with room for parallel requests</td>
</tr>
</tbody></table>
<p>The “practical guidance” column matches the per-model notes on our <a href="https://cloudgpu.app/run/qwen3-32b">Qwen3 32B page</a> and <a href="https://cloudgpu.app/run/llama-3-3-70b">Llama 3.3 70B page</a>.</p>
<h2>A small calculator</h2>
<pre><code class="language-python">def kv_gb(layers, kv_heads, head_dim, ctx, bytes_per_value=2, seqs=1):
    return 2 * layers * kv_heads * head_dim * bytes_per_value * ctx * seqs / 1024**3

def max_ctx(vram_gb, weights_gb, layers, kv_heads, head_dim,
            bytes_per_value=2, overhead_gb=1.5, seqs=1):
    free = vram_gb - weights_gb - overhead_gb
    per_tok = 2 * layers * kv_heads * head_dim * bytes_per_value / 1024**3
    return max(0, int(free / (per_tok * seqs)))

# Qwen3 32B (64 layers, 8 KV heads, head_dim 128), Q4 weights ≈ 19.5 GB
print(kv_gb(64, 8, 128, 32768))          # 8.0
print(max_ctx(32, 19.5, 64, 8, 128))     # ≈ 45k (native limit is 32k)
print(max_ctx(24, 19.5, 64, 8, 128, bytes_per_value=1))  # 8-bit KV: ≈ 24k
</code></pre>
<p>Read <code>num_hidden_layers</code>, <code>num_key_value_heads</code> and <code>head_dim</code> (or <code>hidden_size / num_attention_heads</code>) from the model’s <code>config.json</code>.</p>
<h2>Three ways to fit more context</h2>
<p><strong>1. Quantise the KV cache.</strong> Halving bytes per value halves the cache.</p>
<pre><code class="language-bash"># Ollama: 8-bit KV cache (requires flash attention)
export OLLAMA_FLASH_ATTENTION=1
export OLLAMA_KV_CACHE_TYPE=q8_0
ollama serve
</code></pre>
<pre><code class="language-bash"># vLLM: FP8 KV cache
vllm serve Qwen/Qwen3-32B-AWQ --kv-cache-dtype fp8 --max-model-len 32768
</code></pre>
<p>Quality impact is usually small at 8-bit and more noticeable at 4-bit; test on your own prompts.</p>
<p><strong>2. Set the context you need, not the maximum.</strong> In Ollama, pass <code>"options": {"num_ctx": 16384}</code> per request (or set <code>OLLAMA_CONTEXT_LENGTH</code>). In vLLM, <code>--max-model-len</code> caps the context and <code>--gpu-memory-utilization</code> sets how much VRAM the cache may take.</p>
<p><strong>3. Watch parallelism.</strong> Ollama’s <code>OLLAMA_NUM_PARALLEL</code> and vLLM’s batching both allocate cache per sequence. If memory runs out under load but not in single tests, this is usually why.</p>
<h2>Troubleshooting order when you run out of memory</h2>
<p>Say you run Qwen3 32B (Q4_K_M) with Ollama on a 24 GB RTX 4090, set <code>num_ctx</code> to 32768, and get out-of-memory errors or a sudden slowdown (layers spilling to CPU). The formula explains it: about 19.5 GB of weights plus about 8 GB of FP16 KV cache is more than 24 GB. Try these, least effort first:</p>
<ol>
<li><strong>Lower the context.</strong> Back to 8192 and the KV cache is about 2 GB; total about 23 GB — it runs, but tight.</li>
<li><strong>Quantise the KV cache.</strong> With <code>OLLAMA_FLASH_ATTENTION=1</code> and <code>OLLAMA_KV_CACHE_TYPE=q8_0</code>, the same memory holds roughly twice the context — about 24k by the formula (a ceiling; leave headroom).</li>
<li><strong>Check parallelism.</strong> Set <code>OLLAMA_NUM_PARALLEL=1</code> to rule out several slots sharing the memory.</li>
<li><strong>Change cards.</strong> Still short? Move to a 32 GB RTX 5090 or a 48 GB RTX 4090 48G. Switching means starting a new instance and downloading the model again.</li>
</ol>
<p>After each change, check real usage with <code>nvidia-smi</code> and note the number; next time you size a card, you will have your own data.</p>
<h2>Picking a card from the numbers</h2>
<p>Once you have weights + KV + overhead, round up to the next VRAM class and check <a href="https://cloudgpu.app/deploy">Deploy</a> for live stock. GPUs are billed per minute; current rates are on the <a href="https://cloudgpu.app/pricing">pricing page</a>. For a side-by-side of those cards, see <a href="https://cloudgpu.app/compare/rtx-4090-vs-5090-vs-a100">RTX 4090 vs RTX 5090 vs A100</a>.</p>
<h2>FAQ</h2>
<p><strong>How do I calculate the KV cache size for a model?</strong></p>
<p>Multiply 2 × layers × KV heads × head dimension × bytes per value (2 for FP16) to get bytes per token, then multiply by context length and the number of parallel sequences. The values are in the model’s config.json.</p>
<p><strong>How much VRAM does a 32k context need for Qwen3 32B?</strong></p>
<p>About 8 GB of FP16 KV cache (256 KiB per token × 32,768 tokens), on top of about 19.5 GB of Q4_K_M weights, so a 32 GB card is the comfortable choice.</p>
<p><strong>Why does my model run out of memory only at long context?</strong></p>
<p>The weights are fixed, but the KV cache grows with every token of context and with each parallel request. Lower num_ctx / max-model-len, reduce parallel slots, or quantise the KV cache.</p>
<p><strong>Does an 8-bit KV cache halve memory?</strong></p>
<p>Yes, the cache itself is halved compared with FP16. In Ollama set OLLAMA_KV_CACHE_TYPE=q8_0 with flash attention on; in vLLM use --kv-cache-dtype fp8.</p>
<p><strong>Does the formula work for every model?</strong></p>
<p>It works for standard and grouped-query attention. Models with sliding-window layers or latent attention use less memory than it predicts.</p>
<hr />
<p>Once you have your own numbers, the <a href="https://cloudgpu.app/compare/rtx-4090-vs-5090-vs-a100">RTX 4090 vs RTX 5090 vs A100 comparison</a> lines up the cards by VRAM class. <em>Originally published at</em> <a href="https://cloudgpu.app/blog/kv-cache-vram-context-length-calculator-2026"><em>cloudgpu.app</em></a><em>.</em></p>
<blockquote>
<p>CloudGPU (cloudgpu.app) has no partnership with, authorization from, or endorsement by the model vendor. Model names are trademarks of their owners. Context ceilings are estimates under the stated assumptions, not measurements. Live prices are on <a href="https://cloudgpu.app/pricing">/pricing</a> and live stock on <a href="https://cloudgpu.app/deploy">/deploy</a>.</p>
</blockquote>
]]></content:encoded></item></channel></rss>