Qwen-Deep-Research automates complex research tasks by planning research steps, performing multiple rounds of web searches, and generating structured research reports. It can gather and synthesize information on complex topics without manual effort.
This document applies only to the China (Beijing) region. Use an API key from the China (Beijing) region.
Getting started
Prerequisites
You have get an API key and set the API key as an environment variable.
To use the SDK, install the DashScope SDK.
The model uses a two-step workflow:
Follow-up question: The model analyzes your initial query and asks clarifying questions to define the research scope.
Deep research: Based on your responses, the model performs web searches, analyzes content, and generates a structured research report.
Currently, the model does not support DashScope SDK for Java and OpenAI-compatible API.
import os
import dashscope
# Configure the API key
# If you have not configured the environment variable, replace the following line with your Model Studio API key: API_KEY = "sk-xxx"
API_KEY = os.getenv('DASHSCOPE_API_KEY')
def call_deep_research_model(messages, step_name):
print(f"\n=== {step_name} ===")
try:
responses = dashscope.Generation.call(
api_key=API_KEY,
model="qwen-deep-research",
messages=messages,
# The qwen-deep-research model currently supports only streaming output
stream=True
# To use incremental output, add the incremental_output=True parameter
)
return process_responses(responses, step_name)
except Exception as e:
print(f"An error occurred when calling the API: {e}")
return ""
# Display the phase content
def display_phase_content(phase, content, status):
if content:
print(f"\n[{phase}] {status}: {content}")
else:
print(f"\n[{phase}] {status}")
# Process the responses
def process_responses(responses, step_name):
current_phase = None
phase_content = ""
research_goal = ""
web_sites = []
references = []
keepalive_shown = False # A flag to check if the KeepAlive prompt has been displayed
for response in responses:
# Check the response status code
if hasattr(response, 'status_code') and response.status_code != 200:
print(f"HTTP return code: {response.status_code}")
if hasattr(response, 'code'):
print(f"Error code: {response.code}")
if hasattr(response, 'message'):
print(f"Error message: {response.message}")
print("For more information, see https://www.alibabacloud.com/help/en/model-studio/error-code")
continue
if hasattr(response, 'output') and response.output:
message = response.output.get('message', {})
phase = message.get('phase')
content = message.get('content', '')
status = message.get('status')
extra = message.get('extra', {})
# Detect phase changes
if phase != current_phase:
if current_phase and phase_content:
# Display different completion descriptions based on the phase name and step name
if step_name == "Step 1: Model follow-up question for confirmation" and current_phase == "answer":
print(f"\n Model follow-up question phase completed")
else:
print(f"\n {current_phase} phase completed")
current_phase = phase
phase_content = ""
keepalive_shown = False # Reset the KeepAlive prompt flag
# Display different descriptions based on the phase name and step name
if step_name == "Step 1: Model follow-up question for confirmation" and phase == "answer":
print(f"\n Entering model follow-up question phase")
else:
print(f"\n Entering {phase} phase")
# Process reference information for the Answer phase
if phase == "answer":
if extra.get('deep_research', {}).get('references'):
new_references = extra['deep_research']['references']
if new_references and new_references != references: # Avoid duplicate display
references = new_references
print(f"\n References ({len(references)}):")
for i, ref in enumerate(references, 1):
print(f" {i}. {ref.get('title', 'No title')}")
if ref.get('url'):
print(f" URL: {ref['url']}")
if ref.get('description'):
print(f" Description: {ref['description'][:100]}...")
print()
# Process special information for the WebResearch phase
if phase == "WebResearch":
if extra.get('deep_research', {}).get('research'):
research_info = extra['deep_research']['research']
# Process the streamingQueries status
if status == "streamingQueries":
if 'researchGoal' in research_info:
goal = research_info['researchGoal']
if goal:
research_goal += goal
print(f"\n Research goal: {goal}", end='', flush=True)
# Process the streamingWebResult status
elif status == "streamingWebResult":
if 'webSites' in research_info:
sites = research_info['webSites']
if sites and sites != web_sites: # Avoid duplicate display
web_sites = sites
print(f"\n Found {len(sites)} relevant websites:")
for i, site in enumerate(sites, 1):
print(f" {i}. {site.get('title', 'No title')}")
print(f" Description: {site.get('description', 'No description')[:100]}...")
print(f" URL: {site.get('url', 'No link')}")
if site.get('favicon'):
print(f" Icon: {site['favicon']}")
print()
# Process the WebResultFinished status
elif status == "WebResultFinished":
print(f"\n Web search completed. Found {len(web_sites)} reference sources.")
if research_goal:
print(f" Research goal: {research_goal}")
# Accumulate and display content
if content:
phase_content += content
# Display content in real time
print(content, end='', flush=True)
# Display phase status changes
if status and status != "typing":
print(f"\n Status: {status}")
# Display status description
if status == "streamingQueries":
print(" → Generating research goals and search queries (WebResearch phase)")
elif status == "streamingWebResult":
print(" → Performing search, web page reading, and code execution (WebResearch phase)")
elif status == "WebResultFinished":
print(" → Web search phase completed (WebResearch phase)")
# When the status is 'finished', display token usage
if status == "finished":
if hasattr(response, 'usage') and response.usage:
usage = response.usage
print(f"\n Token usage statistics:")
print(f" Input tokens: {usage.get('input_tokens', 0)}")
print(f" Output tokens: {usage.get('output_tokens', 0)}")
print(f" Request ID: {response.get('request_id', 'Unknown')}")
if phase == "KeepAlive":
# Display the prompt only the first time the KeepAlive phase is entered
if not keepalive_shown:
print("The current step is complete. Preparing for the next step.")
keepalive_shown = True
continue
if current_phase and phase_content:
if step_name == "Step 1: Model follow-up question for confirmation" and current_phase == "answer":
print(f"\n Model follow-up question phase completed")
else:
print(f"\n {current_phase} phase completed")
return phase_content
def main():
# Check the API key
if not API_KEY:
print("Error: The DASHSCOPE_API_KEY environment variable is not set.")
print("Set the environment variable or directly modify the API_KEY variable in the code.")
return
print("User initiates conversation: Research the applications of artificial intelligence in education")
# Step 1: Model follow-up question for confirmation
# The model analyzes the user's question and asks follow-up questions to clarify the research direction.
messages = [{'role': 'user', 'content': 'Research the applications of artificial intelligence in education'}]
step1_content = call_deep_research_model(messages, "Step 1: Model follow-up question for confirmation")
# Step 2: Deep research
# Based on the content of the follow-up question in Step 1, the model executes the complete research process.
messages = [
{'role': 'user', 'content': 'Research the applications of artificial intelligence in education'},
{'role': 'assistant', 'content': step1_content}, # Contains the model's follow-up question
{'role': 'user', 'content': 'I am mainly interested in personalized learning and intelligent assessment.'}
]
call_deep_research_model(messages, "Step 2: Deep research")
print("\n Research complete!")
if __name__ == "__main__":
main()
echo "Step 1: Model follow-up question for confirmation"
curl --location 'https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation' \
--header 'X-DashScope-SSE: enable' \
--header "Authorization: Bearer $DASHSCOPE_API_KEY" \
--header 'Content-Type: application/json' \
--data '{
"input": {
"messages": [
{
"content": "Research the applications of artificial intelligence in education",
"role": "user"
}
]
},
"model": "qwen-deep-research"
}'
echo -e "\n\n"
echo "Step 2: Deep research"
curl --location 'https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation' \
--header 'X-DashScope-SSE: enable' \
--header "Authorization: Bearer $DASHSCOPE_API_KEY" \
--header 'Content-Type: application/json' \
--data '{
"input": {
"messages": [
{
"content": "Research the applications of artificial intelligence in education",
"role": "user"
},
{
"content": "Which specific application scenarios of artificial intelligence in education would you like to focus on?",
"role": "assistant"
},
{
"content": "I am mainly interested in personalized learning.",
"role": "user"
}
]
},
"model": "qwen-deep-research"
}'
Core capabilities
The model uses the phase and status fields to indicate progress.
Phases
Phase | Phase description | Status | Status description |
| Generates follow-up question or the final report |
| Generating the texts |
| Text generation is complete | ||
| Creates a research outline |
| Generating the research plan |
| The research plan is complete | ||
| Web searches and content analysis |
| Generating search queries |
| Performing web searches and analyzing page content | ||
| Web search and information extraction are complete | ||
| Sent between long-running tasks to maintain the connection. Ignore this phase | ||
Specifications
Model | Context window (Tokens) | Max input (Tokens) | Max output (Tokens) |
qwen-deep-research | 1,000,000 | 997,952 | 32,768 |
Billing
Model | Input price (per 1K tokens) | Output price (per 1K tokens) | Free quota |
qwen-deep-research | $0.007742 | $0.023367 | No free quota |
Rules: Billing is based on total input and output tokens. Input tokens include user messages and the model's built-in system prompts. Output tokens include all generated content: follow-up questions, research plans, research goals, search queries, and the final report.
Going live
Handle streaming output
The model supports only streaming output (stream=True). Parse the phase and status fields to track progress.
Handle errors
Check the response status code for non-200 statuses.
Monitor token usage
When the status is finished, retrieve token consumption statistics from response.usage, including input tokens, output tokens, and the request ID.
FAQ
Why is the
outputfield empty for some response chunks?Early streaming chunks might contain only metadata. Subsequent chunks contain the actual content.
How can I determine if a phase is complete?
A phase is complete when the
statusfield changes to "finished".Does the model support OpenAI-compatible API calls?
No, the model does not currently support OpenAI-compatible API calls.
How are the input and output tokens calculated?
Input tokens include the user messages and the model's built-in system prompts. Output tokens include all content generated by the model throughout the research process, such as the follow-up question, research plan, research goals, search queries, and the final report.
API reference
Error codes
If a call fails, see Error messages for troubleshooting.