딥 리서치 에이전트 구축하기
딥 리서치 에이전트 구축하기 (Build a deep research agent)
서브에이전트 위임으로 다단계 웹 리서치 에이전트 구축하기
개요
이 가이드는 Deep Agents를 사용해 처음부터 다단계 웹 리서치 에이전트를 구축하는 방법을 보여 줍니다. 에이전트가 리서치 질문을 집중된 작업으로 분해하고, 특화된 서브 에이전트에게 위임하며, 발견 사항을 종합하여 포괄적인 보고서를 만듭니다.
구축할 에이전트는 다음과 같은 일을 합니다:
- 옵트인 todo 리스트 미들웨어를 사용해 연구 계획 수립
- 격리된 컨텍스트를 가진 서브 에이전트에 집중된 리서치 작업 위임
- 정보를 수집하며 검색 결과 평가 및 다음 단계 계획
- 적절한 인용과 함께 발견 사항을 최종 보고서로 종합
생성된 서브 에이전트들은 Tavily로 웹 검색을 수행하고, 분석을 위해 전체 웹페이지 콘텐츠를 가져옵니다.
핵심 개념
이 튜토리얼은 다음을 다룹니다:
전제 조건
다음에 대한 API 키:
설정
<Tab title="Gemini">
```bash npm wrap theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
npm install deepagents @langchain/google-genai @langchain/core
```
</Tab>
</Tabs>
<Tab title="Gemini">
```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
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
```
</Tab>
</Tabs>
에이전트 구축
프로젝트 디렉터리에 agent.ts를 생성하세요:
```ts theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
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: ***
},
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')"),
}),
},
);
```
```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
`;
```
```ts
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.
`;
```
```ts
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`;
```
```typescript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
import { todoListMiddleware } from "langchain";
```
이 미들웨어를 다음 단계에서 에이전트를 만들 때 포함합니다.
```ts theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
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()],
});
```
에이전트 실행
에이전트를 동기적으로 실행할 수 있습니다 — 전체 결과를 기다린 다음 출력하는 방식, 또는 업데이트가 도착할 때 스트리밍하는 방식입니다.
agent.ts 하단의 해당 탭에 코드를 추가하세요:
for (const msg of result.messages ?? []) {
if (msg.content) {
console.log(msg.content);
}
}
}
main().catch((err) => {
console.error(err);
process.exitCode = 1;
});
}
```
main().catch((err) => {
console.error(err);
process.exitCode = 1;
});
}
```
프로젝트 루트에서 에이전트를 실행하세요:
npx tsx agent.ts
실행 전에 LANGSMITH_API_KEY 환경 변수를 설정했다면 LangSmith에서 에이전트의 추적을 확인하여 다단계 동작을 디버깅하고 모니터링할 수 있습니다.
전체 코드
GitHub에서 완전한 Deep Research 예시를 확인하세요.
다음 단계
이제 에이전트를 구축했으니, 에이전트 파일의 프롬프트 상수를 변경하여 워크플로, 위임 전략 또는 리서처 동작을 조정하는 방식으로 커스터마이즈할 수 있습니다. 위임 한도를 조정하여 더 많은 병렬 서브 에이전트나 위임 라운드를 허용할 수도 있습니다.
이 튜토리얼의 개념에 대해 더 알아보려면 다음 리소스를 확인하세요:
- 서브에이전트: 다른 도구와 프롬프트를 가진 서브에이전트를 구성하는 방법 알아보기
- 커스터마이징: 모델, 도구, 시스템 프롬프트 및 선택적 작업 계획 커스터마이즈
- LangSmith: 리서치 실행 추적 및 다단계 동작 디버깅
- Deep Research 코스: LangGraph로 딥 리서치에 대한 전체 코스
더 알아보기
출처: 문서