← Journal ← Journal

Qwen 3 27B sur Claude Code pour moins de 30 $ la semaine. Qwen 3 27B on Claude Code for under $30 a week.

Un GPU loué à l'heure, un proxy OpenAI-compatible, un modèle open quantisé en 4-bit. On a branché un modèle open-source dans Claude Code à la place du provider par défaut, pour voir ce que ça donne sur du vrai travail. Ce qui suit, c'est le montage, la facture, et l'endroit où le modèle cale. A GPU rented by the hour, an OpenAI-compatible proxy, a 4-bit quantised open model. We swapped Claude Code's default provider for a self-hosted open-source model to see how it holds up on real work. What follows is the setup, the bill, and where the model runs out of road.

La question n'est pas « remplacer Claude ». C'est plus basique : sur une session de code de quatre heures, avec du contexte qui gonfle (codebase entière, doc, recherches web en parallèle), une fraction du travail est répétitive. Écrire un parseur, renommer une fonction à travers vingt fichiers, formuler une requête SQL, relire une traduction. Est-ce qu'un modèle open-source de 27 milliards de paramètres, loué sur un GPU communautaire, suffit pour cette fraction — à 1 % du coût d'un modèle frontière ?

La réponse courte est oui, pour une fraction qui n'est pas nulle mais pas majoritaire. La réponse longue suit.

Le modèle

On utilise Qwen 3 en version 27 milliards de paramètres, chargé via les builds quantisés d'unsloth. La quantisation 4-bit ramène l'empreinte VRAM autour de 18 Go — ça rentre largement sur une RTX 4090 24 Go, avec de la place pour un contexte de 32 k tokens et un peu de KV-cache. La famille Qwen 3 d'Alibaba est aujourd'hui la série open-source qui a le meilleur rapport capacité/ressources en dehors des modèles frontière fermés ; sur les benchmarks publics (MMLU, GPQA, LiveCodeBench), un 27B quantisé reste compétitif avec des modèles beaucoup plus lourds non quantisés.

Ce n'est pas un jouet. Ce n'est pas non plus Opus. On y reviendra.

L'infra — 0,69 $/h GPU, vLLM, Cloudflare Tunnel

Trois briques, rien d'exotique.

1. Le GPU. Un pod GPU 24 Go chez RunPod, 60 Go de volume persistant et 20 Go de container. Tarif affiché : 0,69 $/h pour le GPU en activité, 0,008 $/h pour le disque quand le pod tourne, 0,011 $/h pour le disque quand le pod est stoppé (le stockage persiste, le GPU non). On ne laisse pas le pod allumé en continu : on le démarre avant une session, on le stoppe après. Sur une semaine chargée — 40 heures actives, 128 heures stoppées — le total tombe à environ 28 $. Une semaine calme descend vers 15-20 $.

2. Le serveur d'inférence. vLLM expose une API OpenAI-compatible. Un docker run avec le bon tag, --served-model-name qwen3-27b, le pod écoute sur :8000/v1/chat/completions. Temps de chargement du modèle en 4-bit : ~3 minutes pour la première requête, ensuite stable autour de 15 à 20 tokens/seconde en génération.

3. L'accès. Deux options : port TCP exposé par RunPod directement, ou Cloudflare Tunnel pour un sous-domaine fixe et du TLS propre. On utilise le tunnel — pod IP change à chaque relance, mais l'URL reste la même côté client.

Le branchement dans Claude Code

Claude Code lit la variable ANTHROPIC_BASE_URL et accepte par défaut le format messages d'Anthropic. Pour parler à un backend OpenAI-compatible, on passe par une fine couche de traduction — claude-code-router ou équivalent — qui convertit les appels Anthropic en appels /v1/chat/completions. Trois variables d'env, le CLI redémarre, et c'est branché :

ANTHROPIC_BASE_URL=https://qwen.tunnel.example/v1
ANTHROPIC_API_KEY=sk-local-…
ANTHROPIC_MODEL=qwen3-27b

Les outils, les agents, les hooks, les skills — tout continue de fonctionner sans modification. Le routeur relaie les appels de tool use, le modèle répond en JSON structuré, Claude Code traite la réponse comme si elle venait d'un provider officiel.

Le montage Pod RunPod 24 Go + vLLM + router OpenAI. Trois composants open, une variable d'env. Le reste de la chaîne Claude Code ne sait pas qu'on a changé de modèle.

Ce qui marche bien

Code local, tâches structurées. Écrire un script Python, un Dockerfile, une requête SQL, un composant React isolé. Le modèle formule correctement, respecte la signature demandée, produit une première passe utilisable. Sur ce registre, on est entre 85 et 90 % de la qualité d'un modèle frontière — suffisant pour itérer ensuite.

