ModelsQwenQwen3-VL-30B-A3B-Instruct
providerQwen /

Qwen3-VL-30B-A3B-Instruct

52.5 DZD in 210 DZD out/ 1M tokens
Service tier pricing, in DZD per 1M tokens
TierInputOutputCached input
PriorityLearn more
81324—
43.2172.8—
Prices in DZD per 1M tokens

Qwen3-VL-30B-A3B-Instruct runs the same vision stack as the flagship of its series on roughly three billion active parameters. DeepStack, interleaved multi-axis positional encoding, timestamp-grounded event localisation, and OCR across 32 languages — all present, none reduced. What scales down is the language reasoning over what it sees, not the seeing itself. That combination is unusual and it decides the workload: document archives, receipt pipelines, video indexing at volume, where per-page cost determines whether the corpus gets processed at all rather than how well.

Publicfp8JSONVideoOCRStreamingApache-2.0
Qwen3-VL-30B-A3B-Instruct
Capabilities
ToolsVisionStructured output
ArchitectureMoE
Context Window262K

Qwen3-VL-30B-A3B-Instruct

The same eyes as the flagship. A seventh of the compute.


What Does Not Shrink

The Qwen3-VL series documents its vision capabilities identically across every size, and that is the fact worth leading with.

30B-A3B235B-A22B
Active per token~3B~22B
DeepStack✅✅
Interleaved-MRoPE✅✅
Timestamp alignment✅✅
OCR languages3232
Context262,144262,144

The perception is the same. The reasoning over it is not.

Which means the question is not "how well does it see." It is "how hard is the question you are asking about what it saw."

Transcribe this invoice is a perception task. Both models read the same characters.

Reconcile these three invoices against the contract and explain the discrepancy is a language task, and that is where twenty-two billion active parameters do something three billion cannot.


Three Vision Mechanisms

All present at this size, and each solves a different problem.

DeepStack

Fuses multi-level ViT features to capture fine-grained details and sharpen image–text alignment.

A vision transformer processes an image through many layers. The conventional approach hands the language model the final layer only — which holds semantics and has discarded most of what earlier layers saw.

Early layers carry edges, texture, small structure. Late layers carry meaning. Reading only the last one produces a model that knows what the photograph shows and has lost the fine print inside it.

DeepStack reads several levels. That is why small text in a photograph survives.

Interleaved-MRoPE

Full-frequency allocation over time, width, and height.

Video has three positional axes. A scheme handling two well and the third as an afterthought produces a model that describes frames rather than reasoning across them. Full-frequency allocation across all three is what long-horizon video reasoning requires.

Text–Timestamp Alignment

Moves beyond T-RoPE to precise, timestamp-grounded event localization.

"At what second does this happen" rather than "what happens in this video." Localisation rather than description — and on a model cheap enough to run across an archive, that turns a video library into a searchable index.


OCR Built for Photographs

32 languages, up from 19. And the robustness claims name conditions rather than accuracy:

Low light. Blur. Tilt.

Those are the conditions of a photograph taken by a person — a receipt on a table, an invoice shot at an angle, a sign in a dim room. Not the conditions of a scan.

Also documented: rare and ancient characters, domain jargon, and improved long-document structure parsing.

That last one is what separates OCR output from usable data. Reading characters is one problem; recognising that a page has a header, a table with six columns, and a footnote is another — and it is the one that decides whether the result can go into a database.


Three Billion Active Parameters Changes the Workload

The number that decides what this model is for.

Vision work is high-volume by nature. A document archive is thousands of pages. A receipt pipeline is thousands of photographs a day. A video library is hundreds of hours.

On a flagship model, per-item cost is what decides whether the archive gets processed at all. Not how well — whether.

At three billion active parameters, that calculation changes. The same OCR, the same structure parsing, the same timestamp localisation, at a fraction of the compute per item.

And the pairing that follows. Run this model across everything. Escalate the cases it flags — low-confidence transcriptions, unusual documents, contradictions — to the flagship in the same series. Same three vision mechanisms on both sides, same request shape, one changed model identifier.

That is a real pipeline rather than a compromise, because the perception does not degrade at the first stage. Only the reasoning does, and the first stage is not doing reasoning.


Specifications

Model IDQwen/Qwen3-VL-30B-A3B-Instruct
ArchitectureMixture-of-Experts vision-language
Model classQwen3VLMoeForConditionalGeneration
Total parameters~30B
Activated per token~3B
Context length262,144 tokens
InputText, image, video
OutputText
OCR languages32
Vision mechanismsDeepStack, Interleaved-MRoPE, text–timestamp alignment
ThinkingNot supported — Instruct edition
LicenceApache 2.0
DeveloperQwen Team, Alibaba

The series spans dense and MoE architectures from edge to cloud, with Instruct and reasoning-enhanced Thinking editions at each size.

This is the Instruct edition. It answers directly. A Thinking edition exists at this size for work where deliberation over an image earns its cost.

