DashScope Python SDK
English | 中文
The DashScope Python SDK is the official client for Alibaba Cloud Model Studio (Bailian), covering text generation, multi-modal understanding, embeddings, reranking, image/video generation, speech synthesis & recognition, fine-tuning, agentic RL, applications and more.
Version 2.0 introduces a resource-style client — dashscope.Client() — modeled on the ergonomics of the OpenAI SDK: one client holds a shared connection pool, every capability hangs off it as a typed resource (client.chat, client.images, client.audio, …), responses are typed objects instead of raw dicts, and failures raise exceptions by default. The 1.x module-level API (dashscope.Generation, …) is unchanged and still fully supported, so 2.0 is purely additive.
What's new in 2.0
| 1.x | 2.0 | |
|---|---|---|
| Entry point | Module-level static classes: Generation.call(...) |
A resource-style client: client.chat.completions.create(...) |
| One-liner | — | dashscope.chat("qwen-plus", "Tell me a joke") |
| Response | Raw dict-like; check status_code == HTTPStatus.OK |
Typed object; read resp.output_text, resp.usage.total_tokens |
| Errors | Inspect resp.code / resp.message by hand |
Typed DashScopeError exceptions raised by default (evolving) |
| Streaming | Generator of raw frames | ChatStream with .text_stream, .reasoning_stream, .get_final_message() |
| Protocols | DashScope native + a separate compatible-mode entry | One client speaks native, openai, or anthropic via protocol= |
| Async | Separate Aio* classes |
dashscope.AsyncClient() mirrors the whole sync surface |
| Connections | A fresh session per call | One keep-alive pool per client, shared across resources |
| Config | Module globals (dashscope.api_key, set_region) |
Layered: args → dashscope.settings → env → ~/.dashscope/config.toml |
Installation
pip install -U dashscope
The base install covers SDK API calls, the dashscope CLI command, Agentic RL fine-tuning and the local tokenizer. Python 3.9+ is required. One optional feature group remains:
| Extra | Provides | Install |
|---|---|---|
acli |
Interactive AI assistant (DashScope SDK Expert) | pip install "dashscope[acli]" |
To install from a source checkout:
pip install -e .
Quick start
Set your API key (how to get one):
export DASHSCOPE_API_KEY="sk-xxx"
One line — the fastest way to a completion:
import dashscope
completion = dashscope.chat("qwen-plus", "Tell me a joke")
print(completion.output_text)
Client — the recommended form for anything real. One client, reused across calls:
import dashscope
client = dashscope.Client() # reads DASHSCOPE_API_KEY
resp = client.chat.completions.create(
model="qwen-plus",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Who are you?"},
],
)
print(resp.output_text)
print(resp.usage.total_tokens, "tokens |", resp.request_id)
Streaming — stream=True returns a ChatStream:
stream = client.chat.completions.create(
model="qwen-plus",
messages=[{"role": "user", "content": "Write a haiku about the sea"}],
stream=True,
)
for text in stream.text_stream:
print(text, end="", flush=True)
# Or collapse the whole stream into one merged ChatCompletion (with usage):
# final = stream.get_final_message()
Async — AsyncClient mirrors the sync surface:
import asyncio
import dashscope
async def main():
client = dashscope.AsyncClient()
resp = await client.chat.completions.create(
model="qwen-plus",
messages=[{"role": "user", "content": "Hello"}],
)
print(resp.output_text)
await client.aclose()
asyncio.run(main())
Core concepts
The client
dashscope.Client() (and dashscope.AsyncClient()) is the single entry point. It owns one keep-alive connection pool shared by every resource call, and exposes capabilities as attributes:
client = dashscope.Client(
api_key="sk-xxx", # default: DASHSCOPE_API_KEY
workspace="ws-xxx123", # default: DASHSCOPE_WORKSPACE
region="cn-beijing", # default: DASHSCOPE_REGION
protocol="native", # native | openai | anthropic
timeout=300.0,
max_retries=2,
)
Use it as a context manager to close the pool automatically, or derive a variant with with_options() (unmentioned options are inherited; the connection pool is shared when connection-level options are unchanged):
with dashscope.Client() as client:
client.chat.completions.create(model="qwen-plus", messages=["hi"])
low_latency = client.with_options(timeout=10.0, max_retries=0)
Any call also accepts per-request api_key=, workspace=, and timeout= overrides.
Protocols
One client can speak three wire protocols, selected with protocol= (or DASHSCOPE_PROTOCOL / settings.protocol). The request/response objects stay the same canonical, typed shape regardless of protocol — only the wire format changes:
protocol |
Talks to | Use when |
|---|---|---|
native (default) |
DashScope native API (/api/v1) |
You want the full DashScope feature set |
openai |
OpenAI-compatible mode (/compatible-mode/v1) |
You're porting OpenAI code — no openai package needed |
anthropic |
Anthropic-compatible mode (/apps/anthropic) |
You're porting Anthropic Messages code |
client = dashscope.Client(protocol="openai")
resp = client.chat.completions.create(
model="qwen-plus",
messages=[{"role": "user", "content": "Hello"}],
)
Typed responses
Every response is a typed object. For chat, read output_text for the first choice, or dig into choices, usage, search_info, request_id, and model:
resp = client.chat.completions.create(model="qwen-plus", messages=["hi"])
resp.output_text # choices[0].message.content
resp.choices[0].message.content # same, explicit
resp.choices[0].message.reasoning_content # thinking-model reasoning, if any
resp.choices[0].message.tool_calls # tool calls, if any
resp.usage.input_tokens # also .output_tokens / .total_tokens
resp.request_id
All responses share a common envelope: request_id, status_code, code, message, is_error, and raw headers.
Streaming
stream=True returns a ChatStream (AsyncChatStream for AsyncClient) with typed helpers:
stream = client.chat.completions.create(model="qwen-plus", messages=["hi"], stream=True)
for text in stream.text_stream: # content deltas
...
# stream.reasoning_stream # reasoning deltas (thinking models)
# stream.tool_call_stream # tool-call deltas
# stream.get_final_message() # merged ChatCompletion, incl. usage
By default each frame is incremental. Pass incremental_output=False to receive cumulative snapshots instead (the SDK merges deltas for you).
Note: the SDK does not auto-retry streaming requests. Wrap stream consumption in your own retry/backoff for production — see
examples/04_real_world_scenarios/production_ready_rag_harness.py.
Errors
Still evolving. The 2.0 typed error surface is under active development — new exception classes may be added and the API-error-code → exception mapping may be refined. Catch the base
errors.DashScopeErrorif you need to stay forward-compatible.
Failures raise a typed DashScopeError by default (both non-2xx HTTP statuses and HTTP-200-with-a-business-error land here):
from dashscope.v2 import errors
try:
client.chat.completions.create(model="qwen-plus", messages=["hi"])
except errors.RateLimitError as exc:
print("throttled:", exc.code, exc.status_code, exc.request_id)
except errors.ContentFilterError as exc:
print("blocked by moderation:", exc.message)
except errors.DashScopeError as exc: # base class for all SDK errors
print("request failed:", exc.code, exc.message)
The hierarchy includes APIConnectionError / APITimeoutError (network) and, under APIStatusError: BadRequestError, AuthenticationError, PermissionDeniedError, NotFoundError, RequestTooLargeError, RateLimitError, InternalServerError, ServiceUnavailableError, GatewayTimeoutError, and ContentFilterError.
Prefer to inspect errors inline instead of catching? Build the client with raise_on_error=False — failures come back as a normal response object with is_error=True, code, message, and status_code:
client = dashscope.Client(raise_on_error=False)
resp = client.chat.completions.create(model="qwen-plus", messages=["hi"])
if resp.is_error:
print(resp.code, resp.message)
Authentication
The SDK authenticates with an API key. Get one from the Model Studio console. Provide it in any of these ways (highest priority first):
- Per client —
dashscope.Client(api_key="sk-xxx") - Global settings —
dashscope.settings.api_key = "sk-xxx"(applies to clients created afterwards) - Environment variable —
export DASHSCOPE_API_KEY="sk-xxx" - Config file —
api_keyin~/.dashscope/config.toml - 1.x key file — the file written by
dashscope.save_api_key(...)(~/.dashscope/api_key, orDASHSCOPE_API_KEY_FILE_PATH), honored as the lowest tier so existing 1.x setups keep working
Any call also accepts a per-request api_key= override.
API keys are region-specific. Each region issues its own keys; a key from another region fails with
401. Switchapi_keytogether withregion.
Configuration
Configuration resolves in layers — explicit arguments → dashscope.settings → environment variables → ~/.dashscope/config.toml. Set it once at startup, per client, or not at all.
Global settings facade:
import dashscope
dashscope.settings.api_key = "sk-xxx"
dashscope.settings.workspace = "ws-xxx123"
dashscope.settings.region = "ap-southeast-1"
dashscope.settings.protocol = "openai"
dashscope.settings.timeout = 60.0
dashscope.settings.max_retries = 3
dashscope.settings.log_level = "INFO"
Environment variables:
| Variable | Sets | Default |
|---|---|---|
DASHSCOPE_API_KEY |
API key | — |
DASHSCOPE_WORKSPACE |
Workspace ID (endpoint subdomain) | — |
DASHSCOPE_REGION |
Region | cn-beijing |
DASHSCOPE_PROTOCOL |
native / openai / anthropic |
native |
DASHSCOPE_BASE_URL |
Override the endpoint entirely (escape hatch) | — |
DASHSCOPE_TIMEOUT |
Request timeout (seconds) | 300 |
DASHSCOPE_MAX_RETRIES |
Automatic retries | 2 |
DASHSCOPE_LOG |
Log level | WARNING |
DASHSCOPE_CONFIG |
Path to config.toml |
~/.dashscope/config.toml |
Config file (~/.dashscope/config.toml):
api_key = "sk-xxx"
workspace = "ws-xxx123"
region = "ap-southeast-1"
protocol = "native"
timeout = 300.0
max_retries = 2
Regions and endpoints
By default requests go to the China (Beijing) gateway. When a workspace is set, endpoints are built from the workspace-scoped MaaS gateway https://{workspace}.{region}.maas.aliyuncs.com, with each protocol served under its own path. Point at another region with region= (or DASHSCOPE_REGION / settings.region):
client = dashscope.Client(region="ap-southeast-1", workspace="ws-xxx123")
# -> https://ws-xxx123.ap-southeast-1.maas.aliyuncs.com/api/v1
| Region | Location |
|---|---|
cn-beijing |
China (Beijing) — default |
cn-hongkong |
China (Hong Kong) |
ap-southeast-1 |
Singapore |
ap-northeast-1 |
Japan (Tokyo) |
eu-central-1 |
Germany (Frankfurt) |
us-east-1 |
US (Virginia) |
Notes:
- No workspace configured? The SDK falls back to the legacy shared gateway (
https://dashscope.aliyuncs.comfor Beijing) and emits aUserWarning. It works, but the workspace-scoped gateway is recommended for performance and stability. - WebSocket-based realtime APIs (realtime speech, multimodal dialog) are served in
cn-beijingandap-southeast-1. - Batch inference, fine-tuning and application development are currently available in
cn-beijingandap-southeast-1. base_url=(orDASHSCOPE_BASE_URL) overrides everything — the escape hatch for custom/private gateways; it does not require a workspace.- The 1.x
dashscope.set_region(region, workspace_id)global still works for the 1.x module-level API.
Capabilities
Every capability is a resource on the client. Sync and async clients expose the same surface (async methods are awaited).
| Capability | 2.0 resource | Example |
|---|---|---|
| Text chat / generation | client.chat.completions.create(...) |
text_generation/chat.py |
| Multi-modal chat (vision, video) | client.multimodal.chat.create(...) |
multimodal_vision/multimodal_chat.py |
| Text embedding | client.embeddings.create(...) (+ .jobs for batch) |
embeddings/embeddings.py |
| Multi-modal embedding | client.multimodal.embeddings.create(...) |
embeddings/ |
| Rerank | client.rerank.create(...) |
rerank/rerank.py |
| Decision (System One) | client.decision.create(...) |
decision/decision.py |
| Token counting | client.tokenization.count(...) |
text_generation/tokenization.py |
| Image generation | client.images.generate(...) (+ .jobs) |
image_video_synthesis/images.py |
| Video generation | client.videos.generate(...) (+ .jobs) |
image_video_synthesis/videos.py |
| Speech: ASR / TTS / realtime (preview) | client.audio.asr · client.audio.tts · client.audio.realtime |
audio/ |
| Meeting & audio understanding (TingWu) | client.tingwu.call(...) / .realtime(...) |
audio/tingwu.py |
| Files | client.files.upload/list/get/delete(...) |
files/files.py |
| Models | client.models.list/get(...) |
models/models.py |
| Fine-tuning | client.fine_tunes.create/get/list/wait/cancel/delete(...) |
fine_tuning/fine_tunes.py |
| Model deployments | client.deployments.create/scale/list/delete(...) |
fine_tuning/ |
| Agentic RL | client.rl (.jobs, register_functions, upload_data) |
fine_tuning/reinforcement_learning.py |
| Model Studio applications | client.apps.completions.create(...) |
applications/apps.py |
| AgentStudio (agents, sessions, memory) | client.agentstudio |
03_agent_recipes/agentstudio.py |
A few common shapes:
# Embeddings
resp = client.embeddings.create(model="text-embedding-v4", input=["hello", "world"], dimension=1024)
resp.embeddings[0].embedding
# Multi-modal chat (image understanding)
resp = client.multimodal.chat.create(
model="qwen3-vl-plus",
messages=[{"role": "user", "content": [{"image": "https://.../cat.png"}, {"text": "What is this?"}]}],
)
resp.output_text
# Image generation (submit + wait); use client.images.jobs for manual control
job = client.images.generate(model="wanx2.1-t2i-turbo", prompt="a cozy flower shop", size="1024*1024")
if job.succeeded:
print(job.image_urls)
# A Model Studio application
resp = client.apps.completions.create(app_id="YOUR_APP_ID", prompt="How do I make stew?")
resp.text
Audio is a preview. The 2.0
client.audiosurface is not final and may change; accessing it emits aFutureWarning.
Realtime over one WebSocket
For latency-sensitive realtime audio, open a shared duplex socket and run multiple sessions on it instead of handshaking per task:
connection = client.ws_connection()
session = client.audio.asr.recognize(model="fun-asr-realtime", connection=connection)
# ... drive the session; the caller owns the connection ...
connection.close()
Supported models
| Category | Example models | 2.0 resource |
|---|---|---|
| Text generation | qwen-max, qwen-plus, qwen-flash | client.chat |
| Multi-modal understanding | qwen3-vl-plus, qwen-omni | client.multimodal.chat |
| Text embedding | text-embedding-v4, text-embedding-v3 | client.embeddings |
| Multi-modal embedding | tongyi-embedding-vision-plus | client.multimodal.embeddings |
| Rerank | gte-rerank-v2, qwen3-rerank | client.rerank |
| Image generation | wanx2.1-t2i-turbo, wan-image | client.images |
| Video generation | wanx2.1-t2v, wan-i2v | client.videos |
| Speech synthesis (TTS) | cosyvoice-v1, qwen-tts | client.audio.tts |
| Speech recognition (ASR) | fun-asr-realtime, paraformer-v1 | client.audio.asr |
| Omni (realtime) | qwen-omni-realtime | client.audio.realtime |
For the latest model list, visit the Model Studio model plaza.
AI Assistant: DashScope SDK Expert
The SDK ships with an interactive AI assistant, DashScope SDK Expert, built on the bundled Agentic CLI (dashscope/acli). It answers SDK/API questions, generates runnable examples, shows CLI usage, and diagnoses errors right in your terminal.
- Run
dashscopewith no arguments to start the assistant. On first run it offers to install the knowledge pack (per-domain quick-reference skills: text, multimodal, speech, retrieval, fine-tuning, agent, cli), so guidance comes from the SDK's public interfaces — parameters, outputs, error codes — without reading the source. - Ask it instead of reading docs — e.g.
dashscope expert "how do I stream chat output"(asks once and exits). Type/helpinside the assistant for available commands;dashscope expert --helpshows all forms. - Install with the
acliextra:pip install "dashscope[acli]". - Full walkthrough: DashScope SDK Expert guide.
Shell completion
Run the command for your shell once, then restart the shell (or re-source your config):
| Shell | Install command |
|---|---|
| bash | dashscope --install-completion bash |
| zsh | dashscope --install-completion zsh |
| fish | dashscope --install-completion fish |
Preview the script without installing:
dashscope --show-completion bash
Logging
Set the level via settings or the environment:
dashscope.settings.log_level = "INFO"
export DASHSCOPE_LOG="INFO"
Examples
The examples/ directory is a production best-practices collection built on the 2.0 client, organized as an advancement path:
examples/
├── 01_atomic_capabilities/ Minimal runnable quickref per capability
├── 02_advanced_engineering/ Mock debugging, semantic cache, circuit breaker + multi-region DR
├── 03_agent_recipes/ Tool-call loop, RAG, MCP server, AgentStudio
├── 04_real_world_scenarios/ End-to-end production harnesses (RAG, realtime meetings, customer service)
└── legacy_1x/ 1.x module-level API examples, for reference
See examples/README.md. Several flagship cases run fully offline (mock transports) with no API key.
Migrating from 1.x
The 1.x module-level API is unchanged and still supported — you can adopt 2.0 incrementally. When you're ready, the mapping is direct:
| 1.x | 2.0 |
|---|---|
Generation.call(model=..., messages=..., result_format="message") |
client.chat.completions.create(model=..., messages=...) |
resp.status_code == HTTPStatus.OK then resp.output.choices[0].message.content |
resp.output_text (errors raise by default) |
MultiModalConversation.call(...) |
client.multimodal.chat.create(...) |
TextEmbedding.call(...) |
client.embeddings.create(...) |
TextReRank.call(...) |
client.rerank.create(...) |
ImageSynthesis.call(...) / .async_call(...) |
client.images.generate(...) / client.images.jobs |
dashscope.api_key = "sk-xxx" |
dashscope.Client(api_key=...) or dashscope.settings.api_key = ... |
dashscope.set_region(region, workspace_id) |
dashscope.Client(region=..., workspace=...) |
OpenAI-compatible via dashscope.aigc.chat_completion.Completions |
dashscope.Client(protocol="openai") |
License
This project is licensed under the Apache License (Version 2.0).
Metadata
Release files for dashscope 2.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| dashscope-2.0.1.tar.gz | 2.1 MB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dashscope-2.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 4.5 MB
Release files / dashscope-2.0.1.tar.gz
| Download URL | dashscope-2.0.1.tar.gz |
|---|---|
| Size | 2.1 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
31d93dbddaa9ecddaf43099c9f75e4d204cd54cbd78f70253199ff799e157552
|
|
BLAKE2b-256 checksum How to use checksums |
da8ce5bce8eaf558fad2f36e7c0d6dfcc53eefe9d04411e5a59274d236c71be3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|
Release files / dashscope-2.0.1-py3-none-any.whl
| Download URL | dashscope-2.0.1-py3-none-any.whl |
|---|---|
| Size | 2.4 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
32b9b6ca6d62e49f95bd1f9f2ab9b76f63c2ea6dd20efcef5a2177ae60717afe
|
|
BLAKE2b-256 checksum How to use checksums |
540ae6ba68790d8086e3759d3268593a92386b2bebf2aace9cb852ec47cfb527
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|
Security for dashscope 2.0.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.