Deep Research Workflows
This guide shows how to use the Agent API's medium preset for comprehensive, multi-step research tasks. Deep research performs extended web research, following chains of sources and synthesizing detailed answers. You will learn how to run deep research queries, process results, handle long-running requests, and run batch research workflows.
Prerequisites
Section titled “Prerequisites”Install the Perplexity SDK:
pip install perplexityainpm install @perplexity-ai/perplexity_aiIf you don't have an API key yet:
Get your Perplexity API Key
Navigate to the API Keys tab in the API Portal and generate a new key.
Click here
Then export your API key as an environment variable:
export PERPLEXITY_API_KEY="your-api-key"Basic Deep Research
Section titled “Basic Deep Research”Use the medium preset for comprehensive research queries.
from perplexity import Perplexity
client = Perplexity()
response = client.responses.create(
preset="medium",
input=(
"Provide a comprehensive analysis of the current state of nuclear fusion research. "
"Cover the main approaches (tokamak, stellarator, inertial confinement, laser-driven), "
"key milestones achieved in the past 2 years, major private companies involved, "
"and realistic timelines for commercial fusion power."
),
)
print(f"Model: {response.model}")
print(f"\n{response.output_text}")import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const response = await client.responses.create({
preset: "medium",
input: "Provide a comprehensive analysis of the current state of nuclear fusion research. Cover the main approaches (tokamak, stellarator, inertial confinement, laser-driven), key milestones achieved in the past 2 years, major private companies involved, and realistic timelines for commercial fusion power.",
});
console.log(`Model: ${response.model}`);
console.log(`\n${response.output_text}`);curl "https://api.perplexity.ai/v1/agent" \
-H "Authorization: Bearer $PERPLEXITY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"preset": "medium",
"input": "Provide a comprehensive analysis of the current state of nuclear fusion research."
}'Processing Deep Research Results
Section titled “Processing Deep Research Results”Extract and format the key parts of a deep research response.
from perplexity import Perplexity
client = Perplexity()
def deep_research(query: str) -> dict:
"""Run a deep research query and extract structured results."""
print(f"Researching: {query[:80]}...")
response = client.responses.create(
preset="medium",
input=query,
)
content = response.output_text
usage = response.usage
return {
"content": content,
"model": response.model,
"tokens": {
"input": usage.input_tokens if usage else 0,
"output": usage.output_tokens if usage else 0,
},
"word_count": len(content.split()),
}
if __name__ == "__main__":
output = deep_research(
"What is the current state of solid-state battery technology? "
"Cover the leading companies, technical challenges remaining, "
"and expected timeline for mass production in EVs."
)
print(f"\nModel: {output['model']}")
print(f"Words: {output['word_count']}")
print(f"Tokens: {output['tokens']['input']} in, {output['tokens']['output']} out")
print(f"\n{'='*60}\n")
print(output["content"][:2000])import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
async function deepResearch(query: string) {
console.log(`Researching: ${query.slice(0, 80)}...`);
const response = await client.responses.create({
preset: "medium",
input: query,
});
const content = response.output_text;
const usage = response.usage;
return {
content,
model: response.model,
tokens: {
input: usage?.input_tokens ?? 0,
output: usage?.output_tokens ?? 0,
},
wordCount: content.split(/\s+/).length,
};
}
const output = await deepResearch(
"What is the current state of solid-state battery technology? Cover the leading companies, technical challenges remaining, and expected timeline for mass production in EVs."
);
console.log(`\nModel: ${output.model}`);
console.log(`Words: ${output.wordCount}`);
console.log(`Tokens: ${output.tokens.input} in, ${output.tokens.output} out`);
console.log(`\n${"=".repeat(60)}\n`);
console.log(output.content.slice(0, 2000));Deep Research with Domain Filtering
Section titled “Deep Research with Domain Filtering”Combine deep research with domain filters for focused, authoritative research.
from perplexity import Perplexity
client = Perplexity()
# Deep research restricted to government and academic sources
response = client.responses.create(
model="openai/gpt-5.6-terra",
input=(
"Analyze the current regulatory landscape for AI in healthcare. "
"Cover FDA guidance, EU AI Act implications, and recent enforcement actions."
),
tools=[{
"type": "web_search",
"filters": {
"search_domain_filter": [".gov", ".europa.eu", "who.int", "nature.com", ".edu"],
},
}],
instructions=(
"Conduct thorough research using only government and academic sources. "
"Provide specific regulatory references, dates, and policy details."
),
)
print(response.output_text)import Perplexity from '@perplexity-ai/perplexity_ai';
const client = new Perplexity();
const response = await client.responses.create({
model: "openai/gpt-5.6-terra",
input: "Analyze the current regulatory landscape for AI in healthcare. Cover FDA guidance, EU AI Act implications, and recent enforcement actions.",
tools: [{
type: "web_search" as const,
filters: {
search_domain_filter: [".gov", ".europa.eu", "who.int", "nature.com", ".edu"],
},
}],
instructions: "Conduct thorough research using only government and academic sources. Provide specific regulatory references, dates, and policy details.",
});
console.log(response.output_text);Batch Research with Concurrency
Section titled “Batch Research with Concurrency”Run multiple deep research queries concurrently using asyncio and the Perplexity SDK.
import asyncio
import time
from perplexity import AsyncPerplexity
async def single_research(client: AsyncPerplexity, query: str) -> dict:
"""Run a single deep research query."""
start = time.time()
try:
response = await client.responses.create(
preset="medium",
input=query,
)
return {
"query": query,
"content": response.output_text,
"model": response.model,
"elapsed": time.time() - start,
}
except Exception as e:
return {"query": query, "error": str(e), "elapsed": time.time() - start}
async def batch_research(queries: list[str], max_concurrent: int = 3) -> list[dict]:
"""Run multiple deep research queries with concurrency limits."""
semaphore = asyncio.Semaphore(max_concurrent)
async def limited_research(client, query):
async with semaphore:
return await single_research(client, query)
async with AsyncPerplexity() as client:
tasks = [limited_research(client, q) for q in queries]
return await asyncio.gather(*tasks)
if __name__ == "__main__":
queries = [
"What are the latest advances in room-temperature superconductors?",
"What is the current state of quantum error correction?",
"What are the most promising approaches to carbon capture and storage?",
]
print(f"Starting batch research: {len(queries)} queries\n")
results = asyncio.run(batch_research(queries, max_concurrent=3))
for r in results:
status = "OK" if "content" in r else f"FAILED ({r.get('error')})"
word_count = len(r.get("content", "").split()) if "content" in r else 0
print(f" [{r['elapsed']:.0f}s] {r['query'][:60]}... → {status} ({word_count} words)")import Perplexity from '@perplexity-ai/perplexity_ai';
interface ResearchResult {
query: string;
content?: string;
model?: string;
elapsed: number;
error?: string;
}
const client = new Perplexity();
async function singleResearch(query: string): Promise<ResearchResult> {
const start = Date.now();
try {
const response = await client.responses.create({
preset: 'medium',
input: query,
});
return {
query,
content: response.output_text,
model: response.model,
elapsed: (Date.now() - start) / 1000,
};
} catch (e) {
return { query, error: String(e), elapsed: (Date.now() - start) / 1000 };
}
}
async function batchResearch(queries: string[], maxConcurrent = 3) {
const results: ResearchResult[] = [];
const queue = [...queries];
async function worker() {
while (queue.length) {
const q = queue.shift()!;
results.push(await singleResearch(q));
}
}
await Promise.all(
Array.from({ length: maxConcurrent }, () => worker())
);
return results;
}
const queries = [
'What are the latest advances in room-temperature superconductors?',
'What is the current state of quantum error correction?',
'What are the most promising approaches to carbon capture and storage?',
];
console.log(`Starting batch research: ${queries.length} queries\n`);
const results = await batchResearch(queries, 3);
for (const r of results) {
const status = r.content ? 'OK' : `FAILED (${r.error})`;
const words = r.content ? r.content.split(/\s+/).length : 0;
console.log(` [${r.elapsed.toFixed(0)}s] ${r.query.slice(0, 60)}... → ${status} (${words} words)`);
}Tips and Best Practices
Section titled “Tips and Best Practices”-
Use the
mediumpreset for the simplest integration. It automatically selects the best model and configures tools. -
Combine with domain filters when you need authoritative sources. Use
search_domain_filterto restrict to specific domains. -
Use
instructionsto guide the depth and focus of research. Be specific about what aspects to cover. -
Limit concurrency. Running too many deep research queries simultaneously may trigger rate limits. Use a semaphore to cap concurrent requests to 3-5.
-
Use the async client for batch workflows.
AsyncPerplexityenables concurrent requests without blocking. -
Set
max_output_tokensfor cost control when you need shorter summaries rather than exhaustive reports.