Navigation de codebase. grep, lecture ciblée, retrouver l'appel d'une fonction, résumer ce que fait un module. Dans un contexte < 15 k tokens, Qwen s'en sort honnêtement. Au-delà, il commence à oublier ce qu'il a vu au début.

Édition textuelle bilingue. Relire un article, repérer des répétitions, proposer une reformulation. Le FR est propre, l'EN correct — pas stylistiquement distinctif, mais lisible.

Ce qui casse

Les tâches multi-contraintes. Dès qu'on demande de jongler avec plus de trois contraintes en même temps — architecture avec trade-offs, refacto qui doit préserver une API publique tout en modifiant la structure interne, debug qui exige de garder cinq hypothèses en tête — la qualité chute. Le modèle simplifie, choisit une contrainte dominante et oublie les autres.

Les hallucinations de détail. Noms de fonctions qui n'existent pas, chemins de fichiers inventés, versions de librairie approximatives. Opus hallucine aussi, mais moins souvent sur des détails techniques. Il faut vérifier systématiquement avant d'exécuter la moindre commande proposée.

Le contexte long. Au-delà de 20 k tokens injectés, la cohérence baisse nettement. Lui donner un article complet + son CSS + le JS associé, c'est déjà trop ; il perd des informations du début. Le modèle est annoncé à 32 k, on le considère utilisable jusqu'à 20.

Le travail d'agent long. Enchaîner dix tool calls avec mémoire du résultat de chacun, c'est le point faible. Les premiers appels sont bons, le contexte interne se pollue, et au cinquième ou sixième le modèle produit des arguments incohérents avec ce qu'il vient de lire. C'est précisément le régime où Claude Code brille avec un modèle frontière.

Preuve par l'exemple

Un premier brouillon de cette note a été rédigé par le modèle lui-même, en direct dans la session Claude Code qui tourne sur Qwen. Des coquilles types sont passées — « plaent » pour « placent », « transborder » pour un verbe qui n'existe pas, un paragraphe qui mélangeait deux idées. On les a corrigées dans cette version publiée, mais la structure de l'article, les arguments, l'estimation des coûts, tout ça vient du modèle. C'est exactement le niveau : un assistant sérieux qui demande une relecture. Pas un rédacteur autonome.

Facture exacte de la semaine en cours
40 heures de pod actives · 40 × (0,69 $ GPU + 0,008 $ disk running) = 27,92 $. 128 heures stoppées, GPU non facturé, disk seul · 128 × 0,011 $ = 1,41 $. Total 29,33 $. Bande passante : négligeable (Cloudflare Tunnel gratuit). Volume : 60 Go persistant pour garder les weights entre sessions, 20 Go de container. Comparaison directe impossible à l'identique avec un provider frontière — les workflows ne sont pas les mêmes — mais on note qu'une seule session intensive Opus peut approcher la semaine entière de Qwen.

La conclusion honnête

Qwen 3 27B self-hébergé ne remplace pas un modèle frontière. Il n'est pas au niveau sur les tâches difficiles, et l'opérationnel (démarrer un pod, surveiller le tunnel, gérer les reprises) ajoute un coût caché en friction. Mais pour 30 à 50 % d'un workflow de studio — génération de boilerplate, recherche dans une base, reformulation éditoriale, scripts ponctuels — il fait largement le job, à un coût qui change la psychologie du travail. On n'hésite plus à demander. On essaie, on jette, on recommence.

Le modèle ouvert ne ferme pas la frontière, il ouvre un deuxième étage. Les deux cohabitent. Quand on revient à Opus pour un debug subtil, on le sent — et on comprend ce qu'on paie. Ce contraste, à lui seul, justifie le montage.

The question isn't "replace Claude". It's more basic: across a four-hour coding session with context that bloats (whole codebase, docs, parallel web searches), a chunk of the work is repetitive. Writing a parser, renaming a function across twenty files, drafting a SQL query, reviewing a translation. Can a 27-billion-parameter open-source model, rented on a 24 GB GPU by the hour, handle that chunk — at a small fraction of frontier-model cost?

Short answer: yes, for a chunk that isn't negligible but isn't the majority either. Long answer below.

The model

We run Qwen 3 at 27 billion parameters, loaded via unsloth's quantised builds. 4-bit quantisation brings the VRAM footprint down to ~18 GB — comfortable on a 24 GB RTX 4090, with room for a 32k context and some KV-cache. Alibaba's Qwen 3 family is currently the best capability-per-parameter open series outside closed frontier models; on public benchmarks (MMLU, GPQA, LiveCodeBench) a quantised 27B still holds against much heavier non-quantised models.

Not a toy. Not Opus either. We'll come back to that.

The infra — $0.69/h GPU, vLLM, Cloudflare Tunnel

Three pieces, nothing exotic.

1. The GPU. A 24 GB GPU pod on RunPod, 60 GB persistent volume, 20 GB container. Advertised rate: $0.69/h while the GPU is active, $0.008/h for disk while the pod is running, $0.011/h for disk while the pod is stopped (storage persists, GPU does not). We don't leave the pod running: start it before a session, stop it after. On a heavy week — 40 active hours, 128 stopped hours — total lands around $28. A quiet week drops to $15–20.

2. The inference server. vLLM exposes an OpenAI-compatible API. One docker run with the right tag, --served-model-name qwen3-27b, the pod listens on :8000/v1/chat/completions. Model load in 4-bit: ~3 minutes for the first request, then stable at 15 to 20 tokens/second in generation.

3. Access. Two options: RunPod-exposed TCP port, or Cloudflare Tunnel for a fixed subdomain and clean TLS. We use the tunnel — pod IP changes between restarts, the URL stays the same client-side.

Wiring it into Claude Code

Claude Code reads ANTHROPIC_BASE_URL and speaks Anthropic's messages format by default. To talk to an OpenAI-compatible backend, we use a thin translation layer — claude-code-router or equivalent — that converts Anthropic calls into /v1/chat/completions calls. Three env vars, restart the CLI, it's wired:

ANTHROPIC_BASE_URL=https://qwen.tunnel.example/v1
ANTHROPIC_API_KEY=sk-local-…
ANTHROPIC_MODEL=qwen3-27b

Tools, agents, hooks, skills — everything keeps working unchanged. The router relays tool-use calls, the model replies with structured JSON, Claude Code treats the response as if it came from an official provider.

The rig RunPod 24 GB pod + vLLM + OpenAI router. Three open components, one env var. The rest of the Claude Code chain doesn't know the model changed.

What works

Local code, structured tasks. Writing a Python script, a Dockerfile, a SQL query, an isolated React component. The model gets the shape right, respects the signature, produces a usable first pass. In that register we're at 85 to 90% of frontier-model quality — enough to iterate on top.

Codebase navigation. grep, targeted reads, finding a function's callers, summarising what a module does. In a context under 15k tokens, Qwen holds up. Past that, it starts forgetting what it saw at the top.

Bilingual editing. Reviewing an article, spotting repetition, suggesting a rewrite. French is clean, English is correct — not stylistically distinctive, but readable.

What breaks

Multi-constraint tasks. Ask the model to juggle more than three constraints at once — architecture with trade-offs, a refactor that preserves a public API while changing internal structure, a debug that needs five hypotheses in memory — quality drops. The model simplifies, picks one dominant constraint, forgets the others.

Detail hallucinations. Function names that don't exist, invented file paths, fuzzy library versions. Opus hallucinates too, but less often on technical detail. You verify systematically before running any suggested command.

Long context. Past 20k injected tokens, coherence noticeably drops. Giving it a full article plus its CSS plus its JS is already too much; it loses information from the top. The model is advertised at 32k, we treat it as usable up to 20.

Long agentic work. Chaining ten tool calls while remembering each result — that's the weakness. First calls are good, the internal context gets polluted, and by the fifth or sixth the model produces arguments inconsistent with what it just read. That's precisely the regime where Claude Code shines with a frontier model.

Proof by example

A first draft of this note was written by the model itself, live in a Claude Code session backed by Qwen. Telltale slips went through — a misspelling, a made-up verb, a paragraph that conflated two ideas. We fixed them in this published version, but the structure, the arguments, the cost estimate, all of that came from the model. That's exactly the level: a serious assistant that asks for a pass. Not an autonomous writer.

Exact bill for the current week
40 active pod hours · 40 × ($0.69 GPU + $0.008 disk running) = $27.92. 128 stopped hours, GPU not billed, disk only · 128 × $0.011 = $1.41. Total $29.33. Bandwidth: negligible (Cloudflare Tunnel free). Volume: 60 GB persistent to keep weights between sessions, 20 GB container. No like-for-like comparison with a frontier provider — workflows differ — but we'll note that a single intensive Opus session can approach a full Qwen week.

The honest verdict

Self-hosted Qwen 3 27B doesn't replace a frontier model. It's not at that level on hard tasks, and the ops (spinning a pod, watching the tunnel, handling restarts) add hidden friction. But for 30–50% of a studio workflow — boilerplate generation, codebase lookup, editorial rewriting, one-off scripts — it does the job, at a price that changes the psychology of the work. We stop hesitating before asking. We try, throw away, retry.

The open model doesn't close the frontier, it opens a second floor. The two coexist. When we go back to Opus for a subtle debug, we feel it — and we understand what we pay for. That contrast alone justifies the rig.