개요
DeerFlow는 하위 에이전트, 메모리, 샌드박스, 스킬을 조율하여 몇 분에서 몇 시간에 걸치는 작업을 처리하는 오픈 소스 슈퍼 에이전트 프레임워크입니다. 심층 리서치, 코딩, 콘텐츠 제작을 지원하며 확장 가능한 도구와 멀티 에이전트 워크플로를 제공합니다.
README 미리보기
# 🦌 DeerFlow - 2.0\n\nEnglish | [中文](./README_zh.md) | [日本語](./README_ja.md) | [Français](./README_fr.md) | [Русский](./README_ru.md)\n\n[](./backend/pyproject.toml)\n[](./Makefile)\n[](./LICENSE)\n\n\n> On February 28th, 2026, DeerFlow claimed the 🏆 #1 spot on GitHub Trending following the launch of version 2. Thanks a million to our incredible community — you made this happen! 💪🔥\n\nDeerFlow (**D**eep **E**xploration and **E**fficient **R**esearch **Flow**) is an open-source **super agent harness** that orchestrates **sub-agents**, **memory**, and **sandboxes** to do almost anything — powered by **extensible skills**.\n\nhttps://github.com/user-attachments/assets/a8bcadc4-e040-4cf2-8fda-dd768b999c18\n\n> [!NOTE]\n> **DeerFlow 2.0 is a ground-up rewrite.** It shares no code with v1. If you're looking for the original Deep Research framework, it's maintained on the [`1.x` branch](https://github.com/bytedance/deer-flow/tree/main-1.x) — contributions there are still welcome. Active development has moved to 2.0.\n\n## Official Website\n\n[](https://deerflow.tech)\n\nLearn more and see **real demos** on our [**official website**](https://deerflow.tech).\n\n## Coding Plan from ByteDance Volcengine\n\n\n\n- We strongly recommend using Doubao-Seed-2.0-Code, DeepSeek v3.2 and Kimi 2.5 to run DeerFlow\n- [Learn more](https://www.byteplus.com/en/activity/codingplan?utm_campaign=deer_flow&utm_content=deer_flow&utm_medium=devrel&utm_source=OWO&utm_term=deer_flow)\n- [中国大陆地区的开发者请点击这里](https://www.volcengine.com/activity/codingplan?utm_campaign=deer_flow&utm_content=deer_flow&utm_medium=devrel&utm_source=OWO&utm_term=deer_flow)\n\n## InfoQuest\n\nDeerFlow has newly integrated the intelligent search and crawling toolset independently developed by BytePlus--[InfoQuest (supports free online experience)](https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest)\n\n\n \n\n\n---\n\n## Table of Contents\n\n- [🦌 DeerFlow - 2.0](#-deerflow---20)\n - [Official Website](#offici
FAQ (5)
문제 해결DeerFlow에서 빈 GATEWAY_PORT로 인해 발생하는 "ValueError: invalid literal for int() with base 10: ''" 오류는 어떻게 수정하나요?
게이트웨이가 실패하는 이유는 os.getenv("GATEWAY_PORT", "8001")이 변수가 설정되지 않은 경우에만 기본값을 반환하기 때문입니다. 비어 있지만 정의된 변수는 ""가 되며, int("")는 ValueError를 발생시킵니다.
즉시 적용 가능한 해결 방법: 변수를 해제하거나 유효한 숫자 포트를 지정하세요:
unset GATEWAY_PORT
uv run uvicorn app.gateway.app:app --port 8001
또는 명시적으로 설정하세요:
GATEWAY_PORT=8001 GATEWAY_HOST=0.0.0.0 uv run uvicorn app.gateway.app:app --port 8001
Docker의 경우 -e GATEWAY_PORT=를 사용하지 마세요. 변수를 생략하거나 값을 전달하세요:
docker run -e GATEWAY_PORT=8001 ...
Docker Compose에서는 설정되지 않은 셸 변수가 빈 문자열로 확장되는 것을 방지하기 위해 기본값을 제공하세요:
GATEWAY_PORT: ${PORT:-8001}
GATEWAY_HOST: ${GATEWAY_HOST:-0.0.0.0}
backend/app/gateway/config.py의 영구적인 코드 수정: GATEWAY_PORT=0은 유지하면서 None과 ""만 설정되지 않은 것으로 처리합니다:
port_raw = os.getenv("GATEWAY_PORT")
port = 8001 if port_raw is None or port_raw == "" else int(port_raw)
host = os.getenv("GATEWAY_HOST") or "0.0.0.0"문제 해결디렉터리 스캔 중에 파일이 삭제되어 업로드 목록 조회가 500 FileNotFoundError를 반환하는 문제를 해결하는 방법
backend/packages/harness/deerflow/uploads/manager.py의 list_files_in_dir를 패치하여 파일시스템 경합(race)을 허용하도록 하세요. os.scandir() 이후에 entry.stat(follow_symlinks=False)를 try/except OSError로 감싸고, ENOENT, ENOTDIR, ELOOP와 같은 일시적인 조회 오류의 경우 해당 항목을 건너뛰되, EACCES와 같은 운영 오류는 다시 발생시키세요(re-raise). 또한 os.scandir 이전 또는 도중에 디렉터리가 사라지는 경우도 이미 수집된 항목들을 반환하는 방식으로 처리하세요.
예시:
try:
st = entry.stat(follow_symlinks=False)
except OSError as e:
if e.errno in (errno.ENOENT, errno.ENOTDIR, errno.ELOOP):
continue
raise
이를 방지하기 위해 entry.is_file()에 의존하지 마세요. POSIX에서는 파일시스템을 다시 확인하지 않고 scandir에서 캐시된 d_type을 사용할 수 있습니다. stat()가 FileNotFoundError를 발생시키는 상황을 시뮬레이션하여 사라진 항목은 건너뛰고 나머지 파일들은 반환되는지 확인하는 회귀 테스트를 추가하세요.
문제 해결Python 3.13으로 업그레이드한 후 RunJournal.flush()가 크로스 스레드 미들웨어 이벤트를 유실하는 문제를 해결하는 방법
Python 3.13.16+ 및 3.14.8+에서 asyncio.to_thread()는 이벤트 루프에 양보하지 않고 재개될 수 있습니다. 따라서 워커에서 call_soon_threadsafe()로 큐에 추가된 콜백은 RunJournal.flush()가 버퍼를 확인하는 시점에 여전히 보류 중일 수 있습니다. flush()는 빈 버퍼를 보게 되고, _detach_runtime_dependencies()가 저널을 닫으며, 이후에 도착한 콜백은 _closed에서 조기 반환되어 마지막 미들웨어 이벤트를 조용히 유실합니다.
드레인하기 전에 한 번 양보한 뒤 닫힘 상태를 다시 확인하도록 flush()를 수정합니다:
async def flush(self):
# 크로스 스레드 call_soon_threadsafe 콜백이 소유자 루프에 도착하도록 합니다.
await asyncio.sleep(0)
if self._closed:
return
# 기존 버퍼 드레인/큐 조인 로직이 여기에 이어집니다.
await journal.flush()를 _detach_runtime_dependencies() 앞에 유지하세요. 관찰 가능성/감사 경로에서도 마찬가지로, flush()가 큐를 조인하기 전에 보류 중인 외부 스레드 Usage/Audit 등록을 드레인하고, 워커를 닫힘으로 표시하기 전에 셧다운을 펜스하세요.
다음 명령으로 확인하세요:
cd backend
PYTHONPATH=. uv run pytest tests/test_run_journal.py::test_cross_thread_middleware_events_are_serialized_on_owner_loop
이 회귀는 gh-105836/GH-141696에서 비롯된 CPython _chain_future 변경으로 인해 발생합니다. Python 3.12.15는 추가 루프 반복을 강제하므로 Python 3.12로 고정하는 것이 임시 해결 방법이며, await asyncio.sleep(0) 펜스를 추가하면 3.12, 3.13, 3.14가 모두 수정됩니다.
문제 해결glob 필터에 공백, 따옴표 또는 달러 기호가 포함되어 있을 때 E2B grep이 exit code 2로 실패하는 문제를 어떻게 해결하나요?
E2B issue #6528(fix(e2b): quote grep filename filters)에 대한 수정이 포함된 릴리스로 업그레이드하세요. 이 버그는 E2BSandbox.grep()이 --include=release *.txt와 같이 따옴표 처리되지 않은 셸 인수를 생성하기 때문에 발생하며, 이로 인해 셸이 해당 인수를 분할하거나 확장합니다. 어댑터를 패치할 때는 인수의 일부만이 아니라 전체 인수를 셸 인용 처리하세요. sh -c로 실행할 명령에 추가하기 전에 shlex.quote(f"--include={glob}")를 사용하세요. 트랜스포트가 지원하는 경우 ["grep", f"--include={glob}", ...]와 같은 argv 배열을 전달하는 것이 좋습니다. 이렇게 하면 와일드카드 의미를 유지하면서 공백, 아포스트로피, 큰따옴표, 리터럴 $ 문자가 보존됩니다. 임시 해결 방법으로는 *.txt와 같이 셸 메타 문자가 없는 glob을 사용하고 Python에서 일치하는 경로를 필터링하세요.
문제 해결Helm으로 DeerFlow를 배포할 때 Live Browser WebSocket 연결이 실패(404 / 101 Switching Protocols 미발생)하는 이유는 무엇인가요?
Helm 차트의 nginx ConfigMap(deploy/helm/deer-flow/templates/configmap-nginx.yaml)에는 Live Browser 엔드포인트 /api/threads/<thread_id>/browser/stream을 위한 전용 location이 없습니다. 요청은 일반 threads location으로 전달되며, 이 location은 Upgrade: websocket 헤더를 제거하고 Connection을 close로 재작성하므로, Gateway는 일반 HTTP 요청을 받게 되어 WebSocket 핸드셰이크가 완료되지 않습니다.
수정 방법: Docker/로컬 nginx 설정에 이미 존재하는 것과 동일한 전용 location 블록을 configmap-nginx.yaml의 nginx 템플릿에 추가하세요:
location ~ ^/api/threads/[^/]+/browser/stream {
proxy_pass http://gateway;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 3600s;
}
그런 다음 helm upgrade로 재배포하세요(또는 helm template으로 다시 렌더링한 후 nginx 파드를 재시작하세요). 핸드셰이크가 성공하면 HTTP/1.1 101 Switching Protocols이 반환됩니다. make dev와 Docker 스택에는 이미 이 location이 포함되어 있으므로, 이 버그는 Helm으로 배포된 환경에서만 나타납니다. Gateway는 업그레이드 후에도 인증과 스레드 소유권을 계속 검사합니다.