⏱️ 예상 읽기 시간: 20분

서론: Open Deep Research가 바꾸는 AI 연구의 미래

AI 연구 분야에서 가장 혁신적인 애플리케이션 중 하나인 딥 리서치(Deep Research)가 새로운 전환점을 맞고 있습니다. LangChain AI의 Open Deep Research는 이러한 변화를 주도하는 완전 오픈소스 연구 자동화 에이전트로, 복잡한 연구 과정을 AI가 자동으로 수행할 수 있게 해줍니다.

Open Deep Research의 혁신성

완전한 오픈소스 생태계:

  • 🔓 MIT 라이선스: 상업적 사용 포함 완전 자유
  • 🌟 커뮤니티 검증: GitHub 6.8k stars, 913 forks의 신뢰성
  • 🔧 무제한 커스터마이징: 소스코드 레벨에서 자유로운 수정
  • 📚 투명한 개발: 모든 구현 로직 공개

차세대 에이전트 아키텍처:

  • 🏗️ LangGraph 기반: 최신 AI 워크플로우 엔진 활용
  • 🤖 다중 에이전트: 협업하는 AI 연구원들의 시스템
  • 🔄 반성적 사고: 연구 결과를 스스로 검증하고 개선
  • 병렬 처리: 동시 다발적 연구 수행으로 속도 극대화

범용적 호환성:

  • 🎯 다중 모델 지원: OpenAI, Anthropic, Google Vertex AI 등
  • 🔍 다양한 검색 API: Tavily, OpenAI Native, Anthropic Native
  • 🔌 MCP 서버 연동: Model Context Protocol로 무한 확장
  • 📊 포괄적 평가: 다차원 성능 분석 시스템

이 가이드에서 배울 내용

  1. Open Deep Research 핵심 아키텍처 이해
  2. 로컬 환경 설정 및 빠른 시작
  3. LangGraph Studio 활용 방법
  4. 다중 모델 설정 및 최적화
  5. MCP 서버 연동 및 확장
  6. 연구 워크플로우 커스터마이징
  7. 평가 시스템 구축 및 활용
  8. 프로덕션 배포 전략
  9. 실전 연구 프로젝트 구현

Open Deep Research 핵심 아키텍처

전체 시스템 구조

Multi-Agent Research Architecture:

┌─────────────────────────────────────────────────────────────┐
│                   Research Supervisor                       │
│              (연구 총괄 관리 에이전트)                        │
└─────────────────┬───────────────────────────────────────────┘
                  │
        ┌─────────┼─────────┐
        │         │         │
┌───────▼─────┐ ┌─▼─────┐ ┌─▼──────────┐
│ Researcher  │ │ Search │ │Compression │
│   Agent 1   │ │ Agent  │ │   Agent    │
└─────────────┘ └────────┘ └────────────┘
        │                         │
        │    ┌─────────────┐      │
        └────► Research    ◄──────┘
             │ Results     │
             │ Database    │
             └─────────────┘

주요 구성 요소 분석

1. Research Supervisor (연구 감독자)

  • 역할: 전체 연구 프로세스 조율 및 관리
  • 기능: 연구 계획 수립, 하위 에이전트 관리, 품질 검증
  • 모델: GPT-4o 등 고성능 모델 권장

2. Sub-Research Agents (연구 에이전트들)

  • 역할: 특정 주제에 대한 심화 연구 수행
  • 기능: 정보 수집, 분석, 중간 보고서 작성
  • 특징: 병렬 실행으로 연구 속도 향상

3. Search Integration Layer

  • Tavily API: 모든 모델과 호환되는 범용 검색
  • Native Search: OpenAI/Anthropic 전용 고급 검색
  • Custom Search: 사용자 정의 검색 엔진 연동

4. MCP (Model Context Protocol) System

  • 로컬 MCP: 파일시스템, 데이터베이스 접근
  • 원격 MCP: 클라우드 서비스, API 연동
  • 확장성: 무제한 도구 및 서비스 연결

빠른 시작 가이드 (Quickstart)

환경 준비 및 설치

1단계: 시스템 요구사항 확인

# Python 3.11+ 필수
python --version

# uv 패키지 매니저 설치 (권장)
curl -LsSf https://astral.sh/uv/install.sh | sh

# 또는 pip 설치
pip install uv

2단계: 프로젝트 클론 및 환경 설정

# GitHub에서 프로젝트 클론
git clone https://github.com/langchain-ai/open_deep_research.git
cd open_deep_research

# 가상환경 생성 및 활성화
uv venv
source .venv/bin/activate  # macOS/Linux
# .venv\Scripts\activate  # Windows

# 의존성 설치
uv pip install -r pyproject.toml

3단계: 환경 변수 설정

# 환경 변수 파일 생성
cp .env.example .env