Official FP8 and GGUF builds are published, with community AWQ and lower-bit quantisations alongside.


Capabilities

CapabilityValue
input_typestext, image, video
output_typestext
context_window262144
ocr_languages32
video_localizationTimestamp-grounded
reasoningNot supported — Instruct edition
streamingSupported
tool_callingSupported
structured_outputSupported
multi_imageSupported
requires_promptYes — text prompt required, media optional

Using Qwen3-VL-30B-A3B on DEVUP AI

Base URL: https://api.devupai.com/v1 · Model ID: Qwen/Qwen3-VL-30B-A3B-Instruct

Python

PYTHON
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["DEVUP_API_KEY"],
    base_url="https://api.devupai.com/v1",
)

response = client.chat.completions.create(
    model="Qwen/Qwen3-VL-30B-A3B-Instruct",
    messages=[
        {"role": "user", "content": "Hello world!"}
    ],
    max_tokens=1024,
)

print(response.choices[0].message.content)

Node.js

JAVASCRIPT
import DevupAI from "devupai";

const client = new DevupAI({
  apiKey: process.env.DEVUP_API_KEY,
});

async function main() {
  const response = await client.chat.completions.create({
    model: "Qwen/Qwen3-VL-30B-A3B-Instruct",
    messages: [{ role: "user", content: "Hello world!" }],
    max_tokens: 1024,
  });

  console.log(response.choices[0].message.content);
}

main();

cURL

BASH
curl -X POST "https://api.devupai.com/v1/chat/completions" \
  -H "Authorization: Bearer $DEVUP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen3-VL-30B-A3B-Instruct",
    "messages": [
      { "role": "user", "content": "Hello world!" }
    ],
    "max_tokens": 1024
  }'

A Document Pipeline at Volume

The workload this model exists for, written to survive a run of several thousand.

PYTHON
import base64
import json
from pathlib import Path

SCANS = Path("receipts")
OUTPUT = Path("extracted")
OUTPUT.mkdir(exist_ok=True)

PROMPT = (
    "Transcribe this receipt. Return a single JSON object with keys: merchant, date, currency, "
    "total, line_items (an array of {description, quantity, amount}). Use null for any field the "
    "receipt does not show. Where a value is present but you cannot read it cleanly, use the string "
    "\"UNREADABLE\" rather than guessing. Reply with JSON only."
)


def encode(path: Path) -> str:
    return base64.b64encode(path.read_bytes()).decode("utf-8")


for path in sorted(SCANS.glob("*.jpg")):
    target = OUTPUT / f"{path.stem}.json"
    if target.exists():
        continue  # already done — never pay twice

    try:
        response = client.chat.completions.create(
            model="Qwen/Qwen3-VL-30B-A3B-Instruct",
            messages=[
                {
                    "role": "user",
                    "content": [
                        {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{encode(path)}"}},
                        {"type": "text", "text": PROMPT},
                    ],
                }
            ],
            max_tokens=4096,
            temperature=0.1,
        )
        data = json.loads(response.choices[0].message.content)
    except Exception as exc:
        print(f"{path.name}: {type(exc).__name__} — {exc}")
        continue  # one bad file must not stop the run

    target.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")

    unreadable = json.dumps(data).count("UNREADABLE")
    print(f"{path.name}: {unreadable} unreadable field(s)")

Three lines do the operational work.

Skip-if-exists. A run that dies at file 3,400 of 5,000 resumes rather than restarting.

Catch-and-continue. One corrupted image should not end the job.

Counting UNREADABLE. That number is your escalation signal — files with any unreadable field are exactly the ones worth sending to the larger model, and you get the list for free.


Escalating What the First Pass Flags

The two-tier pattern the shared vision stack makes possible.

PYTHON
FAST = "Qwen/Qwen3-VL-30B-A3B-Instruct"
DEEP = "Qwen/Qwen3-VL-235B-A22B-Instruct"


def extract(path: Path, model: str) -> dict:
    """Run the same extraction on either tier — identical request shape."""
    response = client.chat.completions.create(
        model=model,
        messages=[
            {
                "role": "user",
                "content": [
                    {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{encode(path)}"}},
                    {"type": "text", "text": PROMPT},
                ],
            }
        ],
        max_tokens=4096,
        temperature=0.1,
    )
    return json.loads(response.choices[0].message.content)


result = extract(path, FAST)

if "UNREADABLE" in json.dumps(result):
    result = extract(path, DEEP)
    result["_escalated"] = True

The request shape is identical across tiers. One function, one changed argument — no second integration and no divergent prompt to maintain.

Escalate on a signal, not on a guess. Unreadable fields, missing required values, or a document type your first pass does not recognise. Escalating everything defeats the purpose; escalating nothing defeats the safety net.

Record which tier produced each result. Six months from now, knowing whether a figure came from the fast pass or the careful one is the difference between a spot check and a re-run.


Video Indexing

Where timestamp alignment plus low per-item cost becomes a product.

PYTHON
response = client.chat.completions.create(
    model="Qwen/Qwen3-VL-30B-A3B-Instruct",
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "video_url", "video_url": {"url": video_url}},
                {
                    "type": "text",
                    "text": (
                        "List every distinct topic discussed or shown, with the timestamp in seconds "
                        "where it begins. Describe only what is visible or audible. If the video "
                        "covers one topic throughout, say so with a single entry."
                    ),
                },
            ],
        }
    ],
    max_tokens=8192,
    temperature=0.2,
)

Indexing a library is the use case. One pass per video produces timestamps; those timestamps become a search index; a query returns a moment rather than a file.

On a flagship model that is a project. At three billion active parameters it is a batch job.

Video consumes input tokens rapidly. Measure one short clip before processing an archive — the 262,144-token window fills faster than a minute count suggests, and discovering that at file two hundred is expensive.


Multi-Page Documents

PYTHON
content = []
for index, path in enumerate(sorted(Path("contract_pages").glob("*.jpg")), start=1):
    content.append({"type": "text", "text": f"Page {index}:"})
    content.append({"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{encode(path)}"}})

content.append({
    "type": "text",
    "text": (
        "Transcribe each page, preserving its structure. Label each transcription with its page "
        "number. Do not summarise or merge pages."
    ),
})

response = client.chat.completions.create(
    model="Qwen/Qwen3-VL-30B-A3B-Instruct",
    messages=[{"role": "user", "content": content}],
    max_tokens=32768,
)

Labelling each page before it appears gives the model something to cite and gives you something to verify against.

"Do not summarise or merge" is the operative instruction on a transcription task. A model asked to process several pages will helpfully condense them unless told not to — and a condensed contract is not a transcription.

Keep the analysis on the larger model. Cross-page contradiction and reconciliation are language tasks; transcription is not. This model does the second at a fraction of the cost.


It Answers Directly

The Instruct edition — no reasoning blocks, no thinking mode, no reasoning_content field.

max_tokens covers the answer alone, which matters on document work where a full transcription is already a large output.

Latency tracks input and output size, not question difficulty — which is what makes throughput calculable on a batch pipeline.

And a hard visual question gets a direct answer rather than a worked one. The Thinking edition at this size exists for those, and it is a separate model.


Self-Hosting

The model class is Qwen3VLMoeForConditionalGeneration — distinct from the text models in this generation, and a common cause of loading errors.

Enable flash attention 2. Qwen recommend it explicitly for acceleration and memory saving, especially in multi-image and video scenarios — which is where this model lives.

Enable expert parallelism on the MoE builds.

Reduce context length first on out-of-memory. Community configurations default to 32,768 rather than the full figure, which tells you how often that comes up — and at three billion active parameters, the weights are not what fills the card. The context is.

Official FP8 and GGUF builds are published, with community AWQ alongside. At this size the quantised builds are genuinely accessible rather than a data-centre proposition.


Where It Fits

High-volume document processing — invoices, receipts, forms, identity documents — across 32 languages.

Photograph-based OCR, where low light, blur, and tilt are the normal conditions rather than edge cases.

Video indexing at archive scale, using timestamp localisation on a model cheap enough to run across everything.

The first tier of a two-model pipeline, escalating flagged items to the larger model in the same series.

Screen recording analysis for support and QA tooling.

Self-hosted deployment, where the footprint makes local vision work practical.

Not for complex reasoning about what it saw. That is the larger model, or the Thinking edition at this size.

Not for image generation. It reads; it does not draw.


Practical Notes

Send photographs as taken — the model is built for low light, blur, and tilt.

Ask for structure, not just characters.

Use an explicit UNREADABLE marker rather than allowing reconstruction, and count it as your escalation signal.

Build batch runs with skip-if-exists and catch-and-continue from the start.

Label pages and images so answers can cite them.

Measure video token consumption before processing an archive.

Keep reasoning tasks on the larger model — the vision does not degrade here, the language does.

If self-hosting: the MoE class, flash attention 2, expert parallelism, and reduced context on OOM.


Limitations

Roughly three billion active parameters. The vision stack is the flagship's; the reasoning over it is not.

No thinking mode. The Instruct edition answers directly; a Thinking edition exists at this size.

Text output only. Three input modalities, one output modality.

Video fills the context quickly, and 262,144 tokens is reached sooner than a minute count suggests.

OCR covers 32 languages. Others are outside the documented capability.

Thirty billion parameters must be loaded even though three run per token — the MoE saving is in compute, not memory.

Out-of-memory is a context problem here, not a weights problem. Reduce the configured length first.

A distinct model class from the text models in this generation. Loading it with the wrong class fails.

OCR robustness is not infallibility. A confidently transcribed wrong digit looks exactly like a correct one — which is why the unreadable marker and the escalation path matter more on the cheap tier than on the expensive one.