Deep Research Agent

Deep Research Agent

Deep Research Agent는 많은 웹 소스에서 정보를 수집하고, 이를 평가하며, 인용이 포함된 구조화된 보고서를 만드는 데 사용하는 실험적 에이전트예요.

출처: 문서

본문

이 에이전트는 Agent Pack의 일부로, 현재 실험적입니다. API와 에이전트 아키텍처는 일반적인 폐기(deprecation) 정책을 따르지 않고 어떤 릴리스에서든 변경될 수 있습니다.

When to use this agent

빠른 답변 이상을 원할 때 딥 리서치 에이전트를 사용하세요. 많은 웹 소스에서 정보를 수집하고, 이를 평가하며, 인용이 포함된 구조화된 보고서를 만들어야 하는 질문을 위해 설계되었습니다.

일반적인 사용 사례:

  • 많은 소스에 걸쳐 광범위한 주제 조사
  • 제품, 회사, 기술, 과학적 발견 비교
  • 문헌 리뷰나 시장 개요 준비
  • 여러 하위 주제를 병렬로 조사하면 이점이 있는 복잡한 질문에 답하기

다음 경우에는 덜 유용합니다:

  • 단일 웹 검색이나 RAG 조회로 충분할 때 (멀티 에이전트 워크플로우는 지연과 비용을 추가해요)
  • 정보가 공개 웹이 아니라 사설 지식 베이스에 있을 때 (그 경우 Advanced RAG Agent 사용)

Installation

pip install agent-pack-haystack tavily-haystack trafilatura pypdf arrow

trafilatura, pypdf, arrow는 딥 리서치 에이전트가 런타임에 필요로 하는 별도 설치 항목이에요(HTML·PDF 파싱과 날짜 렌더링). tavily-haystack는 기본 search_tool에만 필요합니다.

환경에 OPENAI_API_KEY와 TAVILY_API_KEY를 설정하세요.

Usage

from haystack.dataclasses import ChatMessage
from haystack_integrations.agent_pack import create_deep_research_agent

agent = create_deep_research_agent()
result = agent.run(messages=[ChatMessage.from_user("your research question")])
print(result["report"])

agent.run(...)은 주요 출력으로 최종 Markdown 보고서인 report를 담은 딕셔너리를 반환합니다. 딕셔너리는 또한 중간 brief(str)와 notes(list[str]), 그리고 표준 Agent 출력인 messages, last_message, step_count, token_usage, tool_call_counts를 실어 나릅니다.

Configuration

모든 것이 create_deep_research_agent의 키워드 인자로 구성됩니다. 모든 파라미터는 키워드 전용이며 선택적입니다.

Main agent

주 에이전트는 오케스트레이터로, 조사를 계획하고 하위 질문을 위임합니다.

  • llm — 오케스트레이터 루프를 구동하는 LLM. 기본값 OpenAIResponsesChatGenerator("gpt-5.4").
  • system_prompt — 미리 만들어진 오케스트레이터 프롬프트를 재정의. 자리표시자 {{ max_subtopics }}가 max_subtopics 값으로 대체됩니다.
  • max_agent_steps — 오케스트레이터 에이전트 루프의 최대 단계 수(reflect와 delegate 라운드). 기본값 8.
  • max_subtopics — 오케스트레이터가 위임할 수 있는 최대 하위 질문 수(너비). 기본값 5.
  • max_concurrent_researchers — 동시에 실행되는 하위 연구자 최대 수. 기본값 5.

Sub-researchers

  • researcher_llm — 각 하위 연구자의 검색·읽기·사고 루프를 구동하는 LLM. 기본값 OpenAIResponsesChatGenerator("gpt-5.4-mini").
  • search_tool — 각 하위 연구자가 사용하는 웹 검색 도구. 기본값 TavilyWebSearchTool(top_k=10)으로, tavily-haystack가 필요해요. 미리 만들어진 연구자 프롬프트는 이 도구를 web_search로 부르므로, 커스텀 도구도 같은 이름으로 지정하거나 프롬프트를 조정하세요.
  • page_summary_llm — read_url 도구 안에서 가져온 페이지를 질문 방향으로 요약하는 데 쓰는 LLM. 기본값 OpenAIResponsesChatGenerator("gpt-5.4-mini").
  • max_researcher_steps — 각 하위 연구자의 에이전트 루프 최대 단계 수. 기본값 20.
  • max_page_chars — 요약 전에 page_summary_llm에 투입되는 원시 페이지 최대 문자 수. 기본값 50000.

Brief and report

Scope와 Write 단계는 각각 자체 ChatGenerator를 가진 단일 LLM 호출이므로, 비용과 성능으로 모델을 섞거나 다른 제공 업체로 교체할 수 있어요.

  • brief_llm — 사용자 쿼리를 집중된 연구 브리프로 재작성하는 LLM. 기본값 OpenAIResponsesChatGenerator("gpt-5.4").
  • report_llm — 브리프와 수집된 노트를 최종 보고서로 바꾸는 LLM. 기본값 OpenAIResponsesChatGenerator("gpt-5.4").

Further customization

도구나 hooks 추가 같은 다른 모든 것을 바꾸려면 반환된 에이전트에 clone()을 사용하세요. 기존 값을 풀어내 내장 도구, 상태 항목, Scope·Write 후크를 유지할 수 있습니다:

agent = create_deep_research_agent()

customized = agent.clone(
    tools=[*agent.tools, my_tool],
    hooks={**agent.hooks, "before_llm": [my_hook]},
)

How it works

아키텍처는 오케스트레이터 역할을 하는 단일 최상위 Haystack Agent를 중심으로 구축됩니다. 두 개의 hooks가 그 루프 전후에 실행되어 Scope, Research, Write 세 가지 논리적 단계를 만듭니다. Research 단계 동안 오케스트레이터는 도구를 통해 격리된 하위 연구자 에이전트를 호출합니다(각각 자체 Agent).

  • Scope — 사용자 질문을 집중된 연구 브리프로 재작성합니다.
  • Research — 오케스트레이터가 브리프를 집중된 하위 질문으로 나누고, 각각을 하위 연구자에게 위임하고, 그 요약을 수집해요.
  • Write — 브리프와 수집된 요약이 최종 보고서가 됩니다: 인라인 [text](url) 인용이 있는 Markdown.

Scope와 Write는 일반 LLM 호출(ChatPromptBuilder와 OpenAIResponsesChatGenerator)로, 직렬화 가능한 후크 클래스(ScopeHook, WriteHook)로 감싸져 있습니다:

  • Scope는 before_run 후크로 실행됩니다. 오케스트레이터의 루프가 시작되기 전에 사용자 쿼리를 브리프로 바꿔 에이전트의 State에 저장해요.
  • Write는 after_run 후크로 실행됩니다. 오케스트레이터의 루프가 끝날 때 브리프와 수집된 notes를 최종 보고서로 바꿉니다.

brief, notes, report는 에이전트의 state_schema에 선언되므로, 단일 agent.run(...) 호출의 출력으로 돌아옵니다.

The agents

Research 단계는 두 개의 중첩 에이전트를 사용합니다. 각각은 Haystack Agent, 즉 도구를 호출하며 답하기로 결정할 때까지 루프하는 LLM입니다.

Orchestrator

오케스트레이터는 리드 에이전트로, 연구 브리프를 받고 전체 조사를 조정합니다.

  • 역할: 브리프를 몇 개의 집중되고 겹치지 않는 하위 질문으로 나누고, 각각을 위임하고, 커버리지를 확인하고, 충분할 때 멈춥니다.
  • 병렬성: 한 턴에 여러 위임 호출을 내보내고, 그것들이 동시에 실행됩니다(max_concurrent_researchers로 제한).
  • 메모리: 하위 연구자가 반환한 요약은 공유 notes 리스트(에이전트의 State)에 추가되며, writer가 나중에 이로 보고서를 만듭니다.
  • Stop 조건: 평문으로 답하거나(연구 완료) max_agent_steps에 도달할 때.

오케스트레이터의 도구:

Tool What it is What it does
research_subtopic 하위 연구자 에이전트를 AgentTool로 노출 하나의 하위 질문을 격리된 컨텍스트에서 연구하고 압축·인용된 요약을 반환. 그 요약만 오케스트레이터에 보이고, 요약은 notes에도 추가됨
think_tool no-op 반성 도구 하위 질문을 계획하고 라운드 사이에 커버리지를 평가하도록 오케스트레이터가 잠시 멈추게 함
Sub-researcher

하위 연구자는 단일 하위 질문에 답하는 재사용 가능한 에이전트예요. 오케스트레이터가 각각 자체 격리된 컨텍스트에서 병렬로 여러 번 실행합니다. 이것이 핵심 아이디어입니다. 각 하위 연구자는 원시 검색 결과를 비공개로 처리하고 간결한 요약만 반환하므로, 오케스트레이터의 컨텍스트가 작게 유지되고 최종 보고서가 일관성을 유지합니다.

  • 역할: 웹 검색, 필요시 유망한 페이지 읽기, 반성, 그다음 정확한 소스 URL에 대한 인라인 인용과 함께 압축된 요약 쓰기.
  • 반환: 최종 텍스트 메시지가 요약입니다(평문을 쓴 즉시 종료).
  • 제한: max_researcher_steps.

하위 연구자의 도구:

Tool What it is What it does
web_search 기본적으로 Tavily 통합의 TavilyWebSearchTool, 또는 전달한 search_tool 웹 검색을 실행하고 제목, 정확한 URL, 스니펫으로 탑 결과 반환
read_url fetch, route, convert-to-text, summarize 파이프라인 위의 PipelineTool 페이지 fetch(LinkContentFetcher), MIME 타입별 route(FileTypeRouter)를 거쳐 HTMLToDocument(Trafilatura)나 PyPDFToDocument(PDF도 파싱)로 전환하고, 에이전트가 전달하는 질문 방향으로 페이지를 요약해 관련 텍스트만 에이전트 컨텍스트에 들어가게 함(전체 페이지 X). 검색 스니펫이 너무 얕을 때만 사용
think_tool no-op 반성 도구 검색 사이에 "무엇을 배웠나? 무엇이 빠졌나? 멈출까 계속할까?"

Context management

딥 리서치 에이전트의 핵심 과제는 각 컨텍스트 윈도우를 작고 집중되게 유지하는 것입니다. 원시 웹 콘텐츠(검색 결과, 전체 페이지, PDF)는 크고 시끄러워요. 그것이 단일 컨텍스트에 모두 쌓이면 모델 출력 품질이 저하됩니다. 격리와 압축으로 이를 피합니다:

  • 각 하위 연구자는 자체 State를 가진 자체 에이전트로 실행되므로, 모든 지저분한 중간 콘텐츠(모든 검색 결과, 모든 가져온 페이지)는 그 비공개 컨텍스트에 남습니다.
  • 그것은 짧은 요약 하나(최종 메시지)를 쓰며 끝납니다. 오직 그 요약만 하위 연구자를 떠납니다. 원시 콘텐츠는 오케스트레이터나 writer에 도달하지 않습니다.

AgentTool 기본 출력 처리와 research_subtopic의 한 설정이 그 요약이 가는 곳을 결정합니다:

Behavior or setting Controls Effect
AgentTool 기본 출력 처리 오케스트레이터의 LLM이 무엇을 도구 결과로 보는지 하위 연구자의 최종 응답 텍스트가 기본적으로 돌아옵니다(전체 메시지 히스토리 X). 오케스트레이터 컨텍스트를 깨끗하게 유지.
outputs_to_state={"notes": {...}} writer를 위해 무엇이 저장되는지 같은 요약이 (텍스트로) 공유 notes 리스트에 추가되어 writer의 입력이 됩니다.

따라서 각 요약은 두 갈래로 이동합니다. 오케스트레이터의 추론으로(더 파고들지 결정) 그리고 notes 축적기로(writer가 사용), 부피 큰 원시 연구는 격리된 채 하위 연구자를 넘어 전파되지 않습니다:

sub-researcher  (private context: searches, pages, reflections)
      │  writes one short summary
      ├─ AgentTool default output → orchestrator's LLM   (decide: done, or dig more?)
      └─ outputs_to_state  → notes → writer        (final report)

더 알아보기 (Learn more)