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.
| 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 |
| 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 |
pip install -U dashscopeThe base install covers SDK API calls and the dashscope CLI command. Python 3.9+ is required. Optional feature groups are available as extras:
| Extra | Provides | Install |
|---|---|---|
acli |
Interactive AI assistant (DashScope SDK Expert) | pip install "dashscope[acli]" |
rl |
Agentic RL fine-tuning | pip install "dashscope[rl]" |
tokenizer |
Local tokenizer without downloads | pip install "dashscope[tokenizer]" |
To install from a source checkout:
pip install -e .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())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.
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"}],
)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_idAll responses share a common envelope: request_id, status_code, code, message, is_error, and raw headers.
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. usageBy 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.
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)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 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 = 2By 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.
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.textAudio is a preview. The 2.0
client.audiosurface is not final and may change; accessing it emits aFutureWarning.
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()| 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.
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.
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 bashSet the level via settings or the environment:
dashscope.settings.log_level = "INFO"export DASHSCOPE_LOG="INFO"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.
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") |
This project is licensed under the Apache License (Version 2.0).