> Raw Markdown twin (generated at build time from the source Markdown). Rendered page: https://docs.gatellm.io/en/sdk/dashscope-native · Doc index: https://docs.gatellm.io/en/llms.txt


# DashScope native SDK & async tasks

Alibaba Cloud Bailian (DashScope) Qwen models can be called via the OpenAI SDK like OpenAI (translation mode), or via the DashScope native SDK through the **passthrough** entry `/v1/services/{*rest}`. The native SDK needs just one variable changed:

```bash
pip install dashscope requests
```

```python
import dashscope

dashscope.base_http_api_url = "http://localhost:7890/v1"   # point at the gateway
dashscope.api_key = "<your access key>"
```

## Passthrough vs translation: choosing a path {#passthrough-vs-translate}

| Entry | Behavior | When to use |
|-------|----------|-------------|
| `/v1/services/{*rest}` | **Passthrough**: body forwarded to DashScope as-is, no protocol conversion | DashScope native SDK, or DashScope-specific fields / async tasks |
| `/v1/chat/completions` | **Translation**: OpenAI ↔ DashScope format | OpenAI SDK, calling Qwen as an OpenAI model |
| `/v3/{model}/{*rest}` | identity passthrough (client protocol == target protocol) | when you need to bypass the `/v1/services` prefix |

## Text generation {#generation}

```python
from dashscope import Generation

resp = Generation.call(
    model="qwen3.8-max",
    messages=[{"role": "user", "content": "Introduce yourself in one sentence"}],
)
print(resp.output.choices[0].message.content)
```

> **Gotcha: `message.content` is an array.** DashScope passthrough returns `output.choices[0].message.content` as an **array** (`[{"text": "..."}]`), not a string, and may also carry `reasoning_content` (the thinking process). Printing it as a string the way older docs do yields `[{...}]`. Extract the text with `content[0]["text"]` or `"".join(p.get("text","") for p in content)`.

## Image (synchronous API) {#image}

```python
from dashscope.aigc.image_generation import ImageGeneration

resp = ImageGeneration.call(
    model="wan2.6-image",
    messages=[{"role": "user", "content": [{"text": "A cat swimming in an ocean of code, cyberpunk style"}]}],
)
# The synchronous API returns in one shot; the image is in message.content
print(resp.output.choices[0].message.content)
```

## Video (async task) {#video-async}

Video generation is a two-stage "submit task → poll result" flow. The SDK's `fetch` polling path differs from the gateway's task-query path (`/v1/services/{model}/tasks/{task_id}`), so raw HTTP is used to demonstrate the full flow:

```python
import time, requests

BASE = "http://localhost:7890/v1/services"
H = {"Authorization": "Bearer <your access key>", "Content-Type": "application/json"}

# 1) Submit the async video task (the model must be configured with direct_path + async_mode,
#    see the DashScope quick deploy)
r = requests.post(f"{BASE}/aigc/video-generation/video-synthesis", headers=H, json={
    "model": "wanx2.1-t2v",
    "input": {"prompt": "A cat swimming in an ocean of code, cyberpunk style"},
    "parameters": {"size": "1280*720"},
})
task_id = r.json()["output"]["task_id"]

# 2) Poll the task status and take the video URL on success
while True:
    s = requests.get(f"{BASE}/wanx2.1-t2v/tasks/{task_id}", headers=H).json()
    status = s["output"]["task_status"]
    if status == "SUCCEEDED":
        print(s["output"]["video_url"])
        break
    if status in ("FAILED", "CANCELED"):
        raise RuntimeError(s)
    time.sleep(5)
```

> Video model config (`direct_path` + `async_mode`) — see [Connect a DashScope upstream → Video generation](/en/quickstart/dashscope.md#video-generation). "Billing per second" only holds for models that declare a `per_second` billing mode; `wanx2.1-t2v` bills per your actual config, see [Pricing & billing](/en/howto/setup-pricing-and-billing.md).

## Embeddings / rerank / ASR {#other}

```python
# Embeddings
from dashscope import TextEmbedding
r = TextEmbedding.call(model="text-embedding-v4", input="hello")
print(r.output["embeddings"][0]["embedding"])

# Rerank
from dashscope import Rerank
r = Rerank.call(model="gte-rerank", query="cat", documents=["a cat", "a car"])
print([x["relevance_score"] for x in r.output["results"]])
```

> Embeddings/rerank can also go over the OpenAI protocol (`/v1/embeddings`, `/v1/rerank`) — the gateway interoperates `openai_embeddings`/`openai_rerank` with `dashscope`. Either path works; see [Protocol interop matrix](/en/reference/protocol-matrix.md).

## Identity passthrough `/v3/{model}/{*rest}` {#identity}

When the client protocol equals the model's configured target protocol, use `/v3/{model}/{*rest}` — the body is forwarded as-is, no conversion:

```bash
curl -X POST "http://localhost:7890/v3/qwen3.8-max/services/aigc/text-generation/generation" \
  -H "Authorization: Bearer <your access key>" \
  -H "Content-Type: application/json" \
  -d '{"model":"qwen3.8-max","input":{"messages":[{"role":"user","content":"hi"}]},"parameters":{"result_format":"message"}}'
```

## Next {#next}

- Full upstream config steps and kind variants: see [Connect a DashScope upstream](/en/quickstart/dashscope.md).
- DashScope realtime models (`dashscope_realtime`) via `/v1/realtime`: see [Realtime & audio](/en/sdk/realtime-and-audio.md).