# .env 파일 편집
nano .env

필수 환경 변수 설정:

# OpenAI API 설정
OPENAI_API_KEY=sk-your-openai-api-key

# Tavily Search API (무료 계정으로 시작 가능)
TAVILY_API_KEY=tvly-your-tavily-api-key

# LangSmith 추적 (선택적)
LANGCHAIN_TRACING_V2=true
LANGCHAIN_API_KEY=ls__your-langsmith-api-key
LANGCHAIN_PROJECT=open-deep-research

# Anthropic API (선택적)
ANTHROPIC_API_KEY=sk-ant-your-anthropic-key

# Google Vertex AI (선택적)
GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json

LangGraph Studio 실행

4단계: 개발 서버 시작

# LangGraph 개발 서버 실행
uvx --refresh --from "langgraph-cli[inmem]" --with-editable . --python 3.11 langgraph dev --allow-blocking

성공적 실행 확인:

🚀 API: http://127.0.0.1:2024
🎨 Studio UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024
📚 API Docs: http://127.0.0.1:2024/docs

5단계: LangGraph Studio 사용

  1. Studio UI 접속: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024
  2. Graph 선택: open_deep_research 그래프 선택
  3. 첫 연구 실행:
    • messages 입력 필드에 연구 질문 입력
    • 예시: “Explain the latest developments in quantum computing”
    • Submit 버튼 클릭

첫 연구 프로젝트 실행

간단한 연구 질문 예제:

# examples/simple_research.py
from src.research_assistant import research_assistant

async def run_simple_research():
    # 연구 질문 정의
    question = "What are the latest breakthroughs in AI safety research in 2024?"
    
    # 연구 실행
    result = await research_assistant.ainvoke({
        "messages": [{"role": "user", "content": question}]
    })
    
    # 결과 출력
    print("연구 결과:")
    print(result["messages"][-1]["content"])

# 실행
import asyncio
asyncio.run(run_simple_research())

실행 결과 예제:

연구 결과:
# AI Safety Research: 2024년 주요 돌파구

## 1. Constitutional AI 발전
- Anthropic의 Claude 3.5 Sonnet에서 개선된 헌법적 AI 구현
- 더 나은 가치 정렬과 해악 방지 메커니즘

## 2. Scalable Oversight
- OpenAI의 슈퍼정렬 팀 연구 결과
- 인간보다 뛰어난 AI 시스템의 감독 방법론

## 3. Interpretability Tools
- Anthropic의 Dictionary Learning for SAEs
- 신경망 내부 표현의 해석 가능성 향상

[상세한 연구 결과 계속...]

고급 설정 및 구성 옵션

연구 동작 설정

핵심 설정 파라미터:

# src/config/research_config.py
from dataclasses import dataclass
from typing import Optional

@dataclass
class ResearchConfig:
    # 일반 설정
    max_structured_output_retries: int = 3
    allow_clarification: bool = True
    max_concurrent_research_units: int = 5
    
    # 연구 프로세스 설정  
    search_api: str = "tavily"  # tavily, openai_native, anthropic_native
    max_researcher_iterations: int = 3
    max_react_tool_calls: int = 5
    
    # 모델 설정
    summarization_model: str = "openai:gpt-4o-mini"
    research_model: str = "openai:gpt-4o"
    compression_model: str = "openai:gpt-4o-mini"
    final_report_model: str = "openai:gpt-4o"

모델 선택 및 최적화

모델별 특성 및 권장 사용:

# src/models/model_selector.py
from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic
from langchain_google_vertexai import ChatVertexAI

class ModelSelector:
    def __init__(self):
        self.model_configs = {
            # OpenAI 모델들
            "openai:gpt-4o": {
                "class": ChatOpenAI,
                "model": "gpt-4o",
                "temperature": 0.1,
                "max_tokens": 4000,
                "supports_structured_output": True,
                "cost_per_1k_tokens": 0.03,
                "best_for": ["research", "final_report"]
            },
            "openai:gpt-4o-mini": {
                "class": ChatOpenAI,
                "model": "gpt-4o-mini", 
                "temperature": 0.1,
                "max_tokens": 2000,
                "supports_structured_output": True,
                "cost_per_1k_tokens": 0.005,
                "best_for": ["summarization", "compression"]
            },
            
            # Anthropic 모델들
            "anthropic:claude-3-5-sonnet": {
                "class": ChatAnthropic,
                "model": "claude-3-5-sonnet-20241022",
                "temperature": 0.1,
                "max_tokens": 4000,
                "supports_structured_output": True,
                "cost_per_1k_tokens": 0.03,
                "best_for": ["research", "analysis"]
            },
            
            # Google 모델들
            "vertex:gemini-pro": {
                "class": ChatVertexAI,
                "model": "gemini-pro",
                "temperature": 0.1,
                "max_output_tokens": 2048,
                "supports_structured_output": True,
                "cost_per_1k_tokens": 0.0025,
                "best_for": ["summarization", "compression"]
            }
        }
    
    def get_optimized_model(self, task_type: str, budget_level: str = "standard"):
        """태스크 유형과 예산에 따른 최적 모델 선택"""
        if budget_level == "premium":
            if task_type in ["research", "final_report"]:
                return "anthropic:claude-3-5-sonnet"
            else:
                return "openai:gpt-4o-mini"
                
        elif budget_level == "budget":
            return "openai:gpt-4o-mini"
            
        else:  # standard
            if task_type in ["research", "final_report"]:
                return "openai:gpt-4o"
            else:
                return "openai:gpt-4o-mini"

검색 API 설정 및 비교

다양한 검색 옵션 설정:

# src/search/search_manager.py
from typing import Dict, Any
import os

class SearchManager:
    def __init__(self):
        self.search_configs = {
            "tavily": {
                "api_key": os.getenv("TAVILY_API_KEY"),
                "max_results": 10,
                "search_depth": "advanced",
                "include_images": False,
                "include_answer": True,
                "compatibility": "all_models",
                "cost": "low"
            },
            
            "openai_native": {
                "requires_model": "openai",
                "web_search_enabled": True,
                "real_time_data": True,
                "accuracy": "high",
                "cost": "medium"
            },
            
            "anthropic_native": {
                "requires_model": "anthropic",
                "web_search_enabled": True,
                "real_time_data": True,
                "accuracy": "high",  
                "cost": "medium"
            }
        }
    
    def configure_search(self, search_type: str, custom_config: Dict[str, Any] = None):
        """검색 엔진 설정"""
        base_config = self.search_configs.get(search_type, {})
        if custom_config:
            base_config.update(custom_config)
        return base_config

# 사용 예제
search_manager = SearchManager()

# Tavily 설정 (가장 범용적)
tavily_config = search_manager.configure_search("tavily", {
    "max_results": 15,
    "search_depth": "advanced",
    "include_domain_filter": ["arxiv.org", "nature.com", "science.org"]
})

MCP (Model Context Protocol) 서버 연동

로컬 MCP 서버 설정

파일시스템 MCP 서버 구성:

# src/mcp/filesystem_mcp.py
import json
import subprocess
from pathlib import Path

class FilesystemMCP:
    def __init__(self, allowed_dirs: list):
        self.allowed_dirs = [Path(d).resolve() for d in allowed_dirs]
        self.server_process = None
    
    def start_server(self):
        """파일시스템 MCP 서버 시작"""
        cmd = [
            "mcp-server-filesystem",
            *[str(d) for d in self.allowed_dirs]
        ]
        
        self.server_process = subprocess.Popen(
            cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )
        
        return self.server_process
    
    def configure_security(self):
        """보안 설정 구성"""
        return {
            "allowed_operations": [
                "read_file",
                "write_file", 
                "list_directory",
                "create_directory",
                "search_files"
            ],
            "restricted_patterns": [
                "*.exe",
                "*.sh",
                "/etc/*",
                "/sys/*"
            ],
            "max_file_size": "10MB",
            "max_depth": 10
        }

# 사용 예제
filesystem_mcp = FilesystemMCP([
    "/Users/researcher/documents",
    "/Users/researcher/projects", 
    "/tmp/research_workspace"
])

security_config = filesystem_mcp.configure_security()
server = filesystem_mcp.start_server()

SQLite 데이터베이스 MCP 연동:

# src/mcp/database_mcp.py
import sqlite3
import json
from typing import Dict, Any

class DatabaseMCP:
    def __init__(self, db_path: str):
        self.db_path = db_path
        self.connection = None
    
    def setup_research_db(self):
        """연구 데이터베이스 스키마 설정"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        # 연구 프로젝트 테이블
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS research_projects (
                id INTEGER PRIMARY KEY,
                title TEXT NOT NULL,
                description TEXT,
                status TEXT DEFAULT 'active',
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        """)
        
        # 연구 결과 테이블
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS research_results (
                id INTEGER PRIMARY KEY,
                project_id INTEGER,
                query TEXT NOT NULL,
                result_text TEXT,
                sources JSON,
                confidence_score REAL,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                FOREIGN KEY (project_id) REFERENCES research_projects (id)
            )
        """)
        
        # 인덱스 생성
        cursor.execute("CREATE INDEX IF NOT EXISTS idx_results_project ON research_results(project_id)")
        cursor.execute("CREATE INDEX IF NOT EXISTS idx_results_created ON research_results(created_at)")
        
        conn.commit()
        conn.close()
    
    def save_research_result(self, project_id: int, query: str, result: Dict[str, Any]):
        """연구 결과 저장"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        cursor.execute("""
            INSERT INTO research_results 
            (project_id, query, result_text, sources, confidence_score)
            VALUES (?, ?, ?, ?, ?)
        """, (
            project_id,
            query,
            result.get('text', ''),
            json.dumps(result.get('sources', [])),
            result.get('confidence', 0.0)
        ))
        
        conn.commit()
        conn.close()

# 사용 예제
db_mcp = DatabaseMCP("/path/to/research.db")
db_mcp.setup_research_db()

원격 MCP 서버 연동

Arcade MCP 서버 설정 (여행 관련 연구):

# src/mcp/remote_mcp.py
import httpx
import json
from typing import Dict, Any

class RemoteMCP:
    def __init__(self, server_config: Dict[str, Any]):
        self.url = server_config["url"]
        self.tools = server_config.get("tools", [])
        self.auth_token = server_config.get("auth_token")
        self.client = httpx.AsyncClient()
    
    async def setup_arcade_travel_research(self):
        """Arcade 여행 연구 MCP 설정"""
        config = {
            "url": "https://api.arcade.dev/v1/mcps/ms_0ujssxh0cECutqzMgbtXSGnjorm",
            "tools": [
                "Search_SearchHotels",
                "Search_SearchOneWayFlights", 
                "Search_SearchRoundtripFlights"
            ],
            "auth_required": True
        }
        
        return config
    
    async def call_mcp_tool(self, tool_name: str, parameters: Dict[str, Any]):
        """원격 MCP 도구 호출"""
        headers = {"Content-Type": "application/json"}
        if self.auth_token:
            headers["Authorization"] = f"Bearer {self.auth_token}"
        
        payload = {
            "tool": tool_name,
            "parameters": parameters
        }
        
        response = await self.client.post(
            f"{self.url}/call_tool",
            json=payload,
            headers=headers
        )
        
        return response.json()

# 실제 사용 예제
async def research_travel_options():
    """여행 옵션 연구 예제"""
    arcade_config = {
        "url": "https://api.arcade.dev/v1/mcps/ms_0ujssxh0cECutqzMgbtXSGnjorm",
        "tools": ["Search_SearchHotels", "Search_SearchRoundtripFlights"]
    }
    
    remote_mcp = RemoteMCP(arcade_config)
    
    # 호텔 검색
    hotel_results = await remote_mcp.call_mcp_tool("Search_SearchHotels", {
        "destination": "Tokyo",
        "check_in": "2024-03-15",
        "check_out": "2024-03-20", 
        "guests": 2
    })
    
    # 항공편 검색
    flight_results = await remote_mcp.call_mcp_tool("Search_SearchRoundtripFlights", {
        "origin": "JFK",
        "destination": "NRT",
        "departure_date": "2024-03-15",
        "return_date": "2024-03-20",
        "passengers": 2
    })
    
    return {
        "hotels": hotel_results,
        "flights": flight_results
    }

평가 시스템 구축 및 활용

다차원 평가 프레임워크

평가 지표 설계:

# tests/evaluators.py
from typing import Dict, Any, List
from dataclasses import dataclass

@dataclass
class EvaluationResult:
    accuracy: float  # 0-1 scale
    completeness: float  # 0-1 scale  
    relevance: float  # 0-1 scale
    clarity: float  # 0-1 scale
    source_quality: float  # 0-1 scale
    overall_score: float  # weighted average
    feedback: str

class ResearchEvaluator:
    def __init__(self):
        self.weights = {
            "accuracy": 0.3,
            "completeness": 0.25,
            "relevance": 0.2,
            "clarity": 0.15,
            "source_quality": 0.1
        }
    
    def evaluate_research_output(self, 
                                research_result: str, 
                                reference_answer: str,
                                sources: List[Dict[str, Any]]) -> EvaluationResult:
        """연구 결과 종합 평가"""
        
        # 정확성 평가
        accuracy = self._evaluate_accuracy(research_result, reference_answer)
        
        # 완성도 평가
        completeness = self._evaluate_completeness(research_result, reference_answer)
        
        # 관련성 평가
        relevance = self._evaluate_relevance(research_result, reference_answer)
        
        # 명확성 평가
        clarity = self._evaluate_clarity(research_result)
        
        # 소스 품질 평가
        source_quality = self._evaluate_source_quality(sources)
        
        # 전체 점수 계산
        overall_score = (
            accuracy * self.weights["accuracy"] +
            completeness * self.weights["completeness"] +
            relevance * self.weights["relevance"] + 
            clarity * self.weights["clarity"] +
            source_quality * self.weights["source_quality"]
        )
        
        # 피드백 생성
        feedback = self._generate_feedback(accuracy, completeness, relevance, clarity, source_quality)
        
        return EvaluationResult(
            accuracy=accuracy,
            completeness=completeness,
            relevance=relevance,
            clarity=clarity,
            source_quality=source_quality,
            overall_score=overall_score,
            feedback=feedback
        )
    
    def _evaluate_accuracy(self, result: str, reference: str) -> float:
        """정확성 평가 - 사실 확인"""
        # LLM 기반 팩트 체킹
        prompt = f"""
        Research Result: {result}
        Reference Answer: {reference}
        
        Rate the factual accuracy of the research result compared to the reference on a scale of 0.0 to 1.0.
        Consider:
        - Factual correctness
        - No misinformation
        - Proper context
        
        Return only the numerical score.
        """
        # 실제 구현에서는 LLM 호출
        return 0.85  # 예시 점수
    
    def _evaluate_completeness(self, result: str, reference: str) -> float:
        """완성도 평가 - 필요한 정보 포함 여부"""
        prompt = f"""
        Research Result: {result}
        Reference Answer: {reference}
        
        Rate how completely the research result covers the topic compared to the reference on a scale of 0.0 to 1.0.
        Consider:
        - Coverage of key points
        - Depth of information
        - Missing important aspects
        
        Return only the numerical score.
        """
        return 0.78  # 예시 점수

배치 평가 시스템

대규모 테스트 데이터셋 평가:

# tests/run_evaluate.py
import asyncio
import json
from typing import List, Dict
from pathlib import Path

class BatchEvaluator:
    def __init__(self, evaluator: ResearchEvaluator):
        self.evaluator = evaluator
        self.results = []
    
    async def run_batch_evaluation(self, test_dataset: List[Dict[str, Any]]):
        """배치 평가 실행"""
        
        print(f"Starting batch evaluation with {len(test_dataset)} test cases...")
        
        for i, test_case in enumerate(test_dataset):
            print(f"Processing test case {i+1}/{len(test_dataset)}: {test_case['question'][:50]}...")
            
            # 연구 실행
            research_result = await self._run_research(test_case["question"])
            
            # 평가 수행
            evaluation = self.evaluator.evaluate_research_output(
                research_result["content"],
                test_case["reference_answer"],
                research_result["sources"]
            )
            
            # 결과 저장
            result = {
                "test_case_id": test_case["id"],
                "question": test_case["question"],
                "research_result": research_result["content"],
                "evaluation": evaluation.__dict__,
                "execution_time": research_result["execution_time"]
            }
            
            self.results.append(result)
            
            print(f"  Overall Score: {evaluation.overall_score:.3f}")
        
        return self.results
    
    def generate_evaluation_report(self) -> Dict[str, Any]:
        """평가 리포트 생성"""
        if not self.results:
            return {"error": "No evaluation results available"}
        
        # 통계 계산
        scores = [r["evaluation"]["overall_score"] for r in self.results]
        
        report = {
            "summary": {
                "total_cases": len(self.results),
                "average_score": sum(scores) / len(scores),
                "max_score": max(scores),
                "min_score": min(scores),
                "median_score": sorted(scores)[len(scores)//2]
            },
            "dimension_breakdown": {
                "accuracy": sum(r["evaluation"]["accuracy"] for r in self.results) / len(self.results),
                "completeness": sum(r["evaluation"]["completeness"] for r in self.results) / len(self.results),
                "relevance": sum(r["evaluation"]["relevance"] for r in self.results) / len(self.results),
                "clarity": sum(r["evaluation"]["clarity"] for r in self.results) / len(self.results),
                "source_quality": sum(r["evaluation"]["source_quality"] for r in self.results) / len(self.results)
            },
            "performance_analysis": {
                "avg_execution_time": sum(r["execution_time"] for r in self.results) / len(self.results),
                "cases_above_threshold": len([s for s in scores if s >= 0.8]),
                "improvement_areas": self._identify_improvement_areas()
            },
            "detailed_results": self.results
        }
        
        return report
    
    def _identify_improvement_areas(self) -> List[str]:
        """개선 영역 식별"""
        dimension_scores = {
            "accuracy": sum(r["evaluation"]["accuracy"] for r in self.results) / len(self.results),
            "completeness": sum(r["evaluation"]["completeness"] for r in self.results) / len(self.results),
            "relevance": sum(r["evaluation"]["relevance"] for r in self.results) / len(self.results),
            "clarity": sum(r["evaluation"]["clarity"] for r in self.results) / len(self.results),
            "source_quality": sum(r["evaluation"]["source_quality"] for r in self.results) / len(self.results)
        }
        
        # 평균 이하 성능 영역 식별
        avg_score = sum(dimension_scores.values()) / len(dimension_scores)
        improvement_areas = [
            dimension for dimension, score in dimension_scores.items() 
            if score < avg_score - 0.05
        ]
        
        return improvement_areas

# 사용 예제
async def run_comprehensive_evaluation():
    """종합 평가 실행"""
    
    # 테스트 데이터셋 로드
    test_dataset = [
        {
            "id": "ai_safety_001",
            "question": "What are the latest developments in AI safety research?",
            "reference_answer": "Recent developments include constitutional AI, scalable oversight, and interpretability tools..."
        },
        {
            "id": "quantum_001", 
            "question": "Explain quantum error correction breakthroughs in 2024",
            "reference_answer": "Major breakthroughs include surface code improvements, logical qubit demonstrations..."
        }
        # ... 더 많은 테스트 케이스
    ]
    
    # 평가 실행
    evaluator = ResearchEvaluator()
    batch_evaluator = BatchEvaluator(evaluator)
    
    results = await batch_evaluator.run_batch_evaluation(test_dataset)
    report = batch_evaluator.generate_evaluation_report()
    
    # 결과 저장
    with open("evaluation_report.json", "w") as f:
        json.dump(report, f, indent=2)
    
    print(f"Evaluation completed. Average score: {report['summary']['average_score']:.3f}")
    return report

# 실행
# asyncio.run(run_comprehensive_evaluation())

프로덕션 배포 및 확장 전략

Docker 컨테이너화

최적화된 Dockerfile:

# Dockerfile
FROM python:3.11-slim

# 시스템 의존성 설치
RUN apt-get update && apt-get install -y \
    git \
    curl \
    && rm -rf /var/lib/apt/lists/*

# uv 설치
RUN pip install uv

# 작업 디렉토리 설정
WORKDIR /app

# 의존성 파일 복사
COPY pyproject.toml uv.lock ./

# 의존성 설치
RUN uv pip install --system -r pyproject.toml

# 애플리케이션 코드 복사
COPY . .

# 환경 변수 설정
ENV PYTHONPATH=/app
ENV LANGCHAIN_TRACING_V2=true

# 포트 노출
EXPOSE 8000

# 헬스체크 추가
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:8000/health || exit 1

# 애플리케이션 실행
CMD ["uvx", "--from", "langgraph-cli[inmem]", "--with-editable", ".", "langgraph", "start", "--host", "0.0.0.0", "--port", "8000"]

Docker Compose 설정:

# docker-compose.yml
version: '3.8'

services:
  open-deep-research:
    build: .
    ports:
      - "8000:8000"
    environment:
      - OPENAI_API_KEY=${OPENAI_API_KEY}
      - TAVILY_API_KEY=${TAVILY_API_KEY}
      - LANGCHAIN_API_KEY=${LANGCHAIN_API_KEY}
      - LANGCHAIN_PROJECT=open-deep-research-prod
      - REDIS_URL=redis://redis:6379
    depends_on:
      - redis
      - postgres
    volumes:
      - ./data:/app/data
      - ./logs:/app/logs
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    command: redis-server --appendonly yes
    restart: unless-stopped

  postgres:
    image: postgres:15
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_DB=research_db
      - POSTGRES_USER=researcher
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./ssl:/etc/nginx/ssl
    depends_on:
      - open-deep-research
    restart: unless-stopped

volumes:
  redis_data:
  postgres_data:

Kubernetes 배포

Kubernetes 매니페스트:

# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: open-deep-research
  labels:
    app: open-deep-research
spec:
  replicas: 3
  selector:
    matchLabels:
      app: open-deep-research
  template:
    metadata:
      labels:
        app: open-deep-research
    spec:
      containers:
      - name: open-deep-research
        image: your-registry/open-deep-research:latest
        ports:
        - containerPort: 8000
        env:
        - name: OPENAI_API_KEY
          valueFrom:
            secretKeyRef:
              name: api-secrets
              key: openai-api-key
        - name: TAVILY_API_KEY
          valueFrom:
            secretKeyRef:
              name: api-secrets
              key: tavily-api-key
        resources:
          requests:
            memory: "512Mi"
            cpu: "250m"
          limits:
            memory: "2Gi"
            cpu: "1000m"
        livenessProbe:
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 8000
          initialDelaySeconds: 5
          periodSeconds: 5

---
apiVersion: v1
kind: Service
metadata:
  name: open-deep-research-service
spec:
  selector:
    app: open-deep-research
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8000
  type: ClusterIP

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: open-deep-research-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
  - hosts:
    - research-api.yourdomain.com
    secretName: research-api-tls
  rules:
  - host: research-api.yourdomain.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: open-deep-research-service
            port:
              number: 80

실전 연구 프로젝트 구현

복합 연구 워크플로우

다단계 연구 프로세스 설계:

# src/workflows/complex_research.py
from typing import List, Dict, Any
from dataclasses import dataclass
import asyncio

@dataclass
class ResearchPhase:
    name: str
    description: str
    agents_required: int
    max_duration: int  # seconds
    dependencies: List[str]

class ComplexResearchWorkflow:
    def __init__(self):
        self.phases = {
            "literature_review": ResearchPhase(
                name="Literature Review",
                description="Comprehensive review of existing literature",
                agents_required=2,
                max_duration=300,
                dependencies=[]
            ),
            "data_collection": ResearchPhase(
                name="Data Collection", 
                description="Gather relevant data and statistics",
                agents_required=3,
                max_duration=600,
                dependencies=["literature_review"]
            ),
            "analysis": ResearchPhase(
                name="Analysis",
                description="Deep analysis of collected information",
                agents_required=2,
                max_duration=400,
                dependencies=["literature_review", "data_collection"]
            ),
            "synthesis": ResearchPhase(
                name="Synthesis",
                description="Synthesize findings into coherent insights",
                agents_required=1,
                max_duration=300,
                dependencies=["analysis"]
            ),
            "validation": ResearchPhase(
                name="Validation",
                description="Validate findings and check for consistency",
                agents_required=1,
                max_duration=200,
                dependencies=["synthesis"]
            )
        }
    
    async def execute_research_pipeline(self, research_question: str) -> Dict[str, Any]:
        """복합 연구 파이프라인 실행"""
        
        results = {}
        execution_order = self._determine_execution_order()
        
        print(f"Starting complex research pipeline for: {research_question}")
        
        for phase_name in execution_order:
            phase = self.phases[phase_name]
            print(f"\n🔬 Executing Phase: {phase.name}")
            print(f"   Description: {phase.description}")
            print(f"   Agents: {phase.agents_required}, Max Duration: {phase.max_duration}s")
            
            # 의존성 확인
            dependencies_met = all(dep in results for dep in phase.dependencies)
            if not dependencies_met:
                missing = [dep for dep in phase.dependencies if dep not in results]
                raise Exception(f"Dependencies not met for {phase_name}: {missing}")
            
            # 단계별 연구 실행
            phase_result = await self._execute_phase(
                phase_name, 
                research_question, 
                results,
                phase
            )
            
            results[phase_name] = phase_result
            print(f"   ✅ Phase completed: {len(phase_result.get('findings', []))} findings")
        
        # 최종 리포트 생성
        final_report = await self._generate_final_report(research_question, results)
        
        return {
            "research_question": research_question,
            "phase_results": results,
            "final_report": final_report,
            "execution_summary": self._create_execution_summary(results)
        }
    
    async def _execute_phase(self, 
                           phase_name: str,
                           research_question: str, 
                           previous_results: Dict[str, Any],
                           phase: ResearchPhase) -> Dict[str, Any]:
        """개별 연구 단계 실행"""
        
        # 단계별 맞춤형 프롬프트 생성
        phase_prompt = self._generate_phase_prompt(
            phase_name, 
            research_question, 
            previous_results
        )
        
        # 다중 에이전트 병렬 실행
        agent_tasks = []
        for i in range(phase.agents_required):
            task = self._run_phase_agent(
                f"agent_{i}",
                phase_prompt,
                research_question,
                previous_results
            )
            agent_tasks.append(task)
        
        # 결과 수집 및 통합
        agent_results = await asyncio.gather(*agent_tasks)
        
        # 결과 통합 및 정제
        integrated_result = await self._integrate_agent_results(
            phase_name,
            agent_results
        )
        
        return integrated_result
    
    def _generate_phase_prompt(self, 
                             phase_name: str,
                             research_question: str,
                             previous_results: Dict[str, Any]) -> str:
        """단계별 맞춤형 프롬프트 생성"""
        
        phase_prompts = {
            "literature_review": f"""
            Conduct a comprehensive literature review for the research question: "{research_question}"
            
            Focus on:
            1. Recent academic papers and publications
            2. Established theories and frameworks
            3. Key researchers and institutions
            4. Research gaps and controversies
            
            Provide citations and assess credibility of sources.
            """,
            
            "data_collection": f"""
            Collect relevant data and statistics for: "{research_question}"
            
            Previous literature review findings: {previous_results.get('literature_review', {}).get('summary', 'None')}
            
            Focus on:
            1. Quantitative data and statistics
            2. Recent surveys and reports
            3. Government and institutional data
            4. Industry reports and market research
            
            Ensure data is current and from reliable sources.
            """,
            
            "analysis": f"""
            Conduct deep analysis based on collected information for: "{research_question}"
            
            Previous findings:
            - Literature: {previous_results.get('literature_review', {}).get('summary', 'None')}
            - Data: {previous_results.get('data_collection', {}).get('summary', 'None')}
            
            Focus on:
            1. Pattern identification and trends
            2. Cause-effect relationships
            3. Comparative analysis
            4. Critical evaluation of findings
            """,
            
            "synthesis": f"""
            Synthesize all research findings into coherent insights for: "{research_question}"
            
            Integration of:
            - Literature insights: {previous_results.get('literature_review', {}).get('key_findings', [])}
            - Data insights: {previous_results.get('data_collection', {}).get('key_findings', [])}
            - Analysis results: {previous_results.get('analysis', {}).get('key_findings', [])}
            
            Create unified conclusions and actionable insights.
            """,
            
            "validation": f"""
            Validate and verify the research findings for: "{research_question}"
            
            Synthesized insights: {previous_results.get('synthesis', {}).get('summary', 'None')}
            
            Focus on:
            1. Fact-checking key claims
            2. Consistency verification
            3. Bias detection
            4. Reliability assessment
            """
        }
        
        return phase_prompts.get(phase_name, f"Research the topic: {research_question}")

# 실제 사용 예제
async def run_complex_ai_safety_research():
    """AI 안전성에 대한 복합 연구 실행"""
    
    workflow = ComplexResearchWorkflow()
    
    research_question = """
    What are the most critical challenges in AI safety for large language models, 
    and what are the most promising approaches to address them in 2024?
    """
    
    result = await workflow.execute_research_pipeline(research_question)
    
    print("\n" + "="*80)
    print("🎯 FINAL RESEARCH REPORT")
    print("="*80)
    print(result["final_report"])
    
    print("\n" + "="*80)
    print("📊 EXECUTION SUMMARY")
    print("="*80)
    for phase, summary in result["execution_summary"].items():
        print(f"{phase}: {summary}")
    
    return result

# 실행 
# asyncio.run(run_complex_ai_safety_research())

결론: Open Deep Research의 무한한 가능성

Open Deep Research가 제공하는 혁신

연구 패러다임의 전환:

  • 🤖 AI 협업 연구: 인간과 AI가 함께하는 새로운 연구 방식
  • 속도의 혁명: 몇 주 걸리던 연구를 몇 시간으로 단축
  • 🎯 정확성 향상: 다중 검증과 반성적 사고로 더 높은 신뢰성
  • 🌐 접근성 확대: 고급 연구 도구의 민주화

실무 적용 가능성:

  • 📊 시장 조사: 경쟁사 분석, 트렌드 예측, 소비자 행동 연구
  • 🔬 학술 연구: 문헌 리뷰, 데이터 분석, 가설 검증
  • 💼 비즈니스 전략: 산업 분석, 리스크 평가, 기회 탐색
  • 🏛️ 정책 연구: 사회 문제 분석, 정책 효과 예측

다음 단계 및 발전 방향

즉시 활용 가능한 프로젝트:

  1. 개인 연구 어시스턴트: 일상적인 질문과 조사 자동화
  2. 업무 리서치 도구: 회사 내 시장 조사 및 경쟁 분석
  3. 학습 도우미: 새로운 기술이나 도메인 학습 지원
  4. 콘텐츠 제작: 블로그, 리포트, 프레젠테이션 자료 생성

고급 확장 방향:

  1. 도메인 특화: 의료, 법률, 금융 등 전문 분야 맞춤화
  2. 실시간 모니터링: 지속적인 정보 추적과 알림 시스템
  3. 협업 플랫폼: 팀 단위 연구 프로젝트 관리
  4. 지식 베이스: 조직 내 축적된 연구 자산 활용

커뮤니티와 기여

오픈소스 생태계 참여:

  • 🛠️ GitHub 기여: 프로젝트 개선 및 버그 리포트
  • 💡 아이디어 제안: 새로운 기능 및 사용 사례 공유
  • 📖 문서화: 사용 가이드 및 튜토리얼 작성
  • 🎓 교육 콘텐츠: 워크샵, 강의, 블로그 포스트 제작

지속적인 학습과 발전:

  • 📚 새로운 모델과 API 출시 동향 파악
  • 🔄 워크플로우 최적화 및 성능 튜닝
  • 📊 평가 지표 개선 및 벤치마크 구축
  • 🌟 실제 사용 사례 공유 및 베스트 프랙티스 개발

Open Deep Research는 단순한 도구를 넘어서 연구와 지식 탐구의 새로운 가능성을 열어주는 플랫폼입니다. 이 가이드를 통해 구축한 시스템을 바탕으로 더욱 혁신적이고 효과적인 연구 프로젝트를 진행하시기 바랍니다.

🚀 지금 바로 시작하세요: GitHub에서 프로젝트를 클론하고 첫 번째 AI 연구 에이전트를 구축해보세요!

“미래의 연구는 AI와 함께합니다. Open Deep Research로 그 미래를 지금 경험하세요.”