概述
本指南展示了如何使用 Deep Agents 构建多步骤网页研究智能体。该智能体将研究问题分解为聚焦的任务,委托给专用子智能体处理,并将最终发现整合为综合报告。 您构建的智能体将实现以下功能:- 使用可选待办事项中间件规划研究
- 将聚焦型研究任务委托给具有独立上下文隔离的子智能体
- 随着信息收集评估搜索结果并规划下一步行动
- 将带有规范引用的发现整合为最终报告
核心概念
本教程涵盖以下内容:先决条件
需要以下 API 密钥:- Anthropic(Claude)或 Google(Gemini)
- Tavily(用于网页搜索,可选;免费套餐足够)
- LangSmith(用于追踪,若使用 SDK 可选;使用 Managed Deep Agents 时必需)
选择路径
本指南展示了如何使用 Managed Deep Agents 和 Deep Agents SDK 构建该智能体。Managed Deep Agents 允许您无需管理基础设施即可部署智能体。Deep Agents SDK 提供最大灵活性,您既可使用相同的 Deep Agents harness 部署,也可通过自定义 LangSmith 部署 自行托管。- Managed Deep Agents
- Deep Agents SDK
托管深度智能体目前处于 公开的 beta 版本,部署于 LangSmith Cloud。
配置
要开始,你需要::::python- Python 和
uv。 :::
- Node.js 和 npm。 :::
- 向你的模型服务提供商申请的 API 密钥。
1
Create the project
:::python::::::js:::
uvx --from managed-deepagents mda init deep-research
cd deep-research
npx managed-deepagents init deep-research
cd deep-research
pnpm dlx managed-deepagents init deep-research
cd deep-research
bunx managed-deepagents init deep-research
cd deep-research
2
Add API keys
将模型提供商密钥、Tavily 密钥和 LangSmith API 密钥添加到
.env:- Claude
- Gemini
.env
ANTHROPIC_API_KEY=<ANTHROPIC_API_KEY>
TAVILY_API_KEY=<TAVILY_API_KEY>
LANGSMITH_API_KEY=<LANGSMITH_API_KEY>
.env
GOOGLE_API_KEY=<GOOGLE_API_KEY>
TAVILY_API_KEY=<TAVILY_API_KEY>
LANGSMITH_API_KEY=<LANGSMITH_API_KEY>
不要将
.env 文件提交到版本控制。该文件包含敏感信息。3
Install search dependencies
:::python::::::js
本教程中的搜索工具无需额外包依赖。它使用内置
uv add tavily-python httpx markdownify
fetch API 和 Tavily HTTP 端点。
:::构建智能体
1
Add tools
创建自定义搜索工具。※ 重要提示:在您之前的输出中占位符集不正确。缺少的 id:[‘0’];意外的额外 id:[]。请再次翻译全文,并保持每个占位符(六边形括号 + 数字)的原位置,且仅出现一次。::::::js
创建 ※ 重要提示:在您之前的输出中占位符集不正确。缺少的 id:[‘0’];意外的额外 id:[‘1’, ‘2’, ‘3’, ‘4’, ‘5’]。请再次翻译全文,并保持每个占位符(六边形括号 + 数字)的原位置,且仅出现一次。:::
tavily_search 工具使用 Tavily 进行 URL 发现,然后获取完整网页内容,使智能体能够基于完整来源进行分析而非摘要。:::python
创建 tools/search.py:tools/search.py
import os
from typing import Annotated, Literal
import httpx
from langchain.tools import InjectedToolArg, tool
from markdownify import markdownify
from tavily import TavilyClient
tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
def fetch_webpage_content(url: str, timeout: float = 10.0) -> str:
"""Fetch webpage and convert HTML to markdown."""
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
try:
response = httpx.get(url, headers=headers, timeout=timeout)
response.raise_for_status()
return markdownify(response.text)
except Exception as e:
return f"Error fetching {url}: {e!s}"
@tool(parse_docstring=True)
def tavily_search(
query: str,
max_results: Annotated[int, InjectedToolArg] = 1,
topic: Annotated[
Literal["general", "news", "finance"], InjectedToolArg
] = "general",
) -> str:
"""Search the web for information on a given query.
Uses Tavily to discover relevant URLs, then fetches and returns full webpage content as markdown.
Args:
query: Search query to execute
max_results: Maximum number of results to return (default: 1)
topic: Topic filter - 'general', 'news', or 'finance' (default: 'general')
Returns:
Formatted search results with full webpage content
"""
search_results = tavily_client.search(
query,
max_results=max_results,
topic=topic,
)
result_texts = []
for result in search_results.get("results", []):
url = result["url"]
title = result["title"]
content = fetch_webpage_content(url)
result_texts.append(f"## {title}\n**URL:** {url}\n\n{content}\n---")
return f"Found {len(result_texts)} result(s) for '{query}':\n\n" + "\n".join(
result_texts
)
tools/search.ts:tools/search.ts
import { tool } from "langchain";
import { z } from "zod";
async function fetchWebpageContent(
url: string,
timeout = 10_000,
): Promise<string> {
try {
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);
const response = await fetch(url, {
headers: {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
},
signal: controller.signal,
});
clearTimeout(id);
if (!response.ok) {
return `Error fetching ${url}: HTTP ${response.status}`;
}
return await response.text();
} catch (e) {
return `Error fetching ${url}: ${e}`;
}
}
export const tavilySearch = tool(
async ({
query,
maxResults = 1,
topic = "general",
}: {
query: string;
maxResults?: number;
topic?: "general" | "news" | "finance";
}) => {
const response = await fetch("https://api.tavily.com/search", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.TAVILY_API_KEY}`,
},
body: JSON.stringify({ query, max_results: maxResults, topic }),
});
const data = (await response.json()) as {
results: Array<{ url: string; title: string }>;
};
const results = data.results ?? [];
const resultTexts: string[] = [];
for (const result of results) {
const content = await fetchWebpageContent(result.url);
resultTexts.push(
`## ${result.title}\n**URL:** ${result.url}\n\n${content}\n---`,
);
}
return (
`Found ${resultTexts.length} result(s) for '${query}':\n\n` +
resultTexts.join("\n")
);
},
{
name: "tavily_search",
description:
"Search the web for information on a given query. Uses Tavily to discover relevant URLs, then fetches and returns full webpage content.",
schema: z.object({
query: z.string().describe("Search query to execute"),
maxResults: z
.number()
.optional()
.default(1)
.describe("Maximum number of results to return (default: 1)"),
topic: z
.enum(["general", "news", "finance"])
.optional()
.default("general")
.describe(
"Topic filter - 'general', 'news', or 'finance' (default: 'general')",
),
}),
},
);
2
Add orchestrator instructions
将研究工作流和子智能体协调指导写入 部署时,Managed Deep Agents 会将上述指令同步至 Context Hub。
instructions.md。Managed Deep Agents 将此文件作为编排系统提示加载:instructions.md
# Research Workflow
Follow this workflow for all research requests:
1. **Plan**: Create a todo list with write_todos to break down the research into focused tasks
2. **Save the request**: Use write_file() to save the user's research question to `/research_request.md`
3. **Research**: Delegate research tasks to sub-agents using the task() tool - ALWAYS use sub-agents for research, never conduct research yourself
4. **Synthesize**: Review all sub-agent findings and consolidate citations (each unique URL gets one number across all findings)
5. **Write Report**: Write a comprehensive final report to `/final_report.md` (see Report Writing Guidelines below)
6. **Verify**: Read `/research_request.md` and confirm you've addressed all aspects with proper citations and structure
## Research Planning Guidelines
- Batch similar research tasks into a single TODO to minimize overhead
- For simple fact-finding questions, use 1 sub-agent
- For comparisons or multi-faceted topics, delegate to multiple parallel sub-agents
- Each sub-agent should research one specific aspect and return findings
## Report Writing Guidelines
When writing the final report to `/final_report.md`, follow these structure patterns:
**For comparisons:**
1. Introduction
2. Overview of topic A
3. Overview of topic B
4. Detailed comparison
5. Conclusion
**For lists/rankings:**
Simply list items with details - no introduction needed:
1. Item 1 with explanation
2. Item 2 with explanation
3. Item 3 with explanation
**For summaries/overviews:**
1. Overview of topic
2. Key concept 1
3. Key concept 2
4. Key concept 3
5. Conclusion
**General guidelines:**
- Use clear section headings (## for sections, ### for subsections)
- Write in paragraph form by default - be text-heavy, not just bullet points
- Do NOT use self-referential language ("I found...", "I researched...")
- Write as a professional report without meta-commentary
- Each section should be comprehensive and detailed
- Use bullet points only when listing is more appropriate than prose
**Citation format:**
- Cite sources inline using [1], [2], [3] format
- Assign each unique URL a single citation number across ALL sub-agent findings
- End report with ### Sources section listing each numbered source
- Number sources sequentially without gaps (1,2,3,4...)
- Format: [1] Source Title: URL (each on separate line for proper list rendering)
- Example:
Some important finding [1]. Another key insight [2].
### Sources
[1] AI Research Paper: https://example.com/paper
[2] Industry Analysis: https://example.com/analysis
# Sub-Agent Research Coordination
Your role is to coordinate research by delegating tasks from your TODO list to specialized research sub-agents.
## Delegation Strategy
**DEFAULT: Start with 1 sub-agent** for most queries:
- "What is quantum computing?" -> 1 sub-agent (general overview)
- "List the top 10 coffee shops in San Francisco" -> 1 sub-agent
- "Summarize the history of the internet" -> 1 sub-agent
- "Research context engineering for AI agents" -> 1 sub-agent (covers all aspects)
**ONLY parallelize when the query EXPLICITLY requires comparison or has clearly independent aspects:**
**Explicit comparisons** -> 1 sub-agent per element:
- "Compare OpenAI vs Anthropic vs DeepMind AI safety approaches" -> 3 parallel sub-agents
- "Compare Python vs JavaScript for web development" -> 2 parallel sub-agents
**Clearly separated aspects** -> 1 sub-agent per aspect (use sparingly):
- "Research renewable energy adoption in Europe, Asia, and North America" -> 3 parallel sub-agents (geographic separation)
- Only use this pattern when aspects cannot be covered efficiently by a single comprehensive search
## Key Principles
- **Bias towards single sub-agent**: One comprehensive research task is more token-efficient than multiple narrow ones
- **Avoid premature decomposition**: Don't break "research X" into "research X overview", "research X techniques", "research X applications" - just use 1 sub-agent for all of X
- **Parallelize only for clear comparisons**: Use multiple sub-agents when comparing distinct entities or geographically separated data
## Parallel Execution Limits
- Use at most 3 parallel sub-agents per iteration
- Make multiple task() calls in a single response to enable parallel execution
- Each sub-agent returns findings independently
## Research Limits
- Stop after 3 delegation rounds if you haven't found adequate sources
- Stop when you have sufficient information to answer comprehensively
- Bias towards focused research over exhaustive exploration
3
Create the agent
您只需将主智能体的指令写入 ::::::js
替换 ※ 重要提示:在您之前的输出中占位符集不正确。缺少的 id:[‘0’]; 预期之外的额外 id:[]。请再次翻译全文,并确保每个六边形括号加数字的占位符都保留在原始位置,且仅出现一次。:::
instructions.md。替换脚手架中的智能体条目为下方完整文件。该文件设置模型、工具、研究子智能体(包括该子智能体的自身提示词),以及@[TodoListMiddleware] 以支持 write_todos 调用 任务规划。 name 是必需的:MDA 使用它作为 LangGraph 助理 ID 和默认部署名称。:::python
替换 agent.py。选择您的服务提供商:- Claude
- Gemini
agent.py
from datetime import datetime
from langchain.agents.middleware import TodoListMiddleware
from managed_deepagents import define_deep_agent
from tools.search import tavily_search
current_date = datetime.now().strftime("%Y-%m-%d")
RESEARCHER_INSTRUCTIONS = """You are a research assistant conducting research on the user's input topic. For context, today's date is {date}.
Your job is to use tools to gather information about the user's input topic.
You can use the tavily_search tool to find resources that can help answer the research question.
You can call it in series or in parallel, your research is conducted in a tool-calling loop.
You have access to the tavily_search tool for conducting web searches.
Think like a human researcher with limited time. Follow these steps:
1. **Read the question carefully** - What specific information does the user need?
2. **Start with broader searches** - Use broad, comprehensive queries first
3. **After each search, pause and assess** - Do I have enough to answer? What's still missing?
4. **Execute narrower searches as you gather information** - Fill in the gaps
5. **Stop when you can answer confidently** - Don't keep searching for perfection
**Tool Call Budgets** (Prevent excessive searching):
- **Simple queries**: Use 2-3 search tool calls maximum
- **Complex queries**: Use up to 5 search tool calls maximum
- **Always stop**: After 5 search tool calls if you cannot find the right sources
**Stop Immediately When**:
- You can answer the user's question comprehensively
- You have 3+ relevant examples/sources for the question
- Your last 2 searches returned similar information
After each search, assess results before continuing: What key information did I find? What's missing? Do I have enough to answer? Should I search more or provide my answer?
When providing your findings back to the orchestrator:
1. **Structure your response**: Organize findings with clear headings and detailed explanations
2. **Cite sources inline**: Use [1], [2], [3] format when referencing information from your searches
3. **Include Sources section**: End with ### Sources listing each numbered source with title and URL
The orchestrator will consolidate citations from all sub-agents into the final report.
"""
research_sub_agent = {
"name": "research-agent",
"description": "Delegate research to the sub-agent. Give one topic at a time.",
"system_prompt": RESEARCHER_INSTRUCTIONS.format(date=current_date),
"tools": [tavily_search],
}
agent = define_deep_agent(
name="deep-research",
model="anthropic:claude-sonnet-4-5-20250929",
tools=[tavily_search],
subagents=[research_sub_agent],
middleware=[TodoListMiddleware()],
)
agent.py
from datetime import datetime
from langchain.agents.middleware import TodoListMiddleware
from managed_deepagents import define_deep_agent
from tools.search import tavily_search
current_date = datetime.now().strftime("%Y-%m-%d")
RESEARCHER_INSTRUCTIONS = """You are a research assistant conducting research on the user's input topic. For context, today's date is {date}.
Your job is to use tools to gather information about the user's input topic.
You can use the tavily_search tool to find resources that can help answer the research question.
You can call it in series or in parallel, your research is conducted in a tool-calling loop.
You have access to the tavily_search tool for conducting web searches.
Think like a human researcher with limited time. Follow these steps:
1. **Read the question carefully** - What specific information does the user need?
2. **Start with broader searches** - Use broad, comprehensive queries first
3. **After each search, pause and assess** - Do I have enough to answer? What's still missing?
4. **Execute narrower searches as you gather information** - Fill in the gaps
5. **Stop when you can answer confidently** - Don't keep searching for perfection
**Tool Call Budgets** (Prevent excessive searching):
- **Simple queries**: Use 2-3 search tool calls maximum
- **Complex queries**: Use up to 5 search tool calls maximum
- **Always stop**: After 5 search tool calls if you cannot find the right sources
**Stop Immediately When**:
- You can answer the user's question comprehensively
- You have 3+ relevant examples/sources for the question
- Your last 2 searches returned similar information
After each search, assess results before continuing: What key information did I find? What's missing? Do I have enough to answer? Should I search more or provide my answer?
When providing your findings back to the orchestrator:
1. **Structure your response**: Organize findings with clear headings and detailed explanations
2. **Cite sources inline**: Use [1], [2], [3] format when referencing information from your searches
3. **Include Sources section**: End with ### Sources listing each numbered source with title and URL
The orchestrator will consolidate citations from all sub-agents into the final report.
"""
research_sub_agent = {
"name": "research-agent",
"description": "Delegate research to the sub-agent. Give one topic at a time.",
"system_prompt": RESEARCHER_INSTRUCTIONS.format(date=current_date),
"tools": [tavily_search],
}
agent = define_deep_agent(
name="deep-research",
model="google_genai:gemini-3-pro-preview",
tools=[tavily_search],
subagents=[research_sub_agent],
middleware=[TodoListMiddleware()],
)
agent.ts。选择您的服务提供商:- Claude
- Gemini
agent.ts
import { defineDeepAgent } from "managed-deepagents";
import { todoListMiddleware } from "langchain";
import { tavilySearch } from "./tools/search";
const currentDate = new Date().toISOString().split("T")[0];
const RESEARCHER_INSTRUCTIONS = `You are a research assistant conducting research on the user's input topic. For context, today's date is {date}.
Your job is to use tools to gather information about the user's input topic.
You can use the tavily_search tool to find resources that can help answer the research question.
You can call it in series or in parallel, your research is conducted in a tool-calling loop.
You have access to the tavily_search tool for conducting web searches.
Think like a human researcher with limited time. Follow these steps:
1. **Read the question carefully** - What specific information does the user need?
2. **Start with broader searches** - Use broad, comprehensive queries first
3. **After each search, pause and assess** - Do I have enough to answer? What's still missing?
4. **Execute narrower searches as you gather information** - Fill in the gaps
5. **Stop when you can answer confidently** - Don't keep searching for perfection
**Tool Call Budgets** (Prevent excessive searching):
- **Simple queries**: Use 2-3 search tool calls maximum
- **Complex queries**: Use up to 5 search tool calls maximum
- **Always stop**: After 5 search tool calls if you cannot find the right sources
**Stop Immediately When**:
- You can answer the user's question comprehensively
- You have 3+ relevant examples/sources for the question
- Your last 2 searches returned similar information
After each search, assess results before continuing: What key information did I find? What's missing? Do I have enough to answer? Should I search more or provide my answer?
When providing your findings back to the orchestrator:
1. **Structure your response**: Organize findings with clear headings and detailed explanations
2. **Cite sources inline**: Use [1], [2], [3] format when referencing information from your searches
3. **Include Sources section**: End with ### Sources listing each numbered source with title and URL
The orchestrator will consolidate citations from all sub-agents into the final report.
`;
const researchSubAgent = {
name: "research-agent",
description: "Delegate research to the sub-agent. Give one topic at a time.",
systemPrompt: RESEARCHER_INSTRUCTIONS.replace("{date}", currentDate),
tools: [tavilySearch],
};
export const agent = defineDeepAgent({
name: "deep-research",
model: "anthropic:claude-sonnet-4-5-20250929",
tools: [tavilySearch],
subagents: [researchSubAgent],
middleware: [todoListMiddleware()],
});
agent.ts
import { defineDeepAgent } from "managed-deepagents";
import { todoListMiddleware } from "langchain";
import { tavilySearch } from "./tools/search";
const currentDate = new Date().toISOString().split("T")[0];
const RESEARCHER_INSTRUCTIONS = `You are a research assistant conducting research on the user's input topic. For context, today's date is {date}.
Your job is to use tools to gather information about the user's input topic.
You can use the tavily_search tool to find resources that can help answer the research question.
You can call it in series or in parallel, your research is conducted in a tool-calling loop.
You have access to the tavily_search tool for conducting web searches.
Think like a human researcher with limited time. Follow these steps:
1. **Read the question carefully** - What specific information does the user need?
2. **Start with broader searches** - Use broad, comprehensive queries first
3. **After each search, pause and assess** - Do I have enough to answer? What's still missing?
4. **Execute narrower searches as you gather information** - Fill in the gaps
5. **Stop when you can answer confidently** - Don't keep searching for perfection
**Tool Call Budgets** (Prevent excessive searching):
- **Simple queries**: Use 2-3 search tool calls maximum
- **Complex queries**: Use up to 5 search tool calls maximum
- **Always stop**: After 5 search tool calls if you cannot find the right sources
**Stop Immediately When**:
- You can answer the user's question comprehensively
- You have 3+ relevant examples/sources for the question
- Your last 2 searches returned similar information
After each search, assess results before continuing: What key information did I find? What's missing? Do I have enough to answer? Should I search more or provide my answer?
When providing your findings back to the orchestrator:
1. **Structure your response**: Organize findings with clear headings and detailed explanations
2. **Cite sources inline**: Use [1], [2], [3] format when referencing information from your searches
3. **Include Sources section**: End with ### Sources listing each numbered source with title and URL
The orchestrator will consolidate citations from all sub-agents into the final report.
`;
const researchSubAgent = {
name: "research-agent",
description: "Delegate research to the sub-agent. Give one topic at a time.",
systemPrompt: RESEARCHER_INSTRUCTIONS.replace("{date}", currentDate),
tools: [tavilySearch],
};
export const agent = defineDeepAgent({
name: "deep-research",
model: "google:gemini-3-pro-preview",
tools: [tavilySearch],
subagents: [researchSubAgent],
middleware: [todoListMiddleware()],
});
运行智能体
1
Run locally
安装依赖项并启动智能体::::python::::::js:::您应该看到 orchestrator 计划包含
uv sync
uv run mda dev
npm install
npx mda dev
pnpm install
pnpm exec mda dev
bun install
bunx mda dev
mda dev 从 .env 加载 API 密钥,启动本地智能体服务器,并在 LangSmith Studio 中打开智能体。在 Studio 中发送研究问题,例如:Compare the main approaches to context engineering for AI agents in 2025.
write_todos,将任务委托给研究子智能体,并生成报告。更多详情请见 在 LangSmith Studio 本地开发。2
Deploy (optional)
:::python::::::js:::成功时,CLI 会打印部署仪表板 URL。请参考 部署。
uv run mda deploy
npx mda deploy
pnpm exec mda deploy
bunx mda deploy
配置
:::python1
Create project directory
mkdir deep-research-agent
cd deep-research-agent
2
Install dependencies
- Claude
- Gemini
pip install deepagents tavily-python httpx markdownify langchain-anthropic langchain-core
uv init
uv add deepagents tavily-python httpx markdownify langchain-anthropic langchain-core
uv sync
pip install deepagents tavily-python httpx markdownify langchain-google-genai langchain-core
uv init
uv add deepagents tavily-python httpx markdownify langchain-google-genai langchain-core
uv sync
3
Set API keys
- Claude
- Gemini
export ANTHROPIC_API_KEY="your_anthropic_api_key"
export TAVILY_API_KEY="your_tavily_api_key"
export LANGSMITH_API_KEY="your_langsmith_api_key" # Optional
export GOOGLE_API_KEY="your_google_api_key"
export TAVILY_API_KEY="your_tavily_api_key"
export LANGSMITH_API_KEY="your_langsmith_api_key" # Optional
1
Create project directory
mkdir deep-research-agent
cd deep-research-agent
2
Install dependencies
- Claude
- Gemini
npm
npm install deepagents langchain @langchain/anthropic @langchain/core zod tsx
npm
npm install deepagents langchain @langchain/google @langchain/core zod tsx
3
Set API keys
- Claude
- Gemini
export ANTHROPIC_API_KEY="your_anthropic_api_key"
export TAVILY_API_KEY="your_tavily_api_key"
export LANGSMITH_API_KEY="your_langsmith_api_key" # Optional
export GOOGLE_API_KEY="your_google_api_key"
export TAVILY_API_KEY="your_tavily_api_key"
export LANGSMITH_API_KEY="your_langsmith_api_key" # Optional
构建智能体
:::python 在项目目录中创建agent.py:
::::::js
在项目目录中创建 agent.ts:
:::1
Add tools
添加自定义搜索工具。::::::js:::
tavily_search 工具使用 Tavily 进行 URL 发现,然后获取完整网页内容,使智能体能够分析完整信息源而非摘要。:::pythonimport os
from typing import Annotated, Literal
import httpx
from langchain.tools import InjectedToolArg, tool
from markdownify import markdownify
from tavily import TavilyClient
tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
def fetch_webpage_content(url: str, timeout: float = 10.0) -> str:
"""Fetch webpage and convert HTML to markdown."""
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
try:
response = httpx.get(url, headers=headers, timeout=timeout)
response.raise_for_status()
return markdownify(response.text)
except Exception as e:
return f"Error fetching {url}: {e!s}"
@tool(parse_docstring=True)
def tavily_search(
query: str,
max_results: Annotated[int, InjectedToolArg] = 1,
topic: Annotated[
Literal["general", "news", "finance"], InjectedToolArg
] = "general",
) -> str:
"""Search the web for information on a given query.
Uses Tavily to discover relevant URLs, then fetches and returns full webpage content as markdown.
Args:
query: Search query to execute
max_results: Maximum number of results to return (default: 1)
topic: Topic filter - 'general', 'news', or 'finance' (default: 'general')
Returns:
Formatted search results with full webpage content
"""
search_results = tavily_client.search(
query,
max_results=max_results,
topic=topic,
)
result_texts = []
for result in search_results.get("results", []):
url = result["url"]
title = result["title"]
content = fetch_webpage_content(url)
result_texts.append(f"## {title}\n**URL:** {url}\n\n{content}\n---")
return f"Found {len(result_texts)} result(s) for '{query}':\n\n" + "\n".join(
result_texts
)
import { tool } from "langchain";
import { z } from "zod";
async function fetchWebpageContent(
url: string,
timeout = 10_000,
): Promise<string> {
try {
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);
const response = await fetch(url, {
headers: {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
},
signal: controller.signal,
});
clearTimeout(id);
if (!response.ok) {
return `Error fetching ${url}: HTTP ${response.status}`;
}
return await response.text();
} catch (e) {
return `Error fetching ${url}: ${e}`;
}
}
const tavilySearch = tool(
async ({
query,
maxResults = 1,
topic = "general",
}: {
query: string;
maxResults?: number;
topic?: "general" | "news" | "finance";
}) => {
const response = await fetch("https://api.tavily.com/search", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.TAVILY_API_KEY}`,
},
body: JSON.stringify({ query, max_results: maxResults, topic }),
});
const data = (await response.json()) as {
results: Array<{ url: string; title: string }>;
};
const results = data.results ?? [];
const resultTexts: string[] = [];
for (const result of results) {
const content = await fetchWebpageContent(result.url);
resultTexts.push(
`## ${result.title}\n**URL:** ${result.url}\n\n${content}\n---`,
);
}
return (
`Found ${resultTexts.length} result(s) for '${query}':\n\n` +
resultTexts.join("\n")
);
},
{
name: "tavily_search",
description:
"Search the web for information on a given query. Uses Tavily to discover relevant URLs, then fetches and returns full webpage content.",
schema: z.object({
query: z.string().describe("Search query to execute"),
maxResults: z
.number()
.optional()
.default(1)
.describe("Maximum number of results to return (default: 1)"),
topic: z
.enum(["general", "news", "finance"])
.optional()
.default("general")
.describe(
"Topic filter - 'general', 'news', or 'finance' (default: 'general')",
),
}),
},
);
2
Create the agent
在工具下方添加提示词常量和创建智能体。三个常量(然后添加模型和智能体。选择您的服务提供商:::::::js
将提示词添加到 然后添加模型和智能体。选择您的服务提供商:※ 重要提示:在您之前的输出中占位符集不正确。缺少的 ID:[‘0’];意外的额外 ID:[]。请再次翻译全文,并保持每个占位符(六边形括号 + 数字)的原位置,且仅出现一次。:::
RESEARCH_WORKFLOW_INSTRUCTIONS、RESEARCHER_INSTRUCTIONS 和 SUBAGENT_DELEGATION_INSTRUCTIONS)必须与 create_deep_agent / createDeepAgent 调用位于同一文件。@[TodoListMiddleware] 是可选的 任务规划,使智能体能调用 write_todos。:::python
将提示词添加到 agent.py:RESEARCH_WORKFLOW_INSTRUCTIONS = """# Research Workflow
Follow this workflow for all research requests:
1. **Plan**: Create a todo list with write_todos to break down the research into focused tasks
2. **Save the request**: Use write_file() to save the user's research question to `/research_request.md`
3. **Research**: Delegate research tasks to sub-agents using the task() tool - ALWAYS use sub-agents for research, never conduct research yourself
4. **Synthesize**: Review all sub-agent findings and consolidate citations (each unique URL gets one number across all findings)
5. **Write Report**: Write a comprehensive final report to `/final_report.md` (see Report Writing Guidelines below)
6. **Verify**: Read `/research_request.md` and confirm you've addressed all aspects with proper citations and structure
## Research Planning Guidelines
- Batch similar research tasks into a single TODO to minimize overhead
- For simple fact-finding questions, use 1 sub-agent
- For comparisons or multi-faceted topics, delegate to multiple parallel sub-agents
- Each sub-agent should research one specific aspect and return findings
## Report Writing Guidelines
When writing the final report to `/final_report.md`, follow these structure patterns:
**For comparisons:**
1. Introduction
2. Overview of topic A
3. Overview of topic B
4. Detailed comparison
5. Conclusion
**For lists/rankings:**
Simply list items with details - no introduction needed:
1. Item 1 with explanation
2. Item 2 with explanation
3. Item 3 with explanation
**For summaries/overviews:**
1. Overview of topic
2. Key concept 1
3. Key concept 2
4. Key concept 3
5. Conclusion
**General guidelines:**
- Use clear section headings (## for sections, ### for subsections)
- Write in paragraph form by default - be text-heavy, not just bullet points
- Do NOT use self-referential language ("I found...", "I researched...")
- Write as a professional report without meta-commentary
- Each section should be comprehensive and detailed
- Use bullet points only when listing is more appropriate than prose
**Citation format:**
- Cite sources inline using [1], [2], [3] format
- Assign each unique URL a single citation number across ALL sub-agent findings
- End report with ### Sources section listing each numbered source
- Number sources sequentially without gaps (1,2,3,4...)
- Format: [1] Source Title: URL (each on separate line for proper list rendering)
- Example:
Some important finding [1]. Another key insight [2].
### Sources
[1] AI Research Paper: https://example.com/paper
[2] Industry Analysis: https://example.com/analysis
"""
RESEARCHER_INSTRUCTIONS = """You are a research assistant conducting research on the user's input topic. For context, today's date is {date}.
Your job is to use tools to gather information about the user's input topic.
You can use the tavily_search tool to find resources that can help answer the research question.
You can call it in series or in parallel, your research is conducted in a tool-calling loop.
You have access to the tavily_search tool for conducting web searches.
Think like a human researcher with limited time. Follow these steps:
1. **Read the question carefully** - What specific information does the user need?
2. **Start with broader searches** - Use broad, comprehensive queries first
3. **After each search, pause and assess** - Do I have enough to answer? What's still missing?
4. **Execute narrower searches as you gather information** - Fill in the gaps
5. **Stop when you can answer confidently** - Don't keep searching for perfection
**Tool Call Budgets** (Prevent excessive searching):
- **Simple queries**: Use 2-3 search tool calls maximum
- **Complex queries**: Use up to 5 search tool calls maximum
- **Always stop**: After 5 search tool calls if you cannot find the right sources
**Stop Immediately When**:
- You can answer the user's question comprehensively
- You have 3+ relevant examples/sources for the question
- Your last 2 searches returned similar information
After each search, assess results before continuing: What key information did I find? What's missing? Do I have enough to answer? Should I search more or provide my answer?
When providing your findings back to the orchestrator:
1. **Structure your response**: Organize findings with clear headings and detailed explanations
2. **Cite sources inline**: Use [1], [2], [3] format when referencing information from your searches
3. **Include Sources section**: End with ### Sources listing each numbered source with title and URL
Example:
## Key Findings
Context engineering is a critical technique for AI agents [1]. Studies show that proper context management can improve performance by 40% [2].
### Sources
[1] Context Engineering Guide: https://example.com/context-guide
[2] AI Performance Study: https://example.com/study
The orchestrator will consolidate citations from all sub-agents into the final report.
"""
SUBAGENT_DELEGATION_INSTRUCTIONS = """# Sub-Agent Research Coordination
Your role is to coordinate research by delegating tasks from your TODO list to specialized research sub-agents.
## Delegation Strategy
**DEFAULT: Start with 1 sub-agent** for most queries:
- "What is quantum computing?" -> 1 sub-agent (general overview)
- "List the top 10 coffee shops in San Francisco" -> 1 sub-agent
- "Summarize the history of the internet" -> 1 sub-agent
- "Research context engineering for AI agents" -> 1 sub-agent (covers all aspects)
**ONLY parallelize when the query EXPLICITLY requires comparison or has clearly independent aspects:**
**Explicit comparisons** -> 1 sub-agent per element:
- "Compare OpenAI vs Anthropic vs DeepMind AI safety approaches" -> 3 parallel sub-agents
- "Compare Python vs JavaScript for web development" -> 2 parallel sub-agents
**Clearly separated aspects** -> 1 sub-agent per aspect (use sparingly):
- "Research renewable energy adoption in Europe, Asia, and North America" -> 3 parallel sub-agents (geographic separation)
- Only use this pattern when aspects cannot be covered efficiently by a single comprehensive search
## Key Principles
- **Bias towards single sub-agent**: One comprehensive research task is more token-efficient than multiple narrow ones
- **Avoid premature decomposition**: Don't break "research X" into "research X overview", "research X techniques", "research X applications" - just use 1 sub-agent for all of X
- **Parallelize only for clear comparisons**: Use multiple sub-agents when comparing distinct entities or geographically separated data
## Parallel Execution Limits
- Use at most {max_concurrent_research_units} parallel sub-agents per iteration
- Make multiple task() calls in a single response to enable parallel execution
- Each sub-agent returns findings independently
## Research Limits
- Stop after {max_researcher_iterations} delegation rounds if you haven't found adequate sources
- Stop when you have sufficient information to answer comprehensively
- Bias towards focused research over exhaustive exploration"""
- Claude
- Gemini
from datetime import datetime
from deepagents import create_deep_agent
from langchain.agents.middleware import TodoListMiddleware
from langchain.chat_models import init_chat_model
max_concurrent_research_units = 3
max_researcher_iterations = 3
current_date = datetime.now().strftime("%Y-%m-%d")
INSTRUCTIONS = (
RESEARCH_WORKFLOW_INSTRUCTIONS
+ "\n\n"
+ "=" * 80
+ "\n\n"
+ SUBAGENT_DELEGATION_INSTRUCTIONS.format(
max_concurrent_research_units=max_concurrent_research_units,
max_researcher_iterations=max_researcher_iterations,
)
)
research_sub_agent = {
"name": "research-agent",
"description": "Delegate research to the sub-agent. Give one topic at a time.",
"system_prompt": RESEARCHER_INSTRUCTIONS.format(date=current_date),
"tools": [tavily_search],
}
model = init_chat_model(model="anthropic:claude-sonnet-4-5-20250929", temperature=0.0)
agent = create_deep_agent(
model=model,
tools=[tavily_search],
system_prompt=INSTRUCTIONS,
subagents=[research_sub_agent],
middleware=[TodoListMiddleware()],
)
from datetime import datetime
from deepagents import create_deep_agent
from langchain.agents.middleware import TodoListMiddleware
from langchain_google_genai import ChatGoogleGenerativeAI
max_concurrent_research_units = 3
max_researcher_iterations = 3
current_date = datetime.now().strftime("%Y-%m-%d")
INSTRUCTIONS = (
RESEARCH_WORKFLOW_INSTRUCTIONS
+ "\n\n"
+ "=" * 80
+ "\n\n"
+ SUBAGENT_DELEGATION_INSTRUCTIONS.format(
max_concurrent_research_units=max_concurrent_research_units,
max_researcher_iterations=max_researcher_iterations,
)
)
research_sub_agent = {
"name": "research-agent",
"description": "Delegate research to the sub-agent. Give one topic at a time.",
"system_prompt": RESEARCHER_INSTRUCTIONS.format(date=current_date),
"tools": [tavily_search],
}
model = ChatGoogleGenerativeAI(model="gemini-3-pro-preview", temperature=0.0)
agent = create_deep_agent(
model=model,
tools=[tavily_search],
system_prompt=INSTRUCTIONS,
subagents=[research_sub_agent],
middleware=[TodoListMiddleware()],
)
agent.ts:const RESEARCH_WORKFLOW_INSTRUCTIONS = `# Research Workflow
Follow this workflow for all research requests:
1. **Plan**: Create a todo list with write_todos to break down the research into focused tasks
2. **Save the request**: Use write_file() to save the user's research question to \`/research_request.md\`
3. **Research**: Delegate research tasks to sub-agents using the task() tool - ALWAYS use sub-agents for research, never conduct research yourself
4. **Synthesize**: Review all sub-agent findings and consolidate citations (each unique URL gets one number across all findings)
5. **Write Report**: Write a comprehensive final report to \`/final_report.md\` (see Report Writing Guidelines below)
6. **Verify**: Read \`/research_request.md\` and confirm you've addressed all aspects with proper citations and structure
## Research Planning Guidelines
- Batch similar research tasks into a single TODO to minimize overhead
- For simple fact-finding questions, use 1 sub-agent
- For comparisons or multi-faceted topics, delegate to multiple parallel sub-agents
- Each sub-agent should research one specific aspect and return findings
## Report Writing Guidelines
When writing the final report to \`/final_report.md\`, follow these structure patterns:
**For comparisons:**
1. Introduction
2. Overview of topic A
3. Overview of topic B
4. Detailed comparison
5. Conclusion
**For lists/rankings:**
Simply list items with details - no introduction needed:
1. Item 1 with explanation
2. Item 2 with explanation
3. Item 3 with explanation
**For summaries/overviews:**
1. Overview of topic
2. Key concept 1
3. Key concept 2
4. Key concept 3
5. Conclusion
**General guidelines:**
- Use clear section headings (## for sections, ### for subsections)
- Write in paragraph form by default - be text-heavy, not just bullet points
- Do NOT use self-referential language ("I found...", "I researched...")
- Write as a professional report without meta-commentary
- Each section should be comprehensive and detailed
- Use bullet points only when listing is more appropriate than prose
**Citation format:**
- Cite sources inline using [1], [2], [3] format
- Assign each unique URL a single citation number across ALL sub-agent findings
- End report with ### Sources section listing each numbered source
- Number sources sequentially without gaps (1,2,3,4...)
- Format: [1] Source Title: URL (each on separate line for proper list rendering)
- Example:
Some important finding [1]. Another key insight [2].
### Sources
[1] AI Research Paper: https://example.com/paper
[2] Industry Analysis: https://example.com/analysis
`;
const RESEARCHER_INSTRUCTIONS = `You are a research assistant conducting research on the user's input topic. For context, today's date is {date}.
Your job is to use tools to gather information about the user's input topic.
You can use the tavily_search tool to find resources that can help answer the research question.
You can call it in series or in parallel, your research is conducted in a tool-calling loop.
You have access to the tavily_search tool for conducting web searches.
Think like a human researcher with limited time. Follow these steps:
1. **Read the question carefully** - What specific information does the user need?
2. **Start with broader searches** - Use broad, comprehensive queries first
3. **After each search, pause and assess** - Do I have enough to answer? What's still missing?
4. **Execute narrower searches as you gather information** - Fill in the gaps
5. **Stop when you can answer confidently** - Don't keep searching for perfection
**Tool Call Budgets** (Prevent excessive searching):
- **Simple queries**: Use 2-3 search tool calls maximum
- **Complex queries**: Use up to 5 search tool calls maximum
- **Always stop**: After 5 search tool calls if you cannot find the right sources
**Stop Immediately When**:
- You can answer the user's question comprehensively
- You have 3+ relevant examples/sources for the question
- Your last 2 searches returned similar information
After each search, assess results before continuing: What key information did I find? What's missing? Do I have enough to answer? Should I search more or provide my answer?
When providing your findings back to the orchestrator:
1. **Structure your response**: Organize findings with clear headings and detailed explanations
2. **Cite sources inline**: Use [1], [2], [3] format when referencing information from your searches
3. **Include Sources section**: End with ### Sources listing each numbered source with title and URL
Example:
## Key Findings
Context engineering is a critical technique for AI agents [1]. Studies show that proper context management can improve performance by 40% [2].
### Sources
[1] Context Engineering Guide: https://example.com/context-guide
[2] AI Performance Study: https://example.com/study
The orchestrator will consolidate citations from all sub-agents into the final report.
`;
const SUBAGENT_DELEGATION_INSTRUCTIONS = `# Sub-Agent Research Coordination
Your role is to coordinate research by delegating tasks from your TODO list to specialized research sub-agents.
## Delegation Strategy
**DEFAULT: Start with 1 sub-agent** for most queries:
- "What is quantum computing?" -> 1 sub-agent (general overview)
- "List the top 10 coffee shops in San Francisco" -> 1 sub-agent
- "Summarize the history of the internet" -> 1 sub-agent
- "Research context engineering for AI agents" -> 1 sub-agent (covers all aspects)
**ONLY parallelize when the query EXPLICITLY requires comparison or has clearly independent aspects:**
**Explicit comparisons** -> 1 sub-agent per element:
- "Compare OpenAI vs Anthropic vs DeepMind AI safety approaches" -> 3 parallel sub-agents
- "Compare Python vs JavaScript for web development" -> 2 parallel sub-agents
**Clearly separated aspects** -> 1 sub-agent per aspect (use sparingly):
- "Research renewable energy adoption in Europe, Asia, and North America" -> 3 parallel sub-agents (geographic separation)
- Only use this pattern when aspects cannot be covered efficiently by a single comprehensive search
## Key Principles
- **Bias towards single sub-agent**: One comprehensive research task is more token-efficient than multiple narrow ones
- **Avoid premature decomposition**: Don't break "research X" into "research X overview", "research X techniques", "research X applications" - just use 1 sub-agent for all of X
- **Parallelize only for clear comparisons**: Use multiple sub-agents when comparing distinct entities or geographically separated data
## Parallel Execution Limits
- Use at most {maxConcurrentResearchUnits} parallel sub-agents per iteration
- Make multiple task() calls in a single response to enable parallel execution
- Each sub-agent returns findings independently
## Research Limits
- Stop after {maxResearcherIterations} delegation rounds if you haven't found adequate sources
- Stop when you have sufficient information to answer comprehensively
- Bias towards focused research over exhaustive exploration`;
- Claude
- Gemini
import { createDeepAgent } from "deepagents";
import { ChatAnthropic } from "@langchain/anthropic";
import { todoListMiddleware } from "langchain";
const maxConcurrentResearchUnits = 3;
const maxResearcherIterations = 3;
const currentDate = new Date().toISOString().split("T")[0];
const INSTRUCTIONS =
RESEARCH_WORKFLOW_INSTRUCTIONS +
"\n\n" +
"=".repeat(80) +
"\n\n" +
SUBAGENT_DELEGATION_INSTRUCTIONS.replace(
"{maxConcurrentResearchUnits}",
String(maxConcurrentResearchUnits),
).replace("{maxResearcherIterations}", String(maxResearcherIterations));
const researchSubAgent = {
name: "research-agent",
description: "Delegate research to the sub-agent. Give one topic at a time.",
systemPrompt: RESEARCHER_INSTRUCTIONS.replace("{date}", currentDate),
tools: [tavilySearch],
};
const model = new ChatAnthropic({
model: "claude-sonnet-4-5-20250929",
temperature: 0,
});
const agent = await createDeepAgent({
model,
tools: [tavilySearch],
systemPrompt: INSTRUCTIONS,
subagents: [researchSubAgent],
middleware: [todoListMiddleware()],
});
import { createDeepAgent } from "deepagents";
import { ChatGoogle } from "@langchain/google/node";
import { todoListMiddleware } from "langchain";
const maxConcurrentResearchUnits = 3;
const maxResearcherIterations = 3;
const currentDate = new Date().toISOString().split("T")[0];
const INSTRUCTIONS =
RESEARCH_WORKFLOW_INSTRUCTIONS +
"\n\n" +
"=".repeat(80) +
"\n\n" +
SUBAGENT_DELEGATION_INSTRUCTIONS.replace(
"{maxConcurrentResearchUnits}",
String(maxConcurrentResearchUnits),
).replace("{maxResearcherIterations}", String(maxResearcherIterations));
const researchSubAgent = {
name: "research-agent",
description: "Delegate research to the sub-agent. Give one topic at a time.",
systemPrompt: RESEARCHER_INSTRUCTIONS.replace("{date}", currentDate),
tools: [tavilySearch],
};
const model = new ChatGoogle({
model: "gemini-3-pro-preview",
temperature: 0,
});
const agent = createDeepAgent({
model,
tools: [tavilySearch],
systemPrompt: INSTRUCTIONS,
subagents: [researchSubAgent],
middleware: [todoListMiddleware()],
});
运行智能体
您可以选择同步运行智能体(等待完整结果后输出)或流式接收更新。:::python 在agent.py 底部添加对应标签的代码:
::::::js
在 agent.ts 底部添加对应标签的代码:
:::- Run synchronously
- Stream updates
:::python::::::js:::
from langchain.messages import HumanMessage
if __name__ == "__main__":
result = agent.invoke(
{
"messages": [
HumanMessage(
content="What are the main differences between RAG and fine-tuning for LLM applications?"
)
]
}
)
for msg in result.get("messages", []):
if hasattr(msg, "content") and msg.content:
print(msg.content)
{
async function main() {
const result = await agent.invoke({
messages: [
{
role: "user",
content:
"What are the main differences between RAG and fine-tuning for LLM applications?",
},
],
});
for (const msg of result.messages ?? []) {
if (msg.content) {
console.log(msg.content);
}
}
}
main().catch((err) => {
console.error(err);
process.exitCode = 1;
});
}
:::python::::::js:::
from langchain.messages import HumanMessage
if __name__ == "__main__":
stream = agent.stream_events(
{
"messages": [
HumanMessage(content="Compare Python vs JavaScript for web development")
]
},
version="v3",
)
for message in stream.messages:
for token in message.text:
print(token, end="", flush=True)
{
async function main() {
const stream = await agent.streamEvents(
{
messages: [
{
role: "user",
content: "Compare Python vs JavaScript for web development",
},
],
},
{ version: "v3" },
);
for await (const message of stream.messages) {
for await (const token of message.text) {
process.stdout.write(token);
}
}
}
main().catch((err) => {
console.error(err);
process.exitCode = 1;
});
}
python agent.py
npx tsx agent.ts
LANGSMITH_API_KEY 环境变量,您可以在 LangSmith 中查看智能体轨迹以调试和监控多步骤行为。完整代码
查看完整 Deep Research 示例 在 GitHub。下一步骤
现在已构建智能体,可通过编辑编排器指令(Managed Deep Agents:instructions.md;SDK: 在您的智能体文件中修改提示常量)来定制工作流。您还可以调整委派限制以允许更多并行子智能体或委派轮次。
关于本教程中涉及的概念,请参考:
- 子智能体: 使用不同工具和提示词配置子智能体
- 自定义: 自定义模型、工具、系统提示词及可选任务规划
- Managed Deep Agents: 使用 managed 部署基础设施构建深度智能体
- LangSmith: 追踪研究运行并调试多步骤行为
- Deep Research Course: 完整的深度研究课程(基于 LangGraph)]
官方原文:src/oss/deepagents/deep-research.mdx · 非官方翻译,译文由 AI 生成,以英文原文为准。