# ๐ฆ DeerFlow - 2.0
[English](./README.md) | [ไธญๆ](./README_zh.md) | [ๆฅๆฌ่ช](./README_ja.md) | [Franรงais](./README_fr.md) | [ะ ัััะบะธะน](./README_ru.md) | [Portuguรชs](./README_pt.md) | ํ๊ตญ์ด
[](./backend/pyproject.toml)
[](./Makefile)
[](./LICENSE)
> 2026๋
2์ 28์ผ, DeerFlow๋ ๋ฒ์ 2 ์ถ์ ์ดํ GitHub Trending์์ ๐ 1์๋ฅผ ์ฐจ์งํ์ต๋๋ค. ๋๋ผ์ด ์ปค๋ฎค๋ํฐ ์ฌ๋ฌ๋ถ๊ป ์ง์ฌ์ผ๋ก ๊ฐ์ฌ๋๋ฆฝ๋๋ค. ์ฌ๋ฌ๋ถ์ด ์ด ์ผ์ ํด๋์ต๋๋ค! ๐ช๐ฅ
DeerFlow(**D**eep **E**xploration and **E**fficient **R**esearch **Flow**)๋ **์๋ธ์์ด์ ํธ**, **๋ฉ๋ชจ๋ฆฌ**, **์๋๋ฐ์ค**๋ฅผ ์ค์ผ์คํธ๋ ์ด์
ํ์ฌ ๊ฑฐ์ ๋ชจ๋ ์ผ์ ํด๋ผ ์ ์๋ ์คํ์์ค **์ํผ ์์ด์ ํธ ํ๋ค์ค**์ด๋ฉฐ, **ํ์ฅ ๊ฐ๋ฅํ ์คํฌ**๋ก ๋์ํฉ๋๋ค.
https://github.com/user-attachments/assets/a8bcadc4-e040-4cf2-8fda-dd768b999c18
> [!NOTE]
> **DeerFlow 2.0์ ์ฒ์๋ถํฐ ์์ ํ ์๋ก ์์ฑ๋์์ต๋๋ค.** v1๊ณผ ๊ณต์ ํ๋ ์ฝ๋๋ ์ ํ ์์ต๋๋ค. ๊ธฐ์กด Deep Research ํ๋ ์์ํฌ๋ฅผ ์ฐพ๊ณ ์๋ค๋ฉด [`1.x` ๋ธ๋์น](https://github.com/bytedance/deer-flow/tree/main-1.x)๋ฅผ ์ฐธ๊ณ ํ์ธ์. ์ด ํ๋ ์์ํฌ๋ ํด๋น ๋ธ๋์น์์ ๊ณ์ ์ ์ง ๊ด๋ฆฌ๋๋ฉฐ, ๊ทธ ๋ธ๋์น์ ๋ํ ๊ธฐ์ฌ๋ ์ฌ์ ํ ํ์ํฉ๋๋ค. ํ๋ฐํ ๊ฐ๋ฐ์ 2.0์ผ๋ก ์ฎ๊ฒจ์ก์ต๋๋ค.
## ๊ณต์ ์น์ฌ์ดํธ
[**๊ณต์ ์น์ฌ์ดํธ**](https://deerflow.tech)์์ ๋ ์์ธํ ์์๋ณด๊ณ **์ค์ ๋ฐ๋ชจ**๋ฅผ ํ์ธํ์ธ์.
๋๋ฉ ํ์ด์ง์ ์ฌ๋ก ์ฐ๊ตฌ๋ ํ์ฉ ๋ชฉ๋ก์ ๋ฑ๋ก๋ ์ฝ๊ธฐ ์ ์ฉ ์ผ์ผ์ด์ค๋ก ์ด๋ฆฌ๋ฉฐ, ๋ก๊ทธ์ธ์ด ํ์ํ์ง ์์ต๋๋ค.
## ์๋งค ํ๋ก์ ํธ
- [**LLM Space**](https://github.com/deer-flow/llm-space) - DeerFlow๋ฅผ ๋ท๋ฐ์นจํ๋ ๋น๋ฐ ๋ฌด๊ธฐ๋ฅผ ๋ง๋ ๋ณด์ธ์. ์์ด์ ํธ ์์ด๋์ด๋ฅผ ํ๋กํ ํ์ดํํ๊ณ , ํ๋ค์ค์ ๊ฐ ๋จ๊ณ๋ฅผ ์ดํด๋ณด๊ณ , ์คํจ๋ฅผ ์ฌ์(replay)ํ๊ณ , ์ฑ๋ฅ์ ๋ฒค์น๋งํฌํ ์ ์๋ ํ๋์ ๋ฐ์คํฌํฑ ๋๊ตฌ์
๋๋ค.
## ByteDance Volcengine์ Coding Plan
- DeerFlow ์คํ์๋ Doubao-Seed-2.0-Code, DeepSeek v3.2, Kimi 2.5 ์ฌ์ฉ์ ์ ๊ทน ๊ถ์ฅํฉ๋๋ค
- [์์ธํ ์์๋ณด๊ธฐ](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)
- [ไธญๅฝๅคง้ๅฐๅบ็ๅผๅ่
่ฏท็นๅป่ฟ้](https://www.volcengine.com/activity/codingplan?utm_campaign=deer_flow&utm_content=deer_flow&utm_medium=devrel&utm_source=OWO&utm_term=deer_flow)
## InfoQuest
InfoQuest reader, ์น ๊ฒ์, ์ด๋ฏธ์ง ๊ฒ์์ 30์ด์ HTTP ์ฐ๊ฒฐ/์ฝ๊ธฐ ๋นํ์ฑ ํ์์์์ ์ฌ์ฉํฉ๋๋ค. ํฌ๋กค๋ง์ `timeout` ๋ฐ `navigation_timeout` ์ค์ ์ ๋ณ๋์ ์๋ฒ ์ธก ์ต์
์ผ๋ก ์ ์ง๋๋ฉฐ, ๋ก์ปฌ HTTP ํ์์์์ ์ ์ดํ์ง ์์ต๋๋ค.
DeerFlow๋ BytePlus๊ฐ ๋
์์ ์ผ๋ก ๊ฐ๋ฐํ ์ง๋ฅํ ๊ฒ์ ๋ฐ ํฌ๋กค๋ง ๋๊ตฌ ์ธํธ๋ฅผ ์๋กญ๊ฒ ํตํฉํ์ต๋๋ค โ [InfoQuest (๋ฌด๋ฃ ์จ๋ผ์ธ ์ฒดํ ์ง์)](https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest)
---
## ๋ชฉ์ฐจ
- [๐ฆ DeerFlow - 2.0](#-deerflow---20)
- [๊ณต์ ์น์ฌ์ดํธ](#๊ณต์-์น์ฌ์ดํธ)
- [์๋งค ํ๋ก์ ํธ](#์๋งค-ํ๋ก์ ํธ)
- [ByteDance Volcengine์ Coding Plan](#bytedance-volcengine์-coding-plan)
- [InfoQuest](#infoquest)
- [๋ชฉ์ฐจ](#๋ชฉ์ฐจ)
- [ํ ์ค ์์ด์ ํธ ์ค์ ](#ํ-์ค-์์ด์ ํธ-์ค์ )
- [๋น ๋ฅธ ์์](#๋น ๋ฅธ-์์)
- [์ค์ ](#์ค์ )
- [์ ํ๋ฆฌ์ผ์ด์
์คํ](#์ ํ๋ฆฌ์ผ์ด์
-์คํ)
- [๋ฐฐํฌ ๊ท๋ชจ ์ฐ์ ](#๋ฐฐํฌ-๊ท๋ชจ-์ฐ์ )
- [์ต์
1: Docker (๊ถ์ฅ)](#์ต์
-1-docker-๊ถ์ฅ)
- [๊ธฐ์กด ์ฒดํฌ์์ ์
๊ทธ๋ ์ด๋](#๊ธฐ์กด-์ฒดํฌ์์-์
๊ทธ๋ ์ด๋)
- [์ต์
2: ๋ก์ปฌ ๊ฐ๋ฐ](#์ต์
-2-๋ก์ปฌ-๊ฐ๋ฐ)
- [์์ ๋ชจ๋](#์์-๋ชจ๋)
- [LangGraph Studio (์ ํ ์ฌํญ)](#langgraph-studio-์ ํ-์ฌํญ)
- [Docker ํ๋ก๋์
๋ฐฐํฌ](#docker-ํ๋ก๋์
-๋ฐฐํฌ)
- [๊ณ ๊ธ](#๊ณ ๊ธ)
- [์๋๋ฐ์ค ๋ชจ๋](#์๋๋ฐ์ค-๋ชจ๋)
- [MCP ์๋ฒ](#mcp-์๋ฒ)
- [IM ์ฑ๋](#im-์ฑ๋)
- [์์ฒญ ํธ๋ ์ด์ค ์๊ด๊ด๊ณ](#์์ฒญ-ํธ๋ ์ด์ค-์๊ด๊ด๊ณ)
- [LangSmith ํธ๋ ์ด์ฑ](#langsmith-ํธ๋ ์ด์ฑ)
- [Langfuse ํธ๋ ์ด์ฑ](#langfuse-ํธ๋ ์ด์ฑ)
- [Monocle ํธ๋ ์ด์ฑ](#monocle-ํธ๋ ์ด์ฑ)
- [์ฌ๋ฌ ํ๋ก๋ฐ์ด๋ ํจ๊ป ์ฌ์ฉํ๊ธฐ](#์ฌ๋ฌ-ํ๋ก๋ฐ์ด๋-ํจ๊ป-์ฌ์ฉํ๊ธฐ)
- [๊ธฐ์กด ์คํ ์คํธ๋ฆผ ๋์](#๊ธฐ์กด-์คํ-์คํธ๋ฆผ-๋์)
- [๊ฐ์ธ ์ก์ธ์ค ํ ํฐ](#๊ฐ์ธ-์ก์ธ์ค-ํ ํฐ)
- [Deep Research์์ ์ํผ ์์ด์ ํธ ํ๋ค์ค๋ก](#deep-research์์-์ํผ-์์ด์ ํธ-ํ๋ค์ค๋ก)
- [ํต์ฌ ๊ธฐ๋ฅ](#ํต์ฌ-๊ธฐ๋ฅ)
- [์คํฌ๊ณผ ๋๊ตฌ](#์คํฌ๊ณผ-๋๊ตฌ)
- [์ปค์คํ
์คํฌ ๋ด๋ณด๋ด๊ธฐ](#์ปค์คํ
-์คํฌ-๋ด๋ณด๋ด๊ธฐ)
- [Claude Code ํตํฉ](#claude-code-ํตํฉ)
- [๋น๊ณต๊ฐ ์ง์ ๊ฒ์ (RAGFlow)](#๋น๊ณต๊ฐ-์ง์-๊ฒ์-ragflow)
- [์ฑํ
๋ณด๊ดํจ](#์ฑํ
-๋ณด๊ดํจ)
- [์ธ์
๋ชฉํ](#์ธ์
-๋ชฉํ)
- [์๋ ์ปจํ
์คํธ ์์ถ](#์๋-์ปจํ
์คํธ-์์ถ)
- [์๋ธ์์ด์ ํธ](#์๋ธ์์ด์ ํธ)
- [์๋๋ฐ์ค์ ํ์ผ ์์คํ
](#์๋๋ฐ์ค์-ํ์ผ-์์คํ
)
- [์์ด์ ํธ ๋ธ๋ผ์ฐ์ ์ ์ด](#์์ด์ ํธ-๋ธ๋ผ์ฐ์ -์ ์ด)
- [์ปจํ
์คํธ ์์ง๋์ด๋ง](#์ปจํ
์คํธ-์์ง๋์ด๋ง)
- [์ฐธ์กฐํ ๋ํ ์ฝ๊ธฐ](#์ฐธ์กฐํ-๋ํ-์ฝ๊ธฐ)
- [ํ์ฌ ์์
๋
ธํธ](#ํ์ฌ-์์
-๋
ธํธ)
- [์ฅ๊ธฐ ๋ฉ๋ชจ๋ฆฌ](#์ฅ๊ธฐ-๋ฉ๋ชจ๋ฆฌ)
- [๊ถ์ฅ ๋ชจ๋ธ](#๊ถ์ฅ-๋ชจ๋ธ)
- [์๋ฒ ๋๋ Python ํด๋ผ์ด์ธํธ](#์๋ฒ ๋๋-python-ํด๋ผ์ด์ธํธ)
- [ํ๋ก์ ํธ](#ํ๋ก์ ํธ)
- [ํ๋ก์ ํธ ์ง์นจ](#ํ๋ก์ ํธ-์ง์นจ)
- [๋ฌธ์ ์๊ฐ](#๋ฌธ์-์๊ฐ)
- [๋ณด๊ด ์ ์ฝ๊ธฐ ๋์](#๋ณด๊ด-์-์ฝ๊ธฐ-๋์)
- [ํด์งํต](#ํด์งํต)
- [์์ฝ ์์
](#์์ฝ-์์
)
- [API๋ก cron ํ์ฐจ ๋ฏธ๋ฆฌ๋ณด๊ธฐ](#api๋ก-cron-ํ์ฐจ-๋ฏธ๋ฆฌ๋ณด๊ธฐ)
- [์
๊ทธ๋ ์ด๋ ์ฐธ๊ณ ์ฌํญ](#์
๊ทธ๋ ์ด๋-์ฐธ๊ณ -์ฌํญ)
- [ํฐ๋ฏธ๋ ์ํฌ๋ฒค์น (TUI)](#ํฐ๋ฏธ๋-์ํฌ๋ฒค์น-tui)
- [๋ฌธ์](#๋ฌธ์)
- [โ ๏ธ ๋ณด์ ๊ณ ์ง](#๏ธ-๋ณด์-๊ณ ์ง)
- [๋ถ์ ์ ํ ๋ฐฐํฌ๋ ๋ณด์ ์ํ์ ์ด๋ํ ์ ์์ต๋๋ค](#๋ถ์ ์ ํ-๋ฐฐํฌ๋-๋ณด์-์ํ์-์ด๋ํ -์-์์ต๋๋ค)
- [Gateway ๊ด๋ฆฌ์ ๊ถํ์ ๊ณง ์ฝ๋ ์คํ ๊ถํ์
๋๋ค](#gateway-๊ด๋ฆฌ์-๊ถํ์-๊ณง-์ฝ๋-์คํ-๊ถํ์
๋๋ค)
- [์ธ๋ถ ์ฑํ
๋ฉ์์ง ์ญํ ](#์ธ๋ถ-์ฑํ
-๋ฉ์์ง-์ญํ )
- [๋ฐฐํฌ ๊ธฐ๋ณธ๊ฐ](#๋ฐฐํฌ-๊ธฐ๋ณธ๊ฐ)
- [๋ณด์ ๊ถ์ฅ ์ฌํญ](#๋ณด์-๊ถ์ฅ-์ฌํญ)
- [๊ธฐ์ฌํ๊ธฐ](#๊ธฐ์ฌํ๊ธฐ)
- [๋ผ์ด์ ์ค](#๋ผ์ด์ ์ค)
- [๊ฐ์ฌ์ ๋ง](#๊ฐ์ฌ์-๋ง)
- [์ฃผ์ ๊ธฐ์ฌ์](#์ฃผ์-๊ธฐ์ฌ์)
- [Star History](#star-history)
## ํ ์ค ์์ด์ ํธ ์ค์
Claude Code, Codex, Cursor, Windsurf ๋๋ ๋ค๋ฅธ ์ฝ๋ฉ ์์ด์ ํธ๋ฅผ ์ฌ์ฉํ๋ค๋ฉด, ์ค์ ์ง์นจ์ ํ ๋ฌธ์ฅ์ผ๋ก ์ ๋ฌํ ์ ์์ต๋๋ค:
```text
Help me clone DeerFlow if needed, then bootstrap it for local development by following https://raw.githubusercontent.com/bytedance/deer-flow/main/Install.md
```
์ด ํ๋กฌํํธ๋ ์ฝ๋ฉ ์์ด์ ํธ์ฉ์
๋๋ค. ์์ด์ ํธ์๊ฒ ํ์ํ๋ฉด ์ ์ฅ์๋ฅผ ํด๋ก ํ๊ณ , ๊ฐ๋ฅํ๋ฉด Docker๋ฅผ ์ ํํ๋ฉฐ, ๋ค์์ ์คํํ ์ ํํ ๋ช
๋ น๊ณผ ์ฌ์ฉ์๊ฐ ์์ง ์ ๊ณตํด์ผ ํ๋ ๋๋ฝ๋ ์ค์ ์ ์๋ ค ์ค ๋ค ๋ฉ์ถ๋๋ก ์ง์ํฉ๋๋ค.
## ๋น ๋ฅธ ์์
### ์ค์
์ด์์๋ ์์ค ํ
ํ๋ฆฟ์ ์์ ํ์ง ์๊ณ ๋ ๋ฆฌํฐ๋ด prepend/append ์ค์ ์ผ๋ก ๋ฆฌ๋ ์์ด์ ํธ, ์๋ธ์์ด์ ํธ, DeerMem ์ถ์ถ ํ๋กฌํํธ๋ฅผ ํ์ฅํ ์ ์์ต๋๋ค. [ํ๋กฌํํธ ์ค๋ฒ๋ ์ด](backend/docs/CONFIGURATION.md#prompt-overlays)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
๋ชจ๋ธ๋ณ๋ก ์ ํํ ์ ์๋ [`request_admission`](backend/docs/CONFIGURATION.md#model-request-admission)์ ์์ฒญ ์๋๋ฅผ ์กฐ์ ํ์ฌ ํ๋ก๋ฐ์ด๋์ ๋ถ๋น ์์ฒญ ์ ์ ํ์ ๋์ง ์๋๋ก ๋์ต๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ๋นํ์ฑํ๋์ด ์์ผ๋ฉฐ, ํ์ฑํํ๋ ค๋ฉด ๋งํฌ๋ ๊ฐ์ด๋๋ฅผ ์ฐธ๊ณ ํ์ธ์. ์ด๋ฅผ ํ์ฑํํ๋ฉด ๋
ธ์ถ๋ SDK ์ฌ์๋์ Claude ๋ฐ Codex ์ด๋ํฐ์ ๋ด๋ถ ์ฌ์๋ ๋ฃจํ๊ฐ ๋นํ์ฑํ๋์ด, ๋ฏธ๋ค์จ์ด ์ฌ์๋๊ฐ ๋ค์ ์์ฒญ ์น์ธ(admission)์ ๊ฑฐ์น๊ฒ ๋ฉ๋๋ค. ๋ฏธ๋ค์จ์ด ์ฌ์๋๋ HTTP 529 ๊ณผ๋ถํ ์๋ต๋ ์ฌ์๋ ๋์์ ํฌํจํฉ๋๋ค. ์น์ธ ์ค์ ์ด ์ฌ์ ์ํ `retry_max_attempts` ๊ฐ์ ๊ฒฝ๊ณ ๋ก ํ์๋ฉ๋๋ค.
Google์ ๊ณต์ Gemini OpenAI ํธํ ์๋ํฌ์ธํธ์๋ [Gemini ์ถ๋ก ํ๋กํ](backend/docs/CONFIGURATION.md#gemini-via-googles-openai-compatible-endpoint)์ ์ฌ์ฉํ์ธ์.
MindIE XML ๋๊ตฌ ํธ์ถ์ [์ธ์ ํ์ฑ ๋ฐ ์ค๋ฐ๊ฟ ํธํ์ฑ ๊ฐ์ด๋](backend/docs/CONFIGURATION.md#mindie-xml-tool-arguments)๋ฅผ ์ฐธ๊ณ ํ์ธ์. ๋๊ธฐ ๋ฐ ๋น๋๊ธฐ ์คํธ๋ฆผ ๋ชจ๋ ์ด ํธํ์ฑ์ ์ ์งํฉ๋๋ค. ๋๊ตฌ๊ฐ ํ์ฑํ๋ ์คํธ๋ฆผ์ ๋น์คํธ๋ฆฌ๋ฐ ์๋ต์์ ์ฒญํฌ๋ฅผ ์๋ฎฌ๋ ์ด์
ํ๋ฉฐ, ๋๊ตฌ๊ฐ ์๋ ์คํธ๋ฆผ์ ๋ค์ดํฐ๋ธ ์คํธ๋ฆผ ๊ทธ๋๋ก ์ ์ง๋ฉ๋๋ค.
1. **DeerFlow ์ ์ฅ์ ํด๋ก **
```bash
git clone https://github.com/bytedance/deer-flow.git
cd deer-flow
```
2. **์ค์ ๋ง๋ฒ์ฌ ์คํ**
ํ๋ก์ ํธ ๋ฃจํธ ๋๋ ํฐ๋ฆฌ(`deer-flow/`)์์ ๋ค์์ ์คํํ์ธ์:
```bash
make setup
```
๋ํํ ๋ง๋ฒ์ฌ๊ฐ ์คํ๋์ด LLM ํ๋ก๋ฐ์ด๋, ์ ํ ์ฌํญ์ธ ์น ๊ฒ์, ๊ทธ๋ฆฌ๊ณ ์๋๋ฐ์ค ๋ชจ๋, bash ์ ๊ทผ, ํ์ผ ์ฐ๊ธฐ ๋๊ตฌ ๊ฐ์ ์คํ/์์ ๊ด๋ จ ์ ํธ ์ฌํญ์ ๊ณ ๋ฅด๋๋ก ์๋ดํฉ๋๋ค. ์ต์ํ์ `config.yaml`์ ์์ฑํ๊ณ ํค๋ฅผ `.env`์ ๊ธฐ๋กํฉ๋๋ค. ์ฝ 2๋ถ ๊ฑธ๋ฆฝ๋๋ค.
๋ง๋ฒ์ฌ์์๋ ์ ํ ์ฌํญ์ธ ์น ๊ฒ์ ํ๋ก๋ฐ์ด๋๋ฅผ ์ค์ ํ๊ฑฐ๋, ์ง๊ธ์ ๊ฑด๋๋ธ ์๋ ์์ต๋๋ค.
Brave ์น ๊ฒ์์ ์ ํจํ ํญ๋ชฉ๊ณผ ๊ทธ๋ ์ง ์์ ํญ๋ชฉ์ด ์์ธ ๊ฒฐ๊ณผ ๋ชฉ๋ก์์ ์ ํจํ ํญ๋ชฉ์ ๋ณด์กดํฉ๋๋ค. ํ์์ด ์๋ชป๋ ์๋ต ์ปจํ
์ด๋๋ ์ฌ์ฉ ๊ฐ๋ฅํ ํญ๋ชฉ์ด ํ๋๋ ์๋ ๋ชฉ๋ก์ ๊ตฌ์กฐํ๋ ํ์ ์ค๋ฅ๋ฅผ ๋ฐํํ๋ฉฐ, ๊ฒฐ๊ณผ๊ฐ ์๊ฑฐ๋ null์ด๊ฑฐ๋ ๋น์ด ์์ผ๋ฉด ๊ธฐ์กด์ "No results found" ์๋ต์ ๊ทธ๋๋ก ์ ์งํฉ๋๋ค. ํ์ ์ค๋ฅ๋ ๋ํ ์๋ชป๋ ์ปจํ
์ด๋์ ๊ฒฝ๋ก์ ํ์
, ๋๋ ์ฌ์ฉ ๊ฐ๋ฅํ ๊ฒฐ๊ณผ ๊ฐ์ฒด๊ฐ ์๋ค๋ ์ฌ์ค์ ๋ก๊ทธ๋ก ๋จ๊ธฐ๋ฉฐ, ๊ฒ์ ์ฟผ๋ฆฌ, ์๊ฒฉ ์ฆ๋ช
, ํ์ด๋ก๋ ๊ฐ์ ํฌํจํ์ง ์์ต๋๋ค.
GroundRoute ์น ๊ฒ์ ๋ฐ ๊ฐ์ ธ์ค๊ธฐ(fetch)๋ ํ์์ด ์๋ชป๋ HTTP ์ฑ๊ณต ํ์ด๋ก๋๋ฅผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค. ๊ฐ์ฒด๊ฐ ์๋ ํ์ด๋ก๋, ๋ฆฌ์คํธ๊ฐ ์๋ `results` ์ปจํ
์ด๋, ๋๋ ๊ฐ์ฒด ํญ๋ชฉ์ด ํ๋๋ ์๋ ๋น์ด ์์ง ์์ ๋ฆฌ์คํธ๋ ํ๋ก๋ฐ์ด๋์ ํ์ ์ค๋ฅ๋ฅผ ๋ฐํํ๋ฉฐ, ๊ทธ ๋ฐ์๋ ์ ํจํ ๋ฆฌ์คํธ์ ์์ธ ๊ฐ์ฒด๊ฐ ์๋ ํญ๋ชฉ์ ์์๋ฅผ ์ ์งํ๋ฉฐ ๊ฑด๋๋๋๋ค. ๊ฒฐ๊ณผ๊ฐ ์๊ฑฐ๋ null์ด๊ฑฐ๋ ๋น์ด ์์ผ๋ฉด ๊ธฐ์กด์ "No results found" ์๋ต์ ๊ทธ๋๋ก ์ ์งํฉ๋๋ค.
Tavily ์น ๊ฒ์ ๋ฐ ๊ฐ์ ธ์ค๊ธฐ๋ ํ์์ด ์๋ชป๋ HTTP ์ฑ๊ณต ํ์ด๋ก๋๋ฅผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค. ๊ฐ์ฒด๊ฐ ์๋ ํ์ด๋ก๋, ๋๋ ๋ฆฌ์คํธ๊ฐ ์๋ `results`/`failed_results` ์ปจํ
์ด๋๋ ํ๋ก๋ฐ์ด๋์ ํ์ ์ค๋ฅ๋ฅผ ๋ฐํํ๋ฉฐ, ๊ทธ ๋ฐ์๋ ์ ํจํ ๋ฆฌ์คํธ์ ์์ธ ๊ฐ์ฒด๊ฐ ์๋ ํญ๋ชฉ์ ์์๋ฅผ ์ ์งํ๋ฉฐ ๊ฑด๋๋๋๋ค. ๊ฒฐ๊ณผ๊ฐ ์๊ฑฐ๋ null์ด๊ฑฐ๋ ๋น์ด ์์ผ๋ฉด ๊ธฐ์กด ์๋ต(๊ฒ์์ `[]`, ๊ฐ์ ธ์ค๊ธฐ๋ `Error: No results found`)์ ๊ทธ๋๋ก ์ ์งํฉ๋๋ค. ๊ฒ์ ํ๋(`title`, `url`, `content`)๊ฐ ์๊ฑฐ๋ null์ด๋ฉด ๋น ํ
์คํธ๋ก ์ ๊ทํ๋๋ฉฐ, ๋ฌธ์์ด์ด ์๋ ๊ฐ์ ธ์ค๊ธฐ `raw_content`๋ ์๋ผ๋ด๊ธฐ ์ ํ์ด ์ ์ฉ๋๊ธฐ ์ ์ ํ
์คํธ๋ก ๋ณํ๋ฉ๋๋ค.
Sofya ์น ๊ฒ์ ๋ฐ ๊ฐ์ ธ์ค๊ธฐ๋ ํ์์ด ์๋ชป๋ HTTP ์ฑ๊ณต ํ์ด๋ก๋๋ฅผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค. ๊ฐ์ฒด๊ฐ ์๋ ํ์ด๋ก๋, ๋ฆฌ์คํธ๊ฐ ์๋ `results` ์ปจํ
์ด๋, ๋๋ ๊ฐ์ฒด ํญ๋ชฉ์ด ํ๋๋ ์๋ ๋น์ด ์์ง ์์ ๋ฆฌ์คํธ๋ ํ๋ก๋ฐ์ด๋์ ํ์ ์ค๋ฅ๋ฅผ ๋ฐํํ๋ฉฐ, ๊ทธ ๋ฐ์๋ ์ ํจํ ๋ฆฌ์คํธ์ ์์ธ ๊ฐ์ฒด๊ฐ ์๋ ํญ๋ชฉ์ ์์๋ฅผ ์ ์งํ๋ฉฐ ๊ฑด๋๋๋๋ค. ๊ฒฐ๊ณผ๊ฐ ์๊ฑฐ๋ null์ด๊ฑฐ๋ ๋น์ด ์์ผ๋ฉด ๊ธฐ์กด์ "No results found" ์๋ต์ ๊ทธ๋๋ก ์ ์งํฉ๋๋ค.
Tencent Cloud WSA ์น ๊ฒ์๋ ํ์์ด ์๋ชป๋ HTTP ์ฑ๊ณต ํ์ด๋ก๋๋ฅผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค. ๋ฆฌ์คํธ๊ฐ ์๋ `Pages` ์ปจํ
์ด๋, ๋๋ ์ฌ์ฉ ๊ฐ๋ฅํ ํ์ด์ง๊ฐ ํ๋๋ ์๋ ๋น์ด ์์ง ์์ ์ปจํ
์ด๋๋ ํ๋ก๋ฐ์ด๋์ ํ์ ์ค๋ฅ๋ฅผ ๋ฐํํ๋ฉฐ, ๊ทธ ๋ฐ์๋ ์ ํจํ ์ปจํ
์ด๋์ ์์ธ ํ์์ด ์๋ชป๋ ํ์ด์ง ํญ๋ชฉ์ ๊ฑด๋๋ฐ์ด ์ ํจํ ํ์ด ๋จ๋๋ก ํฉ๋๋ค. `Pages`๊ฐ ์๊ฑฐ๋ null์ด๊ฑฐ๋ ๋น์ด ์์ผ๋ฉด ๊ธฐ์กด์ "No results found" ์๋ต์ ๊ทธ๋๋ก ์ ์งํฉ๋๋ค.
Serply ์น ๊ฒ์๋ ๋ชจ๋ ๋ฒํฐ์ปฌ์์ ํ์์ด ์๋ชป๋ HTTP ์ฑ๊ณต ํ์ด๋ก๋๋ฅผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค. ๋ฆฌ์คํธ๊ฐ ์๋ `results`/`entries`/`articles` ์ปจํ
์ด๋, ๋๋ ๊ฐ์ฒด ํญ๋ชฉ์ด ํ๋๋ ์๋ ๋น์ด ์์ง ์์ ๋ฆฌ์คํธ๋ ํ๋ก๋ฐ์ด๋์ ํ์ ์ค๋ฅ๋ฅผ ๋ฐํํ๋ฉฐ, ๊ทธ ๋ฐ์๋ ์ ํจํ ๋ฆฌ์คํธ์ ์์ธ ๊ฐ์ฒด๊ฐ ์๋ ํญ๋ชฉ์ ์์๋ฅผ ์ ์งํ๋ฉฐ ๊ฑด๋๋๋๋ค. ์ปจํ
์ด๋๊ฐ ์๊ฑฐ๋ null์ด๊ฑฐ๋ ๋น์ด ์์ผ๋ฉด ๊ธฐ์กด์ "No results found" ์๋ต์ ๊ทธ๋๋ก ์ ์งํฉ๋๋ค.
Jina, Browserless, InfoQuest ์น ๊ฐ์ ธ์ค๊ธฐ๋ ์์ฒญํ ํ์ด์ง URL(๋๋ ์ฌ์ฉ ๊ฐ๋ฅํ HTML base URL)์ ๊ธฐ์ค์ผ๋ก ์๋ ๋งํฌ์ ์ด๋ฏธ์ง ์์ค๋ฅผ ํด์ํ๋ฏ๋ก, ๋ฐํ๋๋ Markdown์๋ ์์ ํ ๋์ ์ฃผ์๊ฐ ํฌํจ๋ฉ๋๋ค. ๋งํฌ ํด์์ ํ์์ด ์๋ชป๋ ํ์ด์ง์ ์์์ ํฌํจํ์ฌ ์ฃผ๋ณ HTML ์์ค๋ฅผ ๊ทธ๋๋ก ๋ณด์กดํฉ๋๋ค.
์์ฒด ํธ์คํ
Browserless, Crawl4AI, Firecrawl, fastCRW ๊ฐ์ ธ์ค๊ธฐ ๋ฐฑ์๋๋ ๊ฐ ๋๊ตฌ์ `network_isolation_confirmed: true`๋ฅผ ์ค์ ํ๊ธฐ ์ ์ ์ฌ์ค, ๋ฃจํ๋ฐฑ, ๋งํฌ ๋ก์ปฌ, ํด๋ผ์ฐ๋ ๋ฉํ๋ฐ์ดํฐ ๋คํธ์ํฌ๋ก๋ถํฐ์ ์์๋ฐ์ด๋ ๊ฒฉ๋ฆฌ๊ฐ ํ์ํฉ๋๋ค. ์ด๋ฌํ ์๋น์ค๋ ๋ฆฌ๋ค์ด๋ ํธ, DNS ํด์, ํ์ ๋ฆฌ์์ค๋ฅผ ์ค์ค๋ก ์ฒ๋ฆฌํ๋ฏ๋ก, DeerFlow๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฌ์ค์ด๊ฑฐ๋ ๊ฒ์ฆํ ์ ์๋ ๋ฐฑ์๋๋ฅผ ๊ฑฐ๋ถํฉ๋๋ค. `allow_private_addresses`๋ ์๋๋ ๋ด๋ถ ๋์ URL์ ํ์ฉํ๋ฉฐ, ๋ฐฑ์๋ ๊ฒ์ฌ๋ฅผ ์ฐํํ์ง ์์ต๋๋ค. [์์ ๊ฐ์ ธ์ค๊ธฐ ๋ฐฐํฌ](backend/docs/CONFIGURATION.md#delegated-fetch-backend-isolation)๋ฅผ ์ฐธ๊ณ ํ์ธ์. `make doctor`๋ ๊ฑฐ๋ถ๋ ๋ฐฑ์๋ ์ค์ ์ ๋ณด๊ณ ํฉ๋๋ค.
Jina ๊ฐ์ ธ์ค๊ธฐ๋ ๋๊ตฌ ์ค์ ์ `max_retries`(๊ธฐ๋ณธ๊ฐ `0`)์ `retry_budget_seconds`(๊ธฐ๋ณธ๊ฐ `30`)๋ฅผ ํตํด ์ตํธ์ธ ๋ฐฉ์์ ์ ํ๋ ์ฌ์๋๋ฅผ ์ง์ํฉ๋๋ค. ์ ํจํ `Retry-After` ํํธ๋ HTTP 429/503์ ๋ํ ์ต์ ๋๊ธฐ ์๊ฐ์ ์ค์ ํ๋ฉฐ, ์ ํจํ ํํธ๊ฐ ์๋ 429๋ ์ต์ข
์คํจ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค. ๋จ์ ์์ฐ ์์ ๋ค์ด๊ฐ ์ ์๋ ํํธ๋ ์ฌ์๋๋ฅผ ์ค์ง์ํต๋๋ค. ๋ก์ปฌ ๋ฐฑ์คํ๋ ๊ณ์ ๋ฌด์์ํ๋ฉ๋๋ค. ์ฌ์๋๋ ์
์คํธ๋ฆผ ์์ฒญ๊ณผ ๋น์ฉ์ ๋๋ฆด ์ ์์ต๋๋ค. [Jina ๊ฐ์ ธ์ค๊ธฐ ์ฌ์๋](backend/docs/CONFIGURATION.md#jina-fetch-retries)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
Jina๋ ์ตํธ์ธ ๋ฐฉ์์ `max_response_bytes` ๋๊ตฌ ์ค์ (์์ ์ ์, ์๋ตํ๊ฑฐ๋ null์ด๋ฉด ๋นํ์ฑํ)๋ ์ง์ํฉ๋๋ค. ์ด ์ค์ ์ ์ถ์ถ ์ ์ ๋์ฝ๋ฉ๋ ์๋ต์ด ์ง๋์น๊ฒ ํฌ๋ฉด ์ค๋จํ๋ฉฐ, ๋ถ๋ถ ์ฑ๊ณต์ด๋ ์ฌ์๋๋ ์์ต๋๋ค. 4096์ ์ถ๋ ฅ ์ํ์ ๊ทธ๋๋ก ์ ์ง๋๋ฉฐ, HTTPX ์์ถ ํด์ ๊ธฐ์ ๋ฉ๋ชจ๋ฆฌ ํ ๋น์ด๋ ๋คํธ์ํฌ ๋์ญํญ์ ์ ํํ์ง๋ ์์ต๋๋ค. [์๋ต ์์ฐ](backend/docs/CONFIGURATION.md#jina-response-byte-budget)์ ์ฐธ๊ณ ํ์ธ์.
Jina๋ ์ตํธ์ธ ๋ฐฉ์์ `request_admission` ๋๊ตฌ ์ถ๊ฐ ์ค์ ์ผ๋ก ๋์ HTTP ์๋์ FIFO ๋๊ธฐ๋ ์ ํํ ์ ์์ต๋๋ค. ํ๋์ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ ์์ฐ์ด ๊ฐ ํ๋ก์ธ์ค ์์ ํด๋ผ์ด์ธํธ์ ์์ด์ ํธ ์ค๋ ๋ ์ ์ฒด์์ ๊ณต์ ๋๋ฉฐ, ๋ ํ๋ฆฌ์นด๋ ์๋ก ๋
๋ฆฝ๋ ์์ฐ์ ๊ฐ์ง๋๋ค. [Jina ์์ฒญ ์น์ธ](backend/docs/CONFIGURATION.md#jina-request-admission)์ ์ฐธ๊ณ ํ์ธ์.
์ธ์ ๋ ์ง `make doctor`๋ฅผ ์คํํ๋ฉด ์ค์ ์ ๊ฒ์ฆํ๊ณ ๋ฐ๋ก ์ ์ฉํ ์ ์๋ ํด๊ฒฐ ํํธ๋ฅผ ์ป์ ์ ์์ต๋๋ค. ๋ก์ปฌ ์ค์ ์ด๋ ๋ฐํ์ ๋ฌธ์ ๋ก GitHub ์ด์๋ฅผ ์ด๋ ค๋ ๊ฒฝ์ฐ `make support-bundle`์ ์คํํ์ธ์. ์ด ๋ช
๋ น์ ๋ณด๊ณ ์๊ฐ ๋ค์์ ํ ์ผ์ ์ถ๋ ฅํ๊ณ , ์ด์์ ๋ถ์ฌ ๋ฃ์ `*-issue-summary.md` ํ์ผ, AI ์ง์ ์ด์ ์์ฑ์ ์ํ `*-issue-draft.md` ํ์ผ, ๊ทธ๋ฆฌ๊ณ ์ ํ ์ฌํญ์ธ ์ฆ๊ฑฐ zip์ `.deer-flow/support-bundles/` ์๋์ ์์ฑํฉ๋๋ค. AI ์ด์์คํดํธ๊ฐ ์ด์๋ฅผ ์์ฑํ๋ค๋ฉด ์ด์์์ ์์ํ์ฌ, ๋๋ฝ๋ ์ฌ์ค์ ์ง์ด๋ด์ง ๋ง๊ณ ๋ชจ๋ REQUIRED ์๋ฆฌ ํ์์๋ฅผ ์ฑ์ ๋ฃ์ผ์ธ์. zip์ ๋ฉ์ธํ
์ด๋๊ฐ ์์ฒญํ๊ฑฐ๋ ์์ฝ๋ง์ผ๋ก ์ถฉ๋ถํ์ง ์์ ๊ฒฝ์ฐ์๋ง ์ฒจ๋ถํ์ธ์. ๋ฉ์ธํ
์ด๋์ AI ๋ถ๋ฅ(triage) ๋๊ตฌ๋ `triage.json`๋ถํฐ ์์ํ ์ ์์ต๋๋ค. ๋ฒ๋ค์๋ ๋ง์คํน๋ ์ง๋จ ์ ๋ณด์ ํ์ผ ๋งค๋ํ์คํธ๋ง ํฌํจ๋๋ฉฐ, `.env`, ์๋ณธ ๋ํ ๋ฉ์์ง, ์ฌ์ฉ์ ํ์ผ ๋ด์ฉ์ ํฌํจ๋์ง ์์ต๋๋ค. ํ์ ํ๋ก์ธ์ค ์ง๋จ์ UTF-8๋ก ์์ง๋๋ฉฐ, Python ํฌํผ๋ UTF-8์ด ์๋ ํธ์คํธ์์๋ UTF-8๋ก ์ถ๋ ฅํ๊ณ ์ธ์ฝ๋ฉํ ์ ์๋ ๋ฌธ์๋ ์ด์ค์ผ์ดํํฉ๋๋ค. ์ค๋ ๋ ๋งค๋ํ์คํธ๋ ๋ก์ปฌ ๋ฐ์ฒ์ ๋ฐํ์ ๊ฒฝ๋ก๋ฅผ ๋ฐ๋ฆ
๋๋ค. ์ฒดํฌ์์์ `.env` ๊ฐ์ด ์
ธ export๋ณด๋ค ์ฐ์ ํ๋ฉฐ, ํ๋ก์ ํธ ๋ฃจํธ ์ฌ์ ์๋ง ์๋ ๊ฒฝ์ฐ์๋ ์ฌ์ ํ `backend/.deer-flow`๋ฅผ ๋จผ์ ์ฌ์ฉํฉ๋๋ค. `DEER_FLOW_HOME="$PWD/backend/.deer-flow"` ๊ฐ์ ๋จ์ ๋ณ์ ์ฐธ์กฐ๋ ์ฒดํฌ์์์ `PWD`๋ก ์ฌ์ฉํ๋ฉฐ, ์์๋ฐ์ดํ๋ก ๋ฌถ์ธ ์ฐธ์กฐ๋ ๋ฆฌํฐ๋ด๋ก ์ ์ง๋ฉ๋๋ค. ์ฒดํฌ์์์ `.env`๋ฅผ ์ฝ์ ์ ์๊ฑฐ๋ UTF-8๋ก ๋์ฝ๋ฉํ ์ ์์ผ๋ฉด, ์ค๋ ๋ ์ง๋จ์ ์
ธ export์ ๊ธฐ๋ณธ ์ ์ฅ ๊ฒฝ๋ก๋ฅผ ์ ์งํฉ๋๋ค. `backend/.env` ๋๋ `DEER_FLOW_ENV_FILE`์ ์ฌ์ฉํ๋ ๋
๋ฆฝ ์คํํ Gateway์ ๊ฒฝ์ฐ, ๋ฒ๋ค์ ์์งํ ๋ ์ค์ ๋ก ์ ์ฉ๋๋ `DEER_FLOW_HOME`์ exportํ๊ณ ์ฒดํฌ์์์ `.env`๊ฐ ์ด๋ฅผ ์ฌ์ ์ํ์ง ์๋๋ก ํ์ธ์. Doctor์ ๋ด๋ถ ๋๊ตฌ ํ๋ก๋ธ๋ ์๋ชป๋ ๋ฐ์ดํธ๋ฅผ ๋์ฒด ๋ฌธ์๋ก ๋ฐ๊พธ๋ฉฐ UTF-8๋ก ๋์ฝ๋ฉํ๋ฏ๋ก, ๋๋จธ์ง ์ง๋จ ์ถ๋ ฅ์ ๊ณ์ ํ์ธํ ์ ์์ต๋๋ค.
์ค๋ ๋ ๋งค๋ํ์คํธ๋ฅผ ์์ฒญํ๋ฉด, ๋น์ด ์์ง ์์ `DEER_FLOW_HOME`์ด ์ค๋๋ ์ฒดํฌ์์ ๋ฐ์ดํฐ ๋์ ๋ฐํ์ ๋ฐ์ดํฐ ๋๋ ํฐ๋ฆฌ๋ฅผ ์ ํํฉ๋๋ค. ์ธ๋ถ ๋ฐ์ดํฐ ๊ฒฝ๋ก๋ ๋ณด๊ณ ์์ `{DEER_FLOW_HOME}`์ผ๋ก ํ์๋๋ฉฐ, ํ์ผ ๋ด์ฉ์ ๊ณ์ ์ ์ธ๋ฉ๋๋ค. ๋ฐํ์ ๊ฒฝ๋ก ์ค์ ๋ ์ฒดํฌ์์์ `.env`์์ ๊ฐ์ ธ์ค๋ฉฐ, ์
ธ export๊ฐ ์ฐ์ ํฉ๋๋ค. ์๋ ๊ฒฝ๋ก๋ `make dev`์์์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ฒดํฌ์์์ ๊ธฐ์ค์ผ๋ก ํด์๋ฉ๋๋ค. ๋ช
์์ ์ธ home์ด ์์ผ๋ฉด, ์ค์ ๋ `DEER_FLOW_PROJECT_ROOT`๊ฐ ํด๋น `.deer-flow` ๋๋ ํฐ๋ฆฌ๋ฅผ ์ ํํ๋ฉฐ, ์ธ๋ถ ๊ฒฝ๋ก๋ ๋ณด๊ณ ์์ ๊ทธ ๋ณ์ ์ด๋ฆ์ผ๋ก ํ์๋ฉ๋๋ค.
> **๊ณ ๊ธ / ์๋ ์ค์ **: `config.yaml`์ ์ง์ ํธ์งํ๊ณ ์ถ๋ค๋ฉด ๋์ `make config`๋ฅผ ์คํํ์ฌ ์ ์ฒด ํ
ํ๋ฆฟ์ ๋ณต์ฌํ์ธ์. ์ ํ์ ์์กด์ฑ ์๋ ๊ฐ์ง๋ ๋ฐ์ดํธ ์์ ํ์(BOM) ์ ๋ฌด์ ๊ด๊ณ์์ด UTF-8 ์ค์ ํ์ผ์ ๋ฐ์๋ค์
๋๋ค. `config.example.yaml`์์ CLI ๊ธฐ๋ฐ ํ๋ก๋ฐ์ด๋(Codex CLI, Claude Code OAuth), OpenRouter, Responses API, `subagents.max_total_per_run` ๊ฐ์ ์๋ธ์์ด์ ํธ ๋ฐํ์ ์ํ ๋ฑ์ ํฌํจํ ์ ์ฒด ๋ ํผ๋ฐ์ค๋ฅผ ํ์ธํ์ธ์.
์ ํ ์ฌํญ์ธ ๋ชจ๋ธ๋ณ ๊ฐ๊ฒฉ ์ค์ ์ ๊ฐ๊ฒฉ์ด ์ง์ ๋ ๋ชจ๋ ๋ชจ๋ธ์์ ํ๋์ ํตํ๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ํตํ๊ฐ ์์ฌ ์์ผ๋ฉด DeerFlow๋ ์๋ชป๋ ํฉ๊ณ๋ฅผ ๋ณด์ฌ ์ฃผ๋ ๋์ Console ๋น์ฉ ์ถ์ ์ ๋นํ์ฑํํฉ๋๋ค.
๊ด๋ฆฌ์๋ **Settings โ Models**๋ฅผ ์ด์ด ํ๋ก๋ฐ์ด๋๋ฅผ ์ ํํ๊ณ ํด๋น ํ๋ก๋ฐ์ด๋์ **API Key**์ **model ID**๋ง ์
๋ ฅํ ์ ์์ต๋๋ค. ์๋ํฌ์ธํธ, ์ธ์ฆ, ์ด๋ํฐ๋ OpenAI, Anthropic, DeepSeek, Alibaba Cloud Bailian/Qwen, Volcengine/Doubao, Moonshot/Kimi, Zhipu/Z.AI, MiniMax์ ๋ํ ๋ฐฑ์๋ ํ๋ฆฌ์
์ผ๋ก ์ ๊ณต๋ฉ๋๋ค. ๋ฆฌ์ ๋ฐ ์๊ธ์ ๋ณ ํญ๋ชฉ์ ๋ช
์์ ์ผ๋ก ๊ตฌ๋ถ๋ฉ๋๋ค. ์์์ model ID๋ฅผ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ๋ด๋ถ ์ด๋ฆ์ ์๋์ผ๋ก ์์ฑ๋๊ณ model ID๊ฐ ๋ฐ๋์ด๋ ์์ ์ ์ผ๋ก ์ ์ง๋ฉ๋๋ค. ์๋ก ์ ์ฅํ ๋ชจ๋ธ์ ํ์ฑํ๋๋ฉฐ, YAML์ ํธ์งํ๊ฑฐ๋ Gateway๋ฅผ ์ฌ์์ํ์ง ์์๋ ๊ธฐ์กด ์ฑํ
๋ฐ Agent ๋ชจ๋ธ ์ ํ๊ธฐ์ ์ฆ์ ๋ฐ์๋ฉ๋๋ค.
**Custom OpenAI-compatible**์ ๊ธฐ์กด/์ปค์คํ
base URL๊ณผ ์ธ์ฆ์ด ์๋ ์๋ํฌ์ธํธ๋ฅผ ๊ณ์ ์ง์ํฉ๋๋ค. **Advanced settings**์์๋ ํ์ ์ด๋ฆ, ํ ํฐ ์ ํ, ๋น์ ์ฌ์ ์๋ฅผ ์ ์งํ๋ฉฐ, ์ ์ ์๋ ID์ ์์๋ก ์ง์ด๋ธ ๊ธฐ๋ฅ์ด ๋ถ์ฌ๋์ง๋ ์์ต๋๋ค. ํธ์งํ ๋ ํค๋ฅผ ๋น์ ๋๋ฉด ๊ฐ์ ์ฐ๊ฒฐ์ ๊ธฐ์กด ํค๊ฐ ์ ์ง๋ฉ๋๋ค. ํ๋ก๋ฐ์ด๋๋ ์ปค์คํ
์๋ํฌ์ธํธ๋ฅผ ๋ฐ๊พธ๋ ค๋ฉด ์ ํค๊ฐ ํ์ํ๋ฉฐ, ํ๋ฆฌ์
๋ชจ๋ธ์ ํค๋ฅผ ์ง์ฐ๊ธฐ ์ ์ ๋นํ์ฑํํด์ผ ํฉ๋๋ค. YAML ๋ชจ๋ธ์ ๊ณ์ ์ฝ๊ธฐ ์ ์ฉ์
๋๋ค.
์ฐ๊ฒฐ ํ
์คํธ๋ ์ฑํ
๊ณผ ๊ฐ์ ๋ชจ๋ธ ํฉํ ๋ฆฌ์ ํ๋กํ ์ฝ์ ์ฌ์ฉํ๋ฉฐ, ์ ํ๋ ์คํธ๋ฆฌ๋ฐ ๋๊ตฌ ํธ์ถ ์์ฒญ์ ๋ณด๋ด๊ณ ์ด์์ ์ ๋ ์ ์ฅํ์ง ์์ต๋๋ค. ํ๋ก๋ฐ์ด๋ ์๊ธ์ด ๋ฐ์ํ ์ ์์ผ๋ฉฐ, ๋ชจ๋ ์์ด์ ํธ, ๋น์ , thinking ์ํฌํ๋ก๋ฅผ ๊ฒ์ฆํ์ง๋ ์์ต๋๋ค. ๊ณต์ DeepSeek ์ปค์คํ
์๋ํฌ์ธํธ๋ ๊ธฐ์กด ์ด๋ํฐ๋ฅผ ์ ์งํ๋ฉฐ, ํ๋ก์๋ model ID๋ง์ผ๋ก DeepSeek๋ก ์ทจ๊ธ๋์ง ์์ต๋๋ค. ํ๋ฆฌ์
, ํธํ์ฑ, ํ์ฅ ๋ฐฉ๋ฒ, ๋ฐฑ์
์๊ตฌ ์ฌํญ์ [์น ๋ชจ๋ธ ๋ฑ๋ก ๋ ํผ๋ฐ์ค](backend/docs/CONFIGURATION.md#models-registered-through-the-web)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
DeepSeek ํ๊ท ํ
์คํธ๋ ์ผ๋ฐ ๋ฐฑ์๋ ํ
์คํธ ์ค์ํธ์ ํจ๊ป ์คํ๋ผ์ธ์ผ๋ก ์คํ๋ฉ๋๋ค. ์ค์ ํ๋ก๋ฐ์ด๋๋ฅผ ๋ช
์์ ์ผ๋ก ๊ฒ์ฆํ๋ ค๋ฉด ํ๊ฒฝ์ `DEEPSEEK_TEST_API_KEY`๋ฅผ ์ค์ ํ๊ณ `backend/`์์ ๋ค์์ ์คํํ์ธ์:
```bash
DEER_FLOW_RUN_LIVE_TESTS=1 uv run --no-sync pytest tests/test_managed_deepseek_live.py -q
```
์ด ์ตํธ์ธ ํ
์คํธ๋ DeepSeek์ ์งง์ ์์ฒญ์ ๋ณด๋ด๋ฏ๋ก ์๊ธ์ด ๋ฐ์ํ ์ ์์ต๋๋ค. ์์ ์ํ๋ฅผ ์ฌ์ฉํ๊ณ , ์๊ฒฉ ์ฆ๋ช
์ ๋ฐฐํฌ ์นดํ๋ก๊ทธ์ ์ ๋ ์ ์ฅํ์ง ์์ผ๋ฉฐ, CI์์๋ ๊ฑด๋๋๋๋ค. `DEEPSEEK_TEST_MODEL`๋ก ๋ค๋ฅธ DeepSeek model ID๋ฅผ ์ ํ์ ์ผ๋ก ์ง์ ํ ์ ์์ต๋๋ค(๊ธฐ๋ณธ๊ฐ: `deepseek-flash`). ๊ฐ์ ํ
์คํธ๋ฅผ ์์ ์ ๋ฆฌ๋น์ ๊ณผ ์์ ํ ๋ฆฌ๋น์ ์์ ์คํํ ์ ์์ผ๋ฉฐ, ์์ ๊ฒฐ๊ณผ๋ ํญ์ ์ฑ๊ณต์
๋๋ค.
YAML ๋ชจ๋ธ์ ์ด ํ์ด์ง์์ ๊ณ์ ์ฝ๊ธฐ ์ ์ฉ์ด๋ฉฐ, ์ด๋ฆ์ด ์ถฉ๋ํ๋ฉด ์ฐ์ ํฉ๋๋ค. ๊ด๋ฆฌํ ๋ชจ๋ธ์ YAML ๋ชจ๋ธ ๋ค์ ์ถ๊ฐ๋ฉ๋๋ค. ํธ์ง ๋ด์ฉ์ ์ ์ค์ ์ค๋
์ท์ ์ ์ฉ๋๋ฉฐ, ์งํ ์ค์ธ ์คํ(run)์ ๊ธฐ์กด ์ค๋
์ท์ ์ ์งํฉ๋๋ค. ๋ชจ๋ธ์ ๋นํ์ฑํํ๋ฉด ์ดํ์ ์ ํ/ํด์ ๋์์์ ์ ์ธ๋๋ฏ๋ก, ๋นํ์ฑํํ๊ธฐ ์ ์ ํด๋น ๋ชจ๋ธ์ ๋ช
์์ ์ผ๋ก ์ฐธ์กฐํ๋ ์ปค์คํ
์์ด์ ํธ๋ ์์ฝ ์์
์ ์๋ฅผ ๋จผ์ ์์ ํ์ธ์. ๊ด๋ฆฌํ ๋ชจ๋ธ์ ๊ฐ์ธ API ํค ํ๋กํ์ด ์๋๋ผ ๋ฐฐํฌ ์ ์ฒด์์ ๊ณต์ ๋๋ฉฐ, ๊ธฐ์กด ๋ชจ๋ธ ๊ถํ ์ ์ฑ
์ ๊ทธ๋๋ก ๋ฐ๋ฆ
๋๋ค.
์ํธํ๋ ์นดํ๋ก๊ทธ์ ์์ฑ๋ ๋ก์ปฌ ์ํธํ ํค๋ `$DEER_FLOW_HOME/managed-models/`(๊ธฐ๋ณธ๊ฐ `.deer-flow/managed-models/`)์ ์ ์ฅ๋ฉ๋๋ค. **๋๋ ํฐ๋ฆฌ ์ ์ฒด**๋ฅผ ์์ ์ ์ฅํ๊ณ ๋ฐฑ์
ํ๋ฉฐ, ํ์ผ ์์คํ
์ ๊ทผ์ ์ ํํ๊ณ , ๊ฐ์ ์นดํ๋ก๊ทธ๋ฅผ ์ฌ์ฉํด์ผ ํ๋ Gateway ์์ปค/๋ ํ๋ฆฌ์นด ๊ฐ์ ๊ณต์ ํ์ธ์. ๋ก์ปฌ ํค๋ ํ์ผ ์์คํ
๊ถํ์ผ๋ก ๋ณดํธ๋๋ฉฐ, ๋ ํ์ผ์ ๋ชจ๋ ์ฝ์ ์ ์๋ ์ฌ๋์๊ฒ๋ ์ํธํ๊ฐ ๋ณดํธ ์๋จ์ด ๋์ง ์์ต๋๋ค. ํค๋ฅผ ์์ด๋ฒ๋ฆฌ๋ฉด ๋ฐฑ์
์์ ๋ณต์ํด์ผ ํฉ๋๋ค. ์นดํ๋ก๊ทธ๋ฅผ ๋ณตํธํํ ์ ์์ผ๋ฉด ์ฝ๊ธฐ์ ์ฐ๊ธฐ๋ ์นดํ๋ก๊ทธ๋ฅผ ๊ต์ฒดํ๋ ๋์ ์คํจํฉ๋๋ค. ์ด ์ ์ฅ ๋ฐฉ์์ SQL ๋ฐฑ์๋์ ๋
๋ฆฝ์ ์ด๋ฉฐ ์ฝ๊ธฐ ์ ์ฉ YAML ๋ง์ดํธ์๋ ํจ๊ป ๋์ํฉ๋๋ค.
์ฌ๋ฌ ๋ชจ๋ธ์ด ์ค์ ๋์ด ์์ผ๋ฉด ์ด๋ ๋ชจ๋ธ ์ ํ๊ธฐ๋ ์ด๊ณ ๋ชจ๋ธ ์์ ๋ณ์ ๋๋ฌ ์ฆ๊ฒจ์ฐพ๊ธฐ์ ์ถ๊ฐํ ์ ์์ต๋๋ค. ์ฆ๊ฒจ์ฐพ๊ธฐ๋ ๋ฉ์ธ ์ฑํ
๊ณผ Side Chat ์ ํ๊ธฐ ๋ชจ๋์์ ๋งจ ์์ ํ์๋๋ฉฐ, ์ด๋ ์ฑํ
์ ์ ํ๋ ๋ชจ๋ธ์ด๋ ๊ธฐ๋ณธ ๋ชจ๋ธ๋ ๋ฐ๊พธ์ง ์์ต๋๋ค. ์ฆ๊ฒจ์ฐพ๊ธฐ๋ ํ์ฌ ๋ธ๋ผ์ฐ์ ์์ ๋ก๊ทธ์ธํ ์ฌ์ฉ์ ๊ธฐ์ค์ผ๋ก ์ ์ฅ๋๋ฏ๋ก ๋ค๋ฅธ ๋ธ๋ผ์ฐ์ ๋ ๊ธฐ๊ธฐ์ ๋๊ธฐํ๋์ง ์์ผ๋ฉฐ, ์์ ์ ์ค์ ์ด ํ์ํ์ง ์์ต๋๋ค. ๊ฐ๊ฒฐํ ์ฆ๊ฒจ์ฐพ๊ธฐ ์ ํ๊ธฐ๋ ์๋์ ์ผ๋ก ๊ฒ์์ ์๋ตํ๊ณ , ๋ ์ค์ง๋ฆฌ ๋ชจ๋ธ ๋ชฉ๋ก์ ์ฆ๊ฒจ์ฐพ๊ธฐ ์ ๋ ฌ๋ง ์ถ๊ฐํฉ๋๋ค.
์๋ ๋ชจ๋ธ ์ค์ ์์
```yaml
models:
- name: gpt-4o
display_name: GPT-4o
use: langchain_openai:ChatOpenAI
model: gpt-4o
api_key: $OPENAI_API_KEY
- name: openrouter-gemini-2.5-flash
display_name: Gemini 2.5 Flash (OpenRouter)
use: langchain_openai:ChatOpenAI
model: google/gemini-2.5-flash-preview
api_key: $OPENROUTER_API_KEY
base_url: https://openrouter.ai/api/v1
- name: opper-claude-sonnet-4-6
display_name: Claude Sonnet 4.6 (Opper)
use: langchain_openai:ChatOpenAI
model: claude-sonnet-4-6
api_key: $OPPER_API_KEY
base_url: https://api.opper.ai/v3/compat
- name: gpt-5-responses
display_name: GPT-5 (Responses API)
use: langchain_openai:ChatOpenAI
model: gpt-5
api_key: $OPENAI_API_KEY
use_responses_api: true
output_version: responses/v1
- name: qwen3-32b-vllm
display_name: Qwen3 32B (vLLM)
use: deerflow.models.vllm_provider:VllmChatModel
model: Qwen/Qwen3-32B
api_key: $VLLM_API_KEY
base_url: http://localhost:8000/v1
supports_thinking: true
when_thinking_enabled:
extra_body:
chat_template_kwargs:
enable_thinking: true
```
OpenRouter ๋ฐ ์ด์ ์ ์ฌํ OpenAI ํธํ ๊ฒ์ดํธ์จ์ด๋ `langchain_openai:ChatOpenAI`์ `base_url`๋ก ์ค์ ํด์ผ ํฉ๋๋ค. ํ๋ก๋ฐ์ด๋๋ณ ํ๊ฒฝ ๋ณ์ ์ด๋ฆ์ ์ ํธํ๋ค๋ฉด `api_key`๊ฐ ํด๋น ๋ณ์๋ฅผ ๋ช
์์ ์ผ๋ก ๊ฐ๋ฆฌํค๋๋ก ํ์ธ์(์: `api_key: $OPENROUTER_API_KEY`).
`write_file` ๋๊ตฌ์ ์ถ๋ ฅ ์์ฐ ํํธ๋ ํ์ฑ ๋ชจ๋ธ์ ์คํจ `max_tokens`๋ฅผ ์ฌ์ฉํฉ๋๋ค. YAML์ `.inf`, `-.inf`, `.nan`, ๊ทธ๋ฆฌ๊ณ ๋ฌธ์ ์ ์ถ์ ์ ๋นํด ๋๋ฌด ํฐ ๊ฐ์ ํฌํจํ์ฌ ์ ํ์ด ์๊ฑฐ๋ ์ฌ์ฉํ ์ ์๋ ๊ฒฝ์ฐ์๋, ๋๊ตฌ ์กฐ๋ฆฝ์ ์คํจ์ํค์ง ์๊ณ ์ด ํํธ๋ฅผ ์๋ตํฉ๋๋ค. ํ๋ก๋ฐ์ด๋๋ณ ๋ชจ๋ธ ๊ฒ์ฆ์ ๊ทธ๋๋ก ์ ์ฉ๋ฉ๋๋ค.
OpenAI ๋ชจ๋ธ์ `/v1/responses`๋ก ๋ผ์ฐํ
ํ๋ ค๋ฉด ๊ณ์ `langchain_openai:ChatOpenAI`๋ฅผ ์ฌ์ฉํ๊ณ `use_responses_api: true`์ `output_version: responses/v1`์ ์ค์ ํ์ธ์.
๋ ๊ฑฐ์ ํ๋กํ์์ thinking์ด ๋นํ์ฑํ๋์ด ์์ผ๋ฉด, `when_thinking_enabled` ํ
ํ๋ฆฟ ์์ ๋น์ด ์๋ `extra_body`, `thinking`, ์ค์ฒฉ๋ `extra_body.thinking` ํค๋ ๋ฐฉ์ธ(dialect) ์ถ๋ก ์ ์๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผ๋ฉ๋๋ค. thinking์ด ํ์ฑํ๋์ด ์์ผ๋ฉด ํ
ํ๋ฆฟ ๊ฐ์ด ์ค์ ๋ ๊ทธ๋๋ก ์ ๋ฌ๋ฉ๋๋ค.
ํ๋ก๋ฐ์ด๋ ๊ณ์ฝ์ด DeerFlow์ ์ผ๋ฐ์ ์ธ thinking/effort ๊ฐ์ ๊ณผ ๋ค๋ฅธ ๋ชจ๋ธ์ ๋ชจ๋ธ๋ณ๋ก ๋งคํ ๊ฐ ํํ์ `reasoning:` ๋ธ๋ก(thinking `unsupported`/`optional`/`required`, ๋ณ์นญ๊ณผ ๊ธฐ๋ณธ๊ฐ์ ํฌํจํ ํ์ฉ effort ๊ฐ, ํ์ด๋ก๋ ๋ฐฉ์ธ, reasoning ํ์คํ ๋ฆฌ ์๊ตฌ ์ฌํญ)์ ์ ์ธํ ์ ์์ต๋๋ค. ์ค์ ๋ง๋ฒ์ฌ์ Z.AI GLM-5.3-Flash ํ๋กํ์ด ์ด๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ชจ๋ ํฌ๊ทธ๋ผ์ด๋ ๋ฐ ๋ฐฑ๊ทธ๋ผ์ด๋ ํธ์ถ์์ thinking์ด ์ผ์ง ์ํ๋ก ์ ์ง๋๋ฉฐ, effort ์ ํ๊ธฐ๋ ๋ชจ๋ธ ๊ณ ์ ์ `low`/`high`/`max` ๋จ๊ณ๋ฅผ ์ ๊ณตํฉ๋๋ค. Ollama์ ๊ธฐ์กด ๋ถ๋ฆฌ์ธ `reasoning: true`๋ ๊ณ์ ๋ค์ดํฐ๋ธ ํ๋ก๋ฐ์ด๋ ์ค์ ์ด๋ฉฐ ChatOllama๋ก ์ ๋ฌ๋ฉ๋๋ค. ํ๋กํ์ ์ปค์คํ
effort `path`๋ก ๋ง์ด๊ทธ๋ ์ด์
ํ ๋๋ ํ๋กํ๊ณผ thinking ํ
ํ๋ฆฟ์์ ๊ธฐ์กด `reasoning_effort` ์ค์ ์ ์ ๊ฑฐํ์ธ์. ์ค์ ๊ฒ์ฆ์ ๋จ์ ์๋ ํค๋ฅผ ๊ฑฐ๋ถํฉ๋๋ค. ์ฑํ
UI๋ ๊ธฐ์ต๋ ํ๋ก๋ฐ์ด๋๋ณ effort๋ฅผ ์ง์ํ์ง ์๋ ๋ ๊ฑฐ์ ๋ชจ๋ธ๋ก ์ ํํ๋ฉด ํด๋น effort๋ฅผ ๋ฒ๋ฆฝ๋๋ค. ์ด ๋ธ๋ก์ด ์๋ ํ๋กํ์ ๊ธฐ์กด ํ๋ก๋ฐ์ด๋ ๋์์ ์ ์งํฉ๋๋ค. ํ์๊ณผ ๊ทธ์ ์์ํ๋ ์๋ ์ค์ ์ `config.example.yaml`์ ์ฐธ๊ณ ํ์ธ์.
vLLM 0.19.0์๋ `deerflow.models.vllm_provider:VllmChatModel`์ ์ฌ์ฉํ์ธ์. Qwen ๊ณ์ด ์ถ๋ก ๋ชจ๋ธ์ ๊ฒฝ์ฐ DeerFlow๋ `extra_body.chat_template_kwargs.enable_thinking`์ผ๋ก ์ถ๋ก ์ ์ผ๊ณ ๋๋ฉฐ, ์ฌ๋ฌ ํด์ ๊ฑธ์น ๋๊ตฌ ํธ์ถ ๋ํ์์ vLLM์ ๋นํ์ค `reasoning` ํ๋๋ฅผ ๋ณด์กดํฉ๋๋ค. ๋ ๊ฑฐ์ `thinking` ์ค์ ์ ํ์ ํธํ์ฑ์ ์ํด ์๋์ผ๋ก ์ ๊ทํ๋๋ฉฐ, ๋ชจ๋ธ ๊ธฐ๋ณธ๊ฐ์ด๋ ํธ์ถ์๊ฐ ์์ ํ `extra_body` ๋์
๋๋ฆฌ๋ ์์ ํ์ง ์์ต๋๋ค. ์ฌ์ฌ์ฉ๋ ๋์
๋๋ฆฌ๋ ์์ฒญ ์ฌ์ด์ ๋ ๊ฑฐ์ ์ค์์น๋ฅผ ๋ฐ๊ฟ ์ ์์ต๋๋ค. ์๋ํฌ์ธํธ๊ฐ ๋ชจ๋ ์คํธ๋ฆฌ๋ฐ ์ฒญํฌ๋ง๋ค ๋์ ์ฌ์ฉ๋ ์ค๋
์ท์ ๋ณด๊ณ ํ๋ค๋ฉด `cumulative_stream_usage: true`๋ฅผ ์ค์ ํ์ฌ DeerFlow๊ฐ ํด๋น ์ค๋
์ท์ ์ฒญํฌ๋ณ ์ฆ๋ถ์ผ๋ก ๋ณํํ๋๋ก ํ์ธ์. ์ด ์ต์
์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋นํ์ฑํ๋์ด ์์ผ๋ฉฐ, ์์ ์ ์ธ completion id๋ฅผ ์ฌ์ฉํ ์ ์์ ๋๋ ์ฌ์ฉ๋์ ๋ณ๊ฒฝํ์ง ์์ต๋๋ค. ์ถ๋ก ๋ชจ๋ธ์ ์๋ฒ๋ฅผ `--reasoning-parser ...`๋ก ์์ํด์ผ ํ ์๋ ์์ต๋๋ค. ๋ก์ปฌ vLLM ๋ฐฐํฌ๊ฐ ๋น์ด ์์ง ์์ ์ด๋ค API ํค๋ ๋ฐ์๋ค์ธ๋ค๋ฉด, `VLLM_API_KEY`์ ์๋ฆฌ ํ์์ ๊ฐ์ ์ค์ ํด๋ ๋ฉ๋๋ค.
`deerflow.models.claude_provider:ClaudeChatModel`๋ก ์ค์ ๋ ๋ชจ๋ธ์์ ํ๋กฌํํธ ์บ์ฑ์ด ํ์ฑํ๋๋ฉด, DeerFlow๋ thinking ๋ฐ redacted-thinking ํ์คํ ๋ฆฌ๋ฅผ ๋ณด์กดํ๋ฉด์ ํด๋น ๋ธ๋ก์ ์ง์ ์บ์ ๋ธ๋ ์ดํฌํฌ์ธํธ๋ฅผ ๋์ง ์์ต๋๋ค. ํ์ฅ thinking์ ๋๊ตฌ ํ์ ํธ์ถ์์๋ ๊ณ์ ํ๋กฌํํธ ์บ์ฑ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
CLI ๊ธฐ๋ฐ ํ๋ก๋ฐ์ด๋ ์์:
```yaml
models:
- name: gpt-5.4
display_name: GPT-5.4 (Codex CLI)
use: deerflow.models.openai_codex_provider:CodexChatModel
model: gpt-5.4
supports_thinking: true
supports_reasoning_effort: true
- name: claude-sonnet-4.6
display_name: Claude Sonnet 4.6 (Claude Code OAuth)
use: deerflow.models.claude_provider:ClaudeChatModel
model: claude-sonnet-4-6
max_tokens: 4096
supports_thinking: true
```
`ClaudeChatModel`์ `auto_thinking_budget: true`(๊ธฐ๋ณธ๊ฐ)์ผ ๋ ์๋ ํ์ฅ thinking ์์ฐ์ ์ ๊ทํํฉ๋๋ค. ์์ฐ์ ์๋ตํ๊ฑฐ๋ null๋ก ๋๋ฉด `max_tokens`์ 80%๊ฐ ํ ๋น๋๋ฉฐ, ์ต์๊ฐ์ 1024 ํ ํฐ์
๋๋ค. ๋ช
์์ ์ธ ์์ฐ์ 1024 ์ด์์ ์ ์์ฌ์ผ ํ๊ณ , ์ผ๋ฐ thinking์ ๊ฒฝ์ฐ `max_tokens`๋ณด๋ค ์๊ฒฉํ ์์์ผ ํฉ๋๋ค. ์ถ๋ ฅ ์ ํ์ด 1024 ์ดํ์ด๋ฉด ๋ก์ปฌ์์ ์คํจํฉ๋๋ค. ์ง์๋๋ ์๋ interleaved thinking์ ๊ฒฝ์ฐ ๋๊ตฌ์ `betas: ["interleaved-thinking-2025-05-14"]`๋ฅผ ์ค์ ํ์ธ์. ์ด๋ thinking ์์ฐ์ ์์์ธ ์ถ๋ ฅ ์ ํ๊ณผ ๊ฐ๊ฑฐ๋ ์ด๋ฅผ ์ด๊ณผํ ์ ์์ต๋๋ค. ์ง์๋๋ ๋ชจ๋ธ์ [Anthropic์ interleaved-thinking ๊ท์น](https://platform.claude.com/docs/en/build-with-claude/extended-thinking#interleaved-thinking-in-manual-mode)์ ์ฐธ๊ณ ํ์ธ์. `auto_thinking_budget: false`๋ ์ด ์ ๊ทํ์ ๊ฒ์ฆ์ ์ฐํํ๋ฉฐ, ๋นํ์ฑํ๋ thinking๊ณผ adaptive thinking์ ๋ณ๊ฒฝ๋์ง ์์ต๋๋ค.
- Codex CLI๋ `~/.codex/auth.json`์ ์ฝ์ต๋๋ค
- Codex ํจ์ ๋๊ตฌ๋ ๋ํ๋ ํํ๋ ํํํ ๋์
๋๋ฆฌ ์ ์์ ๋ช
์๋ `strict: true` ๋๋ `strict: false`๋ฅผ ๋ณด์กดํฉ๋๋ค. ์ค์ ์ด ์๊ฑฐ๋ null์ด๋ฉด ํ๋ก๋ฐ์ด๋ ๊ธฐ๋ณธ๊ฐ์ ์ ์งํฉ๋๋ค. `bind_tools`๋ ๋์
๋๋ฆฌ์ `BaseTool` ์คํค๋ง์ ๊ฐ์ ๋ณํ์ ์ ์ฉํฉ๋๋ค.
- Codex๋ `bind_tools`์ ์ง์ ํธ์ถ์์ `tool_choice`๋ฅผ ๋ฐ๋ฆ
๋๋ค. ๊ฐ์ `auto`, `none`, `required`, ๋๋ ํจ์ ์ด๋ฆ/์ ํ์
๋๋ค. `any`์ `True`๋ `required`๋ฅผ ์๋ฏธํ๊ณ , `None`๊ณผ `False`๋ ํ๋ก๋ฐ์ด๋ ๊ธฐ๋ณธ๊ฐ์ ์ ์งํฉ๋๋ค. ํธ์ถ๋ณ ์ ํ์ ๋ฐ์ธ๋ฉ๋ ์ ์ฑ
์ ์ฌ์ ์ํฉ๋๋ค. ๋ฐ์ธ๋ฉ๋ ์ ํ์ ๋ฐ์ธ๋ฉ ์์ ์ ๊ฒ์ฆ๋๊ณ , ์ง์ ํธ์ถ๊ณผ ์ฌ์ ์๋ HTTP ์์ฒญ ์ ์ ๊ฒ์ฆ๋ฉ๋๋ค. `required`์๋ ํจ์ ๋๊ตฌ๊ฐ ํ๋ ์ด์ ํ์ํ๋ฉฐ, ์ด๋ฆ์ผ๋ก ์ง์ ํ ์ ํ์ ์ ๊ณต๋ ํจ์์ ์ผ์นํด์ผ ํฉ๋๋ค. `auto`์ `none`์ ๋๊ตฌ ์์ด๋ ๋์ํฉ๋๋ค.
- ์๋ฃ๋ Codex ์๋ต์ ํ ํฐ ์ฌ์ฉ๋์ด null์ด๊ฑฐ๋, ์๋ต๋์๊ฑฐ๋, ๋น์ด ์์ด๋ ํ
์คํธ์ ๋๊ตฌ ํธ์ถ์ ๊ทธ๋๋ก ๋ฐํํ๋ฉฐ, ์ฌ์ฉ๋ ๋ฉํ๋ฐ์ดํฐ๋ ์ ๊ณต๋์ง ์์ต๋๋ค.
- Codex ๋ชจ๋ธ ํ๋ก๋ฐ์ด๋๋ SSE ์ฐ๊ฒฐ์ด ๋ซํ๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ์๋ฃ๋ ์๋ต์ ๋ฐํํฉ๋๋ค. ์คํจํ๊ฑฐ๋ ๋ถ์์ ํ ์๋ต์ ํ๋ก๋ฐ์ด๋์ ์ค๋ฅ๋ ์ฌ์ ๋ฅผ ๋ณด๊ณ ํ๋ฉฐ, ๋ถ๋ถ ์ถ๋ ฅ์ ์ฑ๊ณตํ ๋ต๋ณ์ผ๋ก ๋ฐํ๋์ง ์์ต๋๋ค. ๊ฐ์ฒด๊ฐ ์๋ ์ค๋ฅ ์ธ๋ถ ์ ๋ณด๋ ํ
์คํธ๋ก ๋ณด๊ณ ๋ฉ๋๋ค.
- Claude Code๋ `CLAUDE_CODE_OAUTH_TOKEN`, `ANTHROPIC_AUTH_TOKEN`, `CLAUDE_CODE_CREDENTIALS_PATH`, ๋๋ `~/.claude/.credentials.json`์ ๋ฐ์๋ค์
๋๋ค
- `CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR`๋ UTF-8 ํ ํฐ ์ธ๊ณ(handoff)๋ฅผ ๋ฐ์๋ค์ด๊ณ , ๊ฐ์ ํ๋ก์ธ์ค์ ์ดํ ๋ชจ๋ธ ์ธ์คํด์ค์์ ์ด๋ฅผ ์ฌ์ฌ์ฉํฉ๋๋ค. ๋์ฝ๋ฉํ ์ ์๋ ์ธ๊ณ๋ ๊ฑด๋๋ฐ๋ฏ๋ก, Claude Code๋ ์ฌ์ ํ ์ฌ์ ์๋ ์๊ฒฉ ์ฆ๋ช
ํ์ผ์ด๋ ๊ธฐ๋ณธ ์๊ฒฉ ์ฆ๋ช
ํ์ผ์ ์๋ํ ์ ์์ต๋๋ค.
- CLI ์๊ฒฉ ์ฆ๋ช
JSON ํ์ผ์ ํธ์คํธ ๋ก์ผ์ผ๊ณผ ๊ด๊ณ์์ด, BOM์ด ์๋ ์๋ UTF-8์ ๋ฐ์๋ค์
๋๋ค. `make doctor`๋ CLI ์ธ์ฆ์ ๊ฒ์ฌํ ๋ ๊ฐ์ ํ์ผ์ ๋ฐ์๋ค์
๋๋ค. ์๋ชป๋ ํ
์คํธ ์ธ์ฝ๋ฉ์ ์ฝ์ ์ ์๋ ์์ค๋ก ์ทจ๊ธ๋๋ฉฐ, ์ฌ์ ์ ํ์ผ์ด ์๋ชป๋์๋๋ผ๋ Claude Code๋ ๊ธฐ๋ณธ ํ์ผ์ ์๋ํ ์ ์์ต๋๋ค.
- ACP ์์ด์ ํธ ํญ๋ชฉ์ ๋ชจ๋ธ ํ๋ก๋ฐ์ด๋์ ๋ณ๊ฐ์
๋๋ค. `acp_agents.codex`๋ฅผ ์ค์ ํ๋ค๋ฉด `npx -y @zed-industries/codex-acp` ๊ฐ์ Codex ACP ์ด๋ํฐ๋ฅผ ๊ฐ๋ฆฌํค๋๋ก ํ์ธ์
- ๊ฒฝ๋ก๊ฐ ์๋ ์ด๋ฆ์ด๋ ์ ๋ ๊ฒฝ๋ก๋ก ์ง์ ๋ ACP ์์ด์ ํธ `command`๋ ์์ด์ ํธ๊ฐ ์์๋๊ธฐ ์ ์ ํด์๋๋ฏ๋ก, npm์ผ๋ก ์ค์นํ ๋ฐ์ฒ๋ Windows์์ ๋์ํฉ๋๋ค. `npx`๋ `mcode`๋ command-not-found ์ค๋ฅ๋ก ์คํจํ๋ ๋์ ํด๋น `npx.cmd`/`mcode.cmd` shim์ผ๋ก ์คํ๋๋ฉฐ, `C:\Users\me\AppData\Roaming\npm\mcode` ๊ฐ์ ์ ๋ ๊ฒฝ๋ก๋ npm์ ํ์ฅ์ ์๋ ์
ธ ์คํฌ๋ฆฝํธ ์์ ์๋ `mcode.cmd` shim์ผ๋ก ํด์๋๋ฏ๋ก `WinError 193`์ผ๋ก ์คํจํ์ง ์์ต๋๋ค. ์กฐํ์๋ ์์ด์ ํธ ํ์ ํ๋ก์ธ์ค๊ฐ ์ค์ ๋ก ๋ณด๊ฒ ๋ `PATH`(์ค์ ๋์ด ์์ผ๋ฉด `acp_agents..env.PATH`, ๊ทธ๋ ์ง ์์ผ๋ฉด Gateway์ ๊ฒ)๋ฅผ ์ฌ์ฉํ๊ณ , ์คํ ์ ์ ๋ ๊ฒฝ๋ก๋ฅผ ๋๊ธฐ๋ฏ๋ก ์๋ `PATH` ํญ๋ชฉ์ด ์์ด์ ํธ ์์ ์ ์ํฌ์คํ์ด์ค ์์์ ๋ค๋ฅด๊ฒ ํด์๋ ์ ์์ต๋๋ค. ์๋ `command`(์: `bin/mcode`)๋ ์ค์ ๋ ๊ทธ๋๋ก ์ฌ์ฉ๋๋ฉฐ, ํด์ํ ์ ์๋ ๋ช
๋ น์ ์ฌ์ ํ ์๋์ ์ค์น ์๋ด์ ํจ๊ป ๋ณด๊ณ ๋ฉ๋๋ค.
- ๊ฐ ACP ์์ด์ ํธ์ `timeout_seconds`(๊ธฐ๋ณธ๊ฐ: 1800)๋ ์ด๊ธฐํ, ์ธ์
์์ฑ, ํ๋กฌํํธ์ ๊ณตํต์ผ๋ก ์ ์ฉ๋๋ ํ๋์ ์์ฐ์ด๋ฉฐ, ํ์ ํ๋ก์ธ์ค๊ฐ ์์๋ ๋ค๋ถํฐ ๊ณ์ฐ๋ฉ๋๋ค. ํ์์์์ด ๋ฐ์ํ๋ฉด DeerFlow๋ ํธ์ถ์ ์ค๋จํ๊ณ ํ์ ํ๋ก์ธ์ค๋ฅผ ๋ซ์ ๋ค ์ค๋ฅ๋ฅผ ๋ฐํํฉ๋๋ค. ์ํฌ์คํ์ด์ค/MCP ์ค๋น์ ํ์ ํ๋ก์ธ์ค ์ ๋ฆฌ๋ ์ด ์์ฐ์ ํฌํจ๋์ง ์์ต๋๋ค. ์ด ๊ธฐํ์ด ๋ง๋ฃ๋๊ธฐ ์ ์ SDK๊ฐ ๋ฐ์์ํจ `TimeoutError`๋ ์์ฒด ์ค๋ฅ ๋ฉ์์ง๋ฅผ ์ ์งํฉ๋๋ค.
- MiniMax Code๋ ACP๋ฅผ ์ง์ ์ง์ํฉ๋๋ค. ์ค์นํ๊ณ ์ธ์ฆํ ๋ค ACP ์์ด์ ํธ๋ก ์ถ๊ฐํ์ธ์:
```bash
npm install --global @minimax-ai/code
mcode login
```
```yaml
acp_agents:
mcode:
command: mcode
args: ["acp"]
description: MiniMax Code for implementation, refactoring, debugging, and repository tasks
auto_approve_permissions: false
```
`mcode`๋ Gateway ํ๋ก์ธ์ค์ `PATH`์ ์์ด์ผ ํฉ๋๋ค. Docker ํธ์คํธ์๋ง ์ค์นํด์๋ Gateway ์ปจํ
์ด๋ ์์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. DeerFlow๋ ์ค๋ ๋๋ณ ACP ์ํฌ์คํ์ด์ค์์ `invoke_acp_agent`๋ฅผ ํตํด ์ด๋ฅผ ํธ์ถํ๋ฉฐ, ํ์ฑํ๋ MCP ์๋ฒ๋ฅผ ์ ๋ฌํฉ๋๋ค. ์ ๋ขฐํ ์ ์๋ ์์
์์๋ `auto_approve_permissions: false`๋ฅผ ์ ์งํ์ธ์. mcode๊ฐ ํ์ผ์ ํธ์งํ๊ฑฐ๋ ๋ช
๋ น์ ์คํํด์ผ ํ๊ณ ๊ทธ ์์
์ ์ ๋ขฐํ ์ ์์ ๋๋ง ํ์ฑํํ์ธ์.
- macOS์์๋ ํ์ํ๋ฉด Claude Code ์ธ์ฆ ์ ๋ณด๋ฅผ ๋ช
์์ ์ผ๋ก exportํ์ธ์:
```bash
eval "$(python3 scripts/export_claude_code_oauth.py --print-export)"
```
์ด ๋ด๋ณด๋ด๊ธฐ ๋๊ตฌ๋ ํ ํฐ์ ์ถ๋ ฅํ๊ฑฐ๋, ์
ธ export๋ฅผ ๋ด๋ณด๋ด๊ฑฐ๋, ์๊ฒฉ ์ฆ๋ช
ํ์ผ์ ์์ฑํ๊ธฐ ์ ์ ํ์์ด ์๋ชป๋ ์๊ฒฉ ์ฆ๋ช
์ปจํ
์ด๋์ ๋ฌธ์์ด์ด ์๋๊ฑฐ๋ ๋น์ด ์๋ ์ก์ธ์ค ํ ํฐ์ ๊ฑฐ๋ถํฉ๋๋ค. ์ ํจํ ํ ํฐ์ ๋ณ๊ฒฝ ์์ด export๋๋ฉฐ, ํ์ผ๋ก ๋ด๋ณด๋ผ ๋๋ ์๊ฒฉ ์ฆ๋ช
์ปจํ
์ด๋ ์ ์ฒด๋ฅผ ๋ณด์กดํฉ๋๋ค.
API ํค๋ `.env`์ ์ง์ ์ค์ ํ๊ฑฐ๋(๊ถ์ฅ) ์
ธ์์ exportํ ์๋ ์์ต๋๋ค:
```bash
OPENAI_API_KEY=your-openai-api-key
TAVILY_API_KEY=your-tavily-api-key
```
๋ช
์์ ์ธ ๋ฐฑ์๋ dotenv ํ์ผ์ ์ฌ์ฉํ๋ ค๋ฉด, ์์ ์ ์ `DEER_FLOW_ENV_FILE`์ exportํ๊ณ , ํ์ํ๋ฉด `DEER_FLOW_CONFIG_PATH`๋ ํจ๊ป exportํ์ธ์. ์๋ฅผ ๋ค์ด `backend/`์์ ๋ค์๊ณผ ๊ฐ์ด ์คํํฉ๋๋ค:
```bash
DEER_FLOW_ENV_FILE=/srv/deer-flow/stage.env DEER_FLOW_CONFIG_PATH=/srv/deer-flow/stage.yaml make gateway
```
์๋ dotenv ๊ฒฝ๋ก๋ ๋ฐฑ์๋ ํ๋ก์ธ์ค์ ์์
๋๋ ํฐ๋ฆฌ๋ฅผ ๊ธฐ์ค์ผ๋ก ํ๋ฉฐ, ์ ๋ ๊ฒฝ๋ก๋ ํด๋น ๋๋ ํฐ๋ฆฌ์ ๊ด๊ณ์์ด ๋์ํฉ๋๋ค. ์ด๋ฏธ ์กด์ฌํ๋ ํ๋ก์ธ์ค ๋ณ์๊ฐ ์ฐ์ ํฉ๋๋ค. ์ ํ ๋ณ์๋ฅผ ์ค์ ํ์ง ์์ผ๋ฉด ๊ธฐ๋ณธ dotenv ํ์์ด ์ ์ง๋๋ฉฐ, ์ง์ ๋ ๊ฒฝ๋ก๊ฐ ๋น์ด ์๊ฑฐ๋, ์กด์ฌํ์ง ์๊ฑฐ๋, ํ์ผ์ด ์๋๊ฑฐ๋, ์ฝ์ ์ ์์ผ๋ฉด ์์์ด ์คํจํฉ๋๋ค. `PYTHON_DOTENV_DISABLED`๊ฐ dotenv ๋ก๋ฉ์ ๋นํ์ฑํํ๋ ๊ฒฝ์ฐ์๋ ๋ช
์์ ์ ํ์ ์คํจํฉ๋๋ค. ํ์ผ์ ๋ณ๊ฒฝํ ๋ค์๋ ์ฌ์์ํ์ธ์. ์ด ์ค์ ์ ๋ฐฑ์๋ dotenv ์
๋ ฅ๋ง ์ ํํฉ๋๋ค. ์
ธ ๋ฐ์ฒ, Docker Compose, ํ๋ก ํธ์๋๋ ๊ฐ์์ ํ๊ฒฝ ๋ก๋ฉ ๋ฐฉ์์ ์ ์งํ๋ฉฐ, ์ด๋ค์ด ์ด๋ฏธ exportํ ๊ฐ์ด ์ฐ์ ํฉ๋๋ค. `ENV` ํ๋กํ์ ์ ํํ๊ฑฐ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค, ์ ์ฅ์, ํ
๋ํธ๋ฅผ ๊ฒฉ๋ฆฌํ์ง๋ ์์ต๋๋ค. [๋ฐฑ์๋ dotenv ์ ํ](backend/docs/CONFIGURATION.md#backend-dotenv-selection)์ ์ฐธ๊ณ ํ์ธ์.
### ์ ํ๋ฆฌ์ผ์ด์
์คํ
#### ๋ฐฐํฌ ๊ท๋ชจ ์ฐ์
DeerFlow๋ฅผ ์คํํ ๋ฐฉ์์ ๊ณ ๋ฅผ ๋ ์๋ ํ๋ฅผ ์ค์ฉ์ ์ธ ์ถ๋ฐ์ ์ผ๋ก ์ผ์ผ์ธ์.
| ๋ฐฐํฌ ๋์ | ์์ ์ฌ์ | ๊ถ์ฅ | ๋น๊ณ |
|---------|-----------|------------|-------|
| ๋ก์ปฌ ํ๊ฐ / `make dev` | 4 vCPU, 8 GB RAM, 20 GB ์ฌ์ SSD | 8 vCPU, 16 GB RAM | ํธ์คํ
ํ ๋ชจ๋ธ API๋ฅผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์ ํ ๋ช
๋๋ ๊ฐ๋ฒผ์ด ์ธ์
ํ๋์ ์ ํฉํฉ๋๋ค. `2 vCPU / 4 GB`๋ก๋ ๋๊ฐ ๋ถ์กฑํฉ๋๋ค. |
| Docker ๊ฐ๋ฐ / `make docker-start` | 4 vCPU, 8 GB RAM, 25 GB ์ฌ์ SSD | 8 vCPU, 16 GB RAM | ์ด๋ฏธ์ง ๋น๋, ๋ฐ์ธ๋ ๋ง์ดํธ, ์๋๋ฐ์ค ์ปจํ
์ด๋์๋ ์์ ๋ก์ปฌ ๊ฐ๋ฐ๋ณด๋ค ๋ ๋ง์ ์ฌ์ ์์์ด ํ์ํฉ๋๋ค. |
| ์ฅ๊ธฐ ์คํ ์๋ฒ / `make up` | 8 vCPU, 16 GB RAM, 40 GB ์ฌ์ SSD | 16 vCPU, 32 GB RAM | ๊ณต์ ์ฌ์ฉ, ๋ฉํฐ ์์ด์ ํธ ์คํ, ๋ณด๊ณ ์ ์์ฑ, ๋๋ ๋ ๋ฌด๊ฑฐ์ด ์๋๋ฐ์ค ์ํฌ๋ก๋์ ๊ถ์ฅ๋ฉ๋๋ค. |
- ์ด ์์น๋ DeerFlow ์์ฒด๋ง์ ๊ธฐ์ค์ผ๋ก ํฉ๋๋ค. ๋ก์ปฌ LLM๋ ํจ๊ป ํธ์คํ
ํ๋ค๋ฉด ๊ทธ ์๋น์ค์ ์ฌ์์ ๋ณ๋๋ก ์ฐ์ ํ์ธ์.
- ์์ ์ด์ ์๋ฒ์๋ Linux์ Docker ์กฐํฉ์ ๊ถ์ฅํฉ๋๋ค. macOS์ Windows๋ ๊ฐ๋ฐ ๋๋ ํ๊ฐ ํ๊ฒฝ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ข์ต๋๋ค.
- CPU๋ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ฅ ์ด ๊ณ์ ์ต๋์น์ ๋จธ๋ฌธ๋ค๋ฉด ๋จผ์ ๋์ ์คํ ์๋ฅผ ์ค์ด๊ณ , ๊ทธ๋ค์ ํ ๋จ๊ณ ์์ ์ฌ์์ผ๋ก ์ฎ๊ธฐ์ธ์.
#### ์ต์
1: Docker (๊ถ์ฅ)
Docker Desktop / Docker Engine๊ณผ **Docker Compose v2.24 ์ด์**(`docker compose version`)์ด ํ์ํฉ๋๋ค. ์ด์ ๋ฒ์ ์ Compose ํด๋ผ์ด์ธํธ๋ `docker/docker-compose.yaml`๊ณผ `docker/docker-compose-dev.yaml`์ ์ฐ์ธ ์ ํ์ `env_file` ๋ฌธ๋ฒ์ ํด์ํ์ง ๋ชปํฉ๋๋ค.
**๊ฐ๋ฐ**(ํซ ๋ฆฌ๋ก๋, ์์ค ๋ง์ดํธ):
```bash
make docker-init # Pull sandbox image (only once or when image updates)
make docker-start # Start services (auto-detects sandbox mode from config.yaml)
make docker-logs # View logs
```
`make docker-start`๋ `config.yaml`์ด provisioner ๋ชจ๋(`sandbox.use: deerflow.community.aio_sandbox:AioSandboxProvider`์ `provisioner_url` ์ฌ์ฉ)๋ฅผ ์ฐ๋ ๊ฒฝ์ฐ์๋ง `provisioner`๋ฅผ ์์ํฉ๋๋ค.
Docker ๋น๋๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์
์คํธ๋ฆผ `uv` ๋ ์ง์คํธ๋ฆฌ๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๊ฒ์ดํธ์จ์ด ์ด๋ฏธ์ง๋ `uv sync --locked`๋ก ์ค์นํ๊ณ `uv.lock`์ `https://pypi.org/simple`๋ฅผ ๊ณ ์ ํ๋ฏ๋ก, `UV_INDEX_URL`์ ์ด ๊ฐ์ ์ ์งํด์ผ ํฉ๋๋ค. `https://pypi.tuna.tsinghua.edu.cn/simple` ๊ฐ์ ๋ฏธ๋ฌ๋ฅผ exportํ๋ฉด ``The lockfile at `uv.lock` needs to be updated, but `--locked` was provided`` ์ค๋ฅ๋ก ๋น๋๊ฐ ์คํจํฉ๋๋ค(์ด๋ฏธ ๋๊ธฐํ๋ ํ๊ฒฝ์์ `cd backend && UV_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple uv sync --locked --check`๋ก ์ฌํ ๊ฐ๋ฅ; ํ๊ฒฝ ์์ฒด๊ฐ ์ค๋๋ ๊ฒฝ์ฐ์๋ ์ด๋ค ์ธ๋ฑ์ค์์๋ ํ๊ฒฝ ๊ฐฑ์ ๋ง ์๋ดํ๋ฏ๋ก, ๋๊ธฐํ ์์ด ํ์ธํ๋ ค๋ฉด `uv lock --check`๋ฅผ ์ฌ์ฉํ์ธ์). ๋ฏธ๋ฌ์์ ์ค์นํ๋ ค๋ฉด lock์ ๋ค์ ์์ฑํ๊ฑฐ๋ `--locked`๋ฅผ ์ ๊ฑฐํด์ผ ํ๋ฉฐ, ๋ ๋ค ์ด๋ฏธ์ง์ ์ค์น๋๋ ๋ด์ฉ์ด ๋ฌ๋ผ์ง๋ฏ๋ก ๊ธฐ์ฌํ ์ฒดํฌ์์์์๋ ๊ธฐ๋ณธ ์ธ๋ฑ์ค๋ฅผ ์ ์งํ์ธ์. `NPM_REGISTRY=https://registry.npmmirror.com`์ ์ด์ ๋ฌด๊ดํ๋ฉฐ, ํ๋ก ํธ์๋ ์ด๋ฏธ์ง์ `pnpm` ์ค์น์ ๊ฒ์ดํธ์จ์ด ์ด๋ฏธ์ง์ Lark CLI ์ค์น(`backend/Dockerfile`์ด npm์ผ๋ก ์ค์นํ๋ `@larksuite/cli`)์ ์ ์ฉ๋ฉ๋๋ค.
๋ก์ปฌ AIO ์๋๋ฐ์ค์ ์ ์ด ํธ๋ํฝ์ ํญ์ ์ง์ ์ฐ๊ฒฐ๋ฉ๋๋ค. ๋ฃจํ๋ฐฑ/์ฌ์ค ์ฃผ์, ๋จ์ผ ๋ ์ด๋ธ ํด๋ฌ์คํฐ ํธ์คํธ, Docker/Podman ๋ด๋ถ ํธ์คํธ ์ด๋ฆ์ `HTTP_PROXY`๋ `HTTPS_PROXY`๋ฅผ ์์ํ์ง ์์ต๋๋ค. ์ธ๋ถ ์๋๋ฐ์ค FQDN๊ณผ ๊ณต์ธ IP๋ ์ฌ์ ํ ํ๊ฒฝ ๋ณ์์ ํ๋ก์ ์ค์ ์ ๋ฐ๋ฆ
๋๋ค.
๋ฐฑ์๋ ํ๋ก์ธ์ค๋ ๋ค์ ์ค์ ์ ๊ทผ ์ `config.yaml` ๋ณ๊ฒฝ ์ฌํญ์ ์๋์ผ๋ก ๋ฐ์ํ๋ฏ๋ก, ๊ฐ๋ฐ ์ค ๋ชจ๋ธ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์
๋ฐ์ดํธํ ๋ ์๋์ผ๋ก ์ฌ์์ํ ํ์๊ฐ ์์ต๋๋ค.
Gateway ์คํ(run)์ API ์์ฒญ์ด ๊ฐ์ ์ง์ ํ์ง ์์ ๊ฒฝ์ฐ ์ต์์ `recursion_limit` ๊ฐ(`config.yaml`์ ์ค์ )์ ์ฌ์ฉํฉ๋๋ค. ๊ธฐ๋ณธ๊ฐ์ `100`์ด๋ฉฐ, ์ ํจํ ์์ฒญ๋ณ ๊ฐ์ด ์ฐ์ ํ๊ณ `max_recursion_limit`(๊ธฐ๋ณธ๊ฐ `1000`)์ด ๋ ๊ฐ ๋ชจ๋์ ์ํ์ด ๋ฉ๋๋ค. ๋ณ๊ฒฝ ์ฌํญ์ Gateway๋ฅผ ์ฌ์์ํ์ง ์์๋ ๋ค์ ์คํ๋ถํฐ ์ ์ฉ๋ฉ๋๋ค. ์ด ์ต์์ ์ค์ ์ Gateway API ์คํ์ ์ ์ฉ๋๋ฉฐ, IM ์ฑ๋ ์คํ๊ณผ ์๋ฒ ๋๋ `DeerFlowClient` ์คํ์ ๊ฐ์์ ๊ธฐ๋ณธ๊ฐ๊ณผ ํธ์ถ๋ณ ์ฌ์ ์ ๊ฒฝ๋ก๋ฅผ ๊ทธ๋๋ก ์ ์งํฉ๋๋ค.
์ฒดํฌํฌ์ธํธ ์ ์ฅ์ ์ค์ ์ธ `database.checkpoint_channel_mode`์ `database.checkpoint_delta.snapshot_frequency`(๊ธฐ๋ณธ๊ฐ `10`)๋ ์์ธ์
๋๋ค. ๋ ์ค์ ๋ชจ๋ ํ๋ก์ธ์ค๊ฐ ์ฒ์ ์์ด์ ํธ๋ฅผ ๋น๋ํ ๋(`DeerFlowClient`๋ฅผ ํตํ ๊ฒฝ์ฐ ํฌํจ) ๊ณ ์ ๋๋ฏ๋ก, ์์ ํ๊ฒ ๋ณ๊ฒฝํ๋ ค๋ฉด ํ๋ก์ธ์ค๋ฅผ ์ฌ์์ํด์ผ ํฉ๋๋ค.
์ ํ ์ฌํญ์ธ `database.checkpoint_cache` ์น์
(delta ์ฑ๋ ๋ชจ๋ ์ ์ฉ)์ ๊ตฌ์ฒดํ๋ ์ฒดํฌํฌ์ธํธ ์ด๋ ฅ์ ์บ์ํฉ๋๋ค. `type`์ `memory`(๊ธฐ๋ณธ๊ฐ) ๋๋ `redis`์ด๋ฉฐ, `max_entries: 0`์ผ๋ก ์ค์ ํ๋ฉด ์บ์๊ฐ ๋นํ์ฑํ๋ฉ๋๋ค. `redis` ๋ฐฑ์๋๋ Gateway/๋น๋๊ธฐ ๊ฒฝ๋ก ์ ์ฉ์ด๋ฉฐ, ๋๊ธฐ TUI/์๋ฒ ๋๋ ๊ฒฝ๋ก๋ `memory`๋ง ์ง์ํฉ๋๋ค. ์ด ์บ์๋ ์ฑ๋ฅ๋ง์ ์ํ ๊ฒ์ผ๋ก ๋นํ์ฑํํด๋ ๊ฒฐ๊ณผ๊ฐ ๋์ผํฉ๋๋ค. ๋ฐ๋ผ์ ๊ณ ์ ๋๋ ์ผ์ด ์์ผ๋ฉฐ, ํ๋์ ์ฒดํฌํฌ์ธํธ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๊ณต์ ํ๋ ์์ปค๋ค์ด ์๋ก ๋ค๋ฅธ ์บ์ ์ค์ ์ผ๋ก ์คํ๋์ด๋ ์์ ํฉ๋๋ค. Redis ์ค๋ ๋ ์ ๋ฆฌ๋ ์ค์ ๋ `key_prefix`๋ฅผ glob ๋ฉํ๋ฌธ์๊น์ง ํฌํจํด ๋ฆฌํฐ๋ด ํ
์คํธ๋ก ์ทจ๊ธํ๋ฏ๋ก, ์ญ์ ๋ ํด๋น ๋ค์์คํ์ด์ค์ ์ค๋ ๋ ์์์๋ง ์ด๋ฃจ์ด์ง๋๋ค.
> [!TIP]
> Linux์์ Docker ๊ธฐ๋ฐ ๋ช
๋ น์ด `permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock` ์ค๋ฅ๋ก ์คํจํ๋ค๋ฉด, ์ฌ์ฉ์๋ฅผ `docker` ๊ทธ๋ฃน์ ์ถ๊ฐํ๊ณ ๋ค์ ๋ก๊ทธ์ธํ ๋ค ์ฌ์๋ํ์ธ์. ์ ์ฒด ํด๊ฒฐ ๋ฐฉ๋ฒ์ [CONTRIBUTING.md](CONTRIBUTING.md#linux-docker-daemon-permission-denied)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
**ํ๋ก๋์
**(์ด๋ฏธ์ง๋ฅผ ๋ก์ปฌ์์ ๋น๋ํ๊ณ , ๋ฐํ์ ์ค์ ๊ณผ ๋ฐ์ดํฐ๋ฅผ ๋ง์ดํธ):
```bash
make up # Build images and start all production services
make down # Stop and remove containers
```
์ ์: http://localhost:2026
`make up`์ ์ฑ๊ณต์ ๋ณด๊ณ ํ๊ธฐ ์ ์ Gateway์ `/health` ์๋ํฌ์ธํธ๊ฐ ์๋ตํ ๋๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค. ์์ ๋๊ธฐ ์๊ฐ ์์ Gateway๊ฐ ์ ์ ์ํ๊ฐ ๋์ง ์์ผ๋ฉด ๋ฐฐํฌ๋ 0์ด ์๋ ์ฝ๋๋ก ์ข
๋ฃํ๊ณ ์ปจํ
์ด๋ ์ํ์ ์ต๊ทผ Gateway ๋ก๊ทธ๋ฅผ ์ถ๋ ฅํฉ๋๋ค. ํ๋ก๋์
์ด๋ฏธ์ง๋ ์ด๋ฏธ ๋น๋๋ ํ๊ฒฝ์์ ์์ํ๋ฉฐ, ์ปจํ
์ด๋ ์์ ์ Python ์์กด์ฑ์ ์ ๋ ํด์ํ๊ฑฐ๋ ์ค์นํ์ง ์์ต๋๋ค.
`make up`์ด `make docker-start` ์ดํ์ ์ฐ๊ธฐ ๋ถ๊ฐ๋ฅํ ๋ฐํ์ ํ ๋๋ ์ฝ์ ์ ์๋ ์์ ์ ์ฅ๋ ์ํฌ๋ฆฟ์ ๋ณด๊ณ ํ๋ฉด, ์ถ๋ ฅ๋ `sudo chown -R : ''` ๋ณต๊ตฌ ๋ช
๋ น์ ์คํํ ๋ค ์ฌ์๋ํ์ธ์. ์ด ๊ฒ์ฌ๋ ์
ธ์ด๋ `.env`์์ ์ง์ ํ ์ํฌ๋ฆฟ ์ฌ์ ์๋ฅผ ์กด์คํ๊ณ , ์ฝ์ ์ ์๋ ์ฝ๊ธฐ ์ ์ฉ ์ํฌ๋ฆฟ ํ์ผ์ ํ์ฉํ๋ฉฐ, ์ํฌ๋ฆฟ์ ์ฝ๊ฑฐ๋ ์์ฑํ์ง ์๊ณ ๋ `make down`์ ์ฌ์ฉํ ์ ์๊ฒ ๋ก๋๋ค.
์์ ์ ์ฅ์ด ํ์ํ ๋ฐฐํฌ์์๋ `database.backend`๋ฅผ `sqlite` ๋๋ `postgres`๋ก ์ค์ ํ์ธ์. ์ ํํ ๋ฐฑ์๋๋ LangGraph ์ฒดํฌํฌ์ธํฐ, LangGraph Store, DeerFlow ์ ํ๋ฆฌ์ผ์ด์
๋ฐ์ดํฐ๊ฐ ํจ๊ป ์ฌ์ฉํฉ๋๋ค. ๋ ์ด์ ๊ถ์ฅ๋์ง ์๋(deprecated) `checkpointer` ์น์
์ด ์์ผ๋ฉด ํ์ ํธํ์ฑ์ ์ํด ์์ ๋ ๊ฐ์ง๋ฅผ ์ฌ์ ์ํฉ๋๋ค.
Gateway๋ ์์ ์ ์ผ๋ถ ๊ธฐ์กด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํฅ์ ์ฃผ๋ ๋๋ฝ๋ run-change ์คํค๋ง๋ฅผ ์๋์ผ๋ก ๋ณต๊ตฌํฉ๋๋ค(#5516). ์ด ๋ณต๊ตฌ๋ ์คํ ์ด๋ ฅ๊ณผ ๊ธฐ์กด ๋ณ๊ฒฝ ์์น๋ฅผ ๋ณด์กดํ๋ฉฐ, ๋ณต๊ตฌ๋ฅผ ์ด์ ๋ฒ์ ์ผ๋ก ๋ค์ด๊ทธ๋ ์ด๋ํด๋ ๊ทธ ๋ฒ์ ์ ํ์ํ ์คํค๋ง์ ์์น๊ฐ ์ ์ง๋ฉ๋๋ค.
๊ฐ๋ฒผ์ด ๋จ์ผ ํ๋ก์ธ์ค ์ด๋ฒคํธ ์์ ์ ์ฅ์ ์ํด `run_events.backend: jsonl`์ ์ฌ์ฉํ๋ฉด ์ค ๊ตฌ๋ถ์์ ๋จ๋ฝ ๊ตฌ๋ถ์๋ฅผ ํฌํจํ ์ ๋์ฝ๋ ๋ฉ์์ง ๋ด์ฉ์ด ๊ทธ๋๋ก ๋ณด์กด๋ฉ๋๋ค. ๊ธฐ์กด์ ์ ํจํ JSONL ๋ ์ฝ๋๋ ํ์ผ์ ๋ค์ ์ฐ์ง ์์๋ ๊ณ์ ์ฝ์ ์ ์์ต๋๋ค.
ํธ์ถ๋ณ ์ฌ์ฉ๋ ๊ฐ์ฌ๋ฅผ ์ํด, ์ฌ์ฉ๋์ด ์ฑ์์ง LLM ์๋ต์ ์ฆ์ ์ฌ์(replay)ํ๋ฉด ์ฒ์ ์ฌ์ฉ๋์ด ์๊ฑฐ๋ 0์ด์๋๋ผ๋ ์ค์ฒฉ๋ ์ฌ์ฉ๋๊ณผ ์ต์์ ํ ํฐ ์นด์ดํฐ๊ฐ ๋ชจ๋ ์
๋ฐ์ดํธ๋ฉ๋๋ค. ์๋์ ์์ฒญ, ๋ชจ๋ธ, ์ํ ๋ฉํ๋ฐ์ดํฐ๋ ๊ทธ๋๋ก ์ ์ง๋๋ฉฐ, ์ด๋ฏธ ํ๋ฌ์๋ ์ด๋ฒคํธ๋ ๋ค์ ์ฐ์ด์ง ์์ต๋๋ค. [์คํ ์ด๋ฒคํธ ๊ณ์ฝ](contracts/run_event_stream_contract.json)์ ์ฐธ๊ณ ํ์ธ์.
ํตํฉ nginx ์๋ํฌ์ธํธ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋์ผ ์ถ์ฒ(same-origin)์ด๋ฉฐ ๋ธ๋ผ์ฐ์ CORS ํค๋๋ฅผ ๋ด๋ณด๋ด์ง ์์ต๋๋ค. ์ถ์ฒ๊ฐ ๋ถ๋ฆฌ๋์๊ฑฐ๋ ํฌํธ ํฌ์๋ฉ๋ ๋ธ๋ผ์ฐ์ ํด๋ผ์ด์ธํธ๋ฅผ ์คํํ๋ค๋ฉด `GATEWAY_CORS_ORIGINS`์ `http://localhost:3000`๊ณผ ๊ฐ์ ์ ํํ ์ถ์ฒ๋ฅผ ์ผํ๋ก ๊ตฌ๋ถํด ์ค์ ํ์ธ์. ๊ทธ๋ฌ๋ฉด Gateway๊ฐ CORS ํ์ฉ ๋ชฉ๋ก๊ณผ ๊ทธ์ ๋ง๋ CSRF ์ถ์ฒ ๊ฒ์ฌ๋ฅผ ์ ์ฉํฉ๋๋ค.
์ธ๋ถํ๋ ๊ถํ ๋ถ์ฌ(fine-grained authorization)๊ฐ ํ์ฑํ๋ ๊ฒฝ์ฐ, Live Browser ์ฐ๊ฒฐ์๋ ํ๋ ์์ ๋ณด๊ธฐ๋ง ํ ๋๋ ์ค๋ ๋ ์์ ๊ถ๊ณผ ํจ๊ป `threads:write`๊ฐ ํ์ํฉ๋๋ค. ๊ฐ์ ์ฐ๊ฒฐ๋ก ๋ธ๋ผ์ฐ์ ๋ฅผ ์ ์ดํ ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค. ๊ถํ ๊ฒ์ฌ๋ ์ฐ๊ฒฐ ์์ ์ ์คํ๋ฉ๋๋ค. ์
๊ทธ๋ ์ด๋ ํ์๋ ์ด์ ์ฝ๋๊ฐ ์น์ธ(admission)ํ ์ธ์
์ ๋๊ธฐ ์ํด Gateway๋ฅผ ์ฌ์์ํ์ธ์.
๋ธ๋ผ์ฐ์ ๋ก๊ทธ์ธ์ `HttpOnly` ์ธ์
์ฟ ํค๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ก๊ทธ์ธ ํ์ด์ง๋ "keep me signed in"(๋ก๊ทธ์ธ ์ํ ์ ์ง) ์ต์
์ ์ ๊ณตํ๋ฉฐ, ์์ฒญ์ด HTTPS(์ ๋ขฐ๋ `X-Forwarded-Proto: https` ํฌํจ)์ด๊ฑฐ๋ localhost HTTP์ผ ๋ ๋ธ๋ผ์ฐ์ ์ธ์
์ ์ฐ์ฅํฉ๋๋ค. localhost ์์ธ๋ ์ง์ ์์ฒญ์ `Host`๋ฅผ ์ฌ์ฉํ๋ฉฐ ์ ๋ฌ๋(forwarded) ํธ์คํธ ํค๋๋ ๋ฌด์ํฉ๋๋ค. ๋ง์ ์์ ์๋๋ฐ์ค URL์ ํฌํจํ ๊ณต๊ฐ HTTP ๋ฐฐํฌ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ธ์
์ฟ ํค๋ก ํด๋ฐฑํฉ๋๋ค. DeerFlow๋ ๋น๋ฐ๋ฒํธ๋ฅผ ๋ธ๋ผ์ฐ์ ์ ์ฅ์์ ์ ๋ ์ ์ฅํ์ง ์์ผ๋ฉฐ, UI๋ ์ด๋ฉ์ผ ์ฃผ์๋ง ๊ธฐ์ตํ ์ ์์ต๋๋ค.
OIDC/SSO ๊ถํ ๋ถ์ฌ ์๋ํฌ์ธํธ์๋ `?prompt=login`๊ณผ ๊ฐ์ ํ๋ก๋ฐ์ด๋ ์ฟผ๋ฆฌ ๋งค๊ฐ๋ณ์๊ฐ ํฌํจ๋ ์ ์์ต๋๋ค. DeerFlow๋ ๋ก๊ทธ์ธ ์์ฒญ์ ์ถ๊ฐํ ๋ ์ด๋ฌํ ๋งค๊ฐ๋ณ์๋ฅผ ๋ณด์กดํ๋ฉฐ, ์ค์ ๋ `authorization_endpoint` ์ฌ์ ์์๋ ๋ง์ฐฌ๊ฐ์ง๋ก ์ ์ฉ๋ฉ๋๋ค.
๊ด๋ฆฌ์๋ **Settings โ Users**์์ ๊ณ์ ์ ์ ์งํ๊ณ ๋ณต์ํ ์ ์์ต๋๋ค(๊ด๋ฆฌ์ ์ ์ฉ์ด๋ฉฐ, ์ผ๋ฐ ์ฌ์ฉ์์๊ฒ๋ ์ด ์น์
์ด ์จ๊ฒจ์ง๋๋ค). ์ด ํ์ด์ง๋ ๊ฐ ๊ณ์ ์ ์ด๋ฉ์ผ, ์ญํ , ์ํ๋ฅผ ๋ณด์ฌ ์ฃผ๊ณ `PATCH /api/v1/admin/users/{id}`์ ๋์ผํ ํ์ฑํ/๋นํ์ฑํ ์์
์ ์ ๊ณตํฉ๋๋ค. ๋ง์ง๋ง์ผ๋ก ๋จ์ ํ์ฑ ๊ด๋ฆฌ์๋ ๋นํ์ฑํํ ์ ์์ผ๋ฉฐ, Gateway์ ๊ฑฐ๋ถ ์์ธ ๋ฉ์์ง๋ ๊ทธ๋๋ก ํ์๋ฉ๋๋ค. ๋นํ์ฑํ๋ ๊ณ์ ์ ๋ชจ๋ ์ธ์ฆ ๊ฒฝ๋ก์์ ๊ฑฐ๋ถ๋๋ฉฐ, ํด๋น ๊ณ์ ์ ํ์ฑ ์ธ์
์ ๋ค์ ์์ฒญ์์ ์ข
๋ฃ๋๊ณ ๊ณ์ ์ด ๋นํ์ฑํ๋์์์ ์๋ฆฌ๋ ๋ก๊ทธ์ธ ํ์ด์ง๊ฐ ํ์๋ฉ๋๋ค. ๋นํ์ฑํ๋ ๊ณ์ ์ผ๋ก ๋น๋ฐ๋ฒํธ ๋ก๊ทธ์ธ์ ์๋ํ๋ฉด ์๋์ ์ผ๋ก ์ฌ์ ํ "incorrect email or password"(์ด๋ฉ์ผ ๋๋ ๋น๋ฐ๋ฒํธ๊ฐ ์ฌ๋ฐ๋ฅด์ง ์์)๋ผ๊ณ ์๋ตํ๋ฏ๋ก, ์๊ฒฉ ์ฆ๋ช
์ ๊ฐ์ง ์ฌ๋์๊ฒ ๊ณ์ ์ํ๊ฐ ๋
ธ์ถ๋์ง ์์ต๋๋ค.
DeerFlow๋ ํ๋ก์ ๋ค์์ ๋ธ๋ผ์ฐ์ ์ธก ์คํด๊ณผ ์ถ์ฒ๋ฅผ ๋ณต์ํ๊ธฐ ์ํด ์ฌ์ ํ `Forwarded` / `X-Forwarded-*` ํค๋๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ฒ๋ค๋ nginx๋ `X-Forwarded-Proto`๋ฅผ ์ค์ ํ์ง๋ง, ์
์คํธ๋ฆผ์ HTTPS ๊ฐ์ ๋ณด์กดํ๋ฉฐ ๋ชจ๋ ์ ๋ฌ ํค๋๋ฅผ ๋ฎ์ด์ฐ์ง๋ ์์ต๋๋ค. ํธ๋ํฝ์ด DeerFlow์ ๋๋ฌํ๊ธฐ ์ ์ ์ธ๋ถ์ ์ ๋ขฐ๋ ํ๋ก์๊ฐ ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ธ ์ ๋ฌ ํค๋๋ฅผ ๊ต์ฒดํ๊ฑฐ๋ ์ ๊ฑฐํ๋๋ก ์ค์ ํ์ธ์.
> [!IMPORTANT]
> Gateway๋ ์ฌ์ ํ ํ์ฑ ์คํ ์์
์ ํ๋ก์ธ์ค ๋ด์์ ์์ ํ๋ฏ๋ก, ํ๋ก๋์
์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋จ์ผ Gateway ์์ปค(`GATEWAY_WORKERS=1`)๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ฉํฐ ์์ปค ๋ฐฐํฌ์๋ Postgres, Redis ์คํธ๋ฆผ ๋ธ๋ฆฌ์ง(`stream_bridge.type: redis`), `run_ownership.heartbeat_enabled: true`, `run_events.backend: db`๊ฐ ํ์ํฉ๋๋ค. ํ๋ก์ธ์ค ๋ก์ปฌ memory/JSONL ์ด๋ฒคํธ ์ ์ฅ์๋ ์์ปค ๊ฐ์ ๋จ์ผ ์ ๋ฌ ์์์ฆ(singleton delivery receipt)์ ๋ณด์ฅํ ์ ์์ต๋๋ค. Kubernetes ๋ ํ๋ฆฌ์นด๋ Pod๋ง๋ค ์์ปค ํ๋๋ฅผ ์คํํ๋๋ฐ, ์ด๋ ์์ปค ์๋ก๋ ํ์
ํ ์ ์์ต๋๋ค. ์์ ๊ฒ์ดํธ๊ฐ ๋นํ์ฑ ์ํ๋ก ๋จธ๋ฌด๋ฅด์ง ์๊ณ ๋์ผํ ์ ์ ์กฐ๊ฑด์ ๊ฐ์ ํ๋๋ก `deployment.multi_instance: true`(๋๋ Helm ์ฐจํธ ๊ฐ์ ๋ฐฐํฌ ๋๊ตฌ๊ฐ ๋ ํ๋ฆฌ์นด ์์ ๋ฐ๋ผ ์ค์ ํ ์ ์๋ `DEER_FLOW_MULTI_INSTANCE=1`)๋ก ์ด๋ฅผ ์ ์ธํ์ธ์. ์๊ฒฉ ์ฆ๋ช
(`channel_connections`)์ ์ ์ฅํ๋ ์ ์ธ๋ ์ธ์คํด์ค๋ค์ ์ ์ฅ ์ ์ํธํ์ ์ฐ์ด๋ ํ๋์ `DEER_FLOW_CREDENTIALS_KEY`๋ ๊ณต์ ํด์ผ ํฉ๋๋ค(Helm ์ฐจํธ์ `make up`์ด ์ด๋ฅผ ์์ฑํฉ๋๋ค. ์ด ํค๋ ๋ฐฑ์
ํด ๋์ธ์. [backend/docs/CONFIGURATION.md](backend/docs/CONFIGURATION.md#credentials-encryption-key-deer_flow_credentials_key) ์ฐธ๊ณ ). ๋ธ๋ฆฌ์ง๋ ์์ปค ๊ฐ์ SSE ์ ๋ฌ๊ณผ ๋ฒ์๊ฐ ์ ํ๋ `Last-Event-ID` ์ฌ์์ ๊ณต์ ํฉ๋๋ค. ์ ํจํ ์ฌ์ฐ๊ฒฐ ์ปค์๊ฐ ์ด๋ฏธ ์๋ ค ๋๊ฐ๊ฑฐ๋, ์ด๋ฏธ ๋น ์คํธ๋ฆผ ๋๊ธฐ๋ฅผ ์ค์ ํ ๊ตฌ๋
์๊ฐ ์ฒซ ์ ๋ฌ ์ ์ ๋ค์ฒ์ง๋ฉด, Memory์ Redis๋ ๋ถ๋ถ ์ฌ์์ ์กฐ์ฉํ ๋ฐํํ๋ ๋์ ๊ธฐ๊ณ๊ฐ ์ฝ์ ์ ์๋ SSE `gap` ์ด๋ฒคํธ๋ฅผ ๋ด๋ณด๋
๋๋ค. ๊ทธ๋ฌ๋ฉด ์น UI๊ฐ ์์ ์ค๋ ๋/์ด๋ฒคํธ ์ํ๋ฅผ ๋ค์ ๋ถ๋ฌ์ค๊ณ ๋ณด์กด๋ ๋๋ถ๋ถ๋ถํฐ ์ฌ๊ฐํฉ๋๋ค. ๋ฆฌ์ค ์กฐ์ (reconciliation)์ ์ฃฝ์ ์์ปค์ ์คํ์ ์ค๋ฅ๋ก ํ์ํ๊ณ , ๊ทธ ์ ๋ฌ ์์์ฆ์ ์์ ์ ์ฅํ๋ฉฐ, ์ข
๋ฃ ์คํธ๋ฆผ ๋ง์ปค๋ฅผ ๊ฒ์ํ๊ณ , ๋ณด์กด๋ ์คํธ๋ฆผ์ ์ ๋ฆฌ๋ฅผ ์์ฝํ๋ฉฐ, ์ํฅ์ ๋ฐ์ ์ค๋ ๋ ์ํ๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค. SSE, `/wait`, ๋ด๋ถ ์คํธ๋ฆผ ์๋น์๋ ์ ํด ์ํ ์์กด ํ์ธ์ `stream_bridge.heartbeat_interval_seconds`(๊ธฐ๋ณธ๊ฐ `15`)๋ฅผ ์ฌ์ฉํ๋ฉฐ, ์ด ๊ฐ์ ๋ณ๊ฒฝํ๋ ค๋ฉด Gateway๋ฅผ ์ฌ์์ํด์ผ ํฉ๋๋ค. ํ์์ด ์๋ชป๋ Redis ์ฌ์ฐ๊ฒฐ ID๋ ๋ณด์กด๋ ๋ฒํผ๋ฅผ ์ฌ์ํ์ง ์๊ณ ์ ์ด๋ฒคํธ๋ฅผ ์ค์๊ฐ์ผ๋ก ์ด์ด์ ๋ฐ์ผ๋ฉฐ, ๋กค๋ง ๋ฐฉ์์ ๋ณด์กด ๋ฒํผ TTL(`stream_ttl_seconds`)์ ์คํ ํ์์์์ด ์๋๋ผ ์ ๋ฆฌ๋ฅผ ์ํ ์์ ์ฅ์น๋ก ๋จ์ต๋๋ค. `POST /api/v1/auth/login/local`์ ๋ก๊ทธ์ธ ์คํจ ์นด์ดํฐ์ ์ ๊ธ(`auth.local.max_login_attempts` / `lockout_seconds`)์ ๊ณต์ `login_throttle` ํ
์ด๋ธ์ ๋ณด๊ด๋ฉ๋๋ค. ๋จ, ์ ํ๋ฆฌ์ผ์ด์
๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ SQLite ๋๋ Postgres์ธ ๊ฒฝ์ฐ(`auth.local.throttle_storage: auto`, ๊ธฐ๋ณธ๊ฐ)์ ํํ๋ฉฐ, ์ด๋ ๋ชจ๋ ๋ ํ๋ฆฌ์นด๊ฐ ํด๋ผ์ด์ธํธ IP๋น ํ๋์ ์ ๊ธ์ ์ ์ฉํฉ๋๋ค. `memory`๋ ๊ธฐ์กด์ ํ๋ก์ธ์ค๋ณ ์นด์ดํฐ๋ฅผ ์ ์งํ๋๋ฐ, ์ด ๊ฒฝ์ฐ ๋ ํ๋ฆฌ์นด๊ฐ N๊ฐ์ด๋ฉด ๊ณต๊ฒฉ์์๊ฒ N ร `max_login_attempts`๋ฒ์ ์ถ์ธก ๊ธฐํ๊ฐ ์ฃผ์ด์ง๋ฉฐ ์์ ์ ๊ฒฝ๊ณ ๊ฐ ๋ก๊ทธ์ ๋จ์ต๋๋ค. IM ์ฑํ
-์ค๋ ๋ ๋ฐ์ธ๋ฉ์ ์ ํ๋ฆฌ์ผ์ด์
๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ SQLite ๋๋ Postgres์ด๋ฉด ๊ณต์ `channel_thread_bindings` ํ
์ด๋ธ์ ์ ์ฅ๋ฉ๋๋ค(๊ธฐ์กด `channels/store.json`์ ์์ ์ ํ ๋ฒ ๊ฐ์ ธ์จ ๋ค `store.json.migrated`๋ก ์ด๋ฆ์ด ๋ฐ๋๋๋ค). ๊ฐ ํ๋ก๋ฐ์ด๋์ ํ๋ซํผ ์ฐ๊ฒฐ์ ๊ณต์ `channel_leases` ํ
์ด๋ธ์ ํตํด ํ ์ธ์คํด์ค๊ฐ ๋ณด์ ํฉ๋๋ค. `channels.leader_lease`(๊ธฐ๋ณธ๊ฐ `auto`, ๋ฉํฐ ํ๋ก์ธ์ค ์ ํธ๊ฐ ์๋ ๊ณณ์์๋ ์ผ์ง)๋ ๋ณด์ ์ธ์คํด์ค๊ฐ ์ฃฝ์ผ๋ฉด ๋ค๋ฅธ ์ธ์คํด์ค๋ก ์ฐ๊ฒฐ์ ๋๊ธฐ๋ฉฐ, GitHub ์ด์ธ์ IM ์ฑ๋์ด ํ์ฑํ๋์ด ์๋ ๋์์๋ ์์ ๊ฒ์ดํธ๊ฐ `enabled: false`๋ฅผ ๊ฑฐ๋ถํฉ๋๋ค([IM ์ฑ๋ ๋ฆฌ๋ ๋ฆฌ์ค](backend/docs/CONFIGURATION.md#im-channel-leader-lease-channelsleader_lease) ์ฐธ๊ณ ). ํ์(follow-up) ๋ฒํผ์๋ ์ฌ์ ํ ๋ณ๋์ ๋ฉํฐ ์์ปค ์กฐ์ ์ด ํ์ํฉ๋๋ค. ์ด ํ ํด๋ก์ง๋ฅผ ํ ๋์ ๋จธ์ ์์ ์ํํด ๋ณด๋ ค๋ฉด, `make dev-multi`๋ก ๊ณต์ Postgres, Redis, `DEER_FLOW_HOME` ์์ Gateway ๋ ๊ฐ๋ฅผ ์์ํ๊ณ `make dev-multi-check`๋ก ์ธ์คํด์ค ๊ฐ ๊ฒ์ฌ๋ฅผ ์คํํ์ธ์. [backend/docs/CONFIGURATION.md](backend/docs/CONFIGURATION.md#local-two-gateway-harness)์ ๋ก์ปฌ 2-Gateway ํ๋ค์ค๋ฅผ ์ฐธ๊ณ ํ์ธ์.
>
> ๋ก์ปฌ 2-Gateway ํ๋ค์ค๋ ๊ธฐ๋ณธ์ ์ผ๋ก `channels`์ `channel_connections` ์๋์ IM ํ๋ก๋ฐ์ด๋๋ฅผ ๋ชจ๋ ๋นํ์ฑํํฉ๋๋ค. `DEERFLOW_MI_KEEP_CHANNELS=1`์ ์ค์ ํ๋ฉด ์ด๋ฅผ ์ ์งํ๋ฉฐ, `channels.leader_lease`๋ ์ค์ ๋ ๊ทธ๋๋ก ์ ์ง๋ฉ๋๋ค.
>
> SSE ์ฌ์ ๊ฐ๊ทน(replay-gap) ๋ณต๊ตฌ ์ค์ ์น UI๋ ์์ ์ํ๋ฅผ ๋ถ๋ฌ์ค๋ ๋์ ๋ค๋ฅธ ์คํ์ด ์ ์ ํ ์ฌ์ฐ๊ฒฐ ํฌ์ธํฐ๋ฅผ ๋ณด์กดํฉ๋๋ค. ์ด์ ๋ณต๊ตฌ๊ฐ ์์ ์ ์คํธ๋ฆผ์ ๋ค์ ํฉ๋ฅํ ๋ ๊ทธ ํฌ์ธํฐ๋ฅผ ๋ฎ์ด์ธ ์ ์์ต๋๋ค. ์ค๋๋ ์ธ๋ถ ํฌ์ธํฐ๋ผ๋ ๋ณด์กด๋๋ฏ๋ก, ๋ค์ ๋ค์ ๋ถ๋ฌ์ค๊ธฐ์์๋ ํ์ฑ ์คํ ๋ณต๊ตฌ๊ฐ ๋ค์ ํฉ๋ฅํ๊ธฐ ์ ์ ๊ทธ ์คํ์ ๋จผ์ ํ์ธํ ์ ์์ผ๋ฉฐ, ์ด๋ก ์ธํด ์ฌ์ฐ๊ฒฐ ์ฃผ๊ธฐ๊ฐ ํ ๋ฒ ๋ ์ถ๊ฐ๋ ์ ์์ต๋๋ค.
>
> ์ ์ฅ์ ์ ์ฉ SSE ๋ฐ `/wait` ์๋น์๋ run-manager ๋๋ ์์ฝ ์์
์กฐ์ ์ด ์ฃฝ์ ์์ปค์ ์คํ์ ๋ณต๊ตฌํ๋ ๊ฒฝ์ฐ, END ๋ง์ปค๊ฐ ๊ฒ์๋์ง ์์๋๋ผ๋ ํํธ๋นํธ ์ดํ ์ข
๋ฃ๋ ์ ์์ต๋๋ค. ์ผ๋ฐ์ ์ธ ์๋ฃ๋ ๋๋ถ๋ถ ์ด๋ฒคํธ๋ฅผ ๋ณด์กดํ๊ธฐ ์ํด ์ฌ์ ํ END๋ฅผ ๊ธฐ๋ค๋ฆฝ๋๋ค.
>
> ๋จ์ผ ํ๋ก์ธ์ค JSONL ๋ฐฐํฌ์์ ์น์ธ๋ ์ด๋ฒคํธ ์ ์ฅ์ ๋ณ๊ฒฝ์ ์ทจ์ํ๋ฉด, ์ค๋ ๋ ์ฐ๊ธฐ ์ ๊ธ์ ํด์ ํ๊ธฐ ์ ์ ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์ผ I/O, ๋กค๋ฐฑ, ๋ด๋ถ ๊ธฐ๋ก ์ฒ๋ฆฌ๊ฐ ๋ง๋ฌด๋ฆฌ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค. ์ด๋ ์ทจ์๋ ์ด์ ์ฐ๊ธฐ๊ฐ ์ญ์ ๋ ๋ ์ฝ๋๋ฅผ ๋ค์ ๋ง๋ค๊ฑฐ๋ ์ดํ์ ์ฑ๊ณตํ ์ฐ๊ธฐ๋ฅผ ๋กค๋ฐฑํ๋ ๊ฒ์ ๋ง์ต๋๋ค. ๋ฐ๋ผ์ ์ทจ์๋ ๋๋ฆฐ ์ ์ฅ์๋ฅผ ๊ธฐ๋ค๋ฆด ์ ์์ผ๋ฉฐ, ์งํ ์ค์ธ ํ์ผ ์์คํ
์์
์ ์ค์งํ์ง๋ ์์ต๋๋ค. ์์ง ์ ๊ธ ํ๋์ ๊ธฐ๋ค๋ฆฌ๋ ํธ์ถ์๋ ๋ณ๊ฒฝ์ ์์ํ์ง ์๊ณ ์ทจ์ํ ์ ์์ต๋๋ค. ์ฌ๋ฌ ์ค๋ ๋์ ๊ฑธ์น ๋ฐฐ์น๋ ์ทจ์๋ฅผ ์ ํํ๊ธฐ ์ ์ ํ์ฌ ์ค๋ ๋ ๊ทธ๋ฃน์ ๋ชจ๋ ์ฒ๋ฆฌํ๋ฉฐ, ์ดํ์ ์ค๋ ๋ ๊ทธ๋ฃน์ ์์ํ์ง ์์ต๋๋ค.
>
> ์คํ์ด ์ข
๋ฃ ์คํธ๋ฆผ ๋ง์ปค๋ฅผ ๊ฒ์ํ ๋ค์๋ ํ๋ก์ธ์ค ๋ก์ปฌ `RunRecord`๋ ์ ๋ฆฌ๋๊ธฐ ์ ๊น์ง ๊ธฐ์กด์ 5๋ถ ์ ์ ๊ธฐ๊ฐ ๋์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์์ ์ ์ฅ๋ ์คํ ์ด๋ ฅ์ `RunStore`๋ฅผ ํตํด ๊ณ์ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ์คํธ๋ฆผ ๋ธ๋ฆฌ์ง๋ ์์ฒด ์ ๋ฆฌ ์ผ์ ์ ๋ฐ๋ผ ์ ๋ฌ ๋๋ถ๋ถ์ ๋ณด์กดํฉ๋๋ค.
>
> ์คํ ์ทจ์ ์์ฒญ์ ์ด๋ Gateway ์์ปค์๋ ๋๋ฌํ ์ ์์ต๋๋ค. ์ด์ ์์ ์๊ฐ ์๋ ์์ปค๋ ์ค๋จ(interrupt) ๋๋ ๋กค๋ฐฑ ์์ฒญ์ ์ด์ ์๋ ์์ ์๋ฅผ ์ํด ์์ ์ ์ฅํ๊ณ , ์์ ์๋ ๋ฆฌ์ค ๊ฐฑ์ ์ค์ ์ด๋ฅผ ํ์ธํด ์ผ๋ฐ์ ์ธ ์ทจ์ ํ๋ฆ์ ์ํํฉ๋๋ค. ๋ก๋ ๋ฐธ๋ฐ์ ๋ผ์ฐํ
๋ง์ผ๋ก ๋ ์ด์ 409๊ฐ ๋ฐ์ํ์ง ์์ต๋๋ค. ์ฌ์๋๊ฐ ์์ ์์๊ฒ ๋๋ฌํ๋๋ผ๋ ์ฒ์ ์๋ฝ๋ ์์
์ด ์ฐ์ ํ๋ฉฐ, ์๋ฝ๋ ์ทจ์๋ ์์ ์์ ์๋ฃ ์ฒ๋ฆฌ์ ์์์ ์ผ๋ก ๊ฒฝ์ํฉ๋๋ค. ์ฃฝ์ ์์ ์๋ ์ฌ์ ํ ๋ฆฌ์ค ์ธ๊ณ์ ๊ณ ์(orphan) ์คํ ๋ณต๊ตฌ ์ ์ฐจ๋ฅผ ๋ฐ๋ฆ
๋๋ค. ๋ฐ๋ผ์ ์ทจ์ ์ง์ฐ ์๊ฐ์ ์ํ์ ๋ฆฌ์ค ํํธ๋นํธ ๊ฐ๊ฒฉ์ผ๋ก ์ ํด์ง๋๋ค.
> ๋๊ธฐ์ด์ ์๊ฑฐ๋ ์ฌ์๋๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ์ค์ธ ๊ฒฝ์ฐ๋ฅผ ํฌํจํด ๋ชจ๋ธ ๋ณต๊ตฌ ํ๋ก๋ธ๋ฅผ ์ทจ์ํ๋ฉด, ๋ค์ ํธ์ถ์ด ํ๋ก๋ฐ์ด๋๊ฐ ๋ณต๊ตฌ๋์๋์ง ํ์ธํ ์ ์์ต๋๋ค. ์ทจ์๋ ํ๋ก๋ฐ์ด๋ ์คํจ๋ก ์ง๊ณ๋์ง ์์ผ๋ฉฐ, ๋ค๋ฅธ ํธ์ถ์ ํ์ฑ ๋ณต๊ตฌ ํ๋ก๋ธ๋ฅผ ํด์ ํ์ง๋ ์์ต๋๋ค.
>
> ๋ชจ๋ธ ์ฌ์๋๋ ์ ํจํ ํ๋ก๋ฐ์ด๋ `Retry-After` ํํธ๋ฅผ ์ต๋ 24์๊ฐ๊น์ง ๋ฐ๋ฅด๋ฉฐ, ๋ก์ปฌ ๋ฐฑ์คํ ์ํ๋ณด๋ค ๊ธด ๋๊ธฐ๋ ํฌํจ๋ฉ๋๋ค. ํ์์ด ์๋ชป๋์๊ฑฐ๋, ์ ํํ์ง ์๊ฑฐ๋, ์ ํ์ ๋๋ ํํธ๋ ์ผ๋ฐ ๋ฐฑ์คํ๋ฅผ ๋์ ์ฌ์ฉํฉ๋๋ค. ์ด๋ LLM ์ค๋ฅ ์ฒ๋ฆฌ์ ์ซ์/๋ ์ง ํํธ์ Claude ์ฌ์๋ ๊ฒฝ๋ก์ ์ ์ ์ด ํํธ์ ์ ์ฉ๋ฉ๋๋ค.
>
> ๋ฆฌ์ค ํํธ๋นํธ๊ฐ ํ์ฑํ๋ ๊ฒฝ์ฐ, ์ผ์์ ์ธ RunStore ๊ฐฑ์ ์ค๋ฅ๋ ๋ง์ง๋ง์ผ๋ก ํ์ธ๋ ๋ฆฌ์ค๊ฐ ๋ง๋ฃ๋ ๋๊น์ง๋ง ์ฌ์๋๋ฉ๋๋ค. ๊ทธ ํ ์ค๋๋ ์์ปค๋ ๋ก์ปฌ ์คํ์ ์ทจ์ํ๊ณ ์ฒดํฌํฌ์ธํธ, ์๋ฃ ํ
, ์ ๋ฌ ์์์ฆ, ์ค๋ ๋ ์ํ ๋ง๋ฌด๋ฆฌ๋ฅผ ์ต์ ํฉ๋๋ค. ์ด๋ฏธ ์งํ ์ค์ธ ์๊ฒฉ ๋๊ตฌ์ ๋ถ์ ํจ๊ณผ๋ ์ฌ์ ํ ๋ก์ปฌ ์ทจ์ ๋ฒ์ ๋ฐ์ ์์ ์ ์์ต๋๋ค.
>
> ์กฐ์ ์ ํ๋ณด ์ ํ ํ ๋ฆฌ์ค๋ฅผ ๋ค์ ํ์ธํ๋ ์์์ ์ธ๊ณ ์ ์ (takeover claim)๋ฅผ ์ฌ์ฉํ๋ฏ๋ก, ์ฑ๊ณตํ ์์ ์ ๊ฐฑ์ ์ด ๊ณ ์ ์คํ ๋ณต๊ตฌ๋ณด๋ค ์ฐ์ ํ๋ฉฐ ์ค์ง ํ๋์ ์กฐ์ ์๋ง ์คํ์ ๋ณต๊ตฌ๋ ๊ฒ์ผ๋ก ๋ณด๊ณ ํ ์ ์์ต๋๋ค. ์ฌ๋ฌ Gateway ์์ปค๊ฐ Docker/AIO ๋๋ E2B ์๋๋ฐ์ค ๋ฐฑ์๋๋ฅผ ๊ณต์ ํ๋ ๊ฒฝ์ฐ `sandbox.ownership.type: redis`๋ ์ค์ ํ์ธ์. E2B๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ์์๊ณผ ์ฃผ๊ธฐ์ ์กฐ์ ์ค์ ๋ฆฌ์ค๋ฅผ ์ฌ์ฉํ๋ฏ๋ก, ์ค๋ณต/๊ณ ์ ์ ๋ฆฌ๊ฐ ์ด์ ์๋ ๋ค๋ฅธ ์ธ์คํด์ค์ ์๋๋ฐ์ค๋ฅผ ์ข
๋ฃํ ์ ์์ต๋๋ค.
์์ธํ Docker ๊ฐ๋ฐ ๊ฐ์ด๋๋ [CONTRIBUTING.md](CONTRIBUTING.md)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
#### ๊ธฐ์กด ์ฒดํฌ์์ ์
๊ทธ๋ ์ด๋
`config.yaml`, `.env`, `extensions_config.json`์ ๊ทธ๋๋ก ์ ์งํ์ธ์. ํ์ฌ ์ฌ์ฉ ์ค์ธ ์๋น์ค๋ฅผ ์ค์งํ๊ณ `git pull --ff-only`๋ฅผ ์คํํ ๋ค์, ๊ฐ์ ๋ชจ๋๋ก ๋ค์ ์์ํ์ธ์. ์ผ์์ ์ธ ์์ค ์
๊ทธ๋ ์ด๋์์๋ `make config`๋ `make docker-init`์ ๋ค์ ์คํํ์ง ๋ง์ธ์. ์ ๋ฒ์ ์ ์ค์ ๋ณ๊ฒฝ์ด ํ์ํ๋ค๋ฉด ์ฌ์์ํ๊ธฐ ์ ์ `make config-upgrade`๋ฅผ ์คํํ์ธ์. ๋ชจ๋๋ณ ๋ช
๋ น์ [์ด์ ๋ฐ ๋ฌธ์ ํด๊ฒฐ](frontend/src/content/en/application/operations-and-troubleshooting.mdx#upgrading-an-existing-checkout)์ ์ฐธ๊ณ ํ์ธ์.
์ฌ๊ฐ(resume) ๋ช
๋ น ๋ฉฑ๋ฑ์ฑ ์์ ์ฌํญ์ ์ฌ๋ฌ Gateway ์์ปค๋ Pod์ ๋ฐฐํฌํ ๋๋, ์ด ์๋ํฌ์ธํธ๋ฅผ ์๋น์คํ๋ ๋ชจ๋ ์์ปค๊ฐ ์
๊ทธ๋ ์ด๋๋ ๋๊น์ง **ํค๊ฐ ์ง์ ๋ ๋ชจ๋ ์ฌ๊ฐ ์์ฒญ ์ ์ถ๊ณผ ์ฌ์๋**(`command.resume`์ `Idempotency-Key`๋ฅผ ํฌํจํด ์ค๋ ๋ ๋ฒ์์ `/runs`, `/runs/stream`, `/runs/wait`๋ก ๋ณด๋ด๋ ์์ฒญ)๋ฅผ ์
๊ทธ๋ ์ด๋๋ ์์ปค๋ก๋ง ๋ผ์ฐํ
ํ์ธ์. ์ด์ ์์ปค๋ ๋น๊ณต๊ฐ ์ฌ๊ฐ ์๋ณ ์ ๋ณด๋ฅผ ๋ฌด์ํ๊ณ `input`๋ง ๋น๊ตํฉ๋๋ค. ๊ทธ๋์ `input: null`์ธ ๊ฒฝ์ฐ `deny`๋ฅผ ์ฌ์๋ํ๋ฉด ์ด์ ์ `approve` ์คํ์ด ์๋ชป ์ฌ์ฌ์ฉ๋ ์ ์์ต๋๋ค. ๋ก๋ ๋ฐธ๋ฐ์๊ฐ ์
๊ทธ๋ ์ด๋๋ ์์ปค๋ฅผ ๋ถ๋ฆฌํ ์ ์๋ค๋ฉด, ๋ฐฐํฌ๊ฐ ๋๋ ๋๊น์ง ํค๊ฐ ์ง์ ๋ ์ฌ๊ฐ ํธ๋ํฝ์ ์ผ์ ์ค์งํ๊ฑฐ๋, ์ ๋ฒ์ ์ผ๋ก ์ฌ์์ํ๊ธฐ ์ ์ ์ด์ ์์ปค๋ฅผ ๋ชจ๋ ์ค์งํ์ธ์. ์ถ๊ฐํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ง์ด๊ทธ๋ ์ด์
์ ์ด์ ๋ฒ์ ์ ์คํ ์ด๋ ฅ ์ฝ๊ธฐ ์ฝ๋์ ํธํ์ฑ์ ์ ์งํ์ง๋ง, ์ด์ ์์ปค๊ฐ ์ฌ๊ฐ ์์ฒญ์ ์์ ํ๊ฒ ์น์ธ(admission)ํ ์ ์๊ฒ ๋ง๋ค์ง๋ ์์ต๋๋ค. ์
๊ทธ๋ ์ด๋๋ ์์ปค๋ ์๋ณ ์ ๋ณด๊ฐ ์๋ ๋ ๊ฑฐ์ ์ฌ๊ฐ ์คํ์ ์ฌ์๋ํ๋ฉด ๊ฐ์ ๊ฒฐ์ ์ด๋๋ผ๋ 409๋ฅผ ๋ฐํํฉ๋๋ค. ์ ์์
์ ์ ์ถํ ์ง ๊ฒฐ์ ํ๊ธฐ ์ ์ ํด๋น ์คํ๊ณผ ํ์ฌ ์ค๋ ๋ ์ํ๋ฅผ ํ์ธํ์ธ์. [์คํ API ๊ณ์ฝ](backend/docs/API.md#create-run)์ ์ฐธ๊ณ ํ์ธ์.
์ปค์คํ
์คํ ์ ์ฅ์๋ ์ ๊ณต๋ ๋ชจ๋ ๋ฉฑ๋ฑ์ฑ ํ๋๋ฅผ ๋ช
์์ ์ผ๋ก ์ง์ํด์ผ ํฉ๋๋ค. ์ ์ฅ์๊ฐ ๊ทธ ์ง์์ ๋ณด์ฅํ ์ ์์ผ๋ฉด, ํค๊ฐ ์ง์ ๋ ์
๋ ฅ ์์ฒญ๊ณผ ์ฌ๊ฐ ์์ฒญ์ ์คํ ์น์ธ ์ ์ HTTP 503์ ๋ฐํํฉ๋๋ค. ๊ธฐ๋ณธ ์ ๊ณต Memory ๋ฐ SQL ์ ์ฅ์๋ ๋ ํ๋๋ฅผ ๋ชจ๋ ์ง์ํ๋ฉฐ, ๋ช
์์ ์ธ `idempotency_key` ๋งค๊ฐ๋ณ์๋ฅผ ๊ฐ์ง ์ด์ ์ปค์คํ
์ ์ฅ์๋ ํค๊ฐ ์ง์ ๋ ์
๋ ฅ ์์ฒญ์ ๊ณ์ ์๋ฝํฉ๋๋ค.
#### ์ต์
2: ๋ก์ปฌ ๊ฐ๋ฐ
์๋น์ค๋ฅผ ๋ก์ปฌ์์ ์ง์ ์คํํ๊ณ ์ถ๋ค๋ฉด ๋ค์์ ๋ฐ๋ฅด์ธ์.
์ฌ์ ์ค๋น: ๋จผ์ ์์ "์ค์ " ๋จ๊ณ(`make setup`)๋ฅผ ์๋ฃํ์ธ์. `make dev`๋ฅผ ์คํํ๋ ค๋ฉด ํ๋ก์ ํธ ๋ฃจํธ์ ์ ํจํ `config.yaml`์ด ์์ด์ผ ํฉ๋๋ค. ๊ทธ ๋ฃจํธ๋ฅผ ๋ช
์์ ์ผ๋ก ์ง์ ํ๋ ค๋ฉด `DEER_FLOW_PROJECT_ROOT`๋ฅผ, ํน์ ์ค์ ํ์ผ์ ๊ฐ๋ฆฌํค๋ ค๋ฉด `DEER_FLOW_CONFIG_PATH`๋ฅผ ์ค์ ํ์ธ์. ๋ฐํ์ ์ํ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ํ๋ก์ ํธ ๋ฃจํธ ์๋์ `.deer-flow`์ ์ ์ฅ๋๋ฉฐ `DEER_FLOW_HOME`์ผ๋ก ์์น๋ฅผ ์ฎ๊ธธ ์ ์์ต๋๋ค. ์คํฌ์ ๊ธฐ๋ณธ์ ์ผ๋ก ํ๋ก์ ํธ ๋ฃจํธ ์๋์ `skills/`์ ์์ผ๋ฉฐ `DEER_FLOW_SKILLS_PATH`๋ก ์์น๋ฅผ ์ฎ๊ธธ ์ ์์ต๋๋ค. ์์ํ๊ธฐ ์ ์ `make doctor`๋ฅผ ์คํํด ์ค์ ์ ํ์ธํ์ธ์.
์ค์ ๊ฒ์ฌ์ ์์ด์ ํธ ์ ์ฅ์ ๋ง์ด๊ทธ๋ ์ด์
์ ์ ์ฅ์ ๋ฃจํธ์์ `uv run --no-sync --project backend`๋ฅผ ํตํด ์ค์น๋ ๋ฐฑ์๋ ํ๊ฒฝ์ ์ฌ์ฉํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์๋ ๋ฐํ์ ๊ฒฝ๋ก์ ์ค์น๋ ์ ํ์ ์์กด์ฑ์ด ์ ์ง๋ฉ๋๋ค. [์ค์ ๊ฒ์ฌ](backend/docs/SETUP.md#steps)์ [์์ด์ ํธ ์ ์ฅ์ ๋ง์ด๊ทธ๋ ์ด์
](backend/docs/CONFIGURATION.md#agent-storage)์ ์ฐธ๊ณ ํ์ธ์.
Windows์์๋ Git Bash์์ ๋ก์ปฌ ๊ฐ๋ฐ ํ๋ฆ์ ์คํํ์ธ์. bash ๊ธฐ๋ฐ ์๋น์ค ์คํฌ๋ฆฝํธ๋ ๋ค์ดํฐ๋ธ `cmd.exe`์ PowerShell ์
ธ์์ ์ง์๋์ง ์์ผ๋ฉฐ, ์ผ๋ถ ์คํฌ๋ฆฝํธ๊ฐ `cygpath` ๊ฐ์ Git for Windows ์ ํธ๋ฆฌํฐ์ ์์กดํ๊ธฐ ๋๋ฌธ์ WSL์์์ ๋์๋ ๋ณด์ฅ๋์ง ์์ต๋๋ค.
๋ฌธ์์ ์๋ด๋ ๋ฃจํธ `make` ๋ช
๋ น์ ์ ์ฅ์์ `.sh` ํ์ผ์ ๋ช
์์ ์ผ๋ก Bash๋ฅผ ํตํด ํธ์ถํฉ๋๋ค. ๋ฐ๋ผ์ POSIX ์คํ ๊ถํ ๋นํธ๋ฅผ ๋ณด์กดํ์ง ์๋ ์์ค ์์นด์ด๋ธ๋ ํ์ผ ์์คํ
์์๋ ๊ณ์ ๋์ํฉ๋๋ค. ์ด๋ฌํ ์ฒดํฌ์์์์ ์คํฌ๋ฆฝํธ๋ฅผ ์ง์ ํธ์ถํ ๋๋ `bash ./scripts/.sh ...`๋ฅผ ์ฌ์ฉํ์ธ์.
1. **์ฌ์ ์๊ตฌ ์ฌํญ ํ์ธ**:
```bash
make check # Verifies Node.js 22+, pnpm, uv, nginx
```
๋ก์ปฌ `make check`, `make install`, `make dev`, `make start` ์ง์
์ ์ ์ง์ ์คํ ๊ฐ๋ฅํ `pnpm`์ด ์์ผ๋ฉด ์ด๋ฅผ ์ฌ์ฉํ๊ณ , ์์ผ๋ฉด `corepack pnpm`์ผ๋ก ํด๋ฐฑํฉ๋๋ค. ๋ค์ดํฐ๋ธ Windows Python์์๋ ๊ณต์ฉ ์คํ๊ธฐ๊ฐ `pnpm.cmd`๋ฅผ ์ผ๋ฐ `pnpm` ์กฐํ๋ณด๋ค ๋จผ์ ํ์ธํฉ๋๋ค. ์ผ๋ฐ ์กฐํ๋ `PATH`/`PATHEXT`๋ฅผ ๋ฐ๋ฅด๋ฏ๋ก ๊ฐ์ PATH ๋๋ ํฐ๋ฆฌ๋ ๊ทธ๋ณด๋ค ์์ ๋๋ ํฐ๋ฆฌ์ `.exe` ๋๋ `.bat`์ด ์ ํ๋ ์ ์์ต๋๋ค. Corepack ํด๋ฐฑ๋ ๋ง์ฐฌ๊ฐ์ง๋ก `corepack.cmd`๋ฅผ `corepack`๋ณด๋ค ๋จผ์ ํ์ธํฉ๋๋ค. POSIX Python์ MSYS/Cygwin์์ ์คํ๋๋ ๊ฒฝ์ฐ๋ฅผ ํฌํจํด ์ผ๋ฐ ์ด๋ฆ์ ๋จผ์ ์ฌ์ฉํฉ๋๋ค. ์คํ๊ธฐ์ ์ง๋จ ๋๊ตฌ๋ ์ ์ฅ์ ๊ฒฝ๋ก๋ฅผ ์ ๋ ๊ฒฝ๋ก๋ก ํด์ํ๋ฏ๋ก, ํธ์ถ์์ ํ์ฌ ๋๋ ํฐ๋ฆฌ์ ๊ด๊ณ์์ด ์ด ๊ฒ์ฌ๋ค์ด ๋์ํฉ๋๋ค. Corepack์ `frontend/`์์ ์คํ๋๋ฏ๋ก `packageManager` ๋ฒ์ (`frontend/package.json`์ ๊ณ ์ ๋จ)์ ๋ฐ๋ฅด๋ฉฐ, ์ ์ญ pnpm shim์ ํ์ฑํํ ํ์๋ ์์ต๋๋ค.
`make check`๋ ๋๊ตฌ ์ง๋จ ์ถ๋ ฅ์ UTF-8๋ก ๋์ฝ๋ฉํ๋ฉฐ, UTF-8์ด ์๋ ํธ์คํธ์์๋ ์ ๋์ฝ๋ pnpm ์ค๋ฅ๋ฅผ ๋ณด์กดํฉ๋๋ค. ์๋ชป๋ ์ถ๋ ฅ ๋ฐ์ดํธ๋ ๋์ฒด ๋ฌธ์๋ก ๋ฐ๋๋ฏ๋ก, ๊ฒ์ฌ๊ธฐ๋ ์ถ๋ ฅ ๋์ฝ๋ฉ ์ค์ ์ค๋จ๋์ง ์๊ณ ์์กด์ฑ ์คํจ๋ฅผ ๋ณด๊ณ ํ ์ ์์ต๋๋ค.
2. **์์กด์ฑ ์ค์น**:
```bash
make install # Install backend + frontend dependencies + pre-commit hooks
```
ํ
์ค์ ์ uv๋ฅผ ํตํด pre-commit์ ํธ์ถํ๋ฏ๋ก, uv์ ๋๊ตฌ ๋๋ ํฐ๋ฆฌ๊ฐ `PATH`์ ์์ด๋ ๋ฉ๋๋ค.
3. **(์ ํ ์ฌํญ) ์๋๋ฐ์ค ์ด๋ฏธ์ง ๋ฏธ๋ฆฌ ๋ฐ๊ธฐ**:
```bash
# Recommended if using Docker/Container-based sandbox
make setup-sandbox
```
์ด ๋ช
๋ น์ UTF-8 `config.yaml`์์ ์ค์ ๋ ์๋๋ฐ์ค ์ด๋ฏธ์ง๋ฅผ ์ฝ์ผ๋ฉฐ, ์ ํ BOM ์ ๋ฌด์ LF ๋๋ CRLF ์ค ๋ ํ์์ ๊ด๊ณ์์ด ๋์ํฉ๋๋ค.
macOS์์๋ Docker๊ฐ ์ค์น๋์ด ์์ง ์๋๋ผ๋ Apple Container pull์ด ์ฑ๊ณตํ๋ฉด ์ด ๋จ๊ณ๊ฐ ์๋ฃ๋ฉ๋๋ค. Docker๋ฅผ ์ฌ์ฉํ ์ ์์ผ๋ฉด Docker ์ด๋ฏธ์ง๋ ํจ๊ป ๋ฐ์ต๋๋ค.
4. **์๋น์ค ์์**:
```bash
make dev
```
5. **์ ์**: http://localhost:2026
6. **(์ ํ ์ฌํญ) ๋ก์ปฌ ๊ฒํ ์ฉ ์ํ ๋ฉ๋ชจ๋ฆฌ ๋ฐ์ดํฐ ๋ถ๋ฌ์ค๊ธฐ**: `Settings > Memory`๋ฅผ ์ด๊ณ **Import memory**๋ฅผ ํด๋ฆญํ ๋ค์ `backend/docs/memory-settings-sample.json`์ ์ ํํ์ธ์. ๋ธ๋ผ์ฐ์ ๋ ๋ก๊ทธ์ธํ ์ฌ์ฉ์์ ๋ฉ๋ชจ๋ฆฌ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
์ผํ์ฉ ๊ฒํ ํ๊ฒฝ์์ ๋ฑ๋ก๋ ๋ชจ๋ ์ฌ์ฉ์์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ต์ฒดํ๋ ค๋ฉด ๋ค์์ ์คํํ์ธ์.
```bash
cd backend
uv run python ../scripts/load_memory_sample.py --all-users
```
์ผ๊ด ๋ชจ๋๋ SQLite/PostgreSQL ์ฌ์ฉ์ ๋ ์ง์คํธ๋ฆฌ๋ฅผ ์ง์ํ๊ณ , `.deer-flow/memory-sample-backups/` ์๋์ ํ์์คํฌํ๊ฐ ๋ถ์ ๋ฐฑ์
์ ๋ง๋ค๋ฉฐ, ์์ ์ ์ฅ๋์ง ์๋ `database.backend: memory` ๋ชจ๋๋ ๊ฑฐ๋ถํฉ๋๋ค. ์ ์ฒด ๊ฒํ ํ๋ฆ์ [backend/docs/MEMORY_SETTINGS_REVIEW.md](backend/docs/MEMORY_SETTINGS_REVIEW.md)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
๋ก์ปฌ ์๋น์ค๋ ํญ์ ๋ด๋ถ ํฌํธ(`8001`, `3000`, `2026`)๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ฃจํธ `.env` ๋ณ์ `PORT`๋ ๊ฒ์๋ Docker ์ง์
์ (ingress)๋ง ์ค์ ํ๋ฉฐ, `make dev`๊ฐ ์ฌ์ฉํ๋ Next.js ํฌํธ๋ ๋ฐ๊พธ์ง ์์ต๋๋ค.
#### ์์ ๋ชจ๋
DeerFlow๋ ์์ด์ ํธ ๋ฐํ์์ Gateway API ๋ด๋ถ์์ ์คํํฉ๋๋ค. ๊ฐ๋ฐ ๋ชจ๋๋ ํซ ๋ฆฌ๋ก๋๋ฅผ ํ์ฑํํ๊ณ , ํ๋ก๋์
๋ชจ๋๋ ๋ฏธ๋ฆฌ ๋น๋๋ ํ๋ก ํธ์๋๋ฅผ ์ฌ์ฉํฉ๋๋ค.
| | **๋ก์ปฌ ํฌ๊ทธ๋ผ์ด๋** | **๋ก์ปฌ ๋ฐ๋ชฌ** | **Docker ๊ฐ๋ฐ** | **Docker ํ๋ก๋์
** |
|---|---|---|---|---|
| **๊ฐ๋ฐ** | `./scripts/serve.sh --dev`
`make dev` | `./scripts/serve.sh --dev --daemon`
`make dev-daemon` | `./scripts/docker.sh start`
`make docker-start` | โ |
| **ํ๋ก๋์
** | `./scripts/serve.sh --prod`
`make start` | `./scripts/serve.sh --prod --daemon`
`make start-daemon` | โ | `./scripts/deploy.sh`
`make up` |
| ์์
| ๋ก์ปฌ | Docker ๊ฐ๋ฐ | Docker ํ๋ก๋์
|
|---|---|---|---|
| **์ค์ง** | `./scripts/serve.sh --stop`
`make stop` | `./scripts/docker.sh stop`
`make docker-stop` | `./scripts/deploy.sh down`
`make down` |
| **์ฌ์์** | `./scripts/serve.sh --restart [flags]` | `./scripts/docker.sh restart` | โ |
`make start`์ `make start-daemon`์ ์คํํ ๋๋ง๋ค `next build`๋ก ํ๋ก ํธ์๋๋ฅผ ๋ค์ ๋น๋ํฉ๋๋ค. ๋์ ๋ง์ง๋ง ๋น๋๋ฅผ ์ฌ์ฌ์ฉํ๋ ค๋ฉด `SKIP_FRONTEND_BUILD=1`์ ์ ๋ฌํ์ธ์(๋๋ `--skip-frontend-build`๋ฅผ ์ถ๊ฐํ์ธ์. ์ด ํ๋๊ทธ๋ `./scripts/serve.sh --prod`๋ฅผ ์ง์ ํธ์ถํ ๋ ์ฌ์ฉํฉ๋๋ค). ์ด๋ ์ตํธ์ธ ๋ฐฉ์์ด๋ฉฐ, `frontend/.next`์ ์๋ฃ๋ ๋น๋๊ฐ ์์ผ๋ฉด ์ฆ์ ์คํจํฉ๋๋ค.
Gateway๋ `/api/langgraph/*`๋ฅผ ์์ ํ๋ฉฐ, nginx ๋ค์์ ์ด๋ฌํ ๊ณต๊ฐ LangGraph ํธํ ๊ฒฝ๋ก๋ฅผ ์์ฒด ๋ค์ดํฐ๋ธ `/api/*` ๋ผ์ฐํฐ๋ก ๋ณํํฉ๋๋ค.
์คํ ์์ฑ ์ค ๋ฐ์ํ๋ ์ฝ๋ ์์ด์ ํธ ์ํฌํธ๋ ์ ์ฉ ์์ปค ํ์ ์ฌ์ฉํ๋ฏ๋ก, ์์ด์ ํธ ์คํ์ด ๋ก๋๋๋ ๋์์๋ ๊ด๋ จ ์๋ Gateway ์์ฒญ์ ๊ณ์ ์๋ตํฉ๋๋ค. ํฉํ ๋ฆฌ ์ํฌํธ๊ฐ ์คํจํ๋ฉด ํด๋น ์คํ์ ์น์ธ(admission)๋์ง ์์ต๋๋ค.
Gateway ์์ด ์ฝ๊ธฐ ์ ์ฉ ๋ฐ๋ชจ๋ฅผ ์คํํ๋ ค๋ฉด `make build-static`์ `frontend/`์์ ์คํํ ๋ค์, ๊ฐ์ ๋๋ ํฐ๋ฆฌ์์ `HOSTNAME=127.0.0.1 PORT=3000 node --env-file=.env .next/standalone/server.js`๋ฅผ ์คํํ์ธ์. ๋น๋์๋ ๊ณต๊ฐ ๋ฐ๋ชจ ์์ฐ์ด ํฌํจ๋๋ฉฐ, ์ง์๋๋ ๋ฐ๋ชจ API ์ฝ๊ธฐ ์์ฒญ์ ๋ก์ปฌ์์ ์ฒ๋ฆฌ๋ฉ๋๋ค. ์ฐ๊ธฐ๋ ์ฌ์ฉํ ์ ์์ต๋๋ค. ํํ์ด์ง์ GitHub ์คํ ์๋ฅผ ํ์ํ๋ ค๋ฉด Node๋ฅผ ์์ํ๊ธฐ ์ ์ `GITHUB_OAUTH_TOKEN`์ `frontend/.env`์ ์ค์ ํ์ธ์. ํ ํฐ์ ์๋ฒ์๋ง ๋จธ๋ฌด๋ฅด๋ฉฐ, ์๊ฒฉ ์ฆ๋ช
์ด ์๊ฑฐ๋ GitHub ์์ฒญ์ด ์คํจํ๋ฉด ์คํ ์๊ฐ ์จ๊ฒจ์ง๋๋ค. ํ ํฐ์ ๋ณ๊ฒฝํ ํ์๋ Node๋ฅผ ์ฌ์์ํ์ธ์. ๋ค์ ๋น๋ํ ํ์๋ ์์ต๋๋ค.
#### LangGraph Studio (์ ํ ์ฌํญ)
๊ธฐ๋ณธ `make dev` ํ ํด๋ก์ง๋ DeerFlow์ Gateway ๋ด์ฅ ๋ฐํ์์ ์ฌ์ฉํ๋ฉฐ LangGraph Studio๊ฐ ํ์ํ์ง ์์ต๋๋ค. ๋
๋ฆฝ ์คํํ ๊ฐ๋ฐ ์๋ฒ๋ก ๋ฑ๋ก๋ ๋ฆฌ๋ ์์ด์ ํธ ๊ทธ๋ํ๋ฅผ ์ดํด๋ณด๊ณ ํ
์คํธํ๋ ค๋ฉด, `backend/`์์ ๋ช
๋ น์ ์คํํ์ธ์. ๊ทธ๋์ผ CLI๊ฐ `langgraph.json`์ ์ฐพ์ ์ ์์ต๋๋ค.
```bash
cd backend
uv run langgraph dev --allow-blocking
```
์ด ๋ช
๋ น์ ๋ก์ปฌ API์ Studio UI์ URL์ ์ถ๋ ฅํฉ๋๋ค. ์ด ์ธ๋ฉ๋ชจ๋ฆฌ ์๋ฒ๋ ๊ฐ๋ฐ ๋ฐ ํ
์คํธ ์ ์ฉ์
๋๋ค. ์ด ํ๋๊ทธ๋ ๋ก์ปฌ Studio ์์ฒญ ์ค DeerFlow์ ๋๊ธฐ์ ์ค์ ๋ฐ ๊ทธ๋ํ ํฉํ ๋ฆฌ ์ด๊ธฐํ๋ฅผ ํ์ฉํ๋ ๊ฒ์ผ๋ก, ํ๋ก๋์
์๋ฒ ์ค์ ์ผ๋ก ์ทจ๊ธํด์๋ ์ ๋ฉ๋๋ค. ๋ก์ปฌ Studio ์ธ์ฆ์ ์๋์ผ๋ก ์ฒ๋ฆฌ๋๋ฏ๋ก ์ฐ๊ฒฐ์ ์ปค์คํ
ํค๋๊ฐ ํ์ํ์ง ์์ต๋๋ค. ํ๋ก๋์
์ํฌ๋ก๋์๋ ๋ฌธ์์ ์๋ด๋ DeerFlow์ ํ๋ก๋์
์์ ๋ชจ๋๋ ์ง์๋๋ LangSmith ๋ฐฐํฌ๋ฅผ ์ฌ์ฉํ์ธ์. ์ด ๋
๋ฆฝ ์คํํ ๋ชจ๋์์ ์ด์์คํดํธ์ ์์ ๊ถ๊ณผ ์ถ์ฒ(provenance)๋ ์๋ฒ๊ฐ ์์ ํฉ๋๋ค. Studio๋ ๋ฑ๋ก๋ ๊ทธ๋ํ์ ์์ ์ด ์์ฑํ ์ด์์คํดํธ๋ฅผ ์ฐพ์ ์ ์์ผ๋ฉฐ, ์ผ๋ฐ์ ์ธ ์ด์์คํดํธ ๋ฒ์ ์ ํ๋ ๊ณ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ ๊ธด ๋ก์ปฌ ๋ฐํ์์ด ์์ ์ ์ฅ๋ ๊ฐ๋ฐ ์ ์ฅ์๋ฅผ ๋ถ๋ฌ์ค๊ธฐ ์ ์, DeerFlow๋ ๋ ๊ฑฐ์ ์ด์์คํดํธ ํ๊ณผ ๋ฒ์ ์ด๋ ฅ์ ๋ณต๊ตฌํ์ฌ ๊ณผ๊ฑฐ์ ํด๋ผ์ด์ธํธ ๋ฉํ๋ฐ์ดํฐ๊ฐ ์๋ฒ ๊ถํ์ ๋์ด๋ฆฌ๊ฑฐ๋ ๋ฐํ์์ ์์ ์ ์ ๋ฆฌ ๊ณผ์ ์์ ํ๊ธฐ๋์ง ์๋๋ก ํฉ๋๋ค. ๋ฐฑ์๋ ์์กด์ฑ์ `uv sync`๋ก ๋๊ธฐํ๋ ์ํ๋ฅผ ์ ์งํ์ธ์. ์ด ํธํ์ฑ ๊ฒฝ๋ก๋ ์ ์ธ๋ LangGraph ๋ฐํ์ ๋ฒ์ ์ ํ์๋ก ํ๋ฉฐ, ์์ ์ ์ฅ์ ๊ณ์ฝ์ด ๋ ์ด์ ๊ธฐ๋์ ์ผ์นํ์ง ์์ผ๋ฉด ๊ฒฝ๊ณ ๋ฅผ ๋ก๊ทธ๋ก ๋จ๊น๋๋ค. ๋ฌธ์์ ์๋ด๋ ๋ช
๋ น์ LangGraph์ ํ์ผ ๊ธฐ๋ฐ ์ปค์คํ
์ฑ ๋ก๋๋ฅผ ์ฌ์ฉํ๋ฉฐ, ์ด ๋ก๋๋ DeerFlow์ ํ๊ท ํ
์คํธ๋ก๋ ์ง์ ๊ฒ์ฆ๋ฉ๋๋ค.
`if_not_exists="create"`๋ฅผ ์ฌ์ฉํ๋ ๋
๋ฆฝ ์คํํ ์คํ์ ์๋ก ์์ฑ๋ ์ค๋ ๋์ ๊ฒ์ ๊ฐ๋ฅํ ํ๊ทธ๋ฅผ ํฌํจํ ์ค์ ๊ณผ ์คํ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๋ณด์กดํ๋ฉฐ, ํค๊ฐ ์ค๋ณต๋๋ฉด ์คํ ๋ฉํ๋ฐ์ดํฐ๊ฐ ์ฐ์ ํฉ๋๋ค. ์ค๋ ๋ ์์ ๊ถ๊ณผ MCP ์ธ์นด๋ค์ด์
(incarnation)์ ์๋ฒ๊ฐ ์์ ํ๋ฉฐ, ์ดํ ์คํ์ด ์ค๋ ๋์ ์์ฑ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๋์ฒดํ์ง ์์ต๋๋ค.
LangGraph Studio๋ ์ง์ ์คํํ LangGraph Server๋ฅผ ํตํด `backend/langgraph.json`์ ํธ์ถํ๋ ์ํฌํ๋ก์์๋, DeerFlow๊ฐ ํด๋น ๋ฐํ์์ด ๊ฒ์ํ ์ธ์ฆ๋ ์๋ณ ์ ๋ณด๋ฅผ ๋ฐ์ ์ปค์คํ
์์ด์ ํธ ์ค์ /SOUL, ์ฌ์ฉ์ ์คํฌ๊ณผ ์คํฌ ์ ์ฑ
, ์
๋ก๋, ์ค๋ ๋ ๋ฐ์ดํฐ, ๋ฉ๋ชจ๋ฆฌ ์ฝ๊ธฐ/์ฐ๊ธฐ์ ์ฌ์ฉํฉ๋๋ค. ์ด๋ฅผ ํตํด ์ธ์ฆ๋ ์คํ์ด ๊ณต์ `default` ํ์ผ ์์คํ
๋ฒํท์ ์์ด์ง ์์ผ๋ฉฐ, ์๋ฒ๊ฐ ์์ ํ ์๋ณ ์ ๋ณด๊ฐ ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ธ ์ผ๋ฐ์ ์ธ `user_id` ๊ฐ๋ณด๋ค ์ฐ์ ํฉ๋๋ค. ์ด๋ฉ์ผ ์ฃผ์ ๊ฐ์ ์ธ๋ถ ์๋ณ ์ ๋ณด๋ DeerFlow ์ ์ฅ์์ ์ ๊ทผํ๊ธฐ ์ ์ ์ถฉ๋์ ๊ฐํ๊ณ ๋๋ ํฐ๋ฆฌ ์ด๋ฆ์ผ๋ก ์์ ํ ์์ ์ ์ธ ์ฌ์ฉ์ ID๋ก ๋งคํ๋ฉ๋๋ค. ๊ธฐ๋ณธ DeerFlow ์๋น์ค ํ ํด๋ก์ง๋ ์ฌ์ ํ ์์์ ์ค๋ช
ํ Gateway ๋ด์ฅ ๋ฐํ์์
๋๋ค.
Gateway ์คํ์ `/mnt/user-data/outputs` ์๋์์ ์์ฑ๋๊ฑฐ๋ ์์ ๋ ์ํฐํฉํธ์ ๋ํด ๋ค์ดํฐ๋ธ ์ ๋ฌ์ ์๋์ผ๋ก ๊ฐ์ ํฉ๋๋ค. `present_files`๋ ํ์ฌ ์คํ์ด ์์ฑํ ์ถ๋ ฅ์ ํ๋ ์ด์ ์ ์ํด์ผ ํ๋ฉฐ, ์ข
๋ฃ `run.delivery` ์์์ฆ์ด ์์ ์ ์ฅ๋์ด์ผ ํฉ๋๋ค. ๊ฐ์ ์ํฐํฉํธ ๊ฒฝ๋ก๋ ์ถ๋ ฅ ๋๋ ํฐ๋ฆฌ ๊ฒฝ๊ณ๋ฅผ ๊ฒ์ฆํ๊ธฐ ์ ์, ์ถ๋ ฅ์ ์์ฑํ ๊ฒ๊ณผ ๋์ผํ ์ธ์ฆ๋ ์ฌ์ฉ์ ๋ฐ ์ค๋ ๋ ๋ฒ์ ์์์ ํด์๋ฉ๋๋ค. ์ถ๋ ฅ ์ํฐํฉํธ๋ฅผ ์์ฑํ์ง ์๋ ์คํ์ ์ผ๋ฐ์ ์ธ ๋ํ ๋์์ ์ ์งํฉ๋๋ค.
์ค๋ ๋ ๋ฒ์์ `runs.wait()` ํธ์ถ์ด `status: error`๋ก ๋๋๋ฉด, ์ด ํธ์ถ์ ์ด์ ์๋ต ๋์ ํ์ฌ ์คํ์ ์ค๋ฅ๋ฅผ ๋ณด๊ณ ํฉ๋๋ค. ๋น๋๊ธฐ Python LangGraph SDK๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์์ธ๋ฅผ ๋ฐ์์ํต๋๋ค. ๋ฐํ๋ ์ํ์ ์ค๋ฅ๋ฅผ ํ์ธํ๋ ค๋ฉด `raise_error=False`๋ฅผ ์ ๋ฌํ์ธ์.
DeerFlow์ ๊ธฐ๋ณธ ์ ๊ณต ์ปค์คํ
์ด๋ฒคํธ๋ ๋ LangGraph ์คํธ๋ฆฌ๋ฐ ์ธํฐํ์ด์ค ๋ชจ๋์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ค์ดํฐ๋ธ ํด๋ผ์ด์ธํธ๋ ๊ณ์ `stream_mode="custom"`์ ๊ตฌ๋
ํ ์ ์๊ณ , ์ฝ๋ฐฑ ๊ธฐ๋ฐ ํตํฉ์ ๊ฐ์ ํ์ด๋ก๋๋ฅผ `on_custom_event` ๋ ์ฝ๋(`astream_events(version="v2")`์์ ์ ๊ณต)๋ก ๋ฐ์ ์ ์์ต๋๋ค. ์ฝ๋ฐฑ ์ด๋ฒคํธ ์ด๋ฆ์ ํ์ด๋ก๋์ `type` ํ๋์ ์ผ์นํฉ๋๋ค.
#### Docker ํ๋ก๋์
๋ฐฐํฌ
`./scripts/deploy.sh`๋ ๋น๋์ ์์์ ๋ฐ๋ก ์ํํ๋ ๊ฒ์ ์ง์ํฉ๋๋ค.
```bash
# One-step (build + start)
./scripts/deploy.sh
# Two-step (build once, start later)
./scripts/deploy.sh build # build all images
./scripts/deploy.sh start # start pre-built images
# Stop
./scripts/deploy.sh down
```
### ๊ณ ๊ธ
#### ์๋๋ฐ์ค ๋ชจ๋
DeerFlow๋ ์ฌ๋ฌ ์๋๋ฐ์ค ์คํ ๋ชจ๋๋ฅผ ์ง์ํฉ๋๋ค.
- **๋ก์ปฌ ์คํ**(ํธ์คํธ ๋จธ์ ์์ ์๋๋ฐ์ค ์ฝ๋๋ฅผ ์ง์ ์คํ)
- **Docker ์คํ**(๊ฒฉ๋ฆฌ๋ Docker ์ปจํ
์ด๋์์ ์๋๋ฐ์ค ์ฝ๋๋ฅผ ์คํ)
- **Kubernetes๋ฅผ ์ฌ์ฉํ Docker ์คํ**(provisioner ์๋น์ค๋ฅผ ํตํด Kubernetes Pod์์ ์๋๋ฐ์ค ์ฝ๋๋ฅผ ์คํ)
๋ํ ์ํ ์์ ์๋๋ฐ์ค ์ฐธ์กฐ๋ ์๋ฒ๊ฐ ์์ ํฉ๋๋ค. ์ธ๋ถ ์คํ API์ ์ค๋ ๋ ์ํ API๋ ํธ์ถ์๊ฐ ์ ๊ณตํ `sandbox` ๊ฐ์ ๊ฑฐ๋ถํฉ๋๋ค. ์ฒดํฌํฌ์ธํธ๋ฅผ ๋ณต์ํ ๋ ๋ฐํ์์ ๋๊ตฌ๊ฐ ๊ทธ ์ฐธ์กฐ๋ฅผ ์ฌ์ฌ์ฉํ๊ธฐ ์ ์ ์ธ์ฆ๋ ์ฌ์ฉ์์ ์ค๋ ๋๋ฅผ ๊ธฐ์ค์ผ๋ก ์ฐธ์กฐ๋ฅผ ํด์ํฉ๋๋ค. ๋ฐํ์ ์ค๋ ๋ ID๊ฐ ์์ผ๋ฉด, ์ฐธ์กฐ๋ ์๋๋ฐ์ค๊ฐ ์บ์๋์ด ์๋๋ผ๋ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
๋ก์ปฌ ์คํ์์ ํธ์คํธ Bash๊ฐ ํ์ฑํ๋์ด ์์ผ๋ฉด, DeerFlow๋ `uname -s`๋ก OS ๊ฐ์ง๋ฅผ ์์ํ๊ณ Darwin์์๋ ์ด์ด์ `sw_vers`๋ฅผ ์ฌ์ฉํฉ๋๋ค. Linux์์๋ ํ์ฑ ์๋๋ฐ์ค ์ ์ฑ
์ด ํ์ฉํ๋ ๊ฒฝ์ฐ์๋ง `/etc/os-release` ๊ฐ์ ํธ์คํธ ์์คํ
ํ์ผ์ ์ฝ์ต๋๋ค. ํธ์คํธ ํ์ผ ์์คํ
๊ฒฝ๋ก ๊ฒ์ฌ๋ ์ฌ์ ํ ์ ์ฉ๋ฉ๋๋ค. ๊ฒฝ๋ก๊ฐ ์ฐจ๋จ๋๋ฉด, ์์ด์ ํธ๋ ๊ฑฐ๋ถ๋ ๋ช
๋ น์ ๋ฐ๋ณตํ๋ ๋์ ํ์ฉ๋ ๋ช
๋ น ์ ์ฉ ํ์ธ ๋ฐฉ๋ฒ์ด๋ ๊ฐ์ ๊ฒฝ๋ก๋ฅผ ์ฌ์ฉํ๋๋ก ์๋ด๋ฉ๋๋ค.
Docker ๊ฐ๋ฐ ํ๊ฒฝ์์ ์๋น์ค ์์์ `config.yaml`์ ์๋๋ฐ์ค ๋ชจ๋๋ฅผ ๋ฐ๋ฆ
๋๋ค. Local/Docker ๋ชจ๋์์๋ `provisioner`๊ฐ ์์๋์ง ์์ต๋๋ค.
๋ก์ปฌ AIO ์๋๋ฐ์ค์ ํฌํธ ํ ๋น์ TCP ํฌํธ 65535์์ ๋ฉ์ถฅ๋๋ค. ์ค์ ๋ ์์ ํฌํธ๋ถํฐ ๋จ์ ํฌํธ๊ฐ ๋ชจ๋ ์ฌ์ฉ ์ค์ด๋ฉด, ๋ฒ์๋ฅผ ๋ฒ์ด๋ ๋ฐ์ธ๋๋ฅผ ์๋ํ๋ ๋์ ์ฌ์ฉ ๊ฐ๋ฅํ ํฌํธ๊ฐ ์๋ค๊ณ ๋ณด๊ณ ํฉ๋๋ค.
์ํ๋ ๋ชจ๋๋ฅผ ์ค์ ํ๋ ค๋ฉด [์๋๋ฐ์ค ์ค์ ๊ฐ์ด๋](backend/docs/CONFIGURATION.md#sandbox)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
์๊ฒฉ ๋๋ ํฐ๋ฆฌ ๋ชฉ๋ก ์กฐํ๋ ๋ฐํ๋ ํญ๋ชฉ์ด ์๋๋ผ๋ ํ์ ์คํจ(์: ์ฝ์ ์ ์๋ ๋๋ ํฐ๋ฆฌ)๋ฅผ ๋ถ์์ ํ ๊ฒฐ๊ณผ๋ก ๋ณด๊ณ ํฉ๋๋ค. ์์ ๊ฒฝ๋ก๊ฐ ์๋ ๊ฒฝ์ฐ๋ โDirectory not found.โ๋ก ๋ณ๋๋ก ๋ณด๊ณ ํฉ๋๋ค.
์ ํ ์ฌํญ์ธ [Tenki ํด๋ผ์ฐ๋ ์๋๋ฐ์ค ํ๋ก๋ฐ์ด๋](backend/packages/harness/deerflow/community/tenki/README.md)๋ Tenki SDK 1.4.0 ์ด์์ ์ฌ์ฉํฉ๋๋ค. ํ์์์๋ ๋ช
๋ น์ ๋ถ๋ถ ์ถ๋ ฅ์ ๋ณด์กดํ๊ณ `Exit Code: 124`๋ฅผ ๋ณด๊ณ ํ๋ฉฐ, ํฌ์ค ์ฒดํฌ๊ฐ ์คํจํ๋ฉด ์ ์๋๋ฐ์ค๋ฅผ ํ์(reclaim)ํ ์ ์์ต๋๋ค. ํฌ์ค ํ๋ก๋ธ๋ `ok` ์ค ์ฃผ๋ณ์ ๋ก๊ทธ์ธ ์
ธ ์ถ๋ ฅ์ ํ์ฉํ๋ฉฐ, ์คํจํ๋ฉด ์๋๋ฐ์ค๋ฅผ ๊ต์ฒดํ๊ธฐ ์ ์ ์๋๋ฐ์ค ID์ ํ๋ก๋ธ ์ถ๋ ฅ์ ๋ก๊ทธ๋ก ๋จ๊น๋๋ค.
์ ํ ์ฌํญ์ธ OpenSandbox ํ๋ก๋ฐ์ด๋๋ Gateway ๋ฏธ๋ฆฌ ๋ณด๊ธฐ์ ๋ค์ด๋ก๋๋ฅผ ์ํด ํด์ด ์๋ฃ๋ ๋ ์์ฑ๋ ์ถ๋ ฅ ํ์ผ์ ๋ก์ปฌ ์ค๋ ๋ ์ ์ฅ์๋ก ๋ฏธ๋ฌ๋งํฉ๋๋ค. [๋๊ธฐํ ์ ํ๊ณผ ์คํจ ์ ๋์](backend/packages/harness/deerflow/community/opensandbox/README.md#lifecycle-and-contract)์ ์ฐธ๊ณ ํ์ธ์. ์๋ชป๋ UTF-8 ํ์ผ ์ด๋ฆ์ ๋ค๋ฅธ ์ถ๋ ฅ์ ๋ง์ง ์๊ณ ๊ฑด๋๋ฐ๋ฉฐ, ํฌ๊ธฐ๊ฐ ๊ฐ์ ๋ด์ฉ ์์ ๋ ํด์ ์ ์ฌ์ ํ ๋ณต์ฌ๋ฉ๋๋ค. ๋์๋ฌธ์ ๋๋ ์ ๋์ฝ๋์ ๋๋ฑํ ํ์ผยท๋๋ ํฐ๋ฆฌ ์ด๋ฆ์ ๊ฐ์ง ์ถ๋ ฅ์ ๋ณต์ฌ ์ ์ ๊ฑด๋๋ฐ๊ณ , ๊ธฐ์กด ๋ก์ปฌ ๊ฒฝ๋ก์ ๋ณ์นญ์ ๊ฑฐ๋ถ๋์ด ์ด์ ์ ์์ ํ ๋ณต์ฌ๋ณธ์ด ๋ณด์กด๋ฉ๋๋ค.
BoxLite ์ข
๋ฃ๋ ๋ฆ์ VM ๋ฑ๋ก์ ๊ฑฐ๋ถํ๊ณ , ์งํ ์ค์ธ ํ๋(acquisition)์ด ๋๋ ๋๊น์ง SDK ๋ฃจํ๋ฅผ ์ด์ด ๋ก๋๋ค. 5์ด ์์ ์ด๋ฅผ ๋ชจ๋ ์ฒ๋ฆฌํ์ง ๋ชปํ๋ฉด ๋ฆฌ์์ค๊ฐ ์ฌ์ ํ ์์ ๋ ์ํ๋ก ์ข
๋ฃ๊ฐ ์คํจํ๋ฉฐ, ๋ค์ ์๋ํ ์ ์์ต๋๋ค.
#### MCP ์๋ฒ
์ฑํ
UI์์ **Token Usage โ Debug**๋ฅผ ์ผ๋ฉด ์ผ๋ฐ ๋๊ตฌ ํธ์ถ๊ณผ MCP ๋๊ตฌ ํธ์ถ์ ์ดํด๋ณผ ์ ์์ต๋๋ค. ๊ฐ **Tool details** ํจ๋์ ์ ํ ์ํ๋ก ์์ํ๋ฉฐ, ๋๊ตฌ ์ด๋ฆ, ํธ์ถ ID, ์
๋ ฅ, ๊ทธ๋ฆฌ๊ณ ์์ ํ ๊ฒฐ๊ณผ ๋๋ ๋ช
์์ ์ค๋ฅ๋ฅผ ๋ณด์ฌ ์ค๋๋ค. ํฐ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ์๋ ค์ ํ์๋๋ฉฐ, ์ด๋ฆ์ด ๋จ์ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์์ฐ์ ์ด๊ณผํ๋ ํ๋๋ ์ด๋ฆ์ ๋ฐ๊พธ์ง ์๊ณ ์๋ต๋ฉ๋๋ค.
๊ตฌ์กฐํ๋ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ์ด์ค์ผ์ดํ๋ ๋ฌธ์์ด๊ณผ ๋ซ๋ ๊ตฌ๋ถ์๋ฅผ ํฌํจํด ์์ ํ JSON ๊ตฌ๋ฌธ์ ์ ์งํฉ๋๋ค.
๋ฐฐ์ด ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ํ
์คํธ ์์ฐ ์์ ๋ค์ ์์๋ฅผ ํ์ํ ์ ์์ ๋ ๋ฉ์ถ๋ฉฐ, ๊ฐ ์์ฒด๊ฐ ๋ง์ค์ํ์ธ ๊ฒฝ์ฐ์๋ ๊ทธ๋๋ก ๋ณด์กด๋ฉ๋๋ค.
๋ฐฐ์ด ๋์ ์ฐ์์ผ๋ก ์์ฑ๋ ํ์์๋ค์ ์๋ต๋ ๋ท๋ถ๋ถ์ ๋ํ๋ด๋ ๋ง์ค์ํ ํ๋๋ก ํฉ์ณ์ง๊ณ , ๋ค์ ๊ฐ์ด ์ด์ด์ง๋ ํ์์๋ ์๋ ์์น๋ฅผ ์ ์งํฉ๋๋ค.
ํ
์คํธ ๊ฒฐ๊ณผ๋ ๋ค์ ํ์ฑํ์ง ์๊ณ ํฐ ์ซ์ ID์ ์ค๋ณต JSON ํค๋ฅผ ํฌํจํ ์๋ ํํ์ ๊ทธ๋๋ก ์ ์งํฉ๋๋ค. ์ ํ์ ์ด๊ณผํ๋ ํ
์คํธ๋ ์๋ฆผ ์๋ด์ ํจ๊ป ์๋ถ๋ถ๋ง ํ์๋๋ฉฐ, ๊ตฌ์กฐํ๋ ๊ฐ์ฒด์ ๋ฐฐ์ด์ ๋ณ๋๋ก ์์์ด ์ง์ ๋ฉ๋๋ค.
๋ณต์ฌ ๋์์ ํ๋ฉด์ ํ์๋ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ง ๋ณต์ฌํฉ๋๋ค. ์ด ํ๋ฉด์ ๋ธ๋ผ์ฐ์ ๊ฐ ์ด๋ฏธ ์์ ํ ๋ฐ์ดํฐ๋ฅผ ํ๋ก ํธ์๋์์ ๋ณด์ฌ ์ฃผ๋ ๊ฒ์ด๋ฉฐ, ๋ณ๋์ ์ํฌ๋ฆฟ ๋ง์คํน ๊ณ์ธต์ ์์ต๋๋ค.
ํ๋ ๋ชจ๋์์ ์๋ชป๋ ํ์์ TODO ์ํ๋ ํ ํฐ ๊ท์์ ์ค๋จํ์ง ์๊ณ ์ผ๋ฐ์ ์ธ ๋๊ตฌ ๊ฒ์ฆ ์ค๋ฅ๋ฅผ ๋ฐํํ๋ฏ๋ก, ์์ด์ ํธ๊ฐ ํธ์ถ์ ๋ฐ๋ก์ก์ ์ ์์ต๋๋ค.
๋๊ตฌ๊ฐ ์์ฑํ ๊ฒฝ๋ก์ URL์ ์ปจํ
์คํธ ์์ถ ์ดํ์๋ ์งง์ ์ํฐํฉํธ ํธ๋ค๋ก ์ ์ง๋ ์ ์์ต๋๋ค(`tool_artifacts`, `config.yaml`์์ ์ค์ ). ํธ๋ค์ ํ๋ก๋ฐ์ด๋๊ฐ ํธ์ถ ID๋ฅผ ์ฌ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์๋ ์๋ก ๋ค๋ฅธ ๋๊ตฌ ๊ฒฐ๊ณผ ํ์ฐจ๋ฅผ ๊ตฌ๋ถํฉ๋๋ค. ํ์ค MCP ์ด๋ฏธ์ง URL์ stdio ์๋ฒ์ HTTP ์๋ฒ์ ๊ฒฐ๊ณผ๋ฅผ ํฌํจํด ํ์ผ ์ฐธ์กฐ์ ํจ๊ป ์์ง๋ฉ๋๋ค. ๊ฐ์ง๋ ํ์ผ URL์ ์ฟผ๋ฆฌ ๋ฌธ์์ด๊ณผ ํ๋๊ทธ๋จผํธ๋ฅผ ๊ทธ๋๋ก ๋ณด์กดํฉ๋๋ค. PII ๋ง์คํน์ด ํ์ฑํ๋์ด ์์ผ๋ฉด ๋ชจ๋ธ์ ๋ณด์ด๋ ์ํฐํฉํธ ๋ ์ด๋ธ์ ๊ทธ ์ ์ฑ
์ ๋ฐ๋ฅด๋ฉฐ, ๋ด๋ถ ์ฐธ์กฐ๋ ๋๊ตฌ ์ธ์ ํด์์ ์ํด ๊ทธ๋๋ก ์ ์ง๋ฉ๋๋ค. ์ค์ ๋ ๋ ์ง์คํธ๋ฆฌ ์ ํ์ ๊ฐ์ฅ ์ต๊ทผ์ ์ํฐํฉํธ๋ฅผ ์ ์งํ๊ณ , ์ฒดํฌํฌ์ธํธ์ ์ ์ฅ๋ ์ฒ๋ฆฌ ์๋ณ์๋ ์ฌ์์ ํ ์ด๋ฏธ ์ถ์ถ๋ ๊ฒฐ๊ณผ๊ฐ ๋ค์ ์์ง๋์ง ์๋๋ก ๋ง์ต๋๋ค. ํธ๋ค ํด์์ ๊ถํ ํ์ธ๊ณผ ์ฐ๊ธฐ ์์ ์ฑ ๊ฒ์ฌ๋ณด๋ค ๋จผ์ ์คํ๋๋ฉฐ, ์ ์ ์๊ฑฐ๋ ๋ง๋ฃ๋ ํธ๋ค์ ๋๊ตฌ๋ฅผ ์คํํ์ง ์๊ณ ์ค๋ฅ๋ฅผ ๋ฐํํฉ๋๋ค. ํฌ๊ธฐ๊ฐ ์์ ์ ์ ์๋ ๊ตฌ์กฐํ ๊ฒฐ๊ณผ๋ ์ต๋ 4096 UTF-8 ๋ฐ์ดํธ๊น์ง ์์ ํ JSON์ผ๋ก ์ ์ง๋ ์ ์์ผ๋ฉฐ, ๋น์ด ์๊ฑฐ๋ ๋๋ฌด ํฐ ํ์ด๋ก๋๋ ๊ฑด๋๋๋๋ค. ํธ๋ค์ ์์ด์ ํธ ๋ก์ปฌ์
๋๋ค. task ์ธ์๋ ๋ถ๋ชจ ํธ๋ค์ ๊ตฌ์ฒด์ ์ธ ์ฐธ์กฐ๋ก ํด์ํ๋ฉฐ, ์์๋ ๋ณด๊ณ ์๋ ์์ ๋ก์ปฌ ํธ๋ค์ด ์๋ ๊ตฌ์ฒด์ ์ธ ์ฐธ์กฐ๋ฅผ ๋ฐํํด์ผ ํฉ๋๋ค. ์๋ฆฐ ๋ชจ๋ธ ํฌ์(projection)์ ์๋ต๋ ํธ๋ค ์๋ฅผ ์๋ ค ์ค๋๋ค.
DeerFlow๋ ๊ธฐ๋ฅ์ ํ์ฅํ๊ธฐ ์ํด ์ค์ ๊ฐ๋ฅํ MCP ์๋ฒ์ ์คํฌ์ ์ง์ํฉ๋๋ค.
์์(durable) MCP ๋ฐฑ๊ทธ๋ผ์ด๋ ์์
์ด ํ์ฑํ๋์ด ์์ผ๋ฉด, ์์ด์ ํธ๋ `list_background_tasks(status="failed")` ๋๋ `status="input_required"`๋ฅผ ์ฌ์ฉํด ํ์ฌ ์ฑํ
์์ ์คํจํ ์์
์ด๋ ์
๋ ฅ์ ๊ธฐ๋ค๋ฆฌ๋ ์์
์ ์ฐพ์ ์ ์์ต๋๋ค. ๊ทธ ๋ฐ์ ์ง์๋๋ ์ํ๋ `submitted`, `working`, `completed`, `cancelled`์ด๋ฉฐ, ์ํ๋ฅผ ์๋ตํ๋ฉด ๊ธฐ์กด ๋์์ด ์ ์ง๋ฉ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ๊ฒฐ๊ณผ๋ฅผ ์ผ์นํ๋ ๊ฐ์ฅ ์ต๊ทผ ์์
20๊ฐ๋ก ์ ํํ๊ธฐ ์ ์ ํํฐ๋ฅผ ์ ์ฉํฉ๋๋ค. `active_only=true`์ ํจ๊ป ์ฌ์ฉํ๋ฉด ๋ ํํฐ๊ฐ ๋ชจ๋ ์ ์ฉ๋ฉ๋๋ค. ํ์ฑ ์ํ๋ `submitted`, `working`, `input_required`์ด๋ฏ๋ก ์ข
๋ฃ ์ํ๋ฅผ ์ง์ ํ๋ฉด ๋น ๋ชฉ๋ก์ด ๋ฐํ๋ฉ๋๋ค. `GET /api/threads/{thread_id}/mcp-tasks`๋ ๋์ผํ `status` ๋ฐ `active_only` ํํฐ๋ฅผ ์ง์ํ๋ฉฐ, ์ด ํํฐ๋ `limit`(๊ธฐ๋ณธ๊ฐ 50, ๋ฒ์ 1โ100)๋ณด๋ค ๋จผ์ ์ ์ฉ๋ฉ๋๋ค. ์: `?status=failed&limit=20`. ์ ์ ์๋ ์ํ๋ 422๋ฅผ ๋ฐํํ๋ฉฐ, ํํฐ๋ฅผ ์๋ตํ๋ฉด ๊ธฐ์กด ์๋ต์ด ์ ์ง๋ฉ๋๋ค.
HTTP/SSE MCP ์๋ฒ์์๋ OAuth ํ ํฐ ํ๋ฆ(`client_credentials`, `refresh_token`)์ด ์ง์๋ฉ๋๋ค.
ํ ํฐ ์๋ต์ `expires_in` ๊ฐ์ด ์๊ฑฐ๋, ํ์์ด ์๋ชป๋์๊ฑฐ๋, ๋ฒ์๋ฅผ ๋ฒ์ด๋๋ฉด ๊ธฐ๋ณธ ์ ํจ ๊ธฐ๊ฐ 1์๊ฐ์ด ์ฌ์ฉ๋ฉ๋๋ค. ์ฌ๊ธฐ์๋ ํ์ฌ ์๊ฐ์ ๋ํ๋ฉด ๋ง๋ฃ ํ์์คํฌํ๊ฐ ์ค๋ฒํ๋ก๋๋ ์ ํจ ๊ธฐ๊ฐ๋ ํฌํจ๋ฉ๋๋ค.
์์ HTTP/SSE ์์
์ ์ํ ์กฐํ ๋ฐ ์ทจ์ ํธ์ถ์ ์ฌ์์ ์ดํ๋ฅผ ํฌํจํด, ์์ ์ ์ฅ๋ ์์
์์ ์๋ฅผ ๊ธฐ์ค์ผ๋ก ์ค์ ๋ `user_auth` ์๊ฒฉ ์ฆ๋ช
์ ์ ํํฉ๋๋ค. ์์ฒญ๋ณ ์ํฌ๋ฆฟ์ ๋ฐฑ๊ทธ๋ผ์ด๋ ํธ์ถ์ ์ํด ๋ณด๊ด๋์ง ์์ต๋๋ค. ์์ฒญ ๋ฒ์ ์๊ฒฉ ์ฆ๋ช
์ด ์ ์ถ(submit) ์ธ์ฆ์ ์ฌ์ ์ํ๋ ๊ฒฝ์ฐ, ๋ ์๊ฒฉ ์ฆ๋ช
๋ชจ๋ ๊ฐ์ ์๊ฒฉ ์์
์ ๋ํ ์ ๊ทผ ๊ถํ์ด ์์ด์ผ ํฉ๋๋ค.
stdio MCP ์๋ฒ์์๋ `tool_call_timeout`์ผ๋ก ๋๊ตฌ๋ณ ํธ์ถ ํ์์์์ ์ค์ ํ ์ ์์ผ๋ฉฐ, ์์ ๋ฐฑ๊ทธ๋ผ์ด๋ ์์
ํธ์ถ์ HTTP/SSE ์๋ฒ์์๋ ๊ฐ์ ์ค์ ์ ๋ฐ๋ฆ
๋๋ค.
์์ stdio ์ธ์
ํ์ ์ฉ๋์ด ๊ฐ๋ ์ฐผ์ ๋ ์ ํด ์ธ์
๋ง ์ถ์ถํฉ๋๋ค. ํ์ ๋ชจ๋ ์ธ์
์ด ๋๊ตฌ๋ฅผ ์คํ ์ค์ด๋ฉด ์ ์ธ์
์์ฒญ์ ์ฉ๋ ์ค๋ฅ๋ก ์คํจํ๋ฉฐ, ํธ์ถ ํ๋๊ฐ ๋๋ ๋ค ์ฌ์๋ํ ์ ์์ต๋๋ค.
stdio ํ์ผ ์ถ๋ ฅ์์ ๊ฒฝ๋ก ์์ด ํ์ผ ์ด๋ฆ๋ง ์์ผ๋ฉด, ํด๋น ํธ์ถ์ด ์์ฑํ๊ฑฐ๋ ๋ณ๊ฒฝํ ํ์ผ ์ค ์ ์ผํ๊ฒ ์ผ์นํ๋ ํ์ผ์ ์ฐ๊ฒฐ๋ฉ๋๋ค. Windows ๋ฐฑ์ฌ๋์ ๊ฒฝ๋ก๋ฅผ ํฌํจํด ๊ด๋ จ ์๋ ๊ฒฝ๋ก ์์ ๋ค์ด ์๋ ํ์ผ ์ด๋ฆ์ ๊ทธ๋๋ก ๋ก๋๋ค.
HTTP/SSE ๋ฐฑ๊ทธ๋ผ์ด๋ ์์
ํธ์ถ์์ `session_init_timeout`์ ์ฐ๊ฒฐ ์ค์ (SSE ์๋ํฌ์ธํธ ์ด๋ฒคํธ ํฌํจ)๊ณผ MCP ์ด๊ธฐํ๋ฅผ ํฉ์น ์๊ฐ์ ๋ณ๋๋ก ์ ํํ๋ฉฐ, ๋๊ตฌ ํธ์ถ์ด ์์๋๋ฉด ๋ ์ด์ ์ ์ฉ๋์ง ์์ต๋๋ค. ์ด๊ธฐํ ๊ธฐํ ์ด๊ณผ ์ค๋ฅ์๋ ์๋ฒ์ ์ค์ ๋ ์๊ฐ ์ ํ์ด ํ์๋ฉ๋๋ค.
์ผ๋ฐ `task` ์๋ธ์์ด์ ํธ๋ ๋ ๊ฑฐ์ ์ค๋ ๋๋ฅผ ํฌํจํด MCP ํธ์ถ์ ๋ถ๋ชจ ์คํ(run)์ด ํฌ์ฐฉํ ์ค๋ ๋ ์ธ์คํด์ค(incarnation)๋ฅผ ๊ทธ๋๋ก ์ ์งํ๋ฏ๋ก, ์์ํด๋ ๊ฐ์ ์๋ช
์ฃผ๊ธฐ ๋ฒ์๊ฐ ๋ณด์กด๋ฉ๋๋ค.
MCP ๋๊ตฌ ์ด๋ฆ์๋ ์๋ฒ ๊ฐ ์ถฉ๋์ ๋ง๊ธฐ ์ํด ๊ธฐ๋ณธ์ ์ผ๋ก `_` ์ ๋์ฌ๊ฐ ๋ถ์ต๋๋ค. ์๋ฒ๊ฐ ์ด๋ฏธ ์์ฒด ๋๊ตฌ์ ๋ค์์คํ์ด์ค๋ฅผ ๋ถ์ธ๋ค๋ฉด, `extensions_config.json`์ ํด๋น ์๋ฒ ํญ๋ชฉ์ `tool_name_prefix: false`๋ฅผ ์ค์ ํด ์๋ ์ด๋ฆ์ ์ ์งํ์ธ์. ์ ๋์ฌ๋ ๊ฒฐ๊ณผ ์ด๋ฆ์ด ํ์ฑํ๋ ๋ชจ๋ ์๋ฒ์ ๊ฑธ์ณ ๊ณ ์ ํ๊ฒ ์ ์ง๋ ๋๋ง ๋์ธ์.
๋ก๊ทธ์ธํ ์ฌ์ฉ์์ ์๋ฆผ ํ ๊ธ, ๊ธฐ๋ณธ ๋ชจ๋ธ, ๋ํ ๋ชจ๋, ์ถ๋ก ๊ฐ๋๋ ๊ณ์ ์ ์ ์ฅ๋๋ฉฐ ๋ค๋ฅธ ๋ธ๋ผ์ฐ์ ์์๋ ๋ธ๋ผ์ฐ์ ์ ์ฅ์๋ฅผ ์ง์ด ๋ค์๋ ๋ณต์๋ฉ๋๋ค. ๋ธ๋ผ์ฐ์ ์๋ฆผ ๊ถํ์ ์ฌ์ ํ ๊ธฐ๊ธฐ๋ง๋ค ํ์ฉํด์ผ ํฉ๋๋ค. ๋ณ๊ฒฝ ์ฌํญ์ ๋คํธ์ํฌ ์ค๋ฅ ํ ์ฌ์๋๋๋ฉฐ, ์ ์ก๋์ง ์์ ๋ณ๊ฒฝ ์ฌํญ์ ๊ฐ์ ํญ์์ ์๋ก ๊ณ ์นจํด๋ ์ ์ง๋ฉ๋๋ค. ์๋ก ๋ค๋ฅธ ํ๋์ ๋ํ ๋์ ํธ์ง์ ๋ชจ๋ ๋ณด์กด๋๋ฉฐ, ๊ฐ์ ํ๋๋ผ๋ฉด ๋ง์ง๋ง์ผ๋ก ์๋ฒ์ ๊ธฐ๋ก๋ ๊ฐ์ด ์ ์ฉ๋ฉ๋๋ค. ๊ธฐ์กด์ ๋ฒ์๊ฐ ์ง์ ๋์ง ์์ ๋ธ๋ผ์ฐ์ ํ๊ฒฝ์ค์ ์ ๊ณ์ ์์ ์๊ฐ ์์ผ๋ฏ๋ก ์๋์ผ๋ก ์
๋ก๋๋์ง ์์ต๋๋ค. ์
๊ทธ๋ ์ด๋ ํ ํด๋น ์ค์ ์ ํ ๋ฒ ๋ค์ ์ ํํ์ธ์. ์ ์ ๋ฐ๋ชจ์ ์ธ์ฆ์ด ๋นํ์ฑํ๋ ๊ฐ๋ฐ ํ๊ฒฝ์ ๋ธ๋ผ์ฐ์ ๋ก์ปฌ ์ค์ ์ ์ ์งํฉ๋๋ค. ์ค๋ ๋๋ณ ๋ชจ๋ธ ์ฌ์ ์์ ๊ทธ ๋ฐ์ ํ์ ํ๊ฒฝ์ค์ ์ ๋ก์ปฌ์ ๋จ์ต๋๋ค.
์ ์ฑํ
์์๋ ์๋ฒ๊ฐ ๋ํ๋ฅผ ์์ฑํ๊ณ ๋ฉ์์ง๋ฅผ ํ์ธํ๋ ๋์, ์ ์ถํ ์ง๋ฌธ์ด ์คํธ๋ฆฌ๋ฐ๋๋ ์ถ๋ก ๋ฐ ๋๊ตฌ ๋จ๊ณ ์์ ๊ณ์ ํ์๋ฉ๋๋ค.
์ฑํ
ํค๋๋ ์ฌ์ด๋๋ฐ์์ ๋ด๋ณด๋ด๋ Markdown ๋ฐ JSON ๋ํ ๋ด๋ณด๋ด๊ธฐ๋ ํ์ฌ ๋ถ๋ฌ์จ ํ๋ฉด ๋ฐ์ ์๊ฑฐ๋ ๋ชจ๋ธ ์ปจํ
์คํธ์์ ์์ถ๋ ์ด์ ํด์ ํฌํจํด, ์์ ์ ์ฅ๋ ๋ชจ๋ ๊ธฐ๋ก ํ์ด์ง๋ฅผ ์ฝ์ต๋๋ค. ๊ธฐ๋ก ์ฝ๊ธฐ์ ์คํจํ๋ฉด ์ผ๋ถ๋ง ๋ด๊ธด ๋ํ๋ก์ ๋ด๋ ค๋ฐ๋ ๋์ ๋ด๋ณด๋ด๊ธฐ๋ฅผ ์ค๋จํฉ๋๋ค. ๊ณต๊ฐ ๋ฐ๋ชจ๋ ๋ฒ๋ค์ ํฌํจ๋ ๋ฉ์์ง๋ฅผ ๋ด๋ณด๋
๋๋ค.
Capability Center๋ ํ๋ฌ๊ทธ์ธ์ ์คํผ์ค ํ์
, ๋ฌธ์์ ์ง์, ๊ฒ์๊ณผ ๋ฆฌ์์น, ๋น์ฆ๋์ค์ ๋ฐ์ดํฐ, ๊ฐ๋ฐ๊ณผ ์ด์์ผ๋ก ๋ถ๋ฅํฉ๋๋ค. ๋๋ ํฐ๋ฆฌ์๋ ๊ธฐ์กด MCP ์ค์ ๋ฐ Lark์ ํจ๊ป ์ค์ ์ฐธ๊ณ ์๋ฃ๊ฐ ๋ค์ด ์์ต๋๋ค. ๊ถ์ฅ ํตํฉ๊ณผ ๊ธฐ๋ณธ ์ ๊ณต ์ง์์ด ๊ณง ์ค์น๋์๊ฑฐ๋ ๊ฒ์ฆ๋ ์ฐ๊ฒฐ์ ์๋ฏธํ์ง๋ ์์ต๋๋ค. Installed ํํฐ๋ ์ค์ ๋ MCP ํญ๋ชฉ๊ณผ ์ค์น๋ Lark๋ง ๋ณด์ฌ ์ค๋๋ค.
์น ์ธํฐํ์ด์ค์์ ์ค์ ํ ๊ฐ์ธ MCP ์ฐ๊ฒฐ์ ์ฌ์ฉ์๋ณ๋ก ์์ ์ ์ฅ๋ฉ๋๋ค.
๋ฐฐํฌ ๋๊ตฌ๋ ๊ณ์ ๊ณต์ ๋ฉ๋๋ค. ๊ด๋ฆฌ์๋ **Platform provided** ์๋์์ ๊ณต์ MCP ์๋ฒ๋ฅผ ์ถ๊ฐ, ํธ์ง, ํ์ฑํ, ๋นํ์ฑํ, ์ญ์ ํ ์ ์์ผ๋ฉฐ, ์ผ๋ฐ ์ฌ์ฉ์๋ ์กฐ์ ์ปจํธ๋กค ์์ด ์ํ๋ง ๋ณผ ์ ์์ต๋๋ค. ๊ฐ์ธ ํ๋ฌ๊ทธ์ธ ์ค์์น๋ ๋ก๊ทธ์ธํ ์ฌ์ฉ์์ ์ฐ๊ฒฐ์๋ง ์ํฅ์ ์ค๋๋ค. [์ฐ๊ฒฐ ์์ ๊ถ](docs/capability-center.md#personal-and-deployment-mcp-configuration)์ ์ฐธ๊ณ ํ์ธ์.
ํ๋ฌ๊ทธ์ธ ๋งค๋ํ์คํธ, ์ด๋ํฐ ๋ฑ๋ก, ์์ด์ ํธ ๊ธฐ๋ฅ(capability) ์ ํ์ [Capability Center ํตํฉ ๊ณ์ฝ](docs/capability-center.md)์ ์ฐธ๊ณ ํ์ธ์.
DingTalk ๋ฐ WeCom ๊ทธ๋ฃน ์๋ฆผ๊ณผ HubSpot CRM์ ๋ฒ๋ค๋ก ์ ๊ณต๋๋ ์ค์ ๊ฐ๋ฅํ ํ๋ฌ๊ทธ์ธ์
๋๋ค. ๊ด๋ฆฌ์๊ฐ ๋ก๋ด ์๊ฒฉ ์ฆ๋ช
์ด๋ HubSpot ๋น๊ณต๊ฐ ์ฑ ํ ํฐ์ ์ ๊ณตํ๋ฉด, ์์ด์ ํธ๋ ์์ฒญ๋ฐ์ ๊ทธ๋ฃน ์๋ฆผ์ ๋ณด๋ด๊ฑฐ๋, ํ์ฌ ๋ชฉ๋ก์ ์กฐํํ๊ฑฐ๋, ์ฐ๋ฝ์ฒ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ์ค์ ์ ์ ์ฅํ๋ ๊ฒ๋ง์ผ๋ก๋ ์ธ๋ถ์ ์๋ฌด๊ฒ๋ ๊ธฐ๋กํ์ง ์์ต๋๋ค. ์ด ํ๋ฌ๊ทธ์ธ๋ค์ ๊ธฐ์กด MCP ์๋ช
์ฃผ๊ธฐ๋ฅผ ์ฌ์ฌ์ฉํ๋ฉฐ ๋ณ๋์ ํ๋ฌ๊ทธ์ธ ์๋น์ค๊ฐ ํ์ํ์ง ์์ต๋๋ค. ํ์ ํ๋, ์ค์ฝํ, ๊ธฐ๋ฅ ๊ฒฝ๊ณ๋ ์์ ํตํฉ ๊ณ์ฝ์ ์ฐธ๊ณ ํ์ธ์.
ํ๋ฌ๊ทธ์ธ ๋ธ๋๋ ์์ด์ฝ์ ๋ก์ปฌ์ ๋ฒ๋ค๋ก ํฌํจ๋์ด ์์ต๋๋ค. ๊ฐ์ธ MCP ํ๋ฌ๊ทธ์ธ์ ์ถ๊ฐํ๊ฑฐ๋ ํธ์งํ ๋ ์ฌ์ฉ์๋ PNG, JPG, WebP ์ด๋ฏธ์ง(์ต๋ 2 MB)๋ฅผ ์
๋ก๋ํ๊ณ , ๋ฏธ๋ฆฌ ๋ณด๊ณ , ๊ธฐ๋ณธ ์์ด์ฝ์ผ๋ก ๋๋๋ฆด ์ ์์ต๋๋ค. ๋ณ๊ฒฝ ์ฌํญ์ Save๋ฅผ ๋๋ฌ์ผ ์ ์ฉ๋ฉ๋๋ค. ์ปค์คํ
์์ด์ฝ์ ์๋ฒ ํญ๋ชฉ์ ํ์ ์ ์ฉ `presentation.icon` ๋ฉํ๋ฐ์ดํฐ์ ์ ๊ทํ๋ 128px PNG๋ก ์ ์ฅ๋์ด ์ฌ๋ฌ ๋ธ๋ผ์ฐ์ ์์ ์ ์ง๋ฉ๋๋ค. ์ด ์์ด์ฝ์ MCP ์ ์ก ๊ณ์ธต์ผ๋ก ์ ๋ฌ๋์ง ์์ต๋๋ค.
Capability Center > Plugins๋ ๋์์ ์ด๋ฃจ์ด์ง ๋ค๋ฅธ ์๋ฒ์ ๋ณ๊ฒฝ์ ๋ณด์กดํ๋ ๋์ ์ง์ ๋ณ๊ฒฝ ์์ฒญ์ ํตํด MCP ์๋ฒ๋ฅผ ํ ๋ฒ์ ํ๋์ฉ ์ถ๊ฐ, ๊ต์ฒด, ์ญ์ ํฉ๋๋ค. ์ญ์ ๋ ๋ณธ๋ฌธ ์์ด URL๋ก ๋์์ ์ง์ ํ๋ ์์ฒญ์ ์ฌ์ฉํฉ๋๋ค. ํ ์๋ฒ์ stdio ๋ช
๋ น์ด ์๋ชป๋์ด ์์ด๋ ๋ ์ด์ ๋ค๋ฅธ ์๋ฒ์ ํ ๊ธ์ ๋ง์ง ์์ผ๋ฉฐ, ๊ทธ ์๋ชป๋ ์๋ฒ๋ฅผ ํ์ฑํํ๋ ๋์์ ์ฌ์ ํ ๋ช
๋ น ํ์ฉ ๋ชฉ๋ก์ผ๋ก ๋ณดํธ๋๊ณ ๋ฐฑ์๋ ๊ฒ์ฆ ๋ฉ์์ง๊ฐ UI์ ํ์๋ฉ๋๋ค.
SSE/HTTP ์๋ฒ์ ๋์ ์ง์ ์
๋ฐ์ดํธ๋ DeerFlow์ `type` ํ๋์ MCP ์ฌ์์ `transport` ํ๋๋ฅผ ๋ชจ๋ ๋ฐ์ต๋๋ค.
๋ฐํ์ MCP ๋ฐ ์คํฌ ์
๋ฐ์ดํธ๋ `extensions_config.json`์ ์์์ ์ผ๋ก ๊ต์ฒดํ๋ฏ๋ก, ์ฐ๊ธฐ๊ฐ ์ค๊ฐ์ ๋๊ฒจ๋ ๊ณต์ ์ค์ ์ด ์๋ฆฌ๊ฑฐ๋ ์ผ๋ถ๋ง ๊ธฐ๋ก๋ ์ํ๋ก ๋จ์ง ์์ต๋๋ค. ๊ฐ์ ํ์ผ์ ์ฝ๋ ๋ชจ๋ Gateway ์์ปค๋ ์ธ์คํด์ค๋ ๋ค์ ์ฝ๊ธฐ ๋ ์ ๋ฆฌ๋น์ ์ ๋ฐ์ํ๋ฏ๋ก(์บ์๊ฐ ํ์ผ์ ์ฝํ
์ธ ์๋ช
์ ํ์ธํฉ๋๋ค), ํ ๋ ํ๋ฆฌ์นด์์ ๋ณ๊ฒฝํ MCP ๋ฐ ์คํฌ ์ค์ ์ด ์ฌ์์ ์์ด ๋ค๋ฅธ ๋ ํ๋ฆฌ์นด์๋ ์ ์ฉ๋ฉ๋๋ค. ๋ฆฌ๋น์ ์ด ์๊ฑฐ๋, ์๋ ธ๊ฑฐ๋, ์ ํจํ์ง ์์ผ๋ฉด ์์ ํ ๋ฆฌ๋น์ ์ด ๋ฐ์๋ ๋๊น์ง ์ด์ ์ค์ ์ด ์ ์ง๋๋ฉฐ, ๋ฆฌ๋ก๋ ์ค ํ์ผ์ด ์ฌ๋ผ์ง๋ ๊ฒฝ์ฐ๋ ๋ง์ฐฌ๊ฐ์ง์
๋๋ค.
๊ด๋ฆฌ์์ MCP ์บ์ ์ด๊ธฐํ๋ ์ฐ๊ธฐ ๊ฐ๋ฅํ ์ค์ ๋๋ ํฐ๋ฆฌ์ ์๋ ์์ ์ธ๋(generation) ๋ง์ปค๋ฅผ ์ฆ๊ฐ์ํต๋๋ค. ๊ฐ์ ๋๋ ํฐ๋ฆฌ๋ฅผ ๋ง์ดํธํ ๋ชจ๋ Gateway ์์ปค๋ ๋ค์ ์กฐํ ์ ์ ์์ ์ด ์บ์ํ ๋๊ตฌ์ ํ๋ง๋ ์ธ์
์ ํ๊ธฐํฉ๋๋ค. ๋
๋ฆฝ๋ ํ์ผ ์์คํ
์ ์ฐ๋ ๋ ํ๋ฆฌ์นด๋ ์๋ฌต์ ์ผ๋ก ํฌํจ๋์ง ์์ต๋๋ค. ์ค์ ๊ฒฝ๋ก๋ฅผ ์ฌ์ฉํ ์ ์์ผ๋ฉด API๋ ๋์ ํ๋ก์ธ์ค ๋ก์ปฌ ์ด๊ธฐํ๋ผ๊ณ ๋ณด๊ณ ํฉ๋๋ค.
ํ์ฑ๋ ํ์ฅ ์ค์ ๊ณผ ๊ธฐ๋ก๋ ์ฝํ
์ธ ๋ค์ด์ ์คํธ๋ ๊ฐ์ ์ฝ๊ธฐ์์ ์ป์ผ๋ฏ๋ก, ๊ฒฝ์ํ๋ ํธ์ง ๋ค์ ํ์์คํฌํ๋ฅผ ๋ณด์กดํ๋ ๋ฐฑ์
๋ณต์์ด ์ด์ด์ง๋๋ผ๋ ๋ค๋ฅธ ๋ฆฌ๋น์ ์ด ๋ฌด๊ธฐํ ์บ์๋ ์ฑ๋ก ๋จ์ง ์์ต๋๋ค.
์ ์ญ `mcpInterceptors` ์ฒด์ธ์ ๋ณ๊ฒฝํ๋ฉด, ์๋ฒ ์ค์ ์ด ๋์์ ํธ์ง๋๋ ๊ฒฝ์ฐ๋ฅผ ํฌํจํด ๋ชจ๋ ์๋ฒ์ ๋๊ตฌ ๋ํผ๊ฐ ๋ค์ ๋น๋๋ฉ๋๋ค.
`extensions_config.json`์ ํธ์ง๊ธฐ์์ BOM ํฌํจ UTF-8๋ก ์ ์ฅํ ํ์ผ์ ํฌํจํด, ์์ ๋ฐ์ดํธ ์์ ํ์(BOM)์ด ์๊ฑฐ๋ ์๋ UTF-8์ ๋ชจ๋ ๋ฐ์ต๋๋ค.
์ง์ฐ(deferred) MCP ๋๊ตฌ ๊ฒ์์ด ํ์ฑํ๋์ด ์์ผ๋ฉด `tool_search`๋ `keywords:notebook jupyter`์ ๊ฐ์ ์ตํธ์ธ ๋ฆฌํฐ๋ด ํค์๋ ์ฟผ๋ฆฌ๋ฅผ ์ง์ํฉ๋๋ค. ํค์๋๋ ์์์ ๊ด๊ณ์์ด ์ด๋ฆ๊ณผ ์ค๋ช
์ ๋งค์นญ๋๋ฉฐ, ์๋ก ๋ค๋ฅธ ๊ฒ์์ด์ ์ผ์น ๋ฒ์, ๊ทธ๋ค์ ์ด๋ฆ ์ผ์น ์ ์์ผ๋ก ์์๊ฐ ๋งค๊ฒจ์ง๊ณ , ๋์ ์ด๋ฉด ์นดํ๋ก๊ทธ ์์๋ฅผ ์ ์งํฉ๋๋ค. ์ด ๋ชจ๋๋ ์ ๋์ฌ ๋ค์ ์ฒ์ 256์์ ๊ณต๋ฐฑ์ผ๋ก ๊ตฌ๋ถ๋ ๊ณ ์ ๊ฒ์์ด ์ต๋ 16๊ฐ๋ฅผ ์ฌ์ฉํ๋ฉฐ, ์ต๋ 5๊ฐ์ ๋๊ตฌ๋ฅผ ๋ฐํํฉ๋๋ค. ๋ฌธ์ฅ ๋ถํธ๋ ๋ฆฌํฐ๋ด๋ก ์ทจ๊ธ๋ฉ๋๋ค. ์ ๋์ฌ ์๋ ์ฟผ๋ฆฌ์ `+required` ์์ ์ง์ ์ ๊ธฐ์กด ์ ๊ท ํํ์ ์๋ฏธ๋ฅผ ์ ์งํ๋ฉฐ, `select:tool_a,tool_b`๋ ์ฌ์ ํ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํด ์ ํํ ์ผ์นํ๋ ์ด๋ฆ์ ๋ชจ๋ ๊ฐ์ ธ์ต๋๋ค.
MCP ๋ผ์ฐํ
ํํธ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ค๋ฅธ ๋๊ตฌ๋ฅผ ๊ธ์งํ์ง ์์ผ๋ฉด์ ์ผ์นํ๋ ์์ฒญ์ ํน์ MCP ๋๊ตฌ๋ฅผ ์ฐ์ ์ฌ์ฉํ๊ฒ ํ ์๋ ์์ต๋๋ค. `tool_search`๊ฐ MCP ์คํค๋ง๋ฅผ ์ง์ฐ ๋ก๋ํ ๋, ์ผ์นํ๋ ๋ผ์ฐํ
๋ฉํ๋ฐ์ดํฐ๋ ๋ชจ๋ธ ํธ์ถ ์ ์ ์ง์ฐ๋ ์คํค๋ง๋ฅผ ์ต๋ `tool_search.auto_promote_top_k`๊ฐ๊น์ง ์๋์ผ๋ก ์น๊ฒฉํ ์ ์์ต๋๋ค.
์ง์ฐ `tool_search` ์ ๊ท์ ์ฟผ๋ฆฌ๋ `+required` ์์ ์ง์ ์ ํฌํจํด ์นดํ๋ก๊ทธ ์ ์ฒด์์ 100 ms ์คํ ์์ฐ์ ๊ณต์ ํฉ๋๋ค. ํจํด์ 256์๋ก, ๊ฒ์ ๋์ ์ด๋ฆ๊ณผ ์ค๋ช
์ ๊ฐ๊ฐ 65,536์๋ก ์ ํ๋ฉ๋๋ค. ์ ํ์ ์ด๊ณผํ ์ฟผ๋ฆฌ๋ ๋ถ๋ถ ๊ฒฐ๊ณผ๋ฅผ ์น๊ฒฉํ์ง ์๊ณ ์ฌ์๋ ํํธ๋ฅผ ๋ฐํํฉ๋๋ค. ๋ ๋จ์ํ ํจํด์ด๋ `keywords:`, ๋๋ ์ ํํ ์ด๋ฆ๊ณผ ํจ๊ป `select:`๋ฅผ ์ฌ์ฉํ์ธ์. ๋๋ฌด ํฐ ์นดํ๋ก๊ทธ ํ๋๋ ๋๊ตฌ ์ด๋ฆ, ํ๋, ๊ธธ์ด์ ํจ๊ป ๋ณด๊ณ ๋๊ณ , ๊ฐ๋ฅํ๋ฉด MCP ์๋ฒ ์ด๋ฆ๊ณผ ํจ๊ป ๋ก๊ทธ์ ๊ธฐ๋ก๋ฉ๋๋ค. ํจํด์ ๋จ์ํํด๋ ์นดํ๋ก๊ทธ ํ๋๋ ์ค์ด๋ค์ง ์์ผ๋ฏ๋ก `keywords:` ๋๋ `select:`๋ฅผ ์ฌ์ฉํ์ธ์. ์ ํํ ์ด๋ฆ ์ ํ์๋ ์ํ์ด ์์ผ๋ฉฐ ์ ๊ท์ ์ ํ์ ์ฐํํฉ๋๋ค. ๋ฆฌํฐ๋ด `keywords:` ๋ชจ๋๋ ์ ๊ท์ ์ ํ์ ์ฐํํฉ๋๋ค. ์๋ชป๋ ์ ๊ท์ ๊ตฌ๋ฌธ์ ์ฌ์ ํ ๋ฆฌํฐ๋ด ๋ถ๋ถ ๋ฌธ์์ด ๋งค์นญ์ผ๋ก ํด๋ฐฑํฉ๋๋ค.
OpenViking ์ฌ์ฉ์๋ ์์ ์์ ๋ฐ์ธ๋ฉ๋ USER API ํค๋ก `/mcp`์ ๊ณต์ Streamable HTTP ์๋ํฌ์ธํธ๋ฅผ ๋ฑ๋กํ ์ ์์ต๋๋ค. ๋ค์ดํฐ๋ธ `forget` ๋๊ตฌ๋ ๊ธฐ๋ฅ ๋๋ฑ์ฑ์ ์ํด ๋
ธ์ถ๋ฉ๋๋ค. ์ญ์ ๋ ๋๋๋ฆด ์ ์์ผ๋ฏ๋ก ์ฌ์ฉ์์ ๋ช
์์ ์ธ ํ์ธ์ ๋ฐ์ ๋ค์๋ง ํธ์ถํด์ผ ํฉ๋๋ค. DeerFlow๋ ๊ทธ ํ์ธ์ ๊ฐ์ ํ์ง ์์ต๋๋ค. ๋ชจ๋ธ์ด ๋ช
์์ ์ผ๋ก ์ ํํ๋ ์ด MCP ๋๊ตฌ ๊ฒฝ๋ก๋ ๋ณ๋์ ์๋ OpenViking ๋ฉ๋ชจ๋ฆฌ ๋ฐฑ์๋์ ํจ๊ป ์คํ๋ ์ ์์ผ๋ฉฐ, ์๋ ํด ์์ง์ด๋ ํ์์ ๋์ฒดํ์ง ์์ต๋๋ค. [OpenViking MCP ๋๊ตฌ ์ค์ ](backend/docs/MCP_SERVER.md#openviking-mcp-tools)์ ์ฐธ๊ณ ํ์ธ์.
Gateway๋ MCP ์๋ฒ์ ์ผ๋ฐ `submit` / `status` / `cancel` ๋๊ตฌ๋ฅผ ์์ ๋ฐฑ๊ทธ๋ผ์ด๋ ์์
์ผ๋ก ๋ณํํ ์ ์์ต๋๋ค. ์์ด์ ํธ์๋ ์ค์ ๋ submit ๋๊ตฌ์ DeerFlow ๋ก์ปฌ ์์
ID๋ง ๋ณด์
๋๋ค. ์๊ฒฉ ID๋ submit ํธ์ถ์ด ๋ฐํ๋๊ธฐ ์ ์ ์์ ์ ์ฅ๋๋ฉฐ, status์ cancel์ ๋ฐํ์ ๋ด๋ถ์์๋ง ์ฌ์ฉ๋ฉ๋๋ค. ํด๋ง์ ์์ปค ๊ฐ ๋ฆฌ์ค, ์ง์ ์ฌ์๋ ๋ฐฑ์คํ, ๋ฒ์๊ฐ ์ง์ ๋ MCP ์ธ์
, ํฌ๊ธฐ๊ฐ ์ ํ๋ ๊ฒฐ๊ณผ ์ ์ฅ์, ์ฌ์์ ๋ณต๊ตฌ๋ฅผ ์ฌ์ฉํฉ๋๋ค. status ๋๊ตฌ์ `isError`๋ ํฌ๊ธฐ๊ฐ ์ ํ๋ ์ง๋จ ์ ๋ณด๋ก ๋ณด๊ด๋๊ณ ์ฌ์๋๋ฉ๋๋ค. ์๋ฒ๋ ์๊ฒฉ ์์
์ ์๊ตฌ์ ์ธ ๊ฒฐ๊ณผ๋ฅผ `status: "failed"`๊ฐ ํฌํจ๋ ์ผ๋ฐ ๊ตฌ์กฐํ ๊ฒฐ๊ณผ๋ก ๋ณด๊ณ ํฉ๋๋ค. ์๊ฒฉ ํด๋ง ํํธ๋ 24์๊ฐ์ ์ํ์ผ๋ก ํ๋ ์ ํํ ์์์ด๊ณ , ์ํฐํฉํธ ์ฐธ์กฐ JSON์ 64 KiB๋ก ์ ํ๋๋ฉฐ, ์์
๋ฐ ์๋ฒ ์๋ณ์๋ ์์ ์ ์ฅ ์ ์ ์์ SQL ์ปฌ๋ผ ๊ธธ์ด ์ ํ์ ๋ง๋์ง ๊ฒ์ฆ๋ฉ๋๋ค. ์
๋ ฅ ์์ฒญ๊ณผ ์ข
๋ฃ ์
๋ฐ์ดํธ๋ ๋ฉฑ๋ฑ ์์ด์ ํธ ์คํ(run)์ ํตํด ํ์ฌ ์ฑํ
์ ๊นจ์ฐ๋ฉฐ, `list_background_tasks`์ `cancel_background_task`๋ฅผ ์ฌ์ฉํ๋ฉด ์์ด์ ํธ๊ฐ ์ฌ์ฉ์์๊ฒ ์๊ฒฉ ํธ๋ค์ ๋ฌป์ง ์๊ณ ๋ ์์
์ ๊ด๋ฆฌํ ์ ์์ต๋๋ค. ํ์ฌ ์ค๋ ๋์ ์์
์ `GET /api/threads/{thread_id}/mcp-tasks`, ๊ทธ ์์ธ ์๋ํฌ์ธํธ, `POST /api/threads/{thread_id}/mcp-tasks/{task_id}/cancel`๋ก ํ์ธํ ์ ์์ต๋๋ค. ์์
๋ฐํ์์ด ์ค์ ๋ก ์์๋๋ฉด, ์น UI๋ ์ฑํ
ํค๋์์ ๊ฐ์ ์์ ํ ๋ก์ปฌ ๋ทฐ๋ฅผ ์ ๊ณตํ๋ฉฐ ์ค์๊ฐ ์ํ ์๋ก ๊ณ ์นจ, ์ทจ์, ๊ทธ๋ฆฌ๊ณ ํ์ํ ๋ ์กฐํํ๋ ๊ฒฐ๊ณผ, ์ํฐํฉํธ, ์
๋ ฅ ์์ฒญ, ์ํ ์ค๋ฅ, ์ทจ์ ์ฌ์๋ ์ธ๋ถ ์ ๋ณด๋ฅผ ๋ณด์ฌ ์ค๋๋ค. ๊ธฐ๋ณธ ๋นํ์ฑํ ์ํ์ด๊ฑฐ๋ ๋ฉ๋ชจ๋ฆฌ ๋ฐฑ์๋๋ฅผ ์ฐ๋ ๋ฐฐํฌ์์๋ ์ด UI๊ฐ ์จ๊ฒจ์ง๋ฉฐ ์์
์๋ํฌ์ธํธ๋ฅผ ํด๋งํ์ง ์์ต๋๋ค. ์คํจํ ์๊ฒฉ ์ทจ์๋ ๋ฐฑ์คํ์ ํจ๊ป ๋๊ธฐ์ด์ ๋จ์ ์์ผ๋ฉฐ, ํฌ๊ธฐ๊ฐ ์ ํ๋ ์ต์ ์ค๋ฅ์ ์๋ ํ์๊ฐ ํผ์น ์์
์นด๋์ ๊ณ์ ํ์๋ฉ๋๋ค. `config.yaml`์์ `mcp_tasks`๋ฅผ ํ์ฑํํ๊ณ , `extensions_config.json`์์ `task_toolsets`๋ฅผ ์ ํํ ์๋ ๋๊ตฌ ์ด๋ฆ์ผ๋ก ์ค์ ํ ๋ค, SQL ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฐฑ์๋(`sqlite` ๋๋ `postgres`)๋ฅผ ์ฌ์ฉํ์ธ์. ์์
์ด ํ์ฑํ๋ ์๋ฒ์ ์ฐ๊ฒฐ, ์ธ์ฆ, ์ธํฐ์
ํฐ, ํ์์์, ๋ฐ์ธ๋ฉ์ ๋ณ๊ฒฝํ๋ฉด Gateway๋ฅผ ์ฌ์์ํด์ผ ํฉ๋๋ค. ๊ทธ๋์ผ ์์ด์ ํธ์ ๋๊ตฌ ๊ฒ์๊ณผ ๋ฐฑ๊ทธ๋ผ์ด๋ ํธ์ถ์ด ์๋ก ๋ค๋ฅธ ์ค์ ๋ฒ์ ์ ์ฌ์ฉํ์ง ์์ต๋๋ค. `input_required`๋ ํ์ฌ ์๋ฆผ ์ ์ฉ์
๋๋ค. DeerFlow๋ ์์ฒญ์ ํ์ํ ์๋ ์์ง๋ง ์์ง ์ฌ์ฉ์์ ๋ต๋ณ์ ์๊ฒฉ ์์
์ผ๋ก ๋ค์ ๋ณด๋ผ ์๋ ์์ต๋๋ค.
`task_toolsets`๊ฐ ์๋ ๋ฐฐํฌ ์์ค HTTP/SSE ์๋ฒ์์๋ ๊ฒ์, ์ผ๋ฐ ๋๊ตฌ, ๋ฐฑ๊ทธ๋ผ์ด๋ ์์
ํธ์ถ์ด ๋๊ตฌ ์บ์ ์ด๊ธฐํ ์ดํ๋ฅผ ํฌํจํด ํ๋์ Gateway ํ๋ก์ธ์ค ์์์ OAuth ํ ํฐ ์ํ๋ฅผ ๊ณต์ ํฉ๋๋ค. ๊ต์ฒด๋ ๋ฆฌํ๋ ์ ํ ํฐ์ ๋ฉ๋ชจ๋ฆฌ์๋ง ๋จ์ผ๋ฉฐ, ์ค์ ์ ๋ค์ ๊ธฐ๋ก๋๊ฑฐ๋ ํ๋ก์ธ์ค ๊ฐ์ ๊ณต์ ๋์ง ์์ต๋๋ค. ์ฌ์์ ํ์๋ ์ค์ ๋ ๋ฆฌํ๋ ์ ํ ํฐ์ด ์ฌ์ ํ ์ ํจํด์ผ ํฉ๋๋ค.
์๋ฆผ ์คํ ์์๊ณผ ์คํจํ ์์ด์ ํธ ์คํ ์ ๋ฌ์ ์๋ ํ์๊ฐ ํ์๋๋ ์ํ ์๋ ์ง์ ๋ฐฑ์คํ๋ฅผ ์ฌ์ฉํ๋ฉฐ, 5๋ฒ ์คํจํ๋ฉด ์ค๋จํฉ๋๋ค. ์ ํ์ด ์๋ ์ผ๋ฐ ํด์ ๊ฐ ๋๋ ์ธ ๊ธฐํ์ ๋๊ธฐ๋ฉด, ์๋น์ค๋ ์ฒ๋ฆฌ๊ฐ ๋๋ ๋๊น์ง ์์ ๊ถ์ ์ ์งํฉ๋๋ค. ์ญ์ ๋ ์ฑํ
์ฒ๋ผ ์๊ตฌ์ ์ผ๋ก ๊ฑฐ๋ถ๋ ๋์์ ๋์์ด ์ฌ์๋ํ๊ฑฐ๋ ๋ค์ ์์ฑํ์ง ์๊ณ ์ฆ์ ๋ฐ๋ ๋ ํฐ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค. ์ทจ์ ์๋ํฌ์ธํธ๋ ์์ฒญ์ ์์์ ์ผ๋ก ๊ธฐ๋กํ ๋ค ๋ฐํ๋๋ฉฐ, ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆด ์ ์๋ ์๊ฒฉ MCP ํธ์ถ๊ณผ ๊ทธ ์ฌ์๋ ์ผ์ ์ ๋ฐฑ๊ทธ๋ผ์ด๋ ์๋น์ค๊ฐ ๋งก์ต๋๋ค.
์๋ฆผ ์คํ์ ์ ๋ขฐํ ์ ์๋ ์ ๋ฌ ์ง์๋ฅผ, ๋ณ๋๋ก ๊ฐ์ผ ์ ๋ขฐํ ์ ์๋ ์๊ฒฉ ์ด๋ฒคํธ ํ์ด๋ก๋์ ๋ถ๋ฆฌํด ์ ์งํฉ๋๋ค. ์์
๊ด๋ฆฌ ๋๊ตฌ์ ๋
ธ์ถ ์ฌ๋ถ๋ ์คํ ์ค์ ๋ค์ ์ฝ์ ์ค์ ์ด ์๋๋ผ ํ๋ก์ธ์ค์ ํจ๊ป ์์๋ ์์
๋ฐํ์์ด ๊ฒฐ์ ํ๋ฏ๋ก, `mcp_tasks`๋ฅผ ๋ณ๊ฒฝํ๋ฉด Gateway๋ฅผ ์ฌ์์ํด์ผ ํฉ๋๋ค. `list_background_tasks`์ `cancel_background_task`๋ ๋ค๋ฅธ ๋ชจ๋ ๋๊ตฌ์ ๋ง์ฐฌ๊ฐ์ง๋ก ์์ด์ ํธ ์์ฒด์ ๊ถํ ๋ถ์ฌ๊ฐ ๊ด๋ฆฌํ๋ ์ผ๋ฐ ์
๋ฌด ๋๊ตฌ์
๋๋ค.
์์ธํ ๋ด์ฉ์ [MCP ์๋ฒ ๊ฐ์ด๋](backend/docs/MCP_SERVER.md)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
๋ณด์: ์์ฒญ๋ณ MCP ์๊ฒฉ ์ฆ๋ช
์ ๋ฐ๋์ `config.context.secrets`๋ฅผ ํตํด์๋ง ์ ๋ฌํ์ธ์. ์๊ฒฉ ์ฆ๋ช
์ ๋ ์คํ ๋ฉํ๋ฐ์ดํฐ ์์น(`metadata.auth_token` ๋๋ `config.metadata.auth_token`) ์ค ์ด๋์๋ ์ ๋ ๋ฃ์ด์๋ ์ ๋ฉ๋๋ค. ๋ ๊ฑฐ์ ๋ฉํ๋ฐ์ดํฐ ์๊ฒฉ ์ฆ๋ช
์์ ๋ง์ด๊ทธ๋ ์ด์
ํ ๋ ์ง์๋๋ ์ธํฐ์
ํฐ ํ๋ฆ๊ณผ, ํ์ํ ์๊ฒฉ ์ฆ๋ช
๊ต์ฒด ๋ฐ ๋จ์ ์๋ ์ฌ๋ณธ ์ ๋ฆฌ ๋ฐฉ๋ฒ์ [MCP ์๊ฒฉ ์ฆ๋ช
๋ง์ด๊ทธ๋ ์ด์
๋ฐ ์ ๋ฆฌ](backend/docs/MCP_SERVER.md#migrating-legacy-mcp-credentials)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
#### IM ์ฑ๋
DeerFlow๋ ๋ฉ์์ง ์ฑ์์ ์์
์ ๋ฐ์ ์ ์์ต๋๋ค. ์ฑ๋์ ์ค์ ๋์ด ์์ผ๋ฉด ์๋์ผ๋ก ์์๋๋ฉฐ, ์ด๋ค ์ฑ๋๋ ๊ณต์ธ IP๊ฐ ํ์ํ์ง ์์ต๋๋ค.
์ฑ๋ ์ฌ์์์ ์ทจ์ํ๋ฉด ๋๊ธฐ ์ค์ธ ์ค์ ๋ฆฌ๋ก๋๊ฐ ํ๊ธฐ๋๋ฏ๋ก, ๊ทธ ์ดํ์ ์ ์ฉ๋ ์ต์ ๋ฐํ์ ์ค์ ์ด ์ ์ง๋ฉ๋๋ค.
DeerFlow๋ ์ฌ์ฉ์๊ฐ ์์ ํ IM ์ฑ๋ ์ฐ๊ฒฐ์ ์ํฌ์คํ์ด์ค UI์ ๋
ธ์ถํ ์๋ ์์ต๋๋ค. `channel_connections`๊ฐ ํ์ฑํ๋์ด ์์ผ๋ฉด, ๋ก๊ทธ์ธํ ์ฌ์ฉ์๋ ์ฌ์ด๋๋ฐ / Settings > Channels์์ Telegram, Slack, Discord, Feishu/Lark, DingTalk, WeChat, WeCom, QQ, Buzz๋ฅผ ์ฐ๊ฒฐํ ์ ์์ต๋๋ค. ์ด ๊ธฐ๋ฅ์ ๊ธฐ์กด์ ์์๋ฐ์ด๋ `channels.*` ์ ์ก ๊ณ์ธต์ ์ฌ์ฌ์ฉํ๋ฏ๋ก ๊ณต์ธ IP๋ ํ๋ก๋ฐ์ด๋ ์ฝ๋ฐฑ URL์ด ํ์ํ์ง ์์ต๋๋ค. ์ดํ ๋ค์ด์ค๋ IM ๋ฉ์์ง๋ ์ฐ๊ฒฐ๋ DeerFlow ์ฌ์ฉ์ ๊ณ์ ์ผ๋ก ์คํ๋ฉ๋๋ค. ์ค์ ๋ฐฉ๋ฒ๊ณผ ๋ณด์ ์ฐธ๊ณ ์ฌํญ์ [IM ์ฑ๋ ์ฐ๊ฒฐ](backend/docs/IM_CHANNEL_CONNECTIONS.md)์ ์ฐธ๊ณ ํ์ธ์. Buzz ๋ฐฑ๋ก๊ทธ ํ์ด์ง์ ํ์์คํฌํ ๊ธฐ๋ฐ ์ฟผ๋ฆฌ๊ฐ ๋ ์งํํ ์ ์์ผ๋ฉด ๊ฒฝ๊ณ ์ ํจ๊ป ์ค๋จ๋๋ฉฐ, ์ฑ๋์ ์ ๊ฑฐํ๋ฉด ์ค์๊ฐ ๊ตฌ๋
๊ณผ ๋ฐฑ๋ก๊ทธ ๊ตฌ๋
์ด ๋ชจ๋ ๋ซํ๋๋ค.
| ์ฑ๋ | ์ ์ก ๋ฐฉ์ | ๋์ด๋ |
|---------|-----------|------------|
| Telegram | Bot API (๋กฑ ํด๋ง) | ์ฌ์ |
| Slack | Socket Mode | ๋ณดํต |
| Feishu / Lark | WebSocket | ๋ณดํต |
| WeChat | Tencent iLink (๋กฑ ํด๋ง) | ๋ณดํต |
| WeCom | WebSocket | ๋ณดํต |
| QQ | WebSocket (ํ
์คํธ ์ ์ฉ C2C ๋ฐ ๊ทธ๋ฃน @๋ฉ์
, ์์ค๋ณ ์๋ ์๋ต 4/5ํ) | ๋ณดํต |
| DingTalk | Stream Push (WebSocket) | ๋ณดํต |
| Buzz | Nostr ๋ฆด๋ ์ด (WebSocket, NIP-42) | ๋ณดํต |
๊ณต์ฉ IM ์์ ํ์ดํ๋ผ์ธ์ด๋ Feishu/DingTalk์ ๋ด์ฅ ๋ค์ด๋ก๋๋ก ์ ์ฅ๋ ์ฒจ๋ถ ํ์ผ์ ๋์ ์
๋ก๋๊ฐ ๊ฐ์ ์ด๋ฆ์ ๊ณ ๋ฅด๋ ๊ฒฝ์ฐ๋ฅผ ํฌํจํด ์๋ก ๋ค๋ฅธ ํ์ผ ์ด๋ฆ์ ์ ์งํฉ๋๋ค. ์ต์ข
ํ์ผ ์ด๋ฆ์ด ์์ด์ ํธ์ ์ ๋ฌ๋๊ณ ์๋๋ฐ์ค ๋๊ธฐํ์ ์ฌ์ฉ๋๋ฉฐ, ๊ธฐ์กด ๋ํ ํ์ผ์ ๋ฎ์ด์ฐ์ง ์์ต๋๋ค.
**`config.yaml` ์ค์ :**
Discord์ `channels.discord.allowed_guilds`๋ ์์ ์ซ์ ๊ธธ๋ ID ํ๋(๋ฐ์ดํ ์ ๋ฌด ๋ฌด๊ด) ๋๋ YAML ๋ชฉ๋ก์ ๋ฐ์ต๋๋ค. ์ค์ ํ์ง ์๊ฑฐ๋ `null`, `[]`, ๋น ๋ฌธ์์ด์ด๋ฉด ๋ชจ๋ ๊ธธ๋๋ฅผ ํ์ฉํฉ๋๋ค. ์ ํจํ์ง ์์ ํญ๋ชฉ์ ๊ฒฝ๊ณ ์ ํจ๊ป ๋ฌด์๋๋ฉฐ, ๊ทธ ๋ฐ์ ์ค์ ๋ ๊ฐ์์ ์ ํจํ ID๊ฐ ํ๋๋ ๋์ค์ง ์์ผ๋ฉด ๋ชจ๋ ๊ธธ๋๋ฅผ ๊ฑฐ๋ถํ๊ณ ์ค๋ฅ๋ฅผ ๊ธฐ๋กํฉ๋๋ค. `allowed_channels`๋ ํ์ฉ๋ ๊ธธ๋ ์์์ `mention_only`์ ์ ์ฉ์ ๋ฐ์ง ์๋ ์ฑ๋ ID ํ๋(๋ฐ์ดํ ์ ๋ฌด ๋ฌด๊ด) ๋๋ ID์ YAML ๋ชฉ๋ก์ ๋ฐ์ต๋๋ค. ๊ฐ์ด ๋น์ด ์์ผ๋ฉด ์์ธ๊ฐ ์์ผ๋ฏ๋ก, `mention_only`๊ฐ ํ์ฑํ๋์ด ์์ ๋ ๋ชจ๋ ๊ณณ์ ์ ์ฉ๋ฉ๋๋ค.
Discord ์์ ์ฒจ๋ถ ํ์ผ์ ๋ค์ด๋ก๋ ์ ํ์ 25 MiB์
๋๋ค. ํ์ผ ํฌ๊ธฐ ์ด๊ณผ ์๋ด์๋ ์ ์ฉ๋ ์ ํ์ด ํ์๋๋ฏ๋ก, ๋ณด๋ธ ์ฌ๋์ด ์ฒจ๋ถ ํ์ผ ํฌ๊ธฐ๋ฅผ ์ค์ด๊ฑฐ๋ ์์ถํ ์ ์์ต๋๋ค.
```yaml
channels:
# LangGraph-compatible Gateway API base URL (default: http://localhost:8001/api)
langgraph_url: http://localhost:8001/api
# Gateway API URL (default: http://localhost:8001)
gateway_url: http://localhost:8001
# Maximum queued or provider-reserved inbound messages (default: 1000)
inbound_queue_maxsize: 1000
# Fixed number of long-lived inbound handler workers (default: 5)
max_concurrency: 5
# Seconds to drain accepted work before cancelling active handlers (default: 3)
shutdown_grace_period_seconds: 3
# Optional: global session defaults for all mobile channels
session:
assistant_id: lead_agent # or a custom agent name; custom agents are routed via lead_agent + agent_name
config:
recursion_limit: 100
context:
thinking_enabled: true
is_plan_mode: false
subagent_enabled: false
feishu:
enabled: true
app_id: $FEISHU_APP_ID
app_secret: $FEISHU_APP_SECRET
# domain: https://open.feishu.cn # China (default)
# domain: https://open.larksuite.com # International
qq:
enabled: true
app_id: $QQ_APP_ID
client_secret: $QQ_CLIENT_SECRET
allowed_users: [] # QQ OpenIDs, not QQ account numbers; empty allows all; one ID is one entry
wecom:
enabled: true
bot_id: $WECOM_BOT_ID
bot_secret: $WECOM_BOT_SECRET
# Optional: extra host suffixes inbound media downloads may come from, in
# addition to the built-in qq.com family and WeCom's official COS media
# host (ww-aibot-img-1258476243..myqcloud.com); add one here if
# WeCom rotates to a new COS account or media goes through a proxy
allowed_media_hosts: []
slack:
enabled: true
bot_token: $SLACK_BOT_TOKEN # xoxb-...
app_token: $SLACK_APP_TOKEN # xapp-... (Socket Mode)
allowed_users: [] # empty = allow all
telegram:
enabled: true
bot_token: $TELEGRAM_BOT_TOKEN
# Optional: render final Markdown replies as Telegram Rich Messages.
rich_messages: false
allowed_users: [] # numeric user IDs, not @usernames; empty = allow all
wechat:
enabled: false
bot_token: $WECHAT_BOT_TOKEN
ilink_bot_id: $WECHAT_ILINK_BOT_ID
qrcode_login_enabled: true # optional: allow first-time QR bootstrap when bot_token is absent
allowed_users: [] # iLink user IDs; empty allows all; one ID is one entry
polling_timeout: 35 # timing values must be positive finite seconds
polling_retry_delay: 5
qrcode_poll_interval: 2
qrcode_poll_timeout: 180
state_dir: ./.deer-flow/wechat/state
max_inbound_image_bytes: 20971520
max_outbound_image_bytes: 20971520
max_inbound_file_bytes: 52428800
max_outbound_file_bytes: 52428800
# Inbound media downloads stream with the caps above and are restricted to
# these host suffixes (plus *.qq.com and the cdn_base_url host by default)
allowed_media_hosts: []
# Optional: per-channel / per-user session settings
session:
assistant_id: mobile-agent # custom agent names are also supported here
context:
thinking_enabled: false
users:
"123456789":
assistant_id: vip-agent
config:
recursion_limit: 150
context:
thinking_enabled: true
subagent_enabled: true
dingtalk:
enabled: true
client_id: $DINGTALK_CLIENT_ID # Client ID of your DingTalk application
client_secret: $DINGTALK_CLIENT_SECRET # Client Secret of your DingTalk application
allowed_users: [] # empty = allow all
card_template_id: "" # Optional: AI Card template ID for streaming typewriter effect
```
์ฐธ๊ณ :
- `assistant_id: lead_agent`๋ ๊ธฐ๋ณธ LangGraph ์ด์์คํดํธ๋ฅผ ์ง์ ํธ์ถํฉ๋๋ค.
- `assistant_id`๋ฅผ ์ปค์คํ
์์ด์ ํธ ์ด๋ฆ์ผ๋ก ์ค์ ํด๋ DeerFlow๋ ์ฌ์ ํ `lead_agent`๋ฅผ ๊ฑฐ์ณ ๋ผ์ฐํ
ํ๋ฉฐ ๊ทธ ๊ฐ์ `agent_name`์ผ๋ก ์ฃผ์
ํ๋ฏ๋ก, IM ์ฑ๋์ ์ปค์คํ
์์ด์ ํธ์ SOUL/์ค์ ์ด ์ ์ฉ๋ฉ๋๋ค.
- IM ์ฑ๋ ์์ปค๋ ๋ด๋ถ์ ์ผ๋ก Gateway์ LangGraph ํธํ API๋ฅผ ํธ์ถํ๋ฉฐ, ์ค๋ ๋ ๋ฐ ์คํ ์์ฑ์ ํ์ํ ํ๋ก์ธ์ค ๋ก์ปฌ ๋ด๋ถ ์ธ์ฆ๊ณผ CSRF ์ฟ ํค/ํค๋ ์์ ์๋์ผ๋ก ์ฒจ๋ถํฉ๋๋ค.
- ์์ ์์
์ ๋๊ธฐ ๋ฉ์์ง `inbound_queue_maxsize`๊ฐ์ ํ์ฑ ์์ปค `max_concurrency`๊ฐ๋ก ์ ํ๋ฉ๋๋ค. ์ฉ๋์ด ์์ง๋๋ฉด ์์ผ/ํด๋ง ํ๋ก๋ฐ์ด๋๋ DeerFlow์ ์์
์ค ์๋ต์ ๋ณด๋ด๊ธฐ ์ ์ ์ ๋ฉ์์ง๋ฅผ ๋ฒ๋ฆฌ๊ณ , ๋น๋๊ฐ ์ ํ๋ ๊ฒฝ๊ณ ๋ฅผ ๋จ๊น๋๋ค. Buzz๋ ์ฌ์(replay) ์ปค์๋ฅผ ๊ทธ๋๋ก ๋๊ณ ๋ฆด๋ ์ด ์ฌ์์ ์ํด ๋ค์ ์ฐ๊ฒฐํ๋ฉฐ, GitHub ์นํ
์ `503`์ ๋ฐํํด ํด๋น ์ ๋ฌ์ ์คํจ๋ก ํ์ํ๋ฏ๋ก ์๋/API๋ก ์ฌ์ ๋ฌํ ์ ์์ต๋๋ค. ์ข
๋ฃ ์์๋ ์์ฒญ ์น์ธ(admission)์ ์ฆ์ ๋ซ๊ณ , ์ด๋ฏธ ๋ฐ์ ๋ฉ์์ง๊ฐ ์ต๋ `shutdown_grace_period_seconds` ๋์ ์ฒ๋ฆฌ๋๋ ์ฌ์ด ์ฑ๋ ์ ์ก ๊ณ์ธต์ ๊ณ์ ์ฌ์ฉํ ์ ์๋๋ก ์ ์งํ ๋ค์, ํ์ฑ ํธ๋ค๋ฌ๋ฅผ ์ทจ์ํ๊ณ ์๋ฃ๋ฅผ ๊ธฐ๋ค๋ฆฐ ๋ค ํ๋ก๋ฐ์ด๋ ๋ฆฌ์์ค๋ฅผ ๋ซ์ต๋๋ค. Gateway์ ๋ฐ๊นฅ์ชฝ ํ์์์์ ํด๋น ๋ฆฌ์์ค๋ฅผ ๋ถ๋ฆฌํ์ง ์์ ์ฑ ์๋ฃ๋์ง ์์ ์ข
๋ฃ๋ฅผ ์ทจ์ํ ์ ์์ต๋๋ค.
- Telegram ์ข
๋ฃ๋ ํ์์์์ด๋ ์ทจ์๊ฐ ๋ฐ์ํด๋ ์งํ ์ค์ธ ์ ๋ฆฌ ์์
์ ์ ์งํ๋ฏ๋ก, ์ฌ์๋๋ก ์ ๋ฆฌ๋ฅผ ๋ง์น ์ ์์ต๋๋ค. ์์ ๋์ค์ ์ค์งํ๋ฉด ์ด๊ธฐํ๋ ์ทจ์๋๊ณ , ์ผ๋ถ๋ง ์ด๊ธฐํ๋ ๋ด์ HTTP ํด๋ผ์ด์ธํธ๋ฅผ ๋ซ์ ๋ค ์์ปค ๋ฃจํ๋ฅผ ์ข
๋ฃํฉ๋๋ค. Telegram ๋ฃจํ๊ฐ ์ด๋ฏธ ๋ฉ์ถ ๊ฒฝ์ฐ, ์ข
๋ฃ ์ ๋ค์ด๋ก๋ ํด๋ผ์ด์ธํธ๊ฐ ์ด๋ฆฐ ์ฑ ๋จ์ ์์ ์ ์๋ค๊ณ ๊ฒฝ๊ณ ํ๊ณ ๋ฒ๋ ค์ง ์ ๋ฆฌ ์ํ๋ฅผ ํด์ ํฉ๋๋ค. ์ดํ์ ์ค์ง์์๋ ์ด ๊ฒฝ๊ณ ๋ฅผ ๋ฐ๋ณตํ์ง ์์ต๋๋ค.
- Slack ์ค์ง๋ ์งํ ์ค์ธ Socket Mode ์ฐ๊ฒฐ๊ณผ ๊ทธ ์ ๋ฆฌ๋ฅผ ์ต๋ 5์ด ๋์ ๊ธฐ๋ค๋ฆฝ๋๋ค. ์ ๋ฆฌ๊ฐ ์์ง ๋๋์ง ์์์ผ๋ฉด ์ด์ ์ธ์คํด์ค๊ฐ ๊ณ์ ์ถ์ ๋๋ฉฐ, ์ ๋ฆฌ๊ฐ ๋๋ ๋ค ์ฌ์์์ ๋ค์ ์๋ํ ์ ์์ต๋๋ค. SDK ์ ๋ฆฌ ์คํจ๋ ์๋ ์ค๋ฅ๋ฅผ ๋ณด๊ณ ํ๋ฉฐ ๊ณ์ ์ฌ์๋ํ ์ ์์ต๋๋ค.
- Telegram ๊ฐ์ธ ์ฑํ
์์๋ ์คํ ๋์ค ์ฑํ
๊ธฐ๋ก์ ์ง์ด ๊ฒฝ์ฐ์ฒ๋ผ ์ฐธ์กฐ๋ ์ฌ์ฉ์ ๋๋ ๋ด ๋ฉ์์ง๊ฐ ์ญ์ ๋์๋๋ผ๋ ํ
์คํธ, ์ฒจ๋ถ ํ์ผ, ์คํธ๋ฆฌ๋ฐ ์๋ต("Working on it..." ํฌํจ)์ ์ฌ์ ํ ์ ๋ฌํ ์ ์์ต๋๋ค. ํฌ๋ผ ๋ผ์ฐํ
์ ์ ์งํ๊ธฐ ์ํด ๊ทธ๋ฃน์ ์๋ต ๋์ ์๊ตฌ ์ฌํญ์ ๋ณ๊ฒฝ๋์ง ์์ต๋๋ค.
- Feishu/Lark๋ ์ด์ ์ฐ์์ผ๋ก ๋น ๋ฅด๊ฒ ๋ค์ด์ค๋ ํ์ ๋ฉ์์ง๋ฅผ ์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ค ์๋ต์ผ๋ก ๋ฐ๋ก ๋๋ ค๋ณด๋ด์ง ์๊ณ , ๋งคํ๋ DeerFlow `thread_id`๋ณ๋ก ๋๊ธฐ์ด์ ๋ฃ์ต๋๋ค. ํ ํฝ ์๋ต์ ๋๊ธฐ/์คํ ์ค/์ต์ข
ํจ์น ๋์ ์๋ณธ ๋ฉ์์ง์ ๊ฐ๋จํ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๊ฐ ๋ด๊ธด ๋ฉ์์ง๋ณ ์นด๋๋ฅผ ์ ์งํฉ๋๋ค.
- ์คํธ๋ฆฌ๋ฐ IM ์ฑ๋์ ๋ฐฑ์๋ `error` ์ด๋ฒคํธ๋ฅผ ์ ์ก ์คํจ์ฒ๋ผ ์ทจ๊ธํด ๊ฐ์ ์๋ต ๋ฐ ์ฌ์๋ ๊ฒฝ๋ก๋ฅผ ๋ฐ๋ฆ
๋๋ค. ์ฑ๋์ ์ง๋จ์ ์ํด ์ค๋ฅ ์ ํ๊ณผ ๋ฉ์์ง๋ฅผ ๋ก๊ทธ์ ๊ธฐ๋กํฉ๋๋ค.
`.env` ํ์ผ์ ํด๋น API ํค๋ฅผ ์ค์ ํ์ธ์.
```bash
# Telegram
TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrSTUvwxYZ
# Slack
SLACK_BOT_TOKEN=xoxb-...
SLACK_APP_TOKEN=xapp-...
# Feishu / Lark
FEISHU_APP_ID=cli_xxxx
FEISHU_APP_SECRET=your_app_secret
# WeChat iLink
WECHAT_BOT_TOKEN=your_ilink_bot_token
WECHAT_ILINK_BOT_ID=your_ilink_bot_id
# WeCom
WECOM_BOT_ID=your_bot_id
WECOM_BOT_SECRET=your_bot_secret
# DingTalk
DINGTALK_CLIENT_ID=your_client_id
DINGTALK_CLIENT_SECRET=your_client_secret
```
**Telegram ์ค์ **
1. [@BotFather](https://t.me/BotFather)์ ๋ํ๋ฅผ ์์ํด `/newbot`์ ๋ณด๋ด๊ณ HTTP API ํ ํฐ์ ๋ณต์ฌํ์ธ์.
2. `.env`์ `TELEGRAM_BOT_TOKEN`์ ์ค์ ํ๊ณ `config.yaml`์์ ์ฑ๋์ ํ์ฑํํ์ธ์.
3. ๋ด์ ์์ ํ
์คํธ, ์ฌ์ง, ๋ฌธ์(์บก์
์ ๋ฌด ๋ฌด๊ด)๋ฅผ ๋ฐ์ต๋๋ค. ํธ์คํ
๋ Bot API ๋ค์ด๋ก๋๋ ์ฒจ๋ถ ํ์ผ๋น 20 MB๋ก ์ ํ๋ฉ๋๋ค.
**Slack ์ค์ **
1. [api.slack.com/apps](https://api.slack.com/apps)์์ Create New App โ From scratch๋ฅผ ์ ํํด Slack ์ฑ์ ๋ง๋์ธ์.
2. **OAuth & Permissions**์์ Bot Token Scopes๋ฅผ ์ถ๊ฐํ์ธ์: `app_mentions:read`, `chat:write`, `im:history`, `im:read`, `im:write`, `files:write`.
3. **Socket Mode**๋ฅผ ํ์ฑํํ๊ณ โ `connections:write` ์ค์ฝํ๋ก App-Level Token(`xapp-โฆ`)์ ์์ฑํ์ธ์.
4. **Event Subscriptions**์์ ๋ด ์ด๋ฒคํธ `app_mention`, `message.im`์ ๊ตฌ๋
ํ์ธ์.
5. `.env`์ `SLACK_BOT_TOKEN`๊ณผ `SLACK_APP_TOKEN`์ ์ค์ ํ๊ณ `config.yaml`์์ ์ฑ๋์ ํ์ฑํํ์ธ์.
**Feishu / Lark ์ค์ **
1. [Feishu Open Platform](https://open.feishu.cn/)์์ ์ฑ์ ๋ง๋ค๊ณ โ **Bot** ๊ธฐ๋ฅ์ ํ์ฑํํ์ธ์.
2. ๊ถํ์ ์ถ๊ฐํ์ธ์: `im:message`, `im:message.p2p_msg:readonly`, `im:resource`.
3. **Events**์์ `im.message.receive_v1`์ ๊ตฌ๋
ํ๊ณ **Long Connection** ๋ชจ๋๋ฅผ ์ ํํ์ธ์.
4. App ID์ App Secret์ ๋ณต์ฌํ์ธ์. `.env`์ `FEISHU_APP_ID`์ `FEISHU_APP_SECRET`์ ์ค์ ํ๊ณ `config.yaml`์์ ์ฑ๋์ ํ์ฑํํ์ธ์.
5. ๋ด์ ์์ ํ
์คํธ, ์ด๋ฏธ์ง, ํ์ผ ๋ฉ์์ง๋ฅผ ์ง์ํฉ๋๋ค. ์์ ์ฒจ๋ถ ํ์ผ ๋ค์ด๋ก๋๋ ์ฒจ๋ถ ํ์ผ๋น 20 MB๋ก ์ ํ๋ฉ๋๋ค.
6. _(์ ํ ์ฌํญ)_ ๋ํํ ํ์ธ ์ง๋ฌธ(clarification) ์นด๋: `channels.feishu` ์๋์ `card_interaction_enabled: true`๋ฅผ ์ค์ ํ๋ฉด, ์์ด์ ํธ์ ์ ํ์ง ๊ธฐ๋ฐ ํ์ธ ์ง๋ฌธ์ด ์ง๋ฌธ ์์ ๋ฐฐ๊ฒฝ ๋งฅ๋ฝ์ ์ ์งํ ์ฑ ํด๋ฆญ ๊ฐ๋ฅํ ๋ฒํผ ์นด๋๋ก ํ์๋ฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ๊ฐ๋ฐ์ ์ฝ์์์ **Callback Configuration**(ๅ่ฐ้
็ฝฎ โ **Event Subscriptions**์๋ ๋ณ๋์ ํญ)์ ์ด๊ณ , **Long Connection** ๋ชจ๋๋ก `card.action.trigger`๋ฅผ ๊ตฌ๋
ํ ๋ค ์ ์ฑ ๋ฒ์ ์ ๊ฒ์ํ์ธ์. ๋ฒํผ์ ํด๋ฆญํ๋ฉด ์ ํ์ง๋ฅผ ์ง์ ์
๋ ฅํ ๊ฒ๊ณผ ๋๊ฐ์ด ํ์ธ ์ง๋ฌธ์ด ์ฒ๋ฆฌ๋๋ฉฐ, ํ์ธ ์ง๋ฌธ์ ๋ฐ์์ํจ ์ฌ์ฉ์๋ง ํด๋น ์นด๋๋ฅผ ์กฐ์ํ ์ ์์ต๋๋ค. ๋ฒํผ ์๋ต์ ๋ํ ๊ธฐ๋ก์ ์ ์ฅ๋๋ฉฐ, ์ดํ์ ํ์ธ ์ง๋ฌธ๋ ๊ฐ์ ์ค๋ ๋์์ ์ด์ด์ง๋๋ค.
์์ฝ ์์
์ ๊ฒฐ๊ณผ ๋ฐ ์๋ช
์ฃผ๊ธฐ ์๋ฆผ์ ์๋ก์ด ์์ ๋ฉ์์ง ์์ด๋ ์ฐ๊ฒฐ๋ Feishu/Lark ์ฌ์ฉ์์๊ฒ ํธ์ํ ์ ์์ต๋๋ค. ์ด ์๋ฆผ์ WeCom๊ณผ ๊ฐ์ ์๋ฆผ ์์๋ฐ์ค์ ํ์งํ๋ ์์ฝ์ ์ฌ์ฉํฉ๋๋ค. ์ฑ์ด ํด๋น ์ฌ์ฉ์์๊ฒ ๋ฉ์์ง๋ฅผ ๋ณด๋ผ ์ ์์ด์ผ ํฉ๋๋ค. [Feishu ์์ฝ ์์
์๋ฆผ](backend/docs/IM_CHANNEL_CONNECTIONS.md#feishu-scheduled-task-notifications)์ ์ฐธ๊ณ ํ์ธ์.
**WeChat ์ค์ **
1. `config.yaml`์์ `wechat` ์ฑ๋์ ํ์ฑํํ์ธ์.
2. `.env`์ `WECHAT_BOT_TOKEN`์ ์ค์ ํ๊ฑฐ๋, ์ต์ด QR ๋ถํธ์คํธ๋ฉ์ ์ํด `qrcode_login_enabled: true`๋ฅผ ์ค์ ํ์ธ์.
3. `bot_token`์ด ์๊ณ QR ๋ถํธ์คํธ๋ฉ์ด ํ์ฑํ๋์ด ์์ผ๋ฉด, ๋ฐฑ์๋ ๋ก๊ทธ์์ iLink๊ฐ ๋ฐํํ QR ๋ด์ฉ์ ํ์ธํ๊ณ ์ฐ๊ฒฐ(binding) ์ ์ฐจ๋ฅผ ์๋ฃํ์ธ์.
4. QR ์ ์ฐจ๊ฐ ์ฑ๊ณตํ๋ฉด DeerFlow๋ ์ดํ ์ฌ์์์ ๋๋นํด ํ๋ํ ํ ํฐ์ `state_dir` ์๋์ ์์ ์ ์ฅํฉ๋๋ค.
5. Docker Compose ๋ฐฐํฌ์์๋ `state_dir`์ ์์ ๋ณผ๋ฅจ์ ๋์ด, `get_updates_buf` ์ปค์์ ์ ์ฅ๋ ์ธ์ฆ ์ํ๊ฐ ์ฌ์์ ํ์๋ ์ ์ง๋๋๋ก ํ์ธ์.
6. ๋ฐ์ ์ด๋ฏธ์ง/ํ์ผ์ ์ฝ๋ ๋์ `max_outbound_image_bytes` / `max_outbound_file_bytes`(๊ธฐ๋ณธ๊ฐ 20 MiB / 50 MiB)๋ฅผ ์ ์ฉํ๋ฉฐ, ๊ฒฝ๋ก ํด์ ์ดํ์ ํฌ๊ธฐ๊ฐ ์ปค์ง๋ ํ์ผ๋ ํฌํจ๋ฉ๋๋ค. ํฌ๊ธฐ๋ฅผ ์ด๊ณผํ ์ฝ๊ธฐ๋ ์๋ฆฐ ์๋ถ๋ถ์ ๋ณด๋ด๋ ๋์ ์ํธํ/์
๋ก๋ ์ ์ ๊ฑฐ๋ถ๋ฉ๋๋ค. 0 ์ดํ์ ์ ํ๊ฐ์ ํด๋น ์ํ์ ๋นํ์ฑํํฉ๋๋ค.
7. `allowed_users`๋ iLink ์ฌ์ฉ์ ID๋ฅผ ๋ฐ์ต๋๋ค. ์ค์ ํ์ง ์๊ฑฐ๋ `null`, `[]`, ๋น ๋ฌธ์์ด์ด๋ฉด ๋ชจ๋ ์ฌ์ฉ์๋ฅผ ํ์ฉํฉ๋๋ค. ID ํ๋๋ ๋ฌธ์๋ค์ ๋์ด์ด ์๋๋ผ ํ๋์ ํญ๋ชฉ์ด๋ฉฐ, ๋ฐ์ดํ ์์ด ์ด ์ ์ซ๊ฐ ์ซ์๋ ํด๋น ์ ์์ ํ
์คํธ๋ก ์ ์ฅ๋ฉ๋๋ค. ์ผํ๋ ๋ด๋ถ ๊ณต๋ฐฑ์ด ํฌํจ๋ ์ค์นผ๋ผ ๋ฌธ์์ด์ ๊ฒฝ๊ณ ๋ฅผ ๋จ๊ธฐ์ง๋ง ํ๋์ ๋ฆฌํฐ๋ด ID๋ก ์ ์ง๋๋ฏ๋ก, ์ฌ๋ฌ ID๋ YAML ๋ชฉ๋ก์ ์ฌ์ฉํ์ธ์. ์ ํจํ์ง ์์ ํญ๋ชฉ์ ๊ฒฝ๊ณ ์ ํจ๊ป ๋ฌด์๋๋ฉฐ, ๊ทธ ๋ฐ์ ์ค์ ๋ ๊ฐ์์ ์ ํจํ ID๊ฐ ํ๋๋ ๋์ค์ง ์์ผ๋ฉด ๋ชจ๋ ์ฌ์ฉ์๋ฅผ ๊ฑฐ๋ถํ๊ณ ์ค๋ฅ๋ฅผ ๊ธฐ๋กํฉ๋๋ค. `/connect`๋ ์ด ๊ฒ์ฌ ์ ์ ์ฌ์ ํ ํ์ฉ๋๋ฉฐ, ๊ฑฐ๋ถ๋ ๋ฐ์ ์์ ๋ฉ์์ง๋ ์์ ๋ฏธ๋์ด๋ฅผ ๋ค์ด๋ก๋ํ๊ธฐ ์ ์ ๋ฒ๋ ค์ง๋๋ค.
8. ์ข
๋ฃ ์์๋ ์งํ ์ค์ธ ์ปค์ ์ฐ๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฝ๋๋ค. ํ ํฐ์ด ๋ง๋ฃ๋๋ฉด DeerFlow๋ ํด๋ฌ ์ทจ์๋ฅผ ์๋ฃํ๊ธฐ ์ ์ ์ปค์ ์ด๊ธฐํ๋ฅผ ์์ ์ ์ฅํ๊ณ ์ ์ฅ๋ ํ ํฐ์ ์ญ์ ํฉ๋๋ค.
**WeCom ์ค์ **
1. WeCom AI Bot ํ๋ซํผ์์ ๋ด์ ๋ง๋ค๊ณ `bot_id`์ `bot_secret`์ ๋ฐ๊ธ๋ฐ์ผ์ธ์.
2. `config.yaml`์์ `channels.wecom`์ ํ์ฑํํ๊ณ `bot_id` / `bot_secret`์ ์
๋ ฅํ์ธ์.
3. `.env`์ `WECOM_BOT_ID`์ `WECOM_BOT_SECRET`์ ์ค์ ํ์ธ์.
4. ๋ฐฑ์๋ ์์กด์ฑ์ `wecom-aibot-python-sdk`๊ฐ ํฌํจ๋์ด ์๋์ง ํ์ธํ์ธ์. ์ด ์ฑ๋์ WebSocket ์ฅ๊ธฐ ์ฐ๊ฒฐ์ ์ฌ์ฉํ๋ฉฐ ๊ณต๊ฐ ์ฝ๋ฐฑ URL์ด ํ์ํ์ง ์์ต๋๋ค.
5. ํ์ฌ ํตํฉ์ ์์ ํ
์คํธ, ์ด๋ฏธ์ง, ํ์ผ ๋ฉ์์ง๋ฅผ ์ง์ํฉ๋๋ค. ์์ด์ ํธ๊ฐ ์์ฑํ ์ต์ข
์ด๋ฏธ์ง/ํ์ผ๋ WeCom ๋ํ๋ก ๋ค์ ์ ์ก๋ฉ๋๋ค.
**DingTalk ์ค์ **
1. [DingTalk Developer Console](https://open.dingtalk.com/)์์ DingTalk ์ ํ๋ฆฌ์ผ์ด์
์ ๋ง๋ค๊ณ **Robot** ๊ธฐ๋ฅ์ ํ์ฑํํ์ธ์.
2. ๋ก๋ด ์ค์ ํ์ด์ง์์ ๋ฉ์์ง ์์ ๋ชจ๋๋ฅผ **Stream Mode**๋ก ์ค์ ํ์ธ์.
3. `Client ID`์ `Client Secret`์ ๋ณต์ฌํด `.env`์ `DINGTALK_CLIENT_ID`์ `DINGTALK_CLIENT_SECRET`์ ์ค์ ํ๊ณ , `config.yaml`์์ ์ฑ๋์ ํ์ฑํํ์ธ์.
4. *(์ ํ ์ฌํญ)* ์คํธ๋ฆฌ๋ฐ AI Card ์๋ต(ํ์๊ธฐ ํจ๊ณผ)์ ์ฌ์ฉํ๋ ค๋ฉด [DingTalk Card Platform](https://open.dingtalk.com/document/dingstart/typewriter-effect-streaming-ai-card)์์ **AI Card** ํ
ํ๋ฆฟ์ ๋ง๋ ๋ค์, `config.yaml`์์ `card_template_id`๋ฅผ ํด๋น ํ
ํ๋ฆฟ ID๋ก ์ค์ ํ์ธ์. `Card.Streaming.Write` ๋ฐ `Card.Instance.Write` ๊ถํ๋ ์ ์ฒญํด์ผ ํฉ๋๋ค.
DingTalk์ Markdown ํด๋ฐฑ์ ํ๋ฅผ ๋ ์ด๋ธ์ด ๋ถ์ ์ธ์ฉ ๋ธ๋ก์ผ๋ก ํ์ํ๋ฉฐ, ์
์์ ์ด์ค์ผ์ดํ๋ ํ์ดํ(`\|`)์ ์๋ค์ ๋น ์
์ ๋ณด์กดํด ๊ฐ์ด ์ฌ๋ฐ๋ฅธ ์ด ๋ ์ด๋ธ ์๋์ ์ ์ง๋๋๋ก ํฉ๋๋ค.
DeerFlow๊ฐ Docker Compose์์ ์คํ๋ ๋ IM ์ฑ๋์ `gateway` ์ปจํ
์ด๋ ์์์ ์คํ๋ฉ๋๋ค. ์ด ๊ฒฝ์ฐ `channels.langgraph_url`์ด๋ `channels.gateway_url`์ `localhost`๋ก ์ง์ ํ์ง ๋ง์ธ์. `http://gateway:8001/api`, `http://gateway:8001`์ฒ๋ผ ์ปจํ
์ด๋ ์๋น์ค ์ด๋ฆ์ ์ฌ์ฉํ๊ฑฐ๋, `DEER_FLOW_CHANNELS_LANGGRAPH_URL`๊ณผ `DEER_FLOW_CHANNELS_GATEWAY_URL`์ ์ค์ ํ์ธ์.
**๋ช
๋ น์ด**
์ฑ๋์ด ์ฐ๊ฒฐ๋๋ฉด ์ฑํ
์์ ๋ฐ๋ก DeerFlow์ ์ํธ์์ฉํ ์ ์์ต๋๋ค.
| ๋ช
๋ น์ด | ์ค๋ช
|
|---------|-------------|
| `/new` | ์ ๋ํ ์์ |
| `/status` | ํ์ฌ ์ค๋ ๋ ์ ๋ณด ํ์ |
| `/models` | ์ฌ์ฉ ๊ฐ๋ฅํ ๋ชจ๋ธ ๋ชฉ๋ก ํ์ |
| `/model [name\|default]` | ํ์ฌ ๋ํ์ ๋ชจ๋ธ์ ํ์ํ๊ฑฐ๋ ๊ณ ์ |
| `/memory` | ๋ฉ๋ชจ๋ฆฌ ๋ณด๊ธฐ |
| `/agent list` | ๋ด ์ปค์คํ
์์ด์ ํธ ๋ชฉ๋ก ํ์ |
| `/agent use ` | ์ปค์คํ
์์ด์ ํธ๋ก ์ ๋ํ ์์ |
| `/help` | ๋์๋ง ํ์ |
> ๋ช
๋ น์ด ์ ๋์ฌ๊ฐ ์๋ ๋ฉ์์ง๋ ์ผ๋ฐ ์ฑํ
์ผ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค. DeerFlow๊ฐ ์ค๋ ๋๋ฅผ ๋ง๋ค๊ณ ๋ํ ํ์์ผ๋ก ์๋ตํฉ๋๋ค.
์์ด์ ํธ ์ ํ์ ๋ํ ๋จ์๋ก ์ ์ฉ๋ฉ๋๋ค. `/agent use `์ ์ ๋ํ๋ฅผ ์์ํ๊ณ ํด๋น ์ปค์คํ
์์ด์ ํธ๋ฅผ ์ค๋ ๋ ๋ฉํ๋ฐ์ดํฐ์ ๊ณ ์ ํฉ๋๋ค. ๊ธฐ์กด ๋ํ๋ ๋์ค์ ์์ด์ ํธ๋ฅผ ์ ๋ ๋ฐ๊พธ์ง ์์ผ๋ฉฐ, ์ ํ์ Gateway๋ฅผ ์ฌ์์ํด๋ ์ ์ง๋๊ณ , IM์์ ๋ง๋ ์ค๋ ๋๋ฅผ ์น UI์์ ์ด์ด๋ ๊ฐ์ ์ปค์คํ
์์ด์ ํธ๋ก ์ด์ด์ง๋๋ค.
์ ๋ํ์์ ๊ธฐ๋ณธ ์์ด์ ํธ๋ก ๋์๊ฐ๋ ค๋ฉด `/agent use lead_agent`๋ฅผ ์ฌ์ฉํ์ธ์.
๋ชจ๋ธ ์ ํ๋ ๋ํ ๋จ์๋ก ์ ์ฉ๋ฉ๋๋ค. `/model `์ *ํ์ฌ* ๋ํ์ ๋ชจ๋ธ์ ๊ณ ์ ํฉ๋๋ค. ์ด ๋ชจ๋ธ์ ํธ์ถ์์๊ฒ ๋ณด์ด๋ ๋ชจ๋ธ ๋ชฉ๋ก์ ๊ธฐ์ค์ผ๋ก ๊ฒ์ฆ๋๊ณ , Gateway ์ฌ์์ ํ์๋ ์ ์ง๋๋๋ก ์ค๋ ๋ ๋ฉํ๋ฐ์ดํฐ์ ์์ ์ ์ฅ๋๋ฉฐ, ์ ๋ํ๋ฅผ ์์ํ์ง ์๊ณ ๋ค์ ๋ฉ์์ง๋ถํฐ ์ ์ฉ๋ฉ๋๋ค. `/model`์ ์ค์ ์ ์ฉ๋๋ ๋ชจ๋ธ๊ณผ ๊ทธ ์ถ์ฒ๋ฅผ ๋ณด์ฌ ์ฃผ๊ณ , `/model default`๋ ๊ณ ์ ์ ํด์ ํ๋ฉฐ, `/models`๋ ๊ณ ์ ๋ ๋ชจ๋ธ์ ์๋ ค ์ค๋๋ค.
#### ์์ฒญ ํธ๋ ์ด์ค ์๊ด๊ด๊ณ
๋ชจ๋ Gateway HTTP ์๋ต์๋ `X-Trace-Id` ํค๋๊ฐ ํฌํจ๋ฉ๋๋ค. ํธ์ถ์๊ฐ `X-Trace-Id`๋ฅผ ๋ณด๋ด๋ฉด ๊ทธ ID๋ฅผ ์ด์ด๋ฐ๊ณ , ๊ทธ๋ ์ง ์์ผ๋ฉด ์๋ก ์์ฑํ๋ฏ๋ก, ํ๋ก์๋ ์
์คํธ๋ฆผ ์๋น์ค๊ฐ ์ฌ๋ฌ ์๋น์ค์ ๊ฑธ์ณ ํ๋์ ID๋ฅผ ๊ณ ์ ํ ์ ์์ต๋๋ค. ๋ณ๋ ์ค์ ์ด ํ์ ์์ผ๋ฉฐ ๋ ์๋ ์์ต๋๋ค.
๊ฐ์ ID๋ HTTP ์๋ต๋ณด๋ค ์ค๋ ์ง์๋๋ ์์
์๋ ๊ณ์ ๋ถ์ด ์์ต๋๋ค. ๋ถ๋ฆฌ๋์ด ์คํ๋๋ ์คํ(run) ์์
, ๊ทธ ์์
์ด ์์ํ๋ ๋ชจ๋ ์๋ธ์์ด์ ํธ, ๋ฐฑ๊ทธ๋ผ์ด๋ ๋ฉ๋ชจ๋ฆฌ ์
๋ฐ์ดํธ ์ค๋ ๋๊ฐ ์ฌ๊ธฐ์ ํด๋นํฉ๋๋ค. ์ด ID๋ ์คํ ๋ ์ฝ๋(runs API์์ ํ์ธ ๊ฐ๋ฅ), ์ค๋ ๋์ ์ฒดํฌํฌ์ธํธ ๋ฉํ๋ฐ์ดํฐ, Langfuse ํธ๋ ์ด์ค์ `deerflow_trace_id`๋ก ๊ธฐ๋ก๋ฉ๋๋ค. ์์ฝ ์์
, MCP ์์
์๋ฆผ ์คํ, IM ์ฑ๋ ๋ฉ์์ง๋ HTTP ๋ฐ์์ ์์๋๋ฏ๋ก ํ์ฐจ๋ง๋ค ์์ฒด ID๋ฅผ ๋ฐ๊ธํฉ๋๋ค.
๋ก๊ทธ ๋ ์ฝ๋์๋ ํฅ์๋ ๋ก๊น
์ด ์ผ์ ธ ์์ ๋๋ง ํด๋น ID๊ฐ ํฌํจ๋ฉ๋๋ค.
```yaml
logging:
enhance:
enabled: true # print trace_id into log records
format: text # or json
```
์ด ๊ธฐ๋ฅ์ ์ผ๋ฉด ๋ก๊ทธ ํ์์ด ๋ฐ๋๊ธฐ ๋๋ฌธ์ ๊ธฐ๋ณธ์ ์ผ๋ก ๊บผ์ ธ ์์ต๋๋ค. `logging`์ ์ฌ์์์ด ํ์ํ ์ค์ ์ด๋ฏ๋ก `config.yaml`์ ํธ์งํ ๋ค Gateway๋ฅผ ์ฌ์์ํ์ธ์. ์ด ์ค์ ์ ๋ก๊ทธ ์ถ๋ ฅ์๋ง ์ํฅ์ ์ฃผ๋ฉฐ, ID, ์๋ต ํค๋, ์คํ ๋ฉํ๋ฐ์ดํฐ์๋ ์ํฅ์ด ์์ต๋๋ค.
`deerflow_trace_id`๋ DeerFlow ์๊ด๊ด๊ณ ID์
๋๋ค. ์คํ ID๊ฐ ์๋๋ฉฐ, ํ๋ก๋ฐ์ด๋์ ๋ค์ดํฐ๋ธ ํธ๋ ์ด์ค ID๋ ์๋๋๋ค. ์กฐํ ํค๋ ์๋์ด์ ์ด ๊ฐ์ผ๋ก ์ค๋ ๋๋ ์คํ์ ์ฐพ์ ์ฃผ๋ ๊ธฐ๋ฅ์ ์์ผ๋, ๋ก๊ทธ ์ค์ ์๋ก ์ฐ๊ด ์ง๋ ๋ฐ ์ฌ์ฉํ์ธ์. `deerflow_trace_id`๋ฅผ ์คํ ์์ฒญ์ `metadata`๋ `config.context`์ ๋ด์ ๋ณด๋ด๋ฉด ๋ฌด์๋๊ณ ๋ฎ์ด์จ์ง๋ฏ๋ก, ์๋ต ํค๋, ๋ก๊ทธ, ์์ ์ ์ฅ๋ ์คํ์ด ์๋ก ์ด๊ธ๋๋ ์ผ์ด ์์ต๋๋ค. ์๊ด๊ด๊ณ ID๋ฅผ ๊ณ ์ ํ๋ ค๋ฉด `X-Trace-Id` ํค๋๋ฅผ ๋ณด๋ด์ธ์.
Gateway ์คํ ๊ธฐ๋ก์๋ ์ถ๋ ฅ์ด ์๋ ์คํ๊ณผ ํฌ๋์ ํ ๋ณต๊ตฌ๋ ์คํ์ ํฌํจํด, ์คํ๋ง๋ค ์ข
๋ฃ `run.delivery` ์์์ฆ๋ ํ๋์ฉ ๊ธฐ๋ก๋ฉ๋๋ค. ์ ์ ์คํ ์ค์๋ ์์ ์ข
๋ฃ ์คํ ์ํ๋ณด๋ค ๋จผ์ ์์์ฆ์ด ์์ ์ ์ฅ๋ฉ๋๋ค. ๊ณ ์(orphan) ๋ณต๊ตฌ๋ ๋จผ์ ๋ง๋ฃ๋ ๋ฆฌ์ค๋ฅผ ์์์ ์ผ๋ก ํ๋ํ ๋ค์ ์์์ฆ์ ๋ฉฑ๋ฑํ๊ฒ ์ฑ์ ๋ฃ์ผ๋ฏ๋ก, ์ค๋๋ ๋ณต๊ตฌ ์ค์บ์ด ์ด์ ์๋ ์คํ์ ์์ธ ์ ๋ฌ ์ ๋ณด๋ฅผ ๋ฎ์ด์ธ ์ ์์ต๋๋ค. ์ด๋ฒคํธ ์ ์ฅ์ ์ฅ์ ์ค์๋ ์์์ฆ ์์ ์ ์ฅ์ด ์ต์ ๋
ธ๋ ฅ(best-effort) ๋ฐฉ์์ผ๋ก ์ ์ง๋ฉ๋๋ค. ์ฒดํฌํฌ์ธํธ ์ฌ์ ์ ๊ฒ(preflight)์ ์คํจํ ์คํ(๋๋ ์ด์ ๋ง๋ฌด๋ฆฌ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ๋์ ์ทจ์๋ ์คํ)์ ๊ธฐ์กด์ ์๋ฃ ๋ฐ์ดํฐ ๋์์ ์ ์งํฉ๋๋ค. ์ฆ, ์ ๋ฌ ์์(zero-delivery) ์์์ฆ์ ๋ฐ์ง๋ง RunStore ์๋ฃ ํ๋๋ฅผ ๋น ์ค๋
์ท์ผ๋ก ๋ฎ์ด์ฐ์ง๋ ์์ต๋๋ค.
`tool_progress.enabled`๊ฐ true์ด๋ฉด, ๊ฐ์ ์คํ ์ด๋ฒคํธ ๊ธฐ๋ก์ ๊ฒฐ๊ณผ ํ์ง ๊ฐ๋์ ๋จ๊ณ ๋ณํ๋ ๊ธฐ๋ก๋ฉ๋๋ค. ๋ฆฌ๋ ์์ด์ ํธ์ ์ผ๋ฐ task ์๋ธ์์ด์ ํธ ๋ชจ๋์ ๋ฃจํ ๊ฐ์ง ๊ฒฐ์ ๊ณผ ์ง์ฐ(deferred) MCP ๋๊ตฌ ์น๊ฒฉ์ด ๊ธฐ๋ก๋ฉ๋๋ค. ์น๊ฒฉ ์ด๋ฒคํธ๋ ์๋ก ์น๊ฒฉ๋ ์ง์ฐ ๋๊ตฌ ์ด๋ฆ๊ณผ ์ด๋ฅผ ์ ํํ ๊ฒ์ด ๋ผ์ฐํ
๋ฉํ๋ฐ์ดํฐ์ธ์ง `tool_search`์ธ์ง๋ฅผ ๋ํ๋ด๋ฉฐ, ๊ฒ์ ์ฟผ๋ฆฌ, ๋ผ์ฐํ
ํค์๋, ์คํค๋ง, ์ธ์, ๊ฒฐ๊ณผ, ์นดํ๋ก๊ทธ ํด์๋ ์น๊ฒฉ ์ด๋ฒคํธ ์์ฒด์ ๋ณต์ฌํ์ง ์์ต๋๋ค.
#### LangSmith ํธ๋ ์ด์ฑ
DeerFlow๋ ๊ด์ธก์ฑ(observability)์ ์ํ [LangSmith](https://smith.langchain.com) ํตํฉ์ ๊ธฐ๋ณธ ์ ๊ณตํฉ๋๋ค. ํ์ฑํํ๋ฉด ๋ชจ๋ LLM ํธ์ถ, ์์ด์ ํธ ์คํ, ๋๊ตฌ ์คํ์ด ํธ๋ ์ด์ฑ๋์ด LangSmith ๋์๋ณด๋์์ ํ์ธํ ์ ์์ต๋๋ค.
`.env` ํ์ผ์ ๋ค์์ ์ถ๊ฐํ์ธ์.
```bash
LANGSMITH_TRACING=true
LANGSMITH_ENDPOINT=https://api.smith.langchain.com
LANGSMITH_API_KEY=lsv2_pt_xxxxxxxxxxxxxxxx
LANGSMITH_PROJECT=xxx
```
#### Langfuse ํธ๋ ์ด์ฑ
DeerFlow๋ LangChain ํธํ ์คํ์ ๋ํ [Langfuse](https://langfuse.com) ๊ด์ธก์ฑ๋ ์ง์ํฉ๋๋ค.
`.env` ํ์ผ์ ๋ค์์ ์ถ๊ฐํ์ธ์.
```bash
LANGFUSE_TRACING=true
LANGFUSE_PUBLIC_KEY=pk-lf-xxxxxxxxxxxxxxxx
LANGFUSE_SECRET_KEY=sk-lf-xxxxxxxxxxxxxxxx
LANGFUSE_BASE_URL=https://cloud.langfuse.com
```
์์ฒด ํธ์คํ
Langfuse ์ธ์คํด์ค๋ฅผ ์ฌ์ฉํ๋ค๋ฉด `LANGFUSE_BASE_URL`์ ํด๋น ๋ฐฐํฌ URL๋ก ์ค์ ํ์ธ์.
**ํธ๋ ์ด์ค ์๊ด๊ด๊ณ ํ๋.** ๋ชจ๋ ์์ด์ ํธ ์คํ์๋ Langfuse์ ์์ฝ๋ ํธ๋ ์ด์ค ์์ฑ์ด ์ง์ ๋๋ฏ๋ก Sessions ๋ฐ Users ํ์ด์ง๊ฐ ์๋์ผ๋ก ์ฑ์์ง๋๋ค.
- `session_id` = LangGraph `thread_id` โ ๊ฐ์ ๋ํ์ ๋ชจ๋ ํธ๋ ์ด์ค๋ฅผ ๋ฌถ์ต๋๋ค
- `user_id` = `get_effective_user_id()`์์ ์ป์ ์ค์ ์ฌ์ฉ์(์ธ์ฆ ์์ ๋ชจ๋์์๋ `default`๋ก ํด๋ฐฑ)
- `trace_name` = ์ด์์คํดํธ ID(๊ธฐ๋ณธ๊ฐ `lead-agent`)
- `tags` = `[env:, model:]`(๊ธฐ๋ณธ ์ ๊ณต Gateway ๋ฆฌ๋ ์์ด์ ํธ ์คํ๊ณผ ์๋ฒ ๋๋ ํด๋ผ์ด์ธํธ ์คํ์ ๊ธฐ๋ณธ๊ฐ ๋๋ ํด๋ฐฑ ํด์์ ๊ฑฐ์น ๋ค ์ ํ๋ ๋ชจ๋ธ์ ํ๊ทธ๋ก ๋ถ์
๋๋ค. ์ปค์คํ
๊ทธ๋ํ ํฉํ ๋ฆฌ๋ ์์ฒญ๋ ๋ชจ๋ธ๋ง ์ ๊ณตํ ์ ์์ต๋๋ค. ํ๊ฒฝ ํ๊ทธ๋ ์ค์ ๋์ง ์์ ๊ฒฝ์ฐ ์๋ต๋ฉ๋๋ค)
- `metadata.deerflow_trace_id` = DeerFlow ์์ฒญ ์๊ด๊ด๊ณ ID์ด๋ฉฐ, ์์ฒญ ํธ๋ ์ด์ค ์๊ด๊ด๊ณ๊ฐ ํ์ฑํ๋์ด ์์ผ๋ฉด `X-Trace-Id`์ ์ผ์นํฉ๋๋ค
์ด ๊ฐ๋ค์ `RunnableConfig.metadata`์ ์ฃผ์
๋ฉ๋๋ค. ์ฃผ์
์์น๋ Gateway ๊ฒฝ๋ก(`runtime/runs/worker.py::run_agent`)์ ์๋ฒ ๋๋ ๊ฒฝ๋ก(`client.py::DeerFlowClient.stream`) ๋ชจ๋์ ๊ทธ๋ํ ํธ์ถ ๋ฃจํธ์ด๋ฏ๋ก, LangChain ํธํ ์ฝ๋ฐฑ์ด๋ผ๋ฉด ์ด๋ค ๊ฒ์ด๋ ์ด๋ฅผ ์ฝ์ ์ ์์ต๋๋ค. ๋ฐฐํฌ ํ๊ฒฝ๋ณ๋ก ํธ๋ ์ด์ค์ ํ๊ทธ๋ฅผ ๋ถ์ด๋ ค๋ฉด `DEER_FLOW_ENV`(๋๋ `ENVIRONMENT`)๋ฅผ ์ค์ ํ์ธ์.
#### Monocle ํธ๋ ์ด์ฑ
DeerFlow๋ ์์ด์ ํธํ ์ ํ๋ฆฌ์ผ์ด์
์ ์ํ OpenTelemetry ๊ธฐ๋ฐ ํธ๋ ์ด์์ธ [Monocle](https://github.com/monocle2ai/monocle)๋ ์ง์ํฉ๋๋ค. Monocle์ ๊ฐ ์คํ์ ์ฒ์๋ถํฐ ๋๊น์ง ๊ธฐ๋กํฉ๋๋ค. LLM ํธ์ถ, ์์ด์ ํธ ๋จ๊ณ, ๋๊ตฌ ๋ฐ MCP ํธ์ถ์ ์
๋ ฅ, ์ถ๋ ฅ, ์์ ์๊ฐ, ํ ํฐ ์์ ํจ๊ป ๊ธฐ๋กํฉ๋๋ค.
`.env` ํ์ผ์ ๋ค์์ ์ถ๊ฐํ์ธ์.
```bash
MONOCLE_TRACING=true
MONOCLE_EXPORTERS=file # file, console, okahu, s3, blob, gcs (default: file)
OKAHU_API_KEY=okh_xxxxxxxx # required only for the `okahu` exporter
```
๊ฐ ์คํ์ `.monocle/`์ ํธ๋ ์ด์ค ํ์ผ ํ๋๋ฅผ ์๋๋ค. [Monocle VS Code ํ์ฅ](https://marketplace.visualstudio.com/items?itemName=OkahuAI.monocle-apptrace)์์ ์ด๋ฉด ์คํฌ ํ์๋ผ์ธ๊ณผ ํ ํฐ ์๋ฅผ ์ดํด๋ณผ ์ ์์ต๋๋ค. ์์ด์ ํธ ๊ด์ธก์ฑ ํ๋ซํผ์ธ [Okahu](https://www.okahu.ai)์ ์ฐ๊ฒฐํ๋ฉด ์ฌ๋ฌ ์คํ์ ๊ฑธ์ณ ํธ๋ ์ด์ค๋ฅผ ๋ถ์ํ๊ณ , ํธ๋ ์ด์ค ๊ธฐ๋ฐ ํ๊ฐ์ ์์ด์ ํธํ ํ๊ฐ๋ฅผ ์คํํ ์ ์์ต๋๋ค(`okahu` ์ต์คํฌํฐ ์ฌ์ฉ).
ํธ๋ ์ด์ค๋ ์คํฌ์ ์
๋ ฅ๊ณผ ์ถ๋ ฅ(ํ๋กฌํํธ, ๋๊ตฌ ์ธ์, ๋ชจ๋ธ ์๋ต)์ ์๋ฌธ ๊ทธ๋๋ก ์์งํ๋ฉฐ, ํ ํฐ ์ฌ์ฉ๋๊ณผ ์์ ์๊ฐ๋ ํจ๊ป ๊ธฐ๋กํฉ๋๋ค. `file` ์ต์คํฌํฐ๋ ์ด๋ฅผ ๋ก์ปฌ ๋์คํฌ์ ๋ณด๊ดํ๋ฉฐ ๋กํ
์ด์
ํ๊ฑฐ๋ ์ ๋ฆฌํ์ง ์์ผ๋ฏ๋ก `.monocle/`์ ์ฃผ๊ธฐ์ ์ผ๋ก ์ ๋ฆฌํ์ธ์. ์๊ฒฉ ์ต์คํฌํฐ(`okahu`, `s3`, `blob`, `gcs`)๋ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ธ๋ถ๋ก ์ ์กํ๋ฏ๋ก, ์ ๋ขฐํ ์ ์๋ ๋์๋ง ํ์ฑํํ์ธ์. Monocle์ Gateway ์์ ์ ํ ๋ฒ ์ด๊ธฐํ๋ฉ๋๋ค. ์ค์ ์ค๋ฅ(์ ์ ์๋ ์ต์คํฌํฐ, `OKAHU_API_KEY` ๋๋ฝ)๋ ๊ทธ ์์ ์ ๋ก๊ทธ๋ก ๊ธฐ๋ก๋๋ฉฐ, Gateway๋ฅผ ์ฌ์์ํ ๋๊น์ง ํธ๋ ์ด์ฑ์ ๊บผ์ง ์ํ๋ก ์ ์ง๋ฉ๋๋ค.
#### ์ฌ๋ฌ ํ๋ก๋ฐ์ด๋ ํจ๊ป ์ฌ์ฉํ๊ธฐ
LangSmith์ Langfuse๋ LangChain ์ฝ๋ฐฑ์ผ๋ก ์ฐ๊ฒฐ๋๋ฏ๋ก ๋ ๋ค ํ์ฑํํ ์ ์์ผ๋ฉฐ, ์ด ๊ฒฝ์ฐ DeerFlow๋ ๊ฐ ์คํ์ ์์ชฝ์ ๋ชจ๋ ๋ณด๊ณ ํฉ๋๋ค. ํ์ฑํ๋ ํ๋ก๋ฐ์ด๋์ ํ์ ์๊ฒฉ ์ฆ๋ช
์ด ์๊ฑฐ๋ ์ด๊ธฐํ์ ์คํจํ๋ฉด DeerFlow๋ ์ฆ์ ์คํจํ๊ณ ํด๋น ํ๋ก๋ฐ์ด๋ ์ด๋ฆ์ ์๋ ค ์ค๋๋ค. Monocle์ ์ฝ๋ฐฑ์ด ์๋ ์ ์ญ OpenTelemetry ํ๋ก๋ฐ์ด๋๋ฅผ ์ฌ์ฉํ๋ฉฐ, Langfuse๋ ๊ทธ ํ๋ก๋ฐ์ด๋๋ฅผ ๊ณต์ ํ๋ฏ๋ก ์ธ ๊ฐ์ง๋ฅผ ๋ชจ๋ ํจ๊ป ์คํํ ์ ์์ต๋๋ค. ๋ ์คํฌ ํ๋ก์ธ์๊ฐ ๊ฐ์ ๊ณต์ ํ๋ก๋ฐ์ด๋ ์์ ์๊ธฐ ๋๋ฌธ์, ๋ ๋ค ํ์ฑํํ๋ฉด Monocle์ ์ต์คํฌํฐ๋ Langfuse์ ์คํฌ๋ ๋ณด๊ฒ ๋ฉ๋๋ค.
Docker ๋ฐฐํฌ์์๋ ํธ๋ ์ด์ฑ์ด ๊ธฐ๋ณธ์ ์ผ๋ก ๋นํ์ฑํ๋์ด ์์ต๋๋ค. ํ์ฑํํ๋ ค๋ฉด `.env`์ `LANGSMITH_TRACING=true`์ `LANGSMITH_API_KEY`๋ฅผ ์ค์ ํ์ธ์.
#### ๊ธฐ์กด ์คํ ์คํธ๋ฆผ ๋์
`GET`์ผ๋ก ๊ธฐ์กด ์คํ์ SSE ์คํธ๋ฆผ์ ์ฐธ์ฌํ๋ฉด ๊ด์ฐฐ๋ง ํ ์ ์์ต๋๋ค. `action=interrupt|rollback`์ ์ง์ ํ๋ฉด `405`๋ฅผ ๋ฐํํฉ๋๋ค. ์ด ์คํธ๋ฆผ ๊ฒฝ๋ก์์ ์ทจ์๋ `POST`๋ก๋ง ๊ฐ๋ฅํ๋ฉฐ `runs:cancel` ๊ถํ์ด ํ์ํฉ๋๋ค. ์ด์ ๋ฐ๋ผ OpenAPI ๊ณ์ฝ์ `action`๊ณผ `wait`๋ฅผ `POST`์์๋ง ๋
ธ์ถํ๊ณ , `GET` ์์
์ ๊ฒฝ๋ก ๋งค๊ฐ๋ณ์๋ง ๋
ธ์ถํฉ๋๋ค.
#### ๊ฐ์ธ ์ก์ธ์ค ํ ํฐ
๋น๋ํํ ํด๋ผ์ด์ธํธ(CI ํ์ดํ๋ผ์ธ, ์คํฌ๋ฆฝํธ, ์๋ฒ ๊ฐ ํตํฉ)๋ ๋ธ๋ผ์ฐ์ ์ธ์
๋์ **๊ฐ์ธ ์ก์ธ์ค ํ ํฐ**(PAT)์ผ๋ก Gateway API๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค. ๋ก๊ทธ์ธํ ์ํ์์ `POST /api/v1/auth/pats`๋ก ํ ํฐ์ ๋ง๋์ธ์. ์๋ณธ `dfp_...` ๊ฐ์ ๋ฑ ํ ๋ฒ๋ง ํ์๋๋ฉฐ, SHA-256 ๋ค์ด์ ์คํธ๋ง ์ ์ฅ๋ฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ Bearer ์๊ฒฉ ์ฆ๋ช
์ผ๋ก ์ ์กํ์ธ์.
```http
POST /api/threads/search
Authorization: Bearer dfp_...
Content-Type: application/json
{}
```
๊ฐ ํ ํฐ์ ์์ ํ ์ฌ์ฉ์์ ์๋ณ ์ ๋ณด๋ก ์คํ๋๊ณ (์์ ์ ํํฐ๋ง๊ณผ ์ฌ์ฉ์๋ณ ๋ฉ๋ชจ๋ฆฌ๊ฐ ๊ทธ๋๋ก ๋์ํฉ๋๋ค), ํด๋น ์ฌ์ฉ์์ ๊ถํ์ ์ขํ๊ธฐ๋ง ํ ์ ์๋ ์ค์ฝํ ์งํฉ์ ๊ฐ์ง๋ฉฐ, ์ค๋ ๋/์คํ ์๋ช
์ฃผ๊ธฐ ๊ฒฝ๋ก์๋ง ํ์ฉ๋ฉ๋๋ค. ๊ทธ ๋ฐ์ ๋ชจ๋ ๊ฒฝ๋ก๋ PAT ํธ์ถ์์๊ฒ `403`์ผ๋ก ์๋ตํ๋ฉฐ, PAT๋ ์ ๋ ๊ด๋ฆฌ์ ๊ถํ์ ๊ฐ์ง ์์ต๋๋ค. ํ ํฐ์ ์ธ์ ๋ ์ง ์กฐํํ๊ณ ํ๊ธฐํ ์ ์์ผ๋ฉฐ, ํ๊ธฐ๋ ์ฆ์ ์ ์ฉ๋ฉ๋๋ค. PAT๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฐฑ์๋(SQLite/PostgreSQL)๊ฐ ํ์ํฉ๋๋ค. ์ ์ฒด ์ฐธ๊ณ ๋ฌธ์: [API ๋ ํผ๋ฐ์ค โ ๊ฐ์ธ ์ก์ธ์ค ํ ํฐ](backend/docs/API.md#personal-access-tokens).
## Deep Research์์ ์ํผ ์์ด์ ํธ ํ๋ค์ค๋ก
DeerFlow๋ Deep Research ํ๋ ์์ํฌ๋ก ์์ํ๊ณ , ์ปค๋ฎค๋ํฐ๋ ์ด๋ฅผ ๋ง์๊ป ํ์ฉํ์ต๋๋ค. ์ถ์ ์ดํ ๊ฐ๋ฐ์๋ค์ ๋ฆฌ์์น์ ๋ฒ์๋ฅผ ํจ์ฌ ๋์ด ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ ๊ตฌ์ถ, ์ฌ๋ผ์ด๋ ๋ฑ ์์ฑ, ๋์๋ณด๋ ๊ตฌ์ฑ, ์ฝํ
์ธ ์ํฌํ๋ก ์๋ํ์๊น์ง DeerFlow๋ฅผ ํ์ฉํ์ต๋๋ค. ์ ํฌ๊ฐ ์ ํ ์์ํ์ง ๋ชปํ ์ผ๋ค์ด์์ต๋๋ค.
์ด๋ฅผ ํตํด ์ค์ํ ์ฌ์ค์ ์๊ฒ ๋์์ต๋๋ค. DeerFlow๋ ๋จ์ํ ๋ฆฌ์์น ๋๊ตฌ๊ฐ ์๋์์ต๋๋ค. ์์ด์ ํธ๊ฐ ์ค์ ๋ก ์ผ์ ํด๋ผ ์ ์๋๋ก ์ธํ๋ผ๋ฅผ ์ ๊ณตํ๋ ๋ฐํ์, ์ฆ **ํ๋ค์ค**์์ต๋๋ค.
๊ทธ๋์ ์ ํฌ๋ DeerFlow๋ฅผ ์ฒ์๋ถํฐ ๋ค์ ๋ง๋ค์์ต๋๋ค.
DeerFlow 2.0์ ๋ ์ด์ ์ง์ ์ฎ์ด์ ์กฐ๋ฆฝํ๋ ํ๋ ์์ํฌ๊ฐ ์๋๋๋ค. ํ์ํ ๊ฒ์ด ๋ชจ๋ ๊ฐ์ถฐ์ ธ ์๊ณ ์์ ํ ํ์ฅ ๊ฐ๋ฅํ ์ํผ ์์ด์ ํธ ํ๋ค์ค์
๋๋ค. LangGraph์ LangChain์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ฉฐ, ์์ด์ ํธ์ ํ์ํ ๋ชจ๋ ๊ฒ์ ๊ธฐ๋ณธ ์ ๊ณตํฉ๋๋ค. ํ์ผ ์์คํ
, ๋ฉ๋ชจ๋ฆฌ, ์คํฌ, ์๋๋ฐ์ค๋ฅผ ์ธ์ํ๋ ์คํ, ๊ทธ๋ฆฌ๊ณ ๋ณต์กํ ๋ค๋จ๊ณ ์์
์ ์ํด ๊ณํ์ ์ธ์ฐ๊ณ ์๋ธ์์ด์ ํธ๋ฅผ ์์ฑํ๋ ๋ฅ๋ ฅ๊น์ง ํฌํจ๋ฉ๋๋ค.
๊ทธ๋๋ก ์ฌ์ฉํ์ธ์. ์๋๋ฉด ๋ง์๊ป ๋ฏ์ด๊ณ ์ณ ์ฌ๋ฌ๋ถ๋ง์ ๊ฒ์ผ๋ก ๋ง๋์ธ์.
## ํต์ฌ ๊ธฐ๋ฅ
### ์คํฌ๊ณผ ๋๊ตฌ
์ํฌ์คํ์ด์ค ์ฌ์ด๋๋ฐ์์ **Capability Center**๋ฅผ ์ด์ด **Plugins**(MCP ์๋ฒ์ Lark/Feishu ํตํฉ)์ **Skills**๋ฅผ ๊ด๋ฆฌํ์ธ์. ๋ ์นดํ๋ก๊ทธ ๋ชจ๋ ๊ฒ์์ ์ง์ํฉ๋๋ค. ์คํฌ ์นด๋์๋ ๊ฐ๊ฒฐํ ์ค๋ช
์ด ํ์๋๊ณ , ์ ์ฒด ์ค๋ช
์ ์์ธ ๋ณด๊ธฐ์์ ํ์ธํ ์ ์์ต๋๋ค. ๊ธฐ๋ณธ ์ ๊ณต ์คํฌ๊ณผ ์ฌ์ฉ์๊ฐ ๋ง๋ค๊ฑฐ๋ ๊ฐ์ ธ์จ ์คํฌ์ ๋ฐ๋ก ๋์ด๋ฉ๋๋ค. Community ํญ์์๋ `.skill` ์์นด์ด๋ธ๋ฅผ My skills๋ก ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. ์ผ๋ฐ ํ๊ฒฝ์ค์ ์ ๊ณ์ Settings์ ์์ต๋๋ค.
๊ด๋ฆฌ์๋ ์์ ์ ์ปค์คํ
์คํฌ `SKILL.md`์ ์๋ชป๋ YAML์ด ์์ผ๋ฉด Capability Center > Skills์์ **Could not load** ๊ฒฝ๊ณ ๋ฅผ ๋ณผ ์ ์์ต๋๋ค. ๊ฒฝ๊ณ ์๋ ํจํค์ง ๊ธฐ์ค ์๋ ๊ฒฝ๋ก์ ํ์ผ๊ณผ, ๊ฐ๋ฅํ ๊ฒฝ์ฐ ํด๋น ์ค๊ณผ ์ด์ด ํ์๋๋ฉฐ, ๋ฐ์ดํ๋ก ๊ฐ์ธ์ง ์์ ์ฝ๋ก ๊ฐ์ด ์์ผ๋ฉด ๋ฐ์ดํ ์ฌ์ฉ ํํธ๋ ํจ๊ป ํ์๋ฉ๋๋ค. ๋์คํฌ์์ ํ์ผ์ ์์ ํ ๋ค **Reload skills**๋ฅผ ์ ํํ๋ฉด ๋ชฉ๋ก์ด ์๋ก ๊ณ ์ณ์ง๊ณ ์ดํ ์คํ(run)์ ์ฌ์ฉํ ์คํฌ ํ๋กฌํํธ ์บ์๊ฐ ๋ฌดํจํ๋ฉ๋๋ค. ์งํ ์ค์ธ ์คํ์ ๊ธฐ์กด ์ค๋
์ท์ ๊ทธ๋๋ก ์ ์งํฉ๋๋ค. ์ด ๊ธฐ๋ฅ์ ํธ์ถ์๊ฐ ์์ ํ ์ปค์คํ
์คํฌ์๋ง ์ ์ฉ๋๋ฉฐ, legacy/global, public, integration, ์ธ๋ถ ๋งํฌ ํจํค์ง๋ ์ ์ธ๋ฉ๋๋ค. ์ด ๊ฒฝ๊ณ ๋ YAML ๊ตฌ๋ฌธ ์ค๋ฅ๋ง ๋ค๋ฃน๋๋ค. frontmatter ๋๋ฝ, ๋งคํ์ด ์๋ ๋ฉํ๋ฐ์ดํฐ, name ๋๋ description์ ๋๋ฝ/์ค๋ฅ, ์๋ชป๋ allowed-tools ๋๋ required-secrets ์ ์ธ, UTF-8์ด ์๋ ํ์ผ, ํ์ผ ์ฝ๊ธฐ ์คํจ(๊ถํ ๊ฑฐ๋ถ ํฌํจ)๋ ๋ณด๊ณ ๋์ง ์์ต๋๋ค. ๊ฒฝ๊ณ ๊ฐ ์๋ค๊ณ ํด์ ํจํค์ง๊ฐ ์ ํจํ๊ฑฐ๋ ์ฝ์ ์ ์๋ค๋ ๋ป์ ์๋๋๋ค. ๋ฒ์ ์๋ด ๋ฌธ๊ตฌ๋ YAML ๊ฒฝ๊ณ ๊ฐ ์์ ๋๋ ๊ณ์ ํ์๋ฉ๋๋ค. ๊ทธ ๋ฐ์ ๋ก๋ ์คํจ๋ Gateway ๋ก๊ทธ๋ฅผ ํ์ธํ์ธ์. ํ์ฑ์ ์ฌ์ ํ ์๊ฒฉํ๋ฉฐ, ์๋ชป๋ ์คํฌ์ ์์ด์ ํธ๊ฐ ๊ณ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
#### ์ฝ๊ธฐ ์ ์ฉ ์ง์ ์์ค
`config.yaml`์์ `knowledge_search`๋ฅผ `deerflow.community.ragflow.tools:knowledge_search_tool` ๋๋ `deerflow.community.lightrag.tools:knowledge_search_tool` ์ค ํ๋๋ก ์ค์ ํ์ธ์. ๋ ๋ค ์ถ์ฒ๋ฅผ ์ถ์ ํ ์ ์๋ ๊ฒ์(retrieval) ๊ทผ๊ฑฐ๋ฅผ ์ง์ํฉ๋๋ค. ์์ ํ ํ๋ก๋ฐ์ด๋ ๋ก์ผ์ดํฐ๊ฐ ์๋ LightRAG ๋ฐ RAGFlow ์๋ต์ ๊ณต์ DeerFlow ์์ค ๊ณ์ฝ์ ์ฌ์ฉํ๊ณ , ์์ ํ RAGFlow ์๋ต์ ๊ธฐ์กด ์ธ์ฉ ์ค๋
์ท๊ณผ ๋ฒ์ ์ ์ด๋ฅผ ๊ทธ๋๋ก ์ ์งํฉ๋๋ค. ์ง์ ์ธ์ฉ์ ์ฑํ
์์ ํ๋ก๋ฐ์ด๋, ๋ฌธ์ ์ ๋ชฉ, ๊ฒ์๋ ๋ฐ์ท๋ฌธ์ ๋ณด์ฌ ์ฃผ๋ฉฐ, ๋ค์ ๋ถ๋ฌ์จ ๋ค๋ ์๋ธ์์ด์ ํธ๊ฐ ๊ฒ์์ ์ํํ ๊ฒฝ์ฐ์๋ ๋ง์ฐฌ๊ฐ์ง์
๋๋ค. ๋๋ฝ๋ ํ์ด์ง ๋ฒํธ์ ๊ณต๊ฐ URL์ ๊ทธ๋๋ก ๋น์ด ์์ผ๋ฉฐ, URL์ด ์๋ ์์ค๋ ๋ก์ปฌ ๊ทผ๊ฑฐ๋ก ์ฝ์ ์ ์์ต๋๋ค. ์ธ๋ผ์ธ ์ธ์ฉ์ Markdown ์ ํ(sanitization) ํ์๋ ์ฝ์ ์ ์๊ณ , ์ ๊ณต๋ ํ์ด์ง ๋ฒํธ๋ ์ ํํ ์ธํฐํ์ด์ค ์ธ์ด๋ก ํ์๋ฉ๋๋ค. ์ ํ๋ก๋ฐ์ด๋๋ ๊ณต์ ์๋ฒจ๋กํ๋ฅผ ์ฌ์ฉํ๋ฉฐ, ๊ธฐ์กด RAGFlow ์ธ์ฉ ๊ธฐ๋ก๋ ๊ณ์ ์ง์๋ฉ๋๋ค. ์๋ฃ๋ ํ์ ์์
์นด๋๋ฅผ ํผ์น๋ฉด ํด๋น ๋ณด๊ณ ์๊ฐ ์ ๋ฌํ ์ง์ ์์ค๋ฅผ ํ์ธํ ์ ์์ผ๋ฉฐ, ์ ์ฅ๋ ๋ํ๋ฅผ ๋ค์ ์ด ๋๋ ๋ง์ฐฌ๊ฐ์ง์
๋๋ค. ์ถ์ฝ๋ ํผํฉ ํ๋ก๋ฐ์ด๋ ์์
๋ณด๊ณ ์๋ ๋์ด์ง ์ธ์ฉ ์กฐ๊ฐ์ ์ ๊ฑฐํ๋, ๋จ์ ์๋ ๊ณต์ ์์ค ๋งํฌ๋ฅผ ํํํํ์ง ์์ต๋๋ค. ๊ธฐ์กด ์น ์ธ์ฉ๊ณผ ํ
์คํธ ์ ์ฉ Python `knowledge_search(query)` API๋ ๊ณ์ ์ง์๋ฉ๋๋ค. ๋ณ๋์ ์ง์ ๊ด๋ฆฌ ์๋น์ค๋ ํ์ด์ง๋ ํ์ํ์ง ์์ต๋๋ค. [์ง์ ๊ณ์ฝ ๊ฐ์ด๋](backend/docs/KNOWLEDGE.md)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
์คํฌ์ DeerFlow๊ฐ *๊ฑฐ์ ๋ชจ๋ ์ผ*์ ํ ์ ์๊ฒ ํด ์ฃผ๋ ์์์
๋๋ค.
ํ์ค Agent Skill์ ๊ตฌ์กฐํ๋ ๊ธฐ๋ฅ ๋ชจ๋์
๋๋ค. ์ฆ ์ํฌํ๋ก์ ๋ชจ๋ฒ ์ฌ๋ก, ๊ทธ๋ฆฌ๊ณ ๋ณด์กฐ ๋ฆฌ์์ค์ ๋ํ ์ฐธ์กฐ๋ฅผ ์ ์ํ๋ Markdown ํ์ผ์
๋๋ค. DeerFlow์๋ ๋ฆฌ์์น, ๋ณด๊ณ ์ ์์ฑ, ์ฌ๋ผ์ด๋ ์ ์, ์น ํ์ด์ง, ์ด๋ฏธ์ง ๋ฐ ๋์์ ์์ฑ ๋ฑ์ ์ํ ๊ธฐ๋ณธ ์ ๊ณต ์คํฌ์ด ํฌํจ๋์ด ์์ต๋๋ค. ํ์ง๋ง ์ง์ง ๊ฐ์ ์ ํ์ฅ์ฑ์ ์์ต๋๋ค. ์ง์ ์คํฌ์ ์ถ๊ฐํ๊ฑฐ๋, ๊ธฐ๋ณธ ์ ๊ณต ์คํฌ์ ๊ต์ฒดํ๊ฑฐ๋, ์ฌ๋ฌ ์คํฌ์ ์กฐํฉํด ๋ณตํฉ ์ํฌํ๋ก๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
์คํฌ์ ํ๊บผ๋ฒ์ ๋ชจ๋ ๋ก๋๋์ง ์๊ณ , ์์
์ ํ์ํ ๋๋ง ์ ์ง์ ์ผ๋ก ๋ก๋๋ฉ๋๋ค. ๋๋ถ์ ์ปจํ
์คํธ ์๋์ฐ๋ฅผ ๊ฐ๋ณ๊ฒ ์ ์งํ ์ ์๊ณ , ํ ํฐ์ ๋ฏผ๊ฐํ ๋ชจ๋ธ์์๋ DeerFlow๊ฐ ์ ๋์ํฉ๋๋ค.
์ง์ฐ(deferred) ์คํฌ ํ์์ด ํ์ฑํ๋์ด ์์ผ๋ฉด, `describe_skill`์ ์ด๋ฆ๊ณผ ์ค๋ช
์ ๋ฐ์ ์๋ ์ฉ์ด ์ปค๋ฒ๋ฆฌ์ง(์ํ์ด ์์ผ๋ฉฐ Unicode ์ ๊ทํ๋ฅผ ๊ฑฐ์นจ)๋ฅผ ๊ธฐ์ค์ผ๋ก ์ค์น๋ ์คํฌ์ ์์๋ฅผ ๋งค๊น๋๋ค. ๋ฐ๋ผ์ ์ฌ๋ฌ ๋จ์ด๋ก ๋ ์์ฐ์ค๋ฌ์ด ์์ฒญ๋ ์ ํํ ์ผ์นํ๋ ํ๋์ ๋ฌธ๊ตฌ ์์ด ๊ด๋ จ ์คํฌ์ ์ฐพ์ ์ ์์ผ๋ฉฐ, ์ ํ ์ผ์น `select:` ์กฐํ์ ์ด๋ฆ ํ์ `+prefix` ์กฐํ๋ ๊ณ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์์ ๊ฒ์์ ์ต๋ 256์๋ฅผ ์ฌ์ฉํ๊ณ ์ต๋ 5๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํฉ๋๋ค. ์ ํ ์ผ์น `select:` ๋ชฉ๋ก์ ์๋ฆฌ์ง ์์ผ๋ฉฐ ์์ฒญํ ์นดํ๋ก๊ทธ ์ผ์น ํญ๋ชฉ์ ๋ชจ๋ ๋ฐํํฉ๋๋ค.
์คํฌ ๋๋ ํฐ๋ฆฌ๋ ํจํค์ง ๊ฒฝ๊ณ์
๋๋ค. DeerFlow๊ฐ ์คํฌ์ `SKILL.md`๋ฅผ ์ฐพ์ผ๋ฉด, ๊ทธ ํจํค์ง ์๋์ ์ค์ฒฉ๋ `SKILL.md` ํ์ผ(์: ํ๊ฐ์ฉ ํฝ์ค์ฒ)์ ๋ณด์กฐ ๋ฐ์ดํฐ๋ก ๋จ์ผ๋ฉฐ ๋ฐํ์ ์คํฌ๋ก ๋ฑ๋ก๋์ง ์์ต๋๋ค. ์ด ๊ท์น์ public ์คํฌ๊ณผ ์ปค์คํ
์คํฌ๋ฟ ์๋๋ผ ๊ด๋ฆฌํ ํตํฉ ํฉ์๋ ์ ์ฉ๋ฉ๋๋ค. ์์ฒด `SKILL.md`๊ฐ ์๋ ๋ค์์คํ์ด์ค ๋๋ ํฐ๋ฆฌ๋ ์ฌ์ ํ ์ค์ฒฉ๋ ์คํฌ์ ๋ฌถ์ ์ ์์ต๋๋ค.
ํ์์ ์ด์์๊ฐ ๊ด๋ฆฌํ๋ ๋๋ ํฐ๋ฆฌ ์ฌ๋ณผ๋ฆญ ๋งํฌ๋ฅผ ๋ฐ๋ผ๊ฐ์ง๋ง, ์์ ๋๋ ํฐ๋ฆฌ๋ฅผ ๊ฐ๋ฆฌํค๋ ๋งํฌ๋ ๊ฑด๋๋ฐ๋ฏ๋ก ์ํ ๋ค์์คํ์ด์ค๊ฐ ๊ฐ์ ํธ๋ฆฌ๋ฅผ ๋ฐ๋ณตํด์ ๋ค์ ์ค์บํ์ง ์์ต๋๋ค. ๊ฐ์ ์ธ๋ถ ์คํฌ ํธ๋ฆฌ๋ฅผ ๊ฐ๋ฆฌํค๋ ์๋ก ๋
๋ฆฝ๋ ๋งํฌ๋ ๊ณ์ ์ง์๋ฉ๋๋ค.
์คํฌ Markdown๊ณผ ๋ฒ๋ค๋ ํ
์คํธ ๋ฆฌ์์ค๋ UTF-8์ ์ฌ์ฉํฉ๋๋ค. Skill-creator CLI์ ๊ฒํ ์ ํธ๋ฆฌํฐ๋ ํ
์คํธ๋ฅผ ๋ช
์์ ์ผ๋ก UTF-8๋ก ์ฝ๊ณ ์ฐ๋ฏ๋ก, ํ์งํ๋ ์คํฌ์ด ์ด์์ฒด์ ์ ๊ด๊ณ์์ด ์ผ๊ด๋๊ฒ ๋์ํฉ๋๋ค.
`SKILL.md` YAML frontmatter๋ ๋จ๋
์ค์ `---`๋ก ์์ํ๊ณ ๋๋์ผ ํฉ๋๋ค(๋ค์ ์ค๋ ๊ณต๋ฐฑ์ด๋ ํญ์ ํ์ฉ๋ฉ๋๋ค). `---suffix` ๊ฐ์ ์ค์ ๋ซ๋ ๊ตฌ๋ถ์๊ฐ ์๋๋๋ค.
์ปค์คํ
์คํฌ ๊ธฐ๋ก์ ์ ์ฅ๋ ์ฝํ
์ธ ์ ๋ฉํ๋ฐ์ดํฐ ์์ Unicode ์ค ๊ตฌ๋ถ์๋ฅผ ๋ณด์กดํ๋ฏ๋ก, ๊ธฐ๋ก ํ์ธ๊ณผ ๋กค๋ฐฑ ์ ํด๋น ๋ฆฌ๋น์ ์ ๊ณ์ ์ฝ์ ์ ์์ต๋๋ค. ํ์์ด ์๋ชป๋ JSON ๊ธฐ๋ก ๋ ์ฝ๋๋ ์ฌ์ ํ ๊ฑฐ๋ถ๋ฉ๋๋ค.
๋ฒ๋ค๋ `github-deep-research` API ํด๋ผ์ด์ธํธ๋ `requests` ์์ด๋ Python ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ HTTP ํด๋ผ์ด์ธํธ๋ฅผ ์ฌ์ฉํด ๋์ํฉ๋๋ค. ์ด ํด๋ฐฑ์ ๊ฒ์ ์ฟผ๋ฆฌ์ ๋ ์ด๋ธ ํํฐ์ ๊ณต๋ฐฑ, Unicode, ์์ฝ ๋ฌธ์๋ฅผ ๊ทธ๋๋ก ๋ณด์กดํฉ๋๋ค.
์ฌ์ฉ์๋ ์์ฒญ์ `/skill-name`์ผ๋ก ์์ํด, ํ์ฑํ๋(enabled) ์คํฌ์ ํ ํด ๋์ ๋ช
์์ ์ผ๋ก ํ์ฑํ(activate)ํ ์ ์์ต๋๋ค. ์: `/data-analysis analyze uploads/foo.csv`. DeerFlow๋ ํด๋น ์คํฌ์ `SKILL.md`๋ฅผ ์จ๊ฒจ์ง ํ์ฌ ํด ์ปจํ
์คํธ๋ก ๋ก๋ํ๊ณ , ๊ธฐ๋ณธ ํ๋กฌํํธ์๋ ์คํฌ ๋ฉํ๋ฐ์ดํฐ๋ง ๋จ๊ฒจ ๋ก๋๋ค. ์ฌ๋์ ํ์ฑํ๋ ๋นํ์ฑํ๋ ์คํฌ, ์ปค์คํ
์์ด์ ํธ์ ์คํฌ ํ์ฉ ๋ชฉ๋ก, ๊ทธ๋ฆฌ๊ณ `/new`, `/help` ๊ฐ์ ๊ธฐ์กด ์ฑ๋ ๋ช
๋ น์ ์กด์คํฉ๋๋ค.
๋ต๋ณ์ด ์คํฌ์ ๋ก๋ํ๋ฉด ํด๋น ๋ต๋ณ์ ํด๋ฐ์ **Skills used**๊ฐ ํ์๋ฉ๋๋ค. ์์ด์ฝ์ ๋ง์ฐ์ค๋ฅผ ์ฌ๋ฆฌ๊ฑฐ๋ ํด๋ฆญํ๋ฉด ์ฌ์ฉ๋ ์คํฌ๊ณผ ๊ทธ ์ถ์ฒ๋ฅผ ๋ณผ ์ ์์ผ๋ฉฐ, ์คํฌ ์ด๋ฆ์ ๋ง์ฐ์ค๋ฅผ ์ฌ๋ฆฌ๋ฉด ๋ฐ์ค์ด ํ์๋ฉ๋๋ค. ์คํฌ์ ์ ํํ๋ฉด ํฌ๊ธฐ๋ฅผ ์กฐ์ ํ ์ ์๋ ์ฌ์ด๋ ํจ๋(๋ชจ๋ฐ์ผ์์๋ ๋๋ก์ด)์์ ํด๋น `SKILL.md`๋ฅผ ํ์ธํ ์ ์์ต๋๋ค. ์ด ๋ณด๊ธฐ๋ ์ค์ ๋ ์ฝ๊ธฐ ๋๊ตฌ๋ฅผ ํตํ ์ฑ๊ณต์ ์ธ ๋ก๋๋ ๋ช
์์ ์ฌ๋์ ํ์ฑํ ์ค์ ์บก์ฒ๋ ์ค๋
์ท์ ์ฌ์ฉํ๋ฏ๋ก, ์ดํ ์คํฌ์ ์์ ํ๊ฑฐ๋ ์ ๊ฑฐํด๋ ๊ทธ ๊ธฐ๋ก์ ๋ค์ ์ฐ์ด์ง ์์ต๋๋ค. ๋ฐ๋ณต๋ ๋ก๋๋ ์คํ๋ง๋ค ํ ๋ฒ์ฉ, ์ฒ์ ๋ก๋๋ ์์๋๋ก ํ์๋ฉ๋๋ค. ๋ฒ์ ์ฝ๊ธฐ์ ํฌ๊ธฐ ์ํ์ด ์๋ ์ค๋
์ท์ ๋ถ๋ถ(partial)์ผ๋ก ํ์๋๋ฉฐ, ์บก์ฒ๋ ๊ทผ๊ฑฐ๊ฐ ์๋ ์ด์ ๋ํ์๋ ์ด ๋ฉ๋ด๊ฐ ํ์๋์ง ์์ต๋๋ค. ๋ณต์ฌํ๋ฉด YAML frontmatter๋ฅผ ํฌํจํ ์บก์ฒ๋ Markdown์ด ๋ฐํ๋ฉ๋๋ค. ํจํค์ง ๊ธฐ์ค ์๋ ๋งํฌ์ ์ด๋ฏธ์ง๋ ๋ํ ๋ฐ์ผ๋ก ์ด๋ํ์ง ์๊ณ ์ฝ์ ์ ์๋ ์ฐธ์กฐ๋ก ๋จ์ต๋๋ค. ์
ธ ๋ช
๋ น์ฒ๋ผ ๋ค๋ฅธ ๋๊ตฌ๋ฅผ ํตํด ์ํ๋ ์คํฌ ๋ก๋๋ ๋ต๋ณ ํ
์คํธ๋ก๋ถํฐ ์ถ๋ก ํ์ง ์์ต๋๋ค.
์คํฌ์ `allowed-tools` frontmatter๋ ๋ค๋ฅธ ์์ด์ ํธ ํ๋ ์์ํฌ์์ ์ํธ ์ด์์ ์ํด ๋ด์ ๋๋ ํธํ์ฑ ๋ฉํ๋ฐ์ดํฐ์
๋๋ค. DeerFlow๋ ์ด๋ฅผ ํ์ฑํ๊ณ , ๊ฒ์ฆํ๊ณ , ๋ด๋ณด๋ด๊ณ , ์ค๋ช
ํ์ง๋ง, ๋ชจ๋ธ์ ๋ณด์ด๋ ๋๊ตฌ ์คํค๋ง๋ฅผ ํํฐ๋งํ๊ฑฐ๋, ๋๊ตฌ ํธ์ถ์ ๊ฑฐ๋ถํ๊ฑฐ๋, `tool_search` ์น๊ฒฉ์ ๋ค์ ์ฐ๋ ์ผ์ ๊ฒฐ์ฝ ์์ต๋๋ค. ์คํฌ์ ๋จ์ํ ํ์ฑํํ๊ฑฐ๋, ์๋ฆฌ๊ฑฐ๋, ์ปค์คํ
์์ด์ ํธ ๋๋ ์๋ธ์์ด์ ํธ์ `skills` ํ์ฉ ๋ชฉ๋ก์ ๋์ดํ๋ ๊ฒ๋ง์ผ๋ก ์์ด์ ํธ์ ๋๊ตฌ ์ธํธ๊ฐ ๋ฌ๋ผ์ง์ง๋ ์์ต๋๋ค. ์ค์ ๋๊ตฌ ๊ถํ์ Agent ๊ตฌ์ฑ๊ณผ ๊ถํ ๋ถ์ฌ์ ์์ต๋๋ค. ์์ด์ ํธ ์กฐ๋ฆฝ ์์ ์ ํ๋ก๋ฐ์ด๋ ํํฐ๋ง, ๋ฐํ์ ๊ฐ๋๋ ์ผ ์ ์ฉ, ๊ฐ๋๋ ์ผ ํ์ฉ ๋ชฉ๋ก, ์ง์ฐ ์น๊ฒฉ ์นดํ๋ก๊ทธ๊ฐ ๊ถํ ์ํ์ ์ ํฉ๋๋ค. ์คํฌ ๊ฐ์์ฑ๊ณผ ํ์ฑํ ํต์ ๋ ์ฌ์ ํ ๋ณ๋๋ก ๊ฐ์ ๋ฉ๋๋ค. ์ฌ๋์ ํ์ฑํ๋ ๋นํ์ฑํ๋ ์คํฌ๊ณผ ์ปค์คํ
์์ด์ ํธ ํ์ฉ ๋ชฉ๋ก์ ์กด์คํ๋ฉฐ, `skill:activate` ๊ถํ ๋ถ์ฌ ๊ฒฐ์ ์ ๋ช
์์ ์ฌ๋์ ํ์ฑํ์ ์์จ์ ์ธ `SKILL.md` ๋ก๋๋ฅผ ๋ชจ๋ ๊ณ์ ์ ์ดํฉ๋๋ค.
Gateway๋ฅผ ํตํด `.skill` ์์นด์ด๋ธ๋ฅผ ์ค์นํ๋ฉด, DeerFlow๋ ํ์ค ๊ณต๋ฐฑ ๊ตฌ๋ถ `allowed-tools`, ์ ํ์ frontmatter ๋ฉํ๋ฐ์ดํฐ, Claude ํธํ `argument-hint` ํ๋๋ฅผ ๋ฐ์๋ค์ด๋ฏ๋ก ๊ทธ ์ธ์๋ ์ ํจํ ์ธ๋ถ ์คํฌ์ ๊ฑฐ๋ถํ์ง ์์ต๋๋ค. `allowed-tools`์ YAML ๋ฆฌ์คํธ๋ ๊ณ์ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ์ ํํ ๋ฐํ์ ์ด๋ฆ์ด ๋ณด์กด๋ฉ๋๋ค. `WebFetch`, `WebSearch`, `Glob`, `Grep`, `Read` ๊ฐ์ ์ ํํ ์ด์์ฉ ํ๊ธฐ๋ DeerFlow์ `web_fetch`, `web_search`, `glob`, `grep`, `read_file` ๋๊ตฌ์ ๋งคํ๋ฉ๋๋ค. ์๋ฌธ์์ด๊ฑฐ๋ ๊ทธ ๋ฐ์ ์ ์ ์๋ ์ค์นผ๋ผ ์ด๋ฆ์ ๋ณ๊ฒฝ๋์ง ์์ผ๋ฏ๋ก ์ปค์คํ
๋๊ตฌ์ MCP ๋๊ตฌ๋ ์ ํํ ๋ฐํ์ ํ๊ธฐ๋ฅผ ์ ์งํฉ๋๋ค. `Bash(tvly *)`์ฒ๋ผ ๊ดํธ๊ฐ ์๋ ํญ๋ชฉ์ ๊ณต๋ฐฑ, ๋ฐ์ดํ๋ก ๊ฐ์ผ ํ
์คํธ, ์ด์ค์ผ์ดํ๋ ๊ดํธ๊น์ง ํฌํจํด ํ๋์ ๋ฆฌํฐ๋ด ํญ๋ชฉ์ผ๋ก ํ ํฐํ๋ฉ๋๋ค. ์ด๋ฐ ๋ฒ์ ์ง์ ์ ์ธ์ ๋ฌธ์ ๊ทธ๋๋ก์ ํธํ์ฑ ๋ฉํ๋ฐ์ดํฐ๋ก ๋จ์ ์ด๋ค ๋ช
๋ น์ ์คํ ๊ถํ๋ ๋ถ์ฌํ๊ฑฐ๋ ์ ํํ์ง ์์ผ๋ฉฐ, ๋ฌด์์ ์คํํ ์ ์๋์ง๋ ๋๊ตฌ ์ธ์๊ฐ ์๋๋ผ DeerFlow์ Agent ๊ตฌ์ฑ๊ณผ ๊ถํ ๋ถ์ฌ๊ฐ ๊ฒฐ์ ํฉ๋๋ค.
์คํฌ์ ๋นํ์ฑํํ๋ฉด ์๋๋ฐ์ค ํ์ผ ์์คํ
๋ณด๊ธฐ์์๋ ์ ๊ฑฐ๋๋ฏ๋ก, ์
ธ ๋ช
๋ น๊ณผ ๊ตฌ์กฐํ๋ ํ์ผ ๋๊ตฌ๊ฐ ๋์ผํ ํ์ฑํ ์ํ๋ฅผ ๋ฐ๋ฆ
๋๋ค. Local, Docker/AIO, hostPath provisioner, ๊ทธ๋ฆฌ๊ณ ์๋ก ์์ฑ๋ E2B ์๋๋ฐ์ค๋ ํ์ฑํ๋ ์คํฌ๋ง ๋ด์ ํฌ์(projection)์์ `/mnt/skills`๋ฅผ ๊ฐ์ ธ์ค๋ฉฐ, ์ด ํฌ์์ public, custom, legacy ๋๋ ๊ด๋ฆฌํ ํตํฉ ์คํฌ์ด ์ผ๊ณ ๊บผ์ง๊ฑฐ๋, ์์ ยท์์ฑยท์ญ์ ยท์ค์น๋ ๋ ๊ฐฑ์ ๋ฉ๋๋ค. ๊ตฌ์กฐํ๋ `read_file` ํธ์ถ(์ค ๋ฒ์ ์ฝ๊ธฐ์ ์ฐ๊ธฐ ์ ์ฝ๊ธฐ ๊ฒ์ฌ ํฌํจ)์ ์๋๋ฐ์ค ํ๋ก๋ฐ์ด๋์ ๋ง์ดํธ ๋งคํ์ ์ฌ์ฉํ๋ฏ๋ก, ์๋๋ฐ์ค๋ฅผ ํ๋ํ ๋ ์บก์ฒ๋ ์ฌ์ฉ์ ์๋ณ ์ ๋ณด๊ฐ ๊ณ์ ๊ธฐ์ค์ด ๋ฉ๋๋ค. ๊ด๋ฆฌํ ํตํฉ ํจํค์ง๋ ๊ณต์ ๋ ์ํ๋ก ์ ์ง๋์ง๋ง, ํฌ์๋ ํ์ผ ์์คํ
์์์ ๊ฐ์์ฑ์ ๊ฐ ์ฌ์ฉ์์ ํ์ฑํ ์ํ๋ฅผ ๋ฐ๋ฆ
๋๋ค. ๋ฉํฐ ์์ปค Gateway๋ ์ฌ์ฉ์ ํฌ์์ ๋ค์ ๋ง๋ค ๋ ๋์คํฌ์ ํ์ฑํ ์ํ๋ฅผ ๋ค์ ์ฝ์ผ๋ฏ๋ก, ํ ์์ปค๊ฐ ์ฒ๋ฆฌํ ํ ๊ธ์ด ๋ค๋ฅธ ์์ปค์ ๋ค์ ์๋๋ฐ์ค ํ๋์๋ ๋ฐ์๋ฉ๋๋ค. ๊ธฐ์กด E2B ์๋๋ฐ์ค๋ ๋ค์ ์์ฑ๋ ๋๊น์ง ์์ฑ ์์ ์ ์ค๋
์ท์ ์ ์งํฉ๋๋ค. PVC ๊ธฐ๋ฐ provisioner ์คํฌ์ ๋น๋ถ๊ฐ ์ค์ ๋ PVC ์ค๋
์ท/๋ ์ด์์์ ์ ์งํ๋ฉฐ, ๋์ PVC ๊ตฌ์ฒดํ๋ ๋ณ๋๋ก ์ถ์ ๋ฉ๋๋ค.
```
# Paths inside the sandbox container
/mnt/skills/public
โโโ research/SKILL.md
โโโ report-generation/SKILL.md
โโโ slide-creation/SKILL.md
โโโ web-page/SKILL.md
โโโ image-generation/SKILL.md
/mnt/skills/custom
โโโ your-custom-skill/SKILL.md โ yours
/mnt/skills/integrations
โโโ lark-cli/lark-doc/SKILL.md โ managed, read-only
```
๊ธฐ๋ณธ ์ ๊ณต `image-generation` ์คํฌ์ Gemini, MiniMax, OpenAI ํธํ Images API๋ฅผ ์ง์ํฉ๋๋ค. OpenAI ํธํ API๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด `IMAGE_GENERATION_PROVIDER=openai`๋ก ์ ํํ ๋ค์ `IMAGE_GENERATION_API_KEY`, `IMAGE_GENERATION_BASE_URL`, `IMAGE_GENERATION_MODEL`์ ์ค์ ํ์ธ์. ์ปจํ
์ด๋ํ๋ ์๋๋ฐ์ค๋ ๋ช
์์ ์ผ๋ก ํ์ฑํํ ๋ก์ปฌ ํธ์คํธ ์
ธ์์๋ `sandbox.environment`๋ฅผ ํตํด ์ด ๋ณ์๋ค์ ๋
ธ์ถํ์ธ์. ์๋๋ฐ์ค ๋ช
๋ น์ ์๋์ ์ผ๋ก Gateway ํ๋ก์ธ์ค์ API ํค๋ฅผ ์์ํ์ง ์์ต๋๋ค. ๋ก์ปฌ ํ๋ก๋ฐ์ด๋๋ ํด์๋ ์ค์ ๊ฐ์ ๋ณ๊ฒฝ ์์ด ์ฌ์ฉํ๋ฉฐ, ์์ฒญ ๋ฒ์ ์ํฌ๋ฆฟ์ด ์ด์์ ๊ฐ๋ณด๋ค ์ฐ์ ํฉ๋๋ค. ๋ก์ปฌ bash ์ถ๋ ฅ๊ณผ ๋ช
๋ น ์ค๋ฅ์์๋ ์๊ฒฉ ์ฆ๋ช
๊ฐ์ ๋ง์คํนํ๋, ๋ชจ๋ธ ์ด๋ฆ์ด๋ base URL ๊ฐ์ ๋ฌดํดํ ์ค์ ์ ์ฝ์ ์ ์๊ฒ ๋จ๊ฒจ ๋ก๋๋ค.
`LocalSandboxProvider`์์ ์ด๋ ํธ์คํธ ํ์ผ ์์คํ
๊ฒฉ๋ฆฌ๊ฐ ์๋๋ผ ๊ด๋ฆฌํ ๋๊ตฌ ๊ฒฝ๋ก ๊ฒฝ๊ณ์
๋๋ค. ์์ด์ ํธ๋ณ ๋ช
์์ ์คํฌ ์ ์ฑ
์ ํธ์คํธ bash๊ฐ ๋นํ์ฑํ๋ ๊ฒฝ์ฐ(๊ธฐ๋ณธ๊ฐ)์๋ง ํ์ฉ๋ฉ๋๋ค. ํธ์คํธ ํ์ ํ๋ก์ธ์ค๋ ํ๋ก๋ฐ์ด๋์ ๊ฐ์ ๊ฒฝ๋ก ๋งคํ์ ๊ฑฐ์น์ง ์๊ณ ์ ๊ท ๊ฒฝ๋ก์ ์ ๊ทผํ ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค. ์
ธ ์ ๊ทผ๊ณผ ํจ๊ป ํ์ผ ์์คํ
๊ฒฝ๊ณ๋ฅผ ๊ณ์ ๊ฐ์ ํด์ผ ํ๋ค๋ฉด Docker/AIO, Kubernetes provisioner ๋๋ E2B๋ฅผ ์ฌ์ฉํ์ธ์.
Windows์์ ๋ก์ปฌ ์๋๋ฐ์ค์ `cmd.exe` ํด๋ฐฑ์ Python์ UTF-8 ๋ชจ๋์ ๋ฌด๊ดํ๊ฒ, ์ฝ์ ์ถ๋ ฅ ์ฝ๋ ํ์ด์ง(`chcp 65001` ์ดํ์ UTF-8 ํฌํจ)๋ฅผ ์ฌ์ฉํด ๋ด์ฅ ๋ช
๋ น ์ถ๋ ฅ์ ๋์ฝ๋ฉํฉ๋๋ค. ์ฌ์ฉํ ์ ์๋ ์ฝ์ ํ์ด์ง๊ฐ ์์ผ๋ฉด ์์คํ
OEM ํ์ด์ง๋ฅผ ์ฌ์ฉํ๊ณ , ์ตํ ์๋จ์ผ๋ก ANSI๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ค์ดํฐ๋ธ ํ๋ก๊ทธ๋จ์ ๋ค๋ฅธ ์ถ๋ ฅ ์ธ์ฝ๋ฉ์ ์ ํํ ์ ์์ผ๋ฏ๋ก, ํ์ํ๋ฉด ํด๋น ํ๋ก๊ทธ๋จ์ด ์ฝ์ ํ์ด์ง์ ์ผ์นํ๋๋ก ์ค์ ํ์ธ์.
๊ด๋ฆฌํ ํตํฉ์ ๊ณต์ ๋๋ ์ฝ๊ธฐ ์ ์ฉ ์คํฌ ํฉ์ ์ปค์คํ
์คํฌ๊ณผ ์์ง ์๊ณ ์ค์นํฉ๋๋ค. Lark/Feishu CLI ํตํฉ์ `Capability Center โ Plugins โ Lark / Feishu`์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๊ด๋ฆฌ์๊ฐ ๊ณต์ `lark-*` ํฉ์ `{DEER_FLOW_HOME}/integrations/skills/lark-cli` ์๋์ ํ ๋ฒ ์ค์นํ๊ฑฐ๋ ์
๊ทธ๋ ์ด๋ํ๋ฉด, ๋ชจ๋ ์ฌ์ฉ์๊ฐ ๊ฐ์ ํฉ์ ๊ฐ์ ๋
๋ฆฝ๋ ํ์ฑํ ์ํ๋ก ์ฐพ์ ์ฌ์ฉํฉ๋๋ค. ๊ฐ ์ฌ์ฉ์์ ์ฑ ์ค์ ๊ณผ OAuth ๋ฐ์ดํฐ๋ `{DEER_FLOW_HOME}/users/{user_id}/integrations/lark-cli/{config,data}` ์๋์ ๊ฒฉ๋ฆฌ๋ ์ํ๋ก ์ ์ง๋ฉ๋๋ค. ์ด ์ํฌ๋ฆฟ ๋๋ ํฐ๋ฆฌ๋ `0700`์ผ๋ก, ์ผ๋ฐ ์๊ฒฉ ์ฆ๋ช
ํ์ผ์ `0600`์ผ๋ก ๊ถํ์ด ์ ํ๋๋ฉฐ, ์ฌ๋ณผ๋ฆญ ๋งํฌ๋ ๊ฑฐ๋ถ๋ฉ๋๋ค. Windows์์๋ ๋ค๋ฅธ ํ๋ก์ธ์ค๊ฐ ์ก๊ณ ์๋ ํตํฉ ํ์ผ ์ ๊ธ์ ๊ธฐ๋ค๋ฆด ๋ ์ต๋ 15๋ถ ๋์ ์ฌ์๋ํ๋ฉฐ, ๊ทธ ๋ฐ์ ํ์ผ ์ ๊ธ ์ค๋ฅ๋ ์ฆ์ ๋ณด๊ณ ๋ฉ๋๋ค.
์ค์น ํ ์ฌ์ฉ์๋ **Connect Lark**๋ฅผ ํด๋ฆญํด ๋ธ๋ผ์ฐ์ ์ธ์ฆ ๋งํฌ๋ฅผ ์ด ์ ์์ผ๋ฉฐ, ํฐ๋ฏธ๋์์ ์ธ์ฆํ ํ์๋ ์์ต๋๋ค. ๊ฐ์ UI์์ Calendar, Docs, Drive ๊ฐ์ ์ถ๊ฐ ๊ถํ ๋๋ฉ์ธ์ด๋ `lark-cli`๊ฐ ๋ณด๊ณ ํ ํน์ OAuth ์ค์ฝํ๋ฅผ ์์ฒญํ ์๋ ์์ต๋๋ค. ๊ฐ๋ฒผ์ด ์ํ ์๋ก ๊ณ ์นจ์ ๋ก์ปฌ ์๊ฒฉ ์ฆ๋ช
ํธ๋ฆฌ๋ง ๊ฒ์ฌํ๋ฏ๋ก, ๋ช
์์ ์ธ ๋ธ๋ผ์ฐ์ ์๋ฃ ์ ์ฐจ๊ฐ ์ค์๊ฐ ํ ํฐ ๊ฒ์ฆ์ ์ํํ๊ธฐ ์ ๊น์ง UI๋ **Credentials configured (not live-verified)** ์ํ๋ก ํ์ํฉ๋๋ค. ์ดํ ํด๋น ๋์์ **Reconnect Lark**๋ก ์ ์ง๋์ด ์ฌ์ฉ์๊ฐ ์ธ์ฆ์ ๊ต์ฒดํ๊ฑฐ๋ ํ์ฅํ ์ ์์ต๋๋ค. ๋ํ ์ค ์์ด์ ํธ๊ฐ Lark ์ธ์ฆ ๋๋ฝ ๋ฌธ์ ๋ฅผ ๋ง๋๋ฉด, ๊ด๋ฆฌํ `lark-shared` ์๋ด๊ฐ `/workspace/capabilities?tab=plugins&plugin=lark`๋ฅผ ํตํด ์ฌ์ฉ์๋ฅผ ๊ฐ์ ํ๋ฌ๊ทธ์ธ ์ค์ ์ผ๋ก ์๋ดํฉ๋๋ค.
์ค์ ์ด ๋๋ ๋ค์๋ **Change Lark app**์ ์ฌ์ฉํด ์ฌ์ค์น ์์ด ์์ ์ DeerFlow ๊ณ์ ์ด ๋ค๋ฅธ Lark/Feishu ์ฑ์ ๊ฐ๋ฆฌํค๋๋ก ๋ฐ๊ฟ ์ ์์ต๋๋ค. ๊ธฐ์กด ์ฑ์ App ID / App Secret์ ๋ถ์ฌ ๋ฃ๊ฑฐ๋, ๋ธ๋ผ์ฐ์ ์์ ์ฑ์ ๋ค์ ๋ฑ๋กํ๋ฉด ๋ฉ๋๋ค. ์ ํ์ ์ฌ์ฉ์๋ณ๋ก ์ด๋ฃจ์ด์ง๋ฉฐ(๋ค๋ฅธ ์ฌ์ฉ์์ ์๊ฒฉ ์ฆ๋ช
์ ์ ๋ ๊ฑด๋๋ฆฌ์ง ์์), ํ์ฑ ์ฑ์ ๊ต์ฒดํ๊ธฐ ์ ์ ๊ณต์ CLI์ ์ค์๊ฐ ํ
๋ํธ ํ ํฐ ํ๋ก๋ธ๋ก ์ ์๊ฒฉ ์ฆ๋ช
์ ๊ฒ์ฆํ๊ณ , ์ด์ ์ฑ์ OAuth ํ ํฐ์ ํ๊ธฐ/์ญ์ ํฉ๋๋ค. ๊ฑฐ๋ถ๋ ์๊ฒฉ ์ฆ๋ช
๋ณ๊ฒฝ์ ์งํ ์ค์ธ ์ค์ ์ด๋ ์ธ์ฆ ํ๋ฆ์ ๋์ฒดํ์ง ์์ต๋๋ค. CLI๊ฐ ๊ต์ฒดํ ์ฑ์ ์ ์ฅํ๊ธฐ ์ ์ ์ด์ OAuth ๋ฐ์ดํฐ๊ฐ ์ง์์ง๋ฏ๋ก, ์ฌ์ฐ๊ฒฐ ์ค์๋ ์ ํ์ผ ๊ธฐ๋ฐ ํค์ฒด์ธ ์ํฌ๋ฆฟ์ ๊ณ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ DeerFlow๋ ์๋ก ์ฐ๊ฒฐ๋ ์ฑ์ ๋ํ ๋ธ๋ผ์ฐ์ ์ธ์ฆ์ ์ฆ์ ์ด์ด, ์ ํ์ด ์ฌ์ฉ ๊ฐ๋ฅํ ์ฐ๊ฒฐ๋ก ๋ง๋ฌด๋ฆฌ๋๋๋ก ํฉ๋๋ค.
Lark ์คํฌ ํฉ์ ์ค์นํ๋ฉด GitHub์์ ์ต์ ๊ณต์ `larksuite/cli` ๋ฆด๋ฆฌ์ค๋ฅผ ํ์ธํ๊ณ ์ค์น ์์ ์ ํด๋น ๋ฒ์ ์ ์คํฌ์ ๋ค์ด๋ก๋ํ๋ฏ๋ก, ์ด ๋จ๊ณ์์ Gateway์ ์ธ๋ถ ์ธํฐ๋ท ์ ์์ด ํ์ํฉ๋๋ค(๋ฆด๋ฆฌ์ค ์กฐํ์ ์คํจํ๋ฉด ์ต์ ๊ธฐ์ค์ผ๋ก ๊ณ ์ ๋ ๋ฒ์ ์ผ๋ก ํด๋ฐฑํฉ๋๋ค). ์ค์ ํ์ด์ง์๋ ์ค์น๋ ๋ฒ์ ๊ณผ, ๊ฐ๋ฅํ ๊ฒฝ์ฐ ์ต์ ๊ฒ์ ๋ฒ์ ์ด ํ์๋๋ฏ๋ก ๊ด๋ฆฌ์๊ฐ ์ฌ์ค์นํด ์
๊ทธ๋ ์ด๋ํ ์ ์์ต๋๋ค. ์ธํฐ๋ท์ด ์ฐจ๋จ๋(air-gapped) ๋ฐฐํฌ์์๋ ์์นด์ด๋ธ๋ฅผ ๋ฏธ๋ฆฌ ์ค๋นํด ๋๊ณ `DEER_FLOW_LARK_CLI_SKILLS_ARCHIVE`๊ฐ ๋ก์ปฌ ํ์ผ์ ๊ฐ๋ฆฌํค๋๋ก ์ค์ ํ ์ ์์ต๋๋ค. ๋ฌด๊ฒฐ์ฑ์ ๊ณ ์ ๋ ์์นด์ด๋ธ ๋ฐ์ดํธ ํด์์ ์์กดํ์ง ์์ต๋๋ค(GitHub๋ ์์ค ์์นด์ด๋ธ ๋ฐ์ดํธ๊ฐ ์์ ์ ์์ ๋ณด์ฅํ์ง ์์ต๋๋ค). ๋์ ๋ค์ด๋ก๋๋ ๊ณต์ GitHub ํธ์คํธ๋ก ์ ํ๋๊ณ , ๋ชจ๋ ์์นด์ด๋ธ ๋ฉค๋ฒ๋ ๊ตฌ์กฐ์ ์์ ๊ฒ์ฌ๋ฅผ ํต๊ณผํด์ผ ํ๋ฉฐ, ์ค์ ๋ก ์ค์น๋ ์คํฌ ํธ๋ฆฌ(DeerFlow๊ฐ ์ฃผ์
ํ ๊ณต์ ์๋ด ํฌํจ)์ ์ฝํ
์ธ ํด์๊ฐ ๊ธฐ๋ก๋๋ฏ๋ก ์ฌ์ค์น ๊ฐ ์ฝํ
์ธ ๋ณ๊ฒฝ์ ๊ฐ์ฌํ ์ ์์ต๋๋ค.
`sandbox.use`๊ฐ AIO ํ๋ก๋ฐ์ด๋๋ฅผ ์ ํํ ๊ฒฝ์ฐ, ๊ฐ์ ์ค์น ๊ณผ์ ์์ ๊ณต์ Linux amd64 ๋ฐ arm64 CLI ๋ฆด๋ฆฌ์ค ์์นด์ด๋ธ๋ ๋ค์ด๋ก๋ํ๊ณ , ๊ฒ์๋ SHA-256 ์ฒดํฌ์ฌ์ ๊ฒ์ฆํ๊ณ , ์ํคํ
์ฒ๋ณ๋ก ์คํ ํ์ผ ํ๋์ฉ์ ์์ ํ๊ฒ ์ถ์ถํ ๋ค, ๊ทธ ๊ฒฐ๊ณผ ๋ฐํ์์ `/mnt/integrations/lark-cli/runtime`์ ์ฝ๊ธฐ ์ ์ฉ์ผ๋ก ๋ง์ดํธํฉ๋๋ค. ์ด ๋ง์ดํธ ์์ ์ํคํ
์ฒ ์ ํ ๋ฐ์ฒ ๋๋ถ์ `lark-cli`๋ฅผ ์๋๋ฐ์ค `PATH`์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ธํฐ๋ท์ด ์ฐจ๋จ๋ AIO ๋ฐฐํฌ์์๋ `bin/lark-cli`์ ๋ ๊ฐ์ `linux-{amd64,arm64}/lark-cli` ํ์ผ์ ๋ชจ๋ ํฌํจํ๊ณ ์ฌ๋ณผ๋ฆญ ๋งํฌ๊ฐ ์๋ ๋ฐํ์ ํธ๋ฆฌ๋ฅผ ๋ฏธ๋ฆฌ ์ค๋นํ ๋ค, `DEER_FLOW_LARK_CLI_SANDBOX_RUNTIME_DIR`๋ฅผ ๊ทธ ๋๋ ํฐ๋ฆฌ๋ก ์ค์ ํ ์ ์์ต๋๋ค.
> **์๋๋ฐ์ค ์ ๋ขฐ ๊ฒฝ๊ณ:** ๋ธ๋ผ์ฐ์ ๋ Lark ์ฑ ์ํฌ๋ฆฟ์ ๋ฐ์ง ์์ง๋ง, ์์ด์ ํธ ๋ํ๋ ์๋๋ฐ์ค ์์์ `lark-cli`๋ฅผ ์คํํ๋ฏ๋ก ์ฌ์ฉ์๋ณ ์๊ฒฉ ์ฆ๋ช
๋๋ ํฐ๋ฆฌ๊ฐ ์๋๋ฐ์ค์ ๋ง์ดํธ๋ฉ๋๋ค. `config`(์ฅ๊ธฐ ์ ํจ `appSecret` ๋ณด๊ด)๋ **์ฝ๊ธฐ ์ ์ฉ**์ผ๋ก ๋ง์ดํธ๋๊ณ , ๊ทธ ์ธ์๋ ๋น์ด ์๋ `config/locks` ํ์ ๋๋ ํฐ๋ฆฌ๋ `lark-cli` ์กฐ์ ํ์ผ์ ์ํด ์ฐ๊ธฐ ๊ฐ๋ฅํ๊ฒ ๋ฎ์ด ๋ง์ดํธ๋๋ฉฐ, `data`(๊ฐฑ์ ๊ฐ๋ฅํ OAuth ํ ํฐ)๋ ์ฐ๊ธฐ ๊ฐ๋ฅํฉ๋๋ค. ์๊ฒฉ ์ฆ๋ช
์ ๋ด์ config ๋ฐ data ๋ง์ดํธ๋ ์์ด์ ํธ๊ฐ ๊ทธ ์์์ ์คํํ๋ ๋ชจ๋ ํ๋ก์ธ์ค๊ฐ *์ฝ์ ์* ์์ผ๋ฏ๋ก, ๋๊ตฌ ๊ฒฐ๊ณผ ์ ํ๋กฌํํธ ์ธ์ ์
์ ํตํด ์คํ๋ ์ฝ๋๊ฐ ์ด๋ฅผ ์ฝ์ ์ ์์ต๋๋ค. ์ฌ์ด๋์นด ์๊ฒฉ ์ฆ๋ช
๋ธ๋ก์ปค ํ์ ์์
์ด ์๋๋ฐ์ค ์คํ์์ ์ด ๋ง์ดํธ๋ค์ ์ ๊ฑฐํ ๋๊น์ง๋ ์๋๋ฐ์ค๋ฅผ Lark ์๊ฒฉ ์ฆ๋ช
์ ๋ขฐ ๊ฒฝ๊ณ ์์ ์๋ ๊ฒ์ผ๋ก ์ทจ๊ธํ์ธ์.
์๊ฒฉ/Kubernetes ๋ฐฐํฌ(provisioner ๋ฐฑ์๋)์์๋ ์๋๋ฐ์ค `lark-cli` ๋ฐํ์์, ๋ฐ์ด๋๋ฆฌ๋ฅผ ๊ณต์ `emptyDir`๋ก ๋ณต์ฌํ๋ ์ ํ์ init ์ปจํ
์ด๋๋ก ๋์ ์ ๊ณตํ ์ ์์ต๋๋ค. ์ด ๋ฐฉ์์ ์ค์น ์์ ์ GitHub ๋ค์ด๋ก๋๋, hostPath/PVC ๋ฐํ์ ๋ง์ดํธ๋ ํ์ ์์ต๋๋ค. [`docker/lark-cli-init`](docker/lark-cli-init/README.md) ์๋์ ์ด๋ฏธ์ง๋ฅผ ๊ฒ์ํ๊ณ provisioner์ `LARK_CLI_INIT_IMAGE`๋ฅผ ์ค์ ํ์ธ์(Helm ์ฐจํธ์์๋ `provisioner.larkCliInitImage` / `provisioner.larkCliBrokerImage`). ์ค์ ํ์ง ์์ผ๋ฉด ๊บผ์ง ์ํ(๊ธฐ์กด ๋์)๋ก ์ ์ง๋ฉ๋๋ค. Lark ํตํฉ ์ํ(`GET /api/integrations/lark/status`)๋ `sandbox_runtime_mode`, `sandbox_runtime_probed`, `sandbox_runtime_ready`๋ฅผ ๋ณด๊ณ ํฉ๋๋ค. `sandbox_runtime_probed`๋ ๋ฐํ์ ์ค๋น ์ํ๊ฐ ์ค์ ๋ก ํ๊ฐ๋์๋์ง๋ฅผ ๋ํ๋
๋๋ค. ์ด์ ๋ฐฑ์๋์ ์๋ต์๋ ์ด ํ๋๊ทธ๊ฐ ์์ ์ ์์ผ๋ฉฐ, ๊ทธ ๊ฒฝ์ฐ Settings ๋ณ๊ฒฝ ์บ์๋ ํ๊ฐ๋์ง ์์ ํด๋ฐฑ ๊ฐ์ผ๋ก ๋ฎ์ด์ฐ์ง ์๊ณ ๋ง์ง๋ง์ผ๋ก ํ์ธ๋ ๋ฐํ์ ํ๋๋ฅผ ์ ์งํฉ๋๋ค. ๋ฐ๋ผ์ Settings UI๋ ์ฑํ
์์ ์ `lark-cli`๊ฐ ์๋๋ฐ์ค์ ์ค์ ๋ก ์กด์ฌํ ์ง๋ฅผ ๋ณด์ฌ ์ฃผ๋ฉฐ, ์ด๋ก์ ์ํ ๋ค์ ๋์ค์ `command not found`๊ฐ ์จ์ด ์๋ ์ผ์ด ์์ต๋๋ค.
Lark ๋ธ๋ก์ปค ๋ชจ๋์์ AIO์ ์ Bash ์คํ์ ์์๋ ํ์ดํ stdin์ ๋ซ์ต๋๋ค. ์์ ํฐ๋ฏธ๋ ๋ช
๋ น์ ์
๋ ฅ์ ์ ์งํ๋ฉฐ, shim์ ํฐ๋ฏธ๋ stdin์ ๋ฌด์ํฉ๋๋ค. ๋ช
์์ ํ์ดํ๋ผ์ธ, heredoc, ํ์ผ ๋ฆฌ๋๋ ์
์ ์ฌ์ ํ ์ ์์ ์ผ๋ก ์
๋ ฅ์ ์ ๊ณตํ๋ฉฐ, shim์ EOF ์ดํ์๋ง ๊ทธ ์
๋ ฅ์ ์ ๋ฌํฉ๋๋ค. stdin ์ ํด ํ์์์์ด ๋ฐ์ํ๋ฉด ๋ช
๋ น์ ์คํํ์ง ์๊ณ ์ค๋จํ๋ฉฐ, ๋ธ๋ก์ปค ์คํ ๋ก๊ทธ์๋ ์ธ์ ๊ฐ์ด ๊ธฐ๋ก๋์ง ์์ต๋๋ค. ํ์์์ ์ค์ ๊ณผ ์ด๋ฏธ์ง ์ฌ๋น๋ ์๊ตฌ ์ฌํญ์ [๋ธ๋ก์ปค ์ด๋ฏธ์ง ๊ฐ์ด๋](docker/lark-cli-broker/README.md)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
์ ๋ขฐํ ์ ์๋ ์ด์์๊ฐ ์ค์ ๋ ์คํฌ ๋๋ ํฐ๋ฆฌ๋ฅผ MinIO, NFS, CSI ๊ฐ์ ์ธ๋ถ ๋ง์ดํธ๋ก ๊ด๋ฆฌํ๋ ๊ฒฝ์ฐ, ๊ด๋ฆฌ์๋ ํ์ผ์ ๋ณ๊ฒฝํ ๋ค `POST /api/skills/reload`๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค. ์ด ํธ์ถ์ ์์ฒญ์ ์ฒ๋ฆฌํ Gateway ํ๋ก์ธ์ค์ ์คํฌ ํ๋กฌํํธ ์บ์๋ฅผ ๋ฌดํจํํ๊ณ , ์ํ์ด ์ ํด์ง ์๋ก ๊ณ ์นจ ํ์์์๊น์ง ๊ธฐ๋ค๋ฆฐ ๋ค์, ์ฐ๊ธฐ ๊ฐ๋ฅํ ์ค์ ๋๋ ํฐ๋ฆฌ์ ์๋ ์์ ๋ฆฌ์
๋ง์ปค(`.extensions_config.json.skills-cache-reset.json`)๋ฅผ ๊ฐฑ์ ํฉ๋๋ค. ๊ทธ ๋๋ ํฐ๋ฆฌ๋ฅผ ๋ง์ดํธํ ๋ชจ๋ Gateway ์์ปค๋ Pod๋ ๋ค์ ํ๋กฌํํธ๋ฅผ ๋น๋ํ ๋ ์ฝ 1์ด ์ด๋ด์ ๋ง์ปค๋ฅผ ๊ฐ์งํ๊ณ ์ต์ ํ์ผ์ ๋ค์ ์ค์บํ๋ฏ๋ก, ํ ๋ฒ์ ํธ์ถ์ด ๋ณผ๋ฅจ์ ๊ณต์ ํ๋ ๋ชจ๋ ๋ ํ๋ฆฌ์นด์ ๋๋ฌํฉ๋๋ค. ์๋ต์ `scope: shared_config`๋ฅผ ๋ณด๊ณ ํ๋ฉฐ, extensions ์ค์ ๊ฒฝ๋ก๋ฅผ ์ฌ์ฉํ ์ ์์ผ๋ฉด `scope: process`๋ฅผ ๋ณด๊ณ ํฉ๋๋ค. ์คํ ์ค์ธ ์์
์ ๋ฐ๋์ง ์์ต๋๋ค. API๋ฅผ ํตํ ์คํฌ ์ค์น, ์์ , ์ญ์ , ๋กค๋ฐฑ, ํ์ฑํ/๋นํ์ฑํ ํ ๊ธ๋ ๊ฐ์ ๋ง์ปค๋ฅผ ๊ฒ์ํ๋ฏ๋ก, ํ ๋ ํ๋ฆฌ์นด์์ ์ด๋ฃจ์ด์ง ๋ณ๊ฒฝ์ด ์ฌ์์ ์์ด ๋ค๋ฅธ ๋ ํ๋ฆฌ์นด์๋ ์ ์ฉ๋ฉ๋๋ค. ๋ก๋ ์์ค์ ํ์ผ ์์คํ
์คํจ๋ ์ผ๋ฐ์ ์ธ ์๋ฒ ์ค๋ฅ๋ฅผ ๋ฐํํ๋ฉฐ, ๋น ์นดํ๋ก๊ทธ๋ฅผ ๊ฒ์ํ๋ ๋์ ๋ง์ง๋ง์ผ๋ก ์ฑ๊ณต์ ์ผ๋ก ๋ก๋๋ ํ๋ก์ธ์ค ์บ์๋ฅผ ๋ณด์กดํฉ๋๋ค. ๋
๋ฆฝ๋ ํ์ผ ์์คํ
์ ์ฐ๋ ๋ ํ๋ฆฌ์นด๋ ์ด ๋ฒ์์ ํฌํจ๋์ง ์์ต๋๋ค. ๋ง์ดํธ์ ์ง์ ์ฐ๋ฉด DeerFlow์ ์ค์น/์์ API๊ฐ ์ ์ฉํ๋ ๊ฒ์ฆ, SkillScan, ๊ธฐ๋ก์ ์ฐํํ๋ฏ๋ก, ์ด์์๊ฐ ํต์ ํ๋ ์์คํ
๋ง ์ฐ๊ธฐ ๊ถํ์ ๊ฐ์ ธ์ผ ํฉ๋๋ค.
์คํฌ ์ค์น์ ์์ด์ ํธ๊ฐ ๊ด๋ฆฌํ๋ ์คํฌ ์์ ์ LLM ๊ธฐ๋ฐ ์คํฌ ์ค์บ๋๋ณด๋ค ๋จผ์ , ๋ค์ดํฐ๋ธ ๊ฒฐ์ ์ ์์ ์ค์บ๋์ธ **SkillScan**์ ๊ฑฐ์นฉ๋๋ค. 1๋จ๊ณ๋ Semgrep/OpenGrep ์์กด์ฑ ์์ด ์คํ๋ผ์ธ์ผ๋ก ์คํ๋๋ฉฐ, ๊ฐ์ธ ํค๋ ์
ธ ์คํ ๊ฐ์ ๋์ ์ ๋ขฐ๋์ `CRITICAL` ๋ฐ๊ฒฌ ํญ๋ชฉ์ ์ฐจ๋จํ๊ณ , ๊ฒฝ๊ณ ์์ค์ ๋ฐ๊ฒฌ ํญ๋ชฉ์ ๋งฅ๋ฝ์ ๊ฒํ ๋ฅผ ์ํด LLM ์ค์บ๋๋ก ๋๊น๋๋ค. ์ฝ๋ ํ์ผ(`scripts/` ์๋์ ๋ชจ๋ ํ์ผ, `.py`, `.sh`, `.js` ๊ฐ์ ์คํฌ๋ฆฝํธ ํ์ฅ์๋ฅผ ๊ฐ์ง ํ์ผ, ๋๋ `#!`๋ก ์์ํ๋ ํ์ฅ์ ์๋ ํ์ผ)์ด NUL ๋ฌธ์๊ฐ ์๋ UTF-8 ํ
์คํธ๊ฐ ์๋๋ฉด ๊ฒฝ๊ณ ๊ฐ ๋ฐ์ํ๋ฉฐ, ์์ค ํ์ฉ ๋์ฝ๋ฉ์ผ๋ก๋ ๊ณ์ ๋ถ์๋๋ฏ๋ก ์๋ชป๋ ๋ฐ์ดํธ ํ๋๋ก `CRITICAL` ๊ฒ์ฌ๋ฅผ ํผํ ์ ์์ต๋๋ค. ๋ชจ๋๋ ์ด์
์ด๋ํฐ๋ ํ์ JSON ํ์ ์ ํ์ฑํ๊ธฐ ์ ์ ์ผ๋ฐ ํ
์คํธ ๋ชจ๋ธ ์๋ต๊ณผ LangChain Responses API ํ
์คํธ ๋ธ๋ก์ ๋ชจ๋ ์ ๊ทํํฉ๋๋ค. Python ์ธ์คํด์ค ํด๋ผ์ด์ธํธ ์ ์ถ ๊ฒ์ฌ๋ ์ต์ํ์ ๋์ผ ์ค์ฝํ ๊ทผ๊ฑฐ ์ฒด์ธ์ ๋ฐ๋ฆ
๋๋ค. ์ฆ ์๋ ค์ง ํด๋ผ์ด์ธํธ ์์ฑ์์ ๋ฐ์ธ๋ฉ๋ ๋จ์ ์ด๋ฆ, ์ ํ์ ์ธ ์ด๋ฆ ๊ฐ ๋ณ์นญ, ๊ทธ๋ฆฌ๊ณ ๊ทธ ์์ฑ์๊ฐ ์ง์ํ๋ ์ค์ ์ธ๋ถ ์ ์ก ๋ฉ์๋ ํธ์ถ์ด๋ ์ปจํ
์คํธ ๋งค๋์ ์ฌ์ฉ์
๋๋ค. ์์ฑ์ ๋ฃจํธ๋ import๋ก ์
์ฆ๋์ด์ผ ํ๋ฉฐ, ์ ๊ท ์ด๋ฆ์ฒ๋ผ ๋ณด์ด๋ ๋จ์ ์ด๋ฆ์ ๋ชจ๋๋ก ์ถ๋ก ํ์ง ์์ต๋๋ค. ์ค์ฒฉ ์ค์ฝํ๋ ํด๋ผ์ด์ธํธ ํธ๋ค์ ์์ํ์ง ์์ผ๋ฉฐ, ๋ฐ๊นฅ ์ค์ฝํ์์ ๋ค์ ๋ฐ์ธ๋ฉ๋์ง ์๋ ์์ฑ์ import ๋ณ์นญ๋ง ์์ํฉ๋๋ค. ์ปดํ๋ฆฌํจ์
, walrus ์ฐ์ฐ์๋ฅผ ํฌํจํ ๋ฌธ์ฅ, ์ด๋
ธํ
์ด์
, ๋ณต์กํ ๋ฐ์ธ๋ฉ ๋์, ์ง์ํ์ง ์๋ ์ฐ์ฐ, ๋ชจํธํ ๋ถ๊ธฐ ํ๋ฆ์ ์ด ์ ํธ๋ก๋ถํฐ ๋ฐ๊ฒฌ ํญ๋ชฉ์ ๋ง๋ค์ง ์์ต๋๋ค. ๊ฑด๋๋ด ๊ตฌ๋ฌธ์ ๋ฐ์ธ๋ฉํ ์ ์๋ ๋ชจ๋ ์ด๋ฆ์ ๋ณด์์ ์ผ๋ก ๋ฌดํจํํ๋ฏ๋ก, ์ค๋๋ ํด๋ผ์ด์ธํธ ์ํ๋ก ์ธํด ๋ฐ๊ฒฌ ํญ๋ชฉ์ด ์๊ธฐ์ง ์์ต๋๋ค. ์ด ์ต์ ๋
ธ๋ ฅ ๋ถ์์ด ๊ฒฐ์ ์ ์์
์์ฐ์ด๋ ์ฌ๊ท ์ ํ์ ๋๋ฌํ๋๋ผ๋, ํด๋น ํ์ผ์์ ์ด๋ฏธ ์์งํ ๋ฐ๊ฒฌ ํญ๋ชฉ์ ๋ฒ๋ฆฌ์ง ์์ต๋๋ค. `config.yaml`์ `skill_scan.enabled: false`๋ฅผ ์ค์ ํ๋ฉด ๊ฒฐ์ ์ ๋ถ์๊ธฐ๋ง ๋นํ์ฑํ๋๋ฉฐ, ์์ ํ ์์นด์ด๋ธ ์ถ์ถ๊ณผ LLM ์ค์บ๋๋ ๊ณ์ ์คํ๋ฉ๋๋ค.
Windows ์คํฌ๋ฆฝํธ(`.bat`, `.cmd`, `.ps1`, `.psm1`, `.js`, `.jse`, `.vbs`, `.vbe`, `.wsf`), HTML ์ ํ๋ฆฌ์ผ์ด์
(`.hta`), ์คํฌ๋ฆฝํ๋ฆฟ(`.sct`)์ ํ์ผ ์ด๋ฆ์ ๋์๋ฌธ์์ ๊ด๊ณ์์ด `scripts/` ๋ฐ์ ์์ด๋ ์ฝ๋๋ก ๊ฐ์ฃผ๋ฉ๋๋ค. ์ด ํ์ผ๋ค์ SkillScan ๋ถ์๊ณผ ์ค์น ํ๋ก๊ทธ๋จ์ ์คํ ์ฝ๋ ์ ์ฑ
์ ๋ชจ๋ ์ ์ฉ๋ฐ์ต๋๋ค.
SkillScan์ `env` ๋ฐ์ฒ, sudo, ์ธํฐํ๋ฆฌํฐ ๊ฒฝ๋ก, ์
ธ ์ค ์ด์ด ์ฐ๊ธฐ๋ฅผ ํฌํจํด, ์๊ฒฉ ๋ค์ด๋ก๋๋ฅผ ์ผ๋ฐ์ ์ธ ์
ธ๋ก ํ์ดํํ๋ ๊ฒฝ์ฐ๋ฅผ ๊ฒฝ๊ณ ํฉ๋๋ค. ๋์
๊ณผ GNU split-string ์ด์ค์ผ์ดํ๋ฅผ ํฌํจํด, ํ๊ฒฝ ๋คํ์ `env` ๋ช
๋ น์ ๊ตฌ๋ถํฉ๋๋ค. ์
ธ ํ์ฑ๊ณผ ๋ถํ ํ์ฅ์๋ ์ํ์ด ์์ผ๋ฉฐ, ์ํ์ ๋๋ฌํด๋ ์ด๋ฏธ ํ์ง๋ ์น๋ช
์ ๋ฐ๊ฒฌ ํญ๋ชฉ์ ๋ณด์กด๋ฉ๋๋ค. `jq`, `tee` ๊ฐ์ ์
ธ์ด ์๋ ๋๊ตฌ๋ก ํ์ดํํ๋ ๊ฒฝ์ฐ์๋ ์ด ๊ฒฝ๊ณ ๊ฐ ๋ฐ์ํ์ง ์์ต๋๋ค.
SkillScan์ HTTP/HTTPS ์คํด ํ๊ธฐ์ HTTP ํธ์คํธ ์ด๋ฆ์ ๋์๋ฌธ์ ๊ตฌ๋ถ ์์ด ์ฒ๋ฆฌํ๋ฉฐ, ๋๊ดํธ๋ก ๊ฐ์ผ IPv6 ๋ฃจํ๋ฐฑ(`[::1]`) URL์ ๋ก์ปฌ๋ก ์ธ์ํฉ๋๋ค. ์ธ๋ถ IPv6 ์๋ํฌ์ธํธ๋ ์ฌ์ ํ ๋คํธ์ํฌ ๋ฐ๊ฒฌ ํญ๋ชฉ์ ๋ฐ์์ํค๋ฉฐ, ํด๋ผ์ฐ๋ ๋ฉํ๋ฐ์ดํฐ ํธ์คํธ ์ด๋ฆ ํ์ง๋ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ์ง ์์ต๋๋ค.
Python ์๊ฒฉ ์ฆ๋ช
๋งคํ์ ๊ฒฝ์ฐ, SkillScan์ ์ผ๋ฐ ๋์
๋๋ฆฌ ํค๋ ๋ ์ด๋ธ๋ก ์ทจ๊ธํ๊ณ ๋ฆฌํฐ๋ด ๊ฐ์ ๊ฒ์ฌํฉ๋๋ค. `tokens = {"access_token": os.getenv("ACCESS_TOKEN")}` ๊ฐ์ ๋งคํ์ ํ๋์ฝ๋ฉ๋ ์๊ฒฉ ์ฆ๋ช
์ผ๋ก ๋ณด๊ณ ๋์ง ์์ต๋๋ค. ๋จ, ์๋ ค์ง ํด๋ผ์ฐ๋ ๋๋ API ํ ํฐ ํ์๊ณผ ์ผ์นํ๋ ํค๋ ์ฌ์ ํ ๋ด์ฅ๋ ์๊ฒฉ ์ฆ๋ช
์ผ๋ก ๊ฒ์ฌ๋ฉ๋๋ค.
SkillScan์ ์คํฌ์ ํฌํจ๋ ๊ธฐ์กด ํ์๊ณผ ์ต์ ํ์์ `sk-` API ํ ํฐ์ ์ฐจ๋จํฉ๋๋ค. ์ฌ๊ธฐ์๋ OpenAI ํ๋ก์ ํธ ํค, ์๋น์ค ๊ณ์ ํค, ๊ด๋ฆฌ์ ํค์ Anthropic ํค๊ฐ ํฌํจ๋๋ฉฐ, ์ํฌ๋ฆฟ ๋์
์์ด Bearer ํค๋์๋ง ์๋ ๊ฒฝ์ฐ๋ ์ฐจ๋จํฉ๋๋ค. ํ ํฐ ๋ณธ๋ฌธ์๋ `-`์ `_`๊ฐ ํฌํจ๋ ์ ์์ผ๋ฉฐ, ๋ฐ๊ฒฌ ๊ทผ๊ฑฐ๋ ์์ ํ ๋ง์คํน๋ฉ๋๋ค. ์๋ฆฌ ํ์์ ์์๊ฐ ์๋ค๊ณ ํด์ ๊ฐ์ ํ์ผ์ ์ดํ ์๊ฒฉ ์ฆ๋ช
ํ์ง๊ฐ ์ต์ ๋์ง๋ ์์ต๋๋ค. ์์ฝ ์์
์๋ฆผ ์์ฝ๋ ์ธ๋ถ IM ํ๋ซํผ์ผ๋ก ๋ณด๋ด๊ธฐ ์ ์ ์ด ํค ํ์๋ค์ ๋ง์คํนํฉ๋๋ค.
DeerFlow์๋ ์ฝ๊ธฐ ์ ์ฉ ์คํฌ ํ์ง ๊ฒํ ๋ฅผ ์ํ public ์คํฌ์ธ **skill-reviewer**๋ ํฌํจ๋์ด ์์ต๋๋ค. ์ด ์คํฌ์ ๊ธฐ๋ณธ ์ ๊ณต `review_skill_package` ๋๊ตฌ๋ฅผ ์ฌ์ฉํด, ๋์ ์คํฌ์ ํ์ฑํํ๊ฑฐ๋ ์ํฌ๋ฆฟ์ ๋ฐ์ธ๋ฉํ๊ฑฐ๋ ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ๊ฑฐ๋ ์ค์นํ์ง ์๊ณ ๋ ์ค์น๋ ์คํฌ, ๋ก์ปฌ ํจํค์ง, ์์นด์ด๋ธ, ๋ถ์ฌ ๋ฃ์ `SKILL.md` ์ฝํ
์ธ ๋ฅผ ๊ฒ์ฌํฉ๋๋ค. ์ด ๋๊ตฌ๋ ํ๊ทธ๊ฐ ๋ฌด๋ ฅํ๋ ๊ฐ๊ฒฐํ JSON ํ์ด๋ก๋๋ฅผ ๋ชจ๋ธ ์ปจํ
์คํธ์ ๋ฐํํ๊ณ , ์ ์ฒด ์๋ณธ ๊ฒํ ํ์ด๋ก๋๋ ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ์ ์๋น์๋ฅผ ์ํด ๋๊ตฌ ์ํฐํฉํธ์ ๋ณด๊ดํฉ๋๋ค. ๊ฒฐ์ ์ ๊ฒํ ์ฝ์ด๋ DeerFlow ํ์ฑ๊ณผ SkillScan ๊ฒฐ๊ณผ๋ฅผ ์ฌ์ฌ์ฉํ๊ณ , `contracts/skill_review/` ์๋์ ๋ฒ์ ์ด ์ง์ ๋ JSON ๊ณ์ฝ์ ๋ด๋ณด๋ด๋ฉฐ, ๋ฐฑ์๋ CLI์์ ์คํํ ์ ์์ต๋๋ค.
```bash
cd backend
uv run python -m deerflow.skills.review.cli ../skills/public/data-analysis --format text --fail-on error --fail-on-incomplete
```
public ์คํฌ CI ์์ธ(waiver)๋ `.github/skill-review-waivers.v1.json`์ ์ ์๋, ๋์์ด ์ ํํ ์ง์ ๋๊ณ ๋ง๋ฃ ๊ธฐํ์ด ์๋ ์์ธ์
๋๋ค. ์ ๋ขฐํ ์ ์๋ ๊ธฐ์ค(base) ๋งค๋ํ์คํธ๋ง ๋ฐ๊ฒฌ ํญ๋ชฉ์ ์ต์ ํ ์ ์์ผ๋ฏ๋ก, ํ์ผ์ ๋ณ๊ฒฝํ๋ ํ ๋ฆฌํ์คํธ๋ ๋จผ์ ๊ฒํ ๋ ํฅํ ์ ์ฒด ํ์ผ SHA-256์ `preapproved_file_sha256s`์ ๋์ดํ๋ ๋งค๋ํ์คํธ ์ ์ฉ ๋ณ๊ฒฝ์ ๋จธ์งํ๋ ๋ฐฉ์์ผ๋ก ์์ ํ๊ฒ ์ฌ์ ์น์ธํ ์ ์์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ ํ์ผ ๋ณ๊ฒฝ์ ์ดํ ํ ๋ฆฌํ์คํธ๋ก ๋ฐ์ํ ์ ์์ต๋๋ค.
๋๊ตฌ๋ ๊ฐ์ ์ฒ ํ์ ๋ฐ๋ฆ
๋๋ค. DeerFlow๋ ์น ๊ฒ์, ์น ๊ฐ์ ธ์ค๊ธฐ(fetch), ๋ ๋๋ง๋ ์น ์บก์ฒ, ํ์ผ ์์
, bash ์คํ์ผ๋ก ๊ตฌ์ฑ๋ ํต์ฌ ๋๊ตฌ ์ธํธ๋ฅผ ์ ๊ณตํ๋ฉฐ, MCP ์๋ฒ์ Python ํจ์๋ฅผ ํตํ ์ปค์คํ
๋๊ตฌ๋ฅผ ์ง์ํฉ๋๋ค. ๋ฒ๋ค๋ DDG, Brave, Tavily, SearXNG, Serper ๊ฒ์ ํ๋ก๋ฐ์ด๋๋ ์ ํ์ `time_range` ๊ฐ์ผ๋ก `day`, `week`, `month`, `year` ์ค ํ๋๋ฅผ ๋ฐ์ผ๋ฉฐ, ์๋ตํ๋ฉด ๊ธฐ์กด ๊ฒ์ ๋์์ด ์ ์ง๋ฉ๋๋ค. DDG ์ต์ ์ฑ ๊ฒ์์์๋ DeerFlow๊ฐ ์๊ฐ ์ ํ์ ๋ฌด์ํ๋ DDGS ๋ฐฑ์๋๋ฅผ ์ ์ธํฉ๋๋ค. ๋ฌด์์ด๋ ๊ต์ฒดํ๊ณ , ๋ฌด์์ด๋ ์ถ๊ฐํ์ธ์.
DDG ์น ๊ฒ์๊ณผ DDG ์ด๋ฏธ์ง ๊ฒ์์ ๊ฒฝ์ฐ, `config.yaml`์ `max_results`๋ฅผ ์์ ์ ์๋ก ์ง์ ํ๊ฑฐ๋, `max_results: $DDG_MAX_RESULTS` ๊ฐ์ ํ๊ฒฝ ๋ณ์ ์ฐธ์กฐ์ `DDG_MAX_RESULTS=5`๋ฅผ ํจ๊ป ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ค์ ๋ ๊ฐ์ ๋๊ตฌ ํธ์ถ์ `max_results` ์ธ์๋ณด๋ค ์ฐ์ ํฉ๋๋ค. ์๋ชป๋ ๊ฐ(์: `abc`, ๋น ๋ฌธ์์ด, `3.5`), 0, ์์๋ ๊ฒฝ๊ณ ๋ฅผ ๋จ๊ธฐ๊ณ ๊ธฐ๋ณธ๊ฐ์ธ 5๊ฐ ๊ฒฐ๊ณผ๋ก ํด๋ฐฑํฉ๋๋ค. DDG, Brave, Serper ์ด๋ฏธ์ง ๊ฒ์์ ํ๋์ ๊ฒฐ๊ณผ URL ํํฐ๋ฅผ ๊ณต์ ํ๋ฉฐ, ์ด ํํฐ๋ HTTP(S)๊ฐ ์๋ URL, localhost, ํด๋ผ์ฐ๋ ๋ฉํ๋ฐ์ดํฐ ํธ์คํธ ์ด๋ฆ, ๊ทธ๋ฆฌ๊ณ ๋ฉํฐ์บ์คํธ์ ์ฌ์ค IPv4 ์ฃผ์๋ฅผ ๋ด์ฅํ IPv6 ํ๊ธฐ๋ฅผ ํฌํจํ ๋น๊ณต๊ฐ ์ฃผ์ ๋ฆฌํฐ๋ด์ ์ ์ธํฉ๋๋ค. ์ด ํํฐ๋ DNS๋ฅผ ํด์ํ์ง ์์ผ๋ฏ๋ก, ๋ค์ด๋ก๋๋ ์ฐ๊ฒฐํ ๋ ํด์๋ ์ฃผ์๋ฅผ ๊ฒ์ฆํด์ผ ํฉ๋๋ค. ์์ ํ ์ ์ฒด ์ด๋ฏธ์ง URL๋, ์์ ํ ์ธ๋ค์ผ๋ ์๋ ๊ฒฐ๊ณผ๋ ์ ์ธ๋ฉ๋๋ค.
์ด๋ฏธ์ง ๊ฒฐ๊ณผ ํํฐ๋ ๋ก์ปฌ/์ฌ์ค ํธ์คํธ๋ฅผ ๋ถ๋ฅํ๊ธฐ ์ ์ IDNA ํด๋ผ์ด์ธํธ ์ ๊ทํ์ ๋ง์ฐฌ๊ฐ์ง๋ก Unicode ํธ์คํธ ์ด๋ฆ ๊ตฌ๋ถ์(`ใ`, `๏ผ`, `๏ฝก`)๋ ์ ์ผ๋ก ์ธ์ํฉ๋๋ค. ํ์ฉ๋ ๊ฒฐ๊ณผ URL์ ์๋ ํ๊ธฐ๋ฅผ ์ ์งํฉ๋๋ค.
Stdio MCP ์๋ฒ๋ ์ํธ๋ฆฌํฌ์ธํธ๋ ๋ฐ์ดํฐ ํ์ผ์ด ํน์ ์์
๋๋ ํฐ๋ฆฌ์ ์์กดํ๋ ๊ฒฝ์ฐ `extensions_config.json`์ `cwd`๋ฅผ ์ค์ ํ ์ ์์ต๋๋ค. ์ด ์ค์ ์ ํ์๊ณผ ๋๊ตฌ ํธ์ถ ๋ชจ๋์ ์ ์ฉ๋ฉ๋๋ค. [MCP ์ค์ ](backend/docs/MCP_SERVER.md#stdio-working-directory)์ ์ฐธ๊ณ ํ์ธ์. ์๋ตํ๊ฑฐ๋ `null` ๋๋ ๋น ๊ฐ์ผ๋ก ๋๋ฉด ๊ธฐ๋ณธ ์์
๋๋ ํฐ๋ฆฌ๊ฐ ์ ์ง๋ฉ๋๋ค.
Tavily `web_search`๋ ๊ฒ์ ์์ค๋ฅผ ์ ์ดํ๊ธฐ ์ํด `config.yaml`์ ๋๊ตฌ ํญ๋ชฉ์์ ์ ํ์ ์ธ `include_domains` ๋ฐ `exclude_domains` ๋ชฉ๋ก๋ ๋ฐ์ต๋๋ค. ๋น์ด ์์ง ์์ `include_domains`๋ Tavily์ `filter` ๋ชจ๋๋ฅผ ์ฌ์ฉํด ๊ฒฐ๊ณผ๋ฅผ ํด๋น ๋๋ฉ์ธ์ผ๋ก ์ ํํฉ๋๋ค. ์ด๋ ๋ฐฐํฌ ์ค์ ์ด๋ฉฐ, ๋ชจ๋ธ์ ์ฌ์ ํ `query`์ ์ ํ์ `time_range`๋ง ์ ๊ณตํฉ๋๋ค. ํํฐ๋ฅผ ์๋ตํ๋ฉด ๊ธฐ์กด SDK ์์ฒญ์ด ๊ทธ๋๋ก ์ ์ง๋๊ณ , ๋ช
์์ ์ธ ๋น ๋ชฉ๋ก์ ๊ทธ๋๋ก ์ ๋ฌ๋๋ฉฐ ํด๋น ์ข
๋ฅ์ ์ ํ์ ๋์ง ์์ต๋๋ค. [๋๊ตฌ ์ค์ ์์](backend/docs/CONFIGURATION.md#tools)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
Serper ์น ๊ฒ์๊ณผ ์ด๋ฏธ์ง ๊ฒ์์ `SERPER_BASE_URL`๊ณผ ํด๋น ํ๋ก๋ฐ์ด๋์ `SERPER_API_KEY`๋ฅผ ํตํด ๋ค๋ฅธ Serper ํธํ ํ๋ก๋ฐ์ด๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋์ ๊ฐ ๋๊ตฌ๊ฐ `config.yaml`์ ์์ฒด `base_url`๊ณผ `api_key`๋ฅผ ์ค์ ํ ์๋ ์์ผ๋ฉฐ, ๊ฐ ์์ฒญ์ ํ๋์ ์ค์ ์ค๋
์ท์์ ์ด ๊ฐ์ ์ฝ์ต๋๋ค. ํธ์คํธ๊ฐ ํฌํจ๋ ์ ๋ HTTP(S) base URL์ ์ฌ์ฉํ๊ณ , `/search`, `/images`, ์ฟผ๋ฆฌ ๋ฌธ์์ด, ํ๋๊ทธ๋จผํธ๋ ํฌํจํ์ง ๋ง์ธ์. ์๋ชป๋ ์ฌ์ ์๋ HTTP ์์ฒญ ์ ์ ์ค์ ์ค๋ฅ๋ฅผ ๋ฐํํฉ๋๋ค. ํ๊ฒฝ ๋ณ์ ๊ฐ์ด ๋น์ด ์์ผ๋ฉด, ๋๊ตฌ๊ฐ ์ฌ์ ์ํ์ง ์๋ ํ Serper์ ๊ธฐ๋ณธ๊ฐ์ด ์ ์ง๋ฉ๋๋ค. ์ฐ์ ์์์ ํ๋ก๋ฐ์ด๋๊ฐ API ํค๋ฅผ ๋ฐ๋ ๋ฐฉ์์ [Serper ์๋ํฌ์ธํธ](backend/docs/CONFIGURATION.md#serper-endpoints)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
Serper `web_search`๋ ๋ฐฐํฌ ์์ค์ `include_domains`์ `exclude_domains`๋ฅผ ์ง์ํฉ๋๋ค. ๋ฐํ๋ URL ํธ์คํธ(ํ์ ๋๋ฉ์ธ ํฌํจ)๋ฅผ ๊ฒ์ฌํ๋ฉฐ, ์ ์ธ๊ฐ ์ฐ์ ํฉ๋๋ค. ํํฐ๋ก ์ธํด ๊ฒฐ๊ณผ๊ฐ ๋ ์ ๊ฒ, ์ฌ์ง์ด 0๊ฐ๋ก ๋ฐํ๋ ์ ์์ผ๋ฉฐ, ๋ถ์กฑ๋ถ์ ์ฑ์ฐ๋ ์ถ๊ฐ ์์ฒญ์ ์์ต๋๋ค. ์ด๋ ์์ค๋ฅผ ์ ํํ๋ ๊ธฐ๋ฅ์ผ ๋ฟ, ์ฌ์ค ์ ํ์ฑ์ด๋ ์ ์ญ URL ์ ๊ทผ ์ ์ฑ
์ด ์๋๋๋ค. ๋ชจ๋ธ ์ธ์์ ์ด๋ฏธ์ง ๊ฒ์์ ๋ฐ๋์ง ์์ต๋๋ค. ๊ฒ์ฆ ๋ฐ ์ฟผ๋ฆฌ ๊ธธ์ด ์ ํ์ [Serper ์ค์ ](backend/docs/CONFIGURATION.md#serper-source-filters)์ ์ฐธ๊ณ ํ์ธ์.
Serper ์น ๊ฒ์๊ณผ ์ด๋ฏธ์ง ๊ฒ์์ ๊ฐ ๋๊ตฌ ์ค์ ์ `max_retries: 1`(๊ธฐ๋ณธ๊ฐ `0`, ์ต๋ `3`)๋ก ์ตํธ์ธ ๋ฐฉ์์ ์ผ์์ ์ค๋ฅ ๋ณต๊ตฌ๋ฅผ ์ง์ํฉ๋๋ค. `retry_budget_seconds`๋ ์งํ ์ค์ธ ๋๊ธฐ ์์ฒญ์ด ์๋๋ผ ์ฌ์๋ ์ค์ผ์ค๋ง์ ์ํ์ ๋ก๋๋ค. ์์ฐ์ด ์์ง๋๋ฉด ๋ณ๋๋ก ๋ก๊ทธ๊ฐ ๋จ๊ณ , ๋๊ตฌ๋ ๋ง์ง๋ง ์ค๋ฅ๋ฅผ ๋ฐํํฉ๋๋ค. ์ถ๊ฐ ์์ฒญ์ ํ ๋น๋์ ์๋ชจํ๊ฑฐ๋ ๋น์ฉ์ด ๋ฐ์ํ ์ ์์ต๋๋ค. [Serper ์ฌ์๋](backend/docs/CONFIGURATION.md#serper-retries)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
`web_fetch`์ Tavily๋ฅผ ์ฌ์ฉํ ๋, ์ ๋ชฉ์ด ์๋ ์ถ์ถ ํ์ด์ง๋ URL์ ์ ๋ชฉ์ผ๋ก ์ฌ์ฉํ๋ฉฐ, ๊ทธ ์ฝํ
์ธ ๋ ์์ด์ ํธ๊ฐ ๊ณ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ฑํ
์ ๋๊ตฌ ๋จ๊ณ ์ ๋ชฉ์ ํ์ด์ง์ ์ฒซ ๋ฒ์งธ H1 ์ ๋ชฉ ์์ ์ค๋ ๋น ์ค๊ณผ ์ต๋ 3๊ฐ์ ๊ณต๋ฐฑ์ ํ์ฉํฉ๋๋ค. ๊ณต๋ฐฑ๊ณผ ํญ์ด ์์ธ ๊ฒฝ์ฐ๋ฅผ ํฌํจํด ๋ค์ฌ์ฐ๊ธฐ๋ ์ฝ๋๋ ์ ๋ชฉ์ผ๋ก ์ฌ์ฉ๋์ง ์์ผ๋ฉฐ, ๋๊ตฌ ๋จ๊ณ๋ URL๋ก ํด๋ฐฑํฉ๋๋ค. Tavily ๊ฒ์๊ณผ ๊ฐ์ ธ์ค๊ธฐ๋ ๊ฐ๊ฐ `config.yaml`์ ์์ฒด ๋๊ตฌ ํญ๋ชฉ์์ `api_key`๋ฅผ ์ฝ์ผ๋ฉฐ, ์๋ตํ๋ฉด `TAVILY_API_KEY`๋ก ํด๋ฐฑํฉ๋๋ค. ๊ฐ์ ธ์ค๊ธฐ๋ ๊ฒ์ ํญ๋ชฉ์ ํค๋ฅผ ์ฌ์ฌ์ฉํ์ง ์์ผ๋ฏ๋ก, ๊ฒ์์๋ ๋ค๋ฅธ ํ๋ก๋ฐ์ด๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด์ ์ ๊ณต์ Tavily ํค๋ฅผ `web_search` ์๋์๋ง ์ค์ ํ๋ค๋ฉด, `web_fetch` ์๋์๋ ์ค์ ํ๊ฑฐ๋ ๋ ๋๊ตฌ ๋ชจ๋์ `TAVILY_API_KEY`๋ฅผ ์ฌ์ฉํ์ธ์.
๋ด์ค ์ค์ฌ ๋ฆฌ์์น์๋ `make setup`์์ **Webz.io News Search**๋ฅผ ์ ํํ๊ฑฐ๋, `web_search` ๋๊ตฌ์ `use`๋ฅผ `deerflow.community.webz.tools:web_search_tool`๋ก ๋ฐ๊พธ๊ณ `WEBZ_API_KEY`๋ฅผ ์ค์ ํ์ธ์. ๋๊ตฌ์ ๋ช
์ํ `api_key`๊ฐ ํ๊ฒฝ ๋ณ์๋ณด๋ค ์ฐ์ ํฉ๋๋ค. ํธ์ถ์์ ๋ช
์ํ `max_results`๋ ์ค์ ๋ ๊ธฐ๋ณธ๊ฐ์ ์ฌ์ ์ํ๋ฉฐ, ์๋ตํ๋ฉด ์ค์ ๊ฐ ๋๋ 5(1โ100 ๋ฒ์๋ก ์ ํ)๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ถ๋ฆฌ์ธ๊ณผ ์์๋ฅผ ํฌํจํด ์๋ชป ์ค์ ๋ ๊ฐ์๋ 5๋ก ํด๋ฐฑํฉ๋๋ค. ๊ฒฐ๊ณผ์๋ ์ผ์นํ๋ ๊ตฌ์ , ์ ๋ชฉ, URL, ๊ฒ์์ผ, ์์ค ๋ฉํ๋ฐ์ดํฐ๊ฐ ํฌํจ๋ฉ๋๋ค. ์ฑํ
์ ๊ฒ์ ๋จ๊ณ๋ ๋ํ๋ฅผ ๋ค์ ๋ถ๋ฌ์จ ๋ค์๋ ์์ค ์ ๋ชฉ๊ณผ ๋งํฌ๋ฅผ ํ์ํ๋ฉฐ, ํ์์ด ์๋ชป๋ ์์ค ํญ๋ชฉ์ ์ ํจํ ๋งํฌ๋ฅผ ์์ง ์๊ณ ๊ฑด๋๋๋๋ค. `returned_results`๋ ์ผ์นํ๋ ๋ชจ๋ ๋ด์ค ๊ธฐ์ฌ ์๊ฐ ์๋๋ผ ๋ฐํ๋ ํ์ด์ง์ ๊ฒฐ๊ณผ ์๋ฅผ ์
๋๋ค. ํ์์ด ์๋ชป๋ ํญ๋ชฉ์ ๊ฒฝ๊ณ ์ ํจ๊ป ๊ฑด๋๋ฐ๊ณ ์ ํจํ ํญ๋ชฉ์ ์ ์ง๋๋ฉฐ, ์๋ชป๋ ์๋ต์ด๋ ์ ํจํ ํญ๋ชฉ์ด ์๋ ํ์ด์ง๋ ์ค๋ฅ๋ฅผ ๋ฐํํฉ๋๋ค. ๋น ๊ฒฐ๊ณผ ๋ชฉ๋ก์ ์ ํจํฉ๋๋ค. ์ด ๋๊ตฌ๋ ์ธ์ด, ๊ตญ๊ฐ, ์์ค ๋๋ฉ์ธ, ๊ฐ์ฑ, ์นดํ
๊ณ ๋ฆฌ, ๊ฒ์์ผ ํํฐ๋ฅผ ๋ฐ์ต๋๋ค. `time_range`๋ 1, 7, 30, 365์ผ์ UTC ํํ ๋ ์ง์ ๋งคํ๋๋ฉฐ, ๋ช
์์ ์ธ `published_from`์ด ๊ทธ ํํ์ ์ฌ์ ์ํฉ๋๋ค. Webz๋ ์ผ๋ฐ ์น์ด ์๋๋ผ ์ต๊ทผ ๋ด์ค๋ฅผ ๊ฒ์ํ๋ฏ๋ก, ๋ ์ง ํํฐ๋ก ํ๋ก๋ฐ์ด๋์ [๋ฌธ์ํ๋ 30์ผ ๋ฒ์](https://docs.webz.io/docs/webz/news-search-api-response-format)๋ฅผ ๋์ด์ค ์ ์์ต๋๋ค.
#### ์ปค์คํ
์คํฌ ๋ด๋ณด๋ด๊ธฐ
๊ด๋ฆฌ์๋ **Capability Center โ Skills โ My skills โ View details โ Export**์์ ์์ ์ ์ปค์คํ
์คํฌ์ ๋ด๋ณด๋ผ ์ ์์ต๋๋ค. ํ์ผ ๋ชฉ๋ก๊ณผ ์ ์ธ๋ ํ๊ฒฝ ์๊ตฌ ์ฌํญ์ ๊ฒํ ํ ๋ค **Download .skill**์ ์ ํํ์ธ์. ์์นด์ด๋ธ์๋ ๋ณด์กฐ ํ์ผ๊ณผ ๋น ๋๋ ํฐ๋ฆฌ๋ฅผ ํฌํจํด ํ์ฌ ์ ์ฅ๋ ์คํฌ์ด ๋ด๊ธฐ๋ฉฐ, ๋นํ์ฑํ๋ ์คํฌ๋ ๋ด๋ณด๋ผ ์ ์์ต๋๋ค. ๋ฏธ๋ฆฌ ๋ณด๊ธฐ ํ ์คํฌ์ด ๋ณ๊ฒฝ๋์๋ค๋ฉด ๋ค์ด๋ก๋ํ๊ธฐ ์ ์ ํ์ผ ๋ชฉ๋ก์ ์๋ก ๊ณ ์น์ธ์. ๋ค๋ฅธ DeerFlow ์ธ์คํด์ค์์ **Install .skill**๋ก ์์นด์ด๋ธ๋ฅผ ๊ฐ์ ธ์ค์ธ์. ๊ธฐ์กด ์ด๋ฆ๊ณผ์ ์ถฉ๋ ์ฒ๋ฆฌ์ ์ผ๋ฐ ์ค์น ๋ณด์ ๊ฒ์ฌ๋ ๊ทธ๋๋ก ์ ์ฉ๋ฉ๋๋ค.
๊ณ์ ์ค์ , ๋ํ, ๊ทธ๋ฆฌ๊ณ ์คํฌ ํด๋ ๋ฐ์ ๊ธฐ๋ก์ ์ ์ธ๋ฉ๋๋ค. ํด๋ ์์ ํ์ผ์ ์์ฑ์๊ฐ ๋ฃ์ด ๋ ์๊ฒฉ ์ฆ๋ช
๊น์ง ํฌํจํด ๋ณ๊ฒฝ ์์ด ๊ทธ๋๋ก ๋ณด์กด๋๋ฉฐ, ํ์ผ ์ด๋ฆ ์๋ฆผ์ ์ฐธ๊ณ ์ฉ์
๋๋ค. ์์กด์ฑ๊ณผ ์๊ฒฉ ์ฆ๋ช
์ ๋์ ํ๊ฒฝ์์ ์ค์ ํ์ธ์. ๋งํฌ๋ ํด๋/ํ์ผ, ํ๋ ๋งํฌ, ์ง์๋์ง ์๋ ์คํ ๋ฐ์ด๋๋ฆฌ, ์ค์ฒฉ๋ `SKILL.md` ํ์ผ, ์ด์ํ ์ ์๋ ๊ฒฝ๋ก๋ ๋ด๋ณด๋ผ ์ ์์ต๋๋ค. ๋ด๋ณด๋ด๊ธฐ๋ ๋์คํฌ๋ฆฝํฐ ๊ธฐ์ค no-follow ํ์ผ ์์คํ
API๋ฅผ ๊ฐ์ถ ํธ์คํธ(Linux/macOS)๋ฅผ ์ง์ํ๋ฉฐ, ์ง์๋์ง ์๋ ํธ์คํธ์์๋ ๋ช
์์ ์ผ๋ก ์คํจํฉ๋๋ค. ์ ํ: ZIP ํญ๋ชฉ 4096๊ฐ, ํ์ผ๋น 64 MiB, ์ ์ฒด ์ฝํ
์ธ /์์นด์ด๋ธ 100 MiB, frontmatter 1 MiB. YAML ๋ณ์นญ๊ณผ ์ง๋์น๊ฒ ๋ณต์กํ ์ ์ธ์ ์ง์๋์ง ์์ต๋๋ค. ์ผ๋ฐ ์คํฌ๋ฆฝํธ์ ์คํ ๊ถํ ์๋ฏธ๋ POSIX์์ ๊ฐ์ ธ์ฌ ๋ ๋ณด์กด๋์ง๋ง, ํน์ ๊ถํ์ ๋ณต์๋์ง ์์ต๋๋ค. [๋ด๋ณด๋ด๊ธฐ API ๊ณ์ฝ](backend/docs/API.md#export-a-custom-skill)์ ์ฐธ๊ณ ํ์ธ์.
#### Claude Code ํตํฉ
`claude-to-deerflow` ์คํฌ์ ์ฌ์ฉํ๋ฉด [Claude Code](https://docs.anthropic.com/en/docs/claude-code)์์ ์คํ ์ค์ธ DeerFlow ์ธ์คํด์ค์ ์ง์ ์ํธ์์ฉํ ์ ์์ต๋๋ค. ํฐ๋ฏธ๋์ ๋ ๋์ง ์๊ณ ๋ ๋ฆฌ์์น ์์
์ ๋ณด๋ด๊ณ , ์ํ๋ฅผ ํ์ธํ๊ณ , ์ค๋ ๋๋ฅผ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
**์คํฌ ์ค์น**:
```bash
npx skills add https://github.com/bytedance/deer-flow --skill claude-to-deerflow
```
๊ทธ๋ฐ ๋ค์ DeerFlow๊ฐ ์คํ ์ค์ธ์ง ํ์ธํ๊ณ (๊ธฐ๋ณธ ์ฃผ์ `http://localhost:2026`) Claude Code์์ `/claude-to-deerflow` ๋ช
๋ น์ ์ฌ์ฉํ์ธ์.
**ํ ์ ์๋ ์ผ**:
- DeerFlow์ ๋ฉ์์ง๋ฅผ ๋ณด๋ด๊ณ ์คํธ๋ฆฌ๋ฐ ์๋ต ๋ฐ๊ธฐ
- ์คํ ๋ชจ๋ ์ ํ: flash(๋น ๋ฆ), standard, pro(๊ณํ), ultra(์๋ธ์์ด์ ํธ)
- DeerFlow ์ํ ํ์ธ, ๋ชจ๋ธ/์คํฌ/์์ด์ ํธ ๋ชฉ๋ก ์กฐํ
- ์ค๋ ๋์ ๋ํ ๊ธฐ๋ก ๊ด๋ฆฌ
- ๋ถ์ํ ํ์ผ ์
๋ก๋
**ํ๊ฒฝ ๋ณ์**(์ ํ ์ฌํญ, ์ปค์คํ
์๋ํฌ์ธํธ์ฉ):
```bash
DEERFLOW_URL=http://localhost:2026 # Unified proxy base URL
DEERFLOW_GATEWAY_URL=http://localhost:2026 # Gateway API
DEERFLOW_LANGGRAPH_URL=http://localhost:2026/api/langgraph # LangGraph API
```
์ ์ฒด API ๋ ํผ๋ฐ์ค๋ [`skills/public/claude-to-deerflow/SKILL.md`](skills/public/claude-to-deerflow/SKILL.md)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
### ๋น๊ณต๊ฐ ์ง์ ๊ฒ์ (RAGFlow)
๋ต๋ณ์ ํด๋ฆญํ ์ ์๋ ์ง์ ์ธ์ฉ์ผ๋ก ๊ฒ์๋ RAGFlow ๊ทผ๊ฑฐ๋ฅผ ์ธ์ฉํ ์ ์์ต๋๋ค. ์ธ์ฉ ๋๋ ๋ต๋ณ์ ์ง์ ์์ค ๋ชฉ๋ก์ ์๋ ํญ๋ชฉ์ ํด๋ฆญํ๋ฉด ๊ฒ์๋ ์๋ณธ ๋ฐ์ท๋ฌธ, ๋ฐ์ดํฐ์
๋ฐ ๋ฌธ์ ์ด๋ฆ, ๊ทธ๋ฆฌ๊ณ RAGFlow๊ฐ ์ ๊ณตํ๋ ๊ฒฝ์ฐ ํ์ด์ง ๋ฒํธ๋ฅผ ๋ณผ ์ ์์ต๋๋ค. ์ด๋ ๋ํ์ ํจ๊ป ๋ณด์กด๋๋ ๊ฒ์ ์์ ์ ์ค๋
์ท์ด๋ฉฐ, ์ผ๋ฐ `task` ์๋ธ์์ด์ ํธ๊ฐ ์ ๋ฌํ ์์ค๋ ํฌํจํฉ๋๋ค. ๋ํ๋ฅผ ๋ค์ ๋ถ๋ฌ์จ ๋ค์๋ ๊ณ์ ํ์ธํ ์ ์์ต๋๋ค. ๋ฐ์ท๋ฌธ์ ์ ์ฒด ๋ฌธ์์ ์ค์๊ฐ ์ฌ๋ณธ์ด ์๋๋๋ค. RAGFlow์์ ๋ณ๊ฒฝ์ด ์ผ์ด๋๋ ๊ณผ๊ฑฐ ๊ทผ๊ฑฐ๊ฐ ๋ค์ ์ฐ์ด์ง ์์ต๋๋ค. ๋๋ฝ๋ ์์ค ๋ ์ฝ๋๋ ์ถ์ธกํ ๋งํฌ๋ก ๋ฐ๊พธ์ง ์๊ณ ์ฌ์ฉํ ์ ์์์ผ๋ก ํ์๋ฉ๋๋ค. ์์ค ์ค๋
์ท์ ์ง์ ๊ด๋ฆฌ ํ์ด์ง๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ RAGFlow API ํค๋ฅผ ๋
ธ์ถํ์ง ์์ต๋๋ค. ์์ ๋ฐฐ์น ๋ด๋ณด๋ด๊ธฐ์ ๋
๋ฆฝ Markdown ํ์ผ์๋ ์ด๋ฌํ ๋ํํ ์์ค ๋ ์ฝ๋๊ฐ ํฌํจ๋์ง ์์ต๋๋ค. Sources ์น์
์ ์ผ๋ฐ ๋ฌธ์ ์ ๋ชฉ ๋งํฌ๋ ์ธ๋ผ์ธ ์ธ์ฉ๊ณผ ๋์ผํ ๊ทผ๊ฑฐ๋ฅผ ์ฝ๋๋ค. ๋๊ตฌ ์ถ๋ ฅ ์์ฐ์ด ์ ์ฉ๋๋ ๊ฒฝ์ฐ ์์ฐ ์์ ๋ค์ด๊ฐ๋ ์์ ํ ๊ทผ๊ฑฐ ํญ๋ชฉ๋ง ๊ณ์ ์ธ์ฉํ ์ ์์ต๋๋ค. ์๋ฆฐ ๋ฐ์ท๋ฌธ์ ์์ค ๋ ์ฝ๋๋ฅผ ๋จ๊ธฐ๋ ๋์ ์๋ต๋ ์์ค๋ฅผ ๋ณด๊ณ ํฉ๋๋ค.
DeerFlow๋ ์ ํ์ ์ผ๋ก ํ
๋ํธ ๋ฒ์์ RAGFlow ๋ฐฐํฌ์ ์ฐ๊ฒฐํ ์ ์์ต๋๋ค. `knowledge_search` ์์ด์ ํธ ๋๊ตฌ๋ ์ค์ ๋ ๋ฐ์ดํฐ์
๋ฒ์๋ฅผ ํด์ํ๊ณ , ๋ฐ์ดํฐ์
์ ์๋ฒ ๋ฉ ๋ชจ๋ธ๋ณ๋ก ๊ทธ๋ฃนํํ ๋ค ํด๋น ๊ทธ๋ฃน์ ๋ณ๋ ฌ๋ก ๊ฒ์ํ๋ฏ๋ก ์๋ก ๋ค๋ฅธ ์๋ฒ ๋ฉ ๋ชจ๋ธ์ด ์์ฌ ์์ด๋ ํ๋ก๋ฐ์ด๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ง ์์ต๋๋ค. ๋ฐ์ดํฐ์
ID์ API ํค๋ ๋ชจ๋ธ์ ์ ๋ ๋
ธ์ถ๋์ง ์์ต๋๋ค. ์ ํ ์ฌํญ์ธ `list_knowledge_bases` ๋๊ตฌ๋ ์ด๋ฆ๋ง ๋ฐํํฉ๋๋ค.
๋ฉ์ธ ์ฑํ
๊ณผ ์ปค์คํ
์์ด์ ํธ ์ฑํ
์์๋ ์ ํ์ ์ผ๋ก ๋ชจ๋ ์ปจํธ๋กค ์์ ํ์ด์ง ๋ก์ปฌ์ ์์ด์ฝ ์ ์ฉ **Knowledge** ์ ํ๊ธฐ๋ฅผ ํ์ํ ์ ์์ต๋๋ค. ์ ํ๊ธฐ๊ฐ ๊ณ์ ๊ฐ์กฐ ํ์๋์ด ์์ผ๋ฉด ์ง์ ๊ฒ์์ด ํ์ฑ ์ํ์ด๊ณ , ์ค๋ฆฝ ์ํ์ด๋ฉด ๊ฒ์์ด ๊บผ์ ธ ์๋ค๋ ๋ป์
๋๋ค. `config.yaml`์ `knowledge_base.scope_selection_enabled: true`๋ฅผ ์ค์ ํ๊ณ ๊ธฐ๋ณธ ์ ๊ณต RAGFlow `knowledge_search` ํ๋ก๋ฐ์ด๋๋ฅผ ์ฌ์ฉํ๋ฉด ํด๋ง๋ค ํ์ฉ๋ ๋ชจ๋ ๋ฐ์ดํฐ์
, ์ ํํ ๋ฐ์ดํฐ์
/ํ์ผ, ๋๋ ๊ฒ์ ์ ํจ์ ๊ณ ๋ฅผ ์ ์์ต๋๋ค. ๊ฐ์ ์ค์ ํ๋๊ทธ๊ฐ ๋ ์ฑํ
์ ํ์ ๋ชจ๋ ์ ์ดํ๋ฉฐ, ๋นํ์ฑํํ๋ฉด ์ด๋ ์
๋ ฅ์ฐฝ(composer)๋ ์ ํ๊ธฐ๋ฅผ ํ์ํ๊ฑฐ๋ ๋ฒ์๋ฅผ ์ ์ถํ์ง ์์ต๋๋ค. ํ์ด์ง๋ฅผ ์๋ก ๊ณ ์น๊ฑฐ๋ ๋ค๋ฅธ ๋ํ๋ฅผ ์ด๋ฉด ์ ํ์ ์ปค์คํ
์์ด์ ํธ์ ์ ์ฅ๋ ๊ธฐ๋ณธ๊ฐ(๋ฐ์ธ๋ฉ๋์ง ์์ ๊ฒฝ์ฐ ์ ์ฒด)์ผ๋ก ์ด๊ธฐํ๋ฉ๋๋ค. ์ ์ก๋ ๊ฐ ์ฌ์ฉ์ ๋ฉ์์ง๋ ์ฌ์(replay)๊ณผ ๊ธฐ๋ก์ ์ํด ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ ๋ฒ์ ์ค๋
์ท์ ์ ์งํฉ๋๋ค. Gateway๋ ๋ชจ๋ ์ค๋
์ท์ ๊ฒ์ฆํ๊ณ , ์ด์์์ ๋ฐ์ดํฐ์
ํ์ฉ ๋ชฉ๋ก๊ณผ ๊ต์งํฉ์ ๊ตฌํ๋ฉฐ, ์คํ ์ ์ฉ ๋ฒ์๋ฅผ ๋ค์ดํฐ๋ธ ๋ฐ ์์ ์๋ธ์์ด์ ํธ์ ์ ํํ๊ณ , ๋ชจ๋ธ ์
๋ ฅ๊ณผ ์ธ๋ถ ํธ๋ ์ด์ค์์๋ ์ ๊ฑฐํฉ๋๋ค. ํด๋ผ์ด์ธํธ๊ฐ ์ ๊ณตํ ๋ด๋ถ ๋ฐํ์ ์ ์ด๊ฐ๊ณผ ์๊ฒฉ ์ฆ๋ช
๋ ์คํ ๋๋ ์ฒดํฌํฌ์ธํธ ์์ ์ ์ฅ ์ ์ ์คํ(run) ์ปจํ
์คํธ์์ ์ ๊ฑฐ๋ฉ๋๋ค. ๋ฉฑ๋ฑ ์ฌ์๋๋ ์ ๊ท ์ค๋
์ท๊ณผ ๋ ๊ฑฐ์ ์์ ์คํ ์
๋ ฅ์ ๋ชจ๋ ๋ฐ์๋ค์ด๋ฏ๋ก ์
๊ทธ๋ ์ด๋ ํ์๋ ์ฌ์๋ ํธํ์ฑ์ด ์ ์ง๋ฉ๋๋ค. ์ปค์คํ
์์ด์ ํธ๋ **Agents โ Agent settings**์์ ์ ํ์ ํ์ผ ํํฐ๋ ๊ฒ์ ๋๊ธฐ๋ฅผ ํฌํจํ **Default knowledge** ์ ํ์ ์ ์ฅํ ์ ์์ต๋๋ค. ๋ชจ๋ ์ง์ ๋ฒ ์ด์ค๋ฅผ ์ ํํ๋ฉด ๋ฐ์ธ๋ฉ์ด ํด์ ๋ฉ๋๋ค. ๊ฐ์ `knowledge_scope` ํ๋๋ฅผ ์์ด์ ํธ ์์ฑ/์
๋ฐ์ดํธ API์ ์์ด์ ํธ์ ์ ์ฅ๋ ์ค์ ์์ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ์ด ํ๋๋ฅผ ์๋ตํ ์
๋ฐ์ดํธ๋ ๊ธฐ์กด ๊ฐ์ ์ ์งํ๊ณ `null`์ ๊ฐ์ ์ง์๋๋ค. ์ด๋ ๊ธฐ๋ณธ๊ฐ์ผ ๋ฟ ๊ถํ ๊ฒฝ๊ณ๊ฐ ์๋๋๋ค. ๋ฉ์์ง๋ณ๋ก ๋ช
์ํ ์ ํ์ด ๊ธฐ๋ณธ๊ฐ๋ณด๋ค ์ฐ์ ํ๋ฉฐ, ๊ฒ์ ์์ ์๋ ์ฌ์ ํ ์ด์์์ ํ์ฉ ๋ชฉ๋ก์ด ์ ์ฉ๋ฉ๋๋ค. ๋ฉ์์ง ๋ฒ์๊ฐ ์๋ Gateway ์คํ(์์ฝ ํด๊ณผ ์ฑ๋ ํด ํฌํจ)์ ์
๋ ฅ์ฐฝ ์ ํ๊ธฐ๊ฐ ์จ๊ฒจ์ ธ ์์ด๋ ์ ์ฅ๋ ๊ธฐ๋ณธ๊ฐ์ ์ฌ์ฉํ๊ณ ์ค๋
์ท์ผ๋ก ๋จ๊น๋๋ค. ์ฌ์์ฑ/์ฌ๊ฐ๋ ์ดํ์ ์ค์ ๋ณ๊ฒฝ์ ๋ฐ์ํ์ง ์๊ณ ์๋ ํด์ ๋ฒ์๋ฅผ ์ ์งํ๋ฉฐ, ๋ฒ์๊ฐ ์๋ ๋ ๊ฑฐ์ ํด๋ ๋ง์ฐฌ๊ฐ์ง์
๋๋ค. ์ ์ ์๊ฑฐ๋ ์ฌ์ฉํ ์ ์๋ ์ ํ์ ์ ๋ ๊ฒ์ ๋ฒ์๋ฅผ ๋ํ์ง ์์ต๋๋ค. ๋ฉฑ๋ฑ ์ฌ์๋๋ ๊ธฐ๋ณธ๊ฐ์ด ์ถ๊ฐ, ๋ณ๊ฒฝ, ํด์ ๋๋๋ผ๋ ์๋ ์คํ๊ณผ ๋ฒ์๋ฅผ ์ ์งํ๋ฉฐ, ์ด ๊ธฐ๋ฅ ์ด์ ์ ๋ฐ์๋ค์ฌ์ง ๋ฒ์ ์๋ ์คํ๋ ๋ง์ฐฌ๊ฐ์ง์
๋๋ค. ์ด ๊ธฐ๋ณธ๊ฐ์ Gateway๊ฐ ํธ์คํ
ํ๋ ์ปค์คํ
์์ด์ ํธ ํด์ ์ ์ฉ๋๋ฉฐ, ํ๋ค์ค/ํด๋ผ์ด์ธํธ๋ฅผ ์ง์ ํตํฉํ ๊ฒฝ์ฐ์๋ ๊ณ์ ์์ฒด ์คํ ๋ฒ์๋ฅผ ์ ๊ณตํฉ๋๋ค.
Agent settings์์ **Tool access**๋ ์ค์ ๋ ๋ชจ๋ ๋๊ตฌ ๊ทธ๋ฃน์ ์์ํ๊ฑฐ๋, ์ ํํ ๊ทธ๋ฃน๋ง ํ์ฉํ๊ฑฐ๋, ๋ชจ๋ ๊ทธ๋ฃน์ ๋นํ์ฑํํ ์ ์์ต๋๋ค. ์ ์ฅ๋ ๊ทธ๋ฃน์ ์นดํ๋ก๊ทธ๋ฅผ ๋ถ๋ฌ์ค๋ ์ค์ด๊ฑฐ๋ ๋ถ๋ฌ์ค์ง ๋ชปํ ๊ฒฝ์ฐ์๋ ๊ณ์ ํ์๋๋ฉฐ ์ ๊ฑฐํ ์ ์์ต๋๋ค. ์ ์ฅ๋ ๊ทธ๋ฃน์ ์นดํ๋ก๊ทธ๋ฅผ ์ฑ๊ณต์ ์ผ๋ก ๋ถ๋ฌ์ ํด๋น ๊ทธ๋ฃน์ด ์๋ค๊ณ ํ์ธ๋ ๊ฒฝ์ฐ์๋ง ์ฌ์ฉํ ์ ์์์ผ๋ก ํ์๋ฉ๋๋ค. `knowledge`๋ฅผ ์ ๊ฑฐํ๋ ์ ํ์ ์ ์ฅํ๋ฉด ์ ์ฅ๋ ๊ธฐ๋ณธ ์ง์ ์ ํ๋ ํจ๊ป ์ง์์ง๋๋ค. ์ด์ ์ ์ง์ ์ ๊ทผ ๊ถํ์ด ์๋ ์์ด์ ํธ์ ์ง์ ์ ๊ทผ์ ํ์ฑํํ ๋๋ ๋จผ์ ๋๊ตฌ ์ ๊ทผ์ ์ ์ฅํ ๋ค์, ์ค์ ์ ๋ค์ ์ด์ด ๊ธฐ๋ณธ ์ง์ ๋ฒ ์ด์ค๋ฅผ ์ ํํ์ธ์.
`knowledge_base` ๋ธ๋ก์ ํ๋ก๋ฐ์ด๋ ์ค๋ฆฝ์ ์ด๋ฉฐ ์ง์ ๊ธฐ๋ฅ(capability)๊ณผ ์ ํ๊ธฐ์ ํ์ฑํ ์ฌ๋ถ๋ง ์ ์ดํฉ๋๋ค. RAGFlow ์ฐ๊ฒฐ, ๋ฐ์ดํฐ์
ํ์ฉ ๋ชฉ๋ก, ๊ฒ์ ํ๋ผ๋ฏธํฐ(`base_url`, `api_key`, `datasets`, `page_size`, ์๊ณ๊ฐ, ์ถ๋ ฅ ์ ํ)๋ `tools[].name: knowledge_search` ํญ๋ชฉ์ ์ค์ ํด์ผ ํ๋ฉฐ, `knowledge_base`์์๋ ์ ๋ ์ฝ์ง ์์ต๋๋ค. ์ปค์คํ
์์ด์ ํธ ์ฑํ
์์ฒญ์ ์ ํ๋ ์์ด์ ํธ ์ด๋ฆ์ `assistant_id`์ `context.agent_name` ๋ชจ๋์ ๋ด์ ๋ณด๋ด๋ฏ๋ก, Gateway ๋ฒ์ ์น์ธ(admission)๊ณผ ๋ฐํ์ ์์ด์ ํธ ๋ก๋ฉ์ด ๊ฐ์ ์๋ณ ์ ๋ณด๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ฉ์ธ ์ฑํ
์์ฒญ์ `lead_agent`๋ฅผ ์ฌ์ฉํ๋ฉฐ, ๋ ์๋ณ ์ ๋ณด ๋ชจ๋ ๊ณต์ ์ค์ ์ด RAGFlow ํ๋ก๋ฐ์ด๋๋ฅผ ํ์ฑํํ ๊ฒฝ์ฐ์๋ง ์น์ธ๋ฉ๋๋ค. ๋๊ธฐ ์ค์ธ ํ์ธ ์ง๋ฌธ(clarification)์ ๋ตํ ๋๋ ๋ช
์์ ์ผ๋ก ์ ์ถ๋ ํ์ฌ ์ ํ๊ธฐ ์ค๋
์ท์ด ์ฐ์ ํ๋ฉฐ, ์ด๋ฅผ ์๋ตํ ํด๋ผ์ด์ธํธ๋ ์ด์ ํด์์ ์น์ธ๋ ๋ฒ์๋ฅผ ์์ํฉ๋๋ค. ํธ์ง ํ ์ฌ์์ฑ๋ ๊ฐ์ ํด๋ฐฑ์ ๋ฐ๋ฅด๋ฉฐ, ํ์ผ ์นดํ๋ก๊ทธ๋ ๋ฐ์ดํฐ์
์ ์ ์ฒด ํ์ผ์์ ์ ํํ ํ์ผ๋ก ์ ํํ ํ์๋ง ๋ถ๋ฌ์ต๋๋ค. ์ด๋ฒ ๋ฆด๋ฆฌ์ค๋ ์ํฌ์คํ์ด์ค ์ฌ์ด๋๋ฐ์ ๋
๋ฆฝ๋ Knowledge ํญ๋ชฉ์ด๋ DeerFlow ์ง์ ๊ด๋ฆฌ ํ์ด์ง๋ฅผ ์ถ๊ฐํ์ง ์์ต๋๋ค. ๋ฐ์ดํฐ์
๊ณผ ๋ฌธ์์ ์์ฑ, ์
๋ก๋, ํ์ฑ, ์ญ์ ๋ RAGFlow์์ ์ง์ ์ํํ์ธ์.
๊ฐ ๋ฉ์์ง์์๋ ์ฌ์ ํ ์ต๋ 1000๊ฐ์ ๋ฌธ์๋ฅผ ์ ํํ ์ ์์ต๋๋ค. ํ๋์ ๋ฐ์ดํฐ์
์์ 100๊ฐ๋ฅผ ์ด๊ณผํ๋ ๋ฌธ์๋ฅผ ์ ํํ๋ฉด DeerFlow๋ ์ ์ฒด ์ ํ์ ์ ์งํ๋ฉด์ ์ต๋ 100๊ฐ ๋จ์์ ๋ฐฐ์น๋ก ๋๋์ด ๊ฒ์ฆํฉ๋๋ค. ์ด๋ ๋ฐฐ์น์๋ ์ ๊ทผํ ์ ์๊ฑฐ๋ ๊ฒ์ํ ์ ์๋ ๋ฌธ์๊ฐ ์์ผ๋ฉด ๊ฒ์์ด ๊ฑฐ๋ถ๋ฉ๋๋ค.
๊ณ ๊ธ ๋ฐฐํฌ์์๋ `config.yaml`์์ `authorization.enabled`๋ฅผ ์ค์ ํ์ฌ ํ๋ฌ๊ทธํ ๊ถํ ๋ถ์ฌ๋ฅผ ํ์ฑํํ ์ ์์ต๋๋ค. ์ค์ ๋ `AuthorizationProvider`๋ ๊ฑฐ๋ถ๋ ๋๊ตฌ๊ฐ ๋ชจ๋ธ์ด๋ ์ง์ฐ(deferred) ๋๊ตฌ ์นดํ๋ก๊ทธ์ ๋๋ฌํ๊ธฐ ์ ์ ๊ฑธ๋ฌ๋ด๊ณ , ์ดํ ๊ธฐ์กด ๊ฐ๋๋ ์ผ ๋ฏธ๋ค์จ์ด๋ฅผ ํตํด ๋ชจ๋ ๋น์ฆ๋์ค ๋๊ตฌ ์คํ ์ ์ ๊ฐ์ ํ๋ก๋ฐ์ด๋๋ก ๋ค์ ๊ฒ์ฌํฉ๋๋ค. Gateway์ `threads:*` ๋ฐ `runs:*` ๋ผ์ฐํธ ๊ถํ๋ ๊ฐ์ ํ๋ก๋ฐ์ด๋์์ ๋์ถ๋๋ฉฐ, ๊ธฐ์กด ์์ ์ ๊ฒ์ฌ์ ๊ด๋ฆฌ์ ์ ์ฉ ๊ด๋ฆฌ ๊ฒ์ดํธ๋ ๊ทธ๋๋ก ์ ์ง๋ฉ๋๋ค. ์์ด์ ํธ ์คํ์ ์์ํ๊ฑฐ๋ ํฅํ ์คํ์ ๊ฐ๋ฅํ๊ฒ ํ๋ ๋ชจ๋ HTTP ๋ผ์ฐํธ์๋ `runs:create`๊ฐ ํ์ํฉ๋๋ค. ์ฌ๊ธฐ์๋ ์ํ ๋น์ ์ฅ `POST /api/runs/stream` ๋ฐ `POST /api/runs/wait` ์๋ํฌ์ธํธ์ ์์ฝ ์์
์ ์์ฑ, ์
๋ฐ์ดํธ, ์ฌ๊ฐ, ์๋ ํธ๋ฆฌ๊ฑฐ ๋ณ๊ฒฝ ์์
์ด ํฌํจ๋ฉ๋๋ค. ์์ฝ ์์
๋ณ๊ฒฝ ์์
์ ๊ธฐ์กด์ `threads:write` ์๊ตฌ ์ฌํญ์ ๊ทธ๋๋ก ์ ์งํ๋ฉฐ, ์ํ ๋น์ ์ฅ ๋ผ์ฐํธ๋ ์์ฒญ ๋ณธ๋ฌธ์ ์ ํ ์ฌํญ์ธ ์ค๋ ๋ ID๊ฐ ์ ๊ณต๋๋ฉด ๋ณ๋๋ก ์์ ๊ถ์ ๊ฐ์ ํฉ๋๋ค. ์์ฑ๋ `tool_search`๋ ํ์ฌ ๋น๋์์ ์ด๋ฏธ ํํฐ๋ง๋ ์ง์ฐ ๋๊ตฌ ์นดํ๋ก๊ทธ๋ฅผ ์๋จ์์ ์ ๊ณตํ๋ ๊ฒฝ์ฐ์๋ง ๋ ๋ฒ์งธ ๋๊ตฌ ๊ฒ์ฌ๋ฅผ ๊ฑด๋๋ธ ์ ์์ต๋๋ค. ๋ชจ๋ธ ์ ๊ทผ๋ ๊ฐ์ ํ๋ก๋ฐ์ด๋๋ฅผ ๋ฐ๋ฆ
๋๋ค. Gateway์ `models` ๋ชฉ๋ก์ ์ฃผ์ฒด(principal)๋ณ๋ก ํํฐ๋ง๋๊ณ , `model:use`๋ ๋ชจ๋ธ ์์ธ ์์ฒญ ์์ ๋ฐํ์์ด ์์ด์ ํธ์ ๋ชจ๋ธ์ ํด์ํ ๋ ๋ค์ ๊ฐ์ ๋๋ฉฐ, ๊ฑฐ๋ถ๋ ๊ธฐ๋ณธ ๋ชจ๋ธ์ `model:use`๋ ํต๊ณผํ๋ ๋จ์ ํ๋ณด ์ค ์ฒซ ๋ฒ์งธ๋ก ํด๋ฐฑํฉ๋๋ค. ๊ธฐ๋ณธ ์ ๊ณต RBAC ํ๋ก๋ฐ์ด๋๋ ์ญํ ๋ณ `tools`, `routes`, `models`, `skills`, `sandbox` ํ์ฉ/๊ฑฐ๋ถ ์ ์ฑ
์ ์ง์ํ๋ฉฐ `default_role`์ด ์ค์ ๋ ์ญํ ์ ๊ฐ๋ฆฌํค๋์ง ๊ฒ์ฆํฉ๋๋ค. ๊ถํ ๋ถ์ฌ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋นํ์ฑํ๋์ด ์์ต๋๋ค. ํ๋ก๋ฐ์ด๋์ `roles` ๋งคํ์ ์ ์ธ๋ ์ปค์คํ
์ญํ ์ ๊ด๋ฆฌ์ API(`GET /api/v1/admin/users`, `PATCH /api/v1/admin/users/{id}`; ๊ด๋ฆฌ์ ์ ์ฉ์ด๋ฉฐ ๋ง์ง๋ง ๊ด๋ฆฌ์์ ๊ฐ๋ฑ์ ๋ฐฉ์ง๋จ)๋ก ์ฌ์ฉ์์๊ฒ ํ ๋นํ๋ฉด ์ค์ ๋ก ์ ์ฉ๋ฉ๋๋ค. ์๋ฌด๋ ๋ณด์ ํ์ง ์์ ์ ์ธ๋ ์ญํ ์ ์๋ฌด ๊ถํ๋ ๋ถ์ฌํ์ง ์์ต๋๋ค. `config.example.yaml`๊ณผ [๊ถํ ๋ถ์ฌ RFC](docs/plans/2026-07-10-pluggable-authorization-rfc.md)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
ํ์ ์ง๋ฌธ ์ ์๋ ์ ํ๋ ๋ชจ๋ธ์ ํธ์ถํ๊ธฐ ์ ์ `model:use`๋ฅผ ๊ฒ์ฌํ๋ฉฐ, ์ด๋ฆ์ด ์ ๊ณต๋์ง ์์์ ๋์ ๊ธฐ๋ณธ ๋ชจ๋ธ๋ ํฌํจ๋ฉ๋๋ค. ๊ฑฐ๋ถ๋ ๋ชจ๋ธ์ LLM์ ํธ์ถํ์ง ์๊ณ HTTP 403์ ๋ฐํํ๋ฉฐ, ๊ถํ ๋ถ์ฌ ํ๋ก๋ฐ์ด๋ ์ฅ์ ๋ ์ค์ ๋ `fail_closed` ์ ์ฑ
์ ๋ฐ๋ฆ
๋๋ค.
๋น์ ์ ์ง์ํ๋ ์์ด์ ํธ์ ๊ฒฝ์ฐ `view_image`์ ๊ทธ ๋ค์ ์ด์ด์ง๋ ๋ชจ๋ธ ์ปจํ
์คํธ ์ด๋ฏธ์ง ์ฝ๊ธฐ์๋ `sandbox:execute`๊ฐ ํ์ํฉ๋๋ค. ๋๊ตฌ ์ด๋ฆ๋ง ํ์ฉํด์๋ ์ด๋ฏธ์ง ํ์ผ ์ ๊ทผ ๊ถํ์ด ๋ถ์ฌ๋์ง ์์ผ๋ฉฐ, ์๋๋ฐ์ค ์คํ์ด ๊ฑฐ๋ถ๋ ์ญํ ์ ๊ถํ์ด ๋ณ๊ฒฝ๋ ํ ์ด์ ์ ๊ธฐ๋ก๋ ์ด๋ฏธ์ง ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๋ค์ ์ฝ์ ์ ์์ต๋๋ค. ์ธ๋ถ ์คํ ์
๋ ฅ๊ณผ ์ค๋ ๋ ์ํ ์
๋ฐ์ดํธ๋ก๋ `viewed_images`๋ `thread_data`๋ฅผ ์ค์ ํ ์ ์์ต๋๋ค. ์ ์ฅ๋ ์ด๋ฏธ์ง๋ฅผ ํธ์คํธ ์ฌ๋ณธ์์ ์ฝ์ ๋๋ ํด๋น ๊ฒฝ๋ก๊ฐ ํ์ฌ ์ฌ์ฉ์์ ์ค๋ ๋์ ๊ธฐ๋ก๋ ๊ฐ์ ์ด๋ฏธ์ง ๊ฒฝ๋ก๋ก ํด์๋์ด์ผ ํฉ๋๋ค.
๊ฐ ๋ชจ๋ธ ์์ฒญ์๋ ์ต๊ทผ์ ๋ณธ ์ด๋ฏธ์ง๊ฐ ์ต๋ 4๊ฐ, base64 ์ด๋ฏธ์ง ๋ฐ์ดํฐ๊ฐ ์ต๋ 28 MiB๊น์ง ํฌํจ๋ฉ๋๋ค. ์ด ์ ํ์ผ๋ก ์ ์ธ๋ ์ด๋ฏธ์ง๋ ์๋ต๋ ๊ฒ์ผ๋ก ๋ณด๊ณ ๋๋ฉฐ, ์์ด์ ํธ๋ `view_image`๋ฅผ ๋ค์ ํธ์ถํด ์ด๋ฏธ์ง๋ฅผ ์ปจํ
์คํธ๋ก ๋ค์ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
๊ณ ๊ธ ๋ฐฐํฌ์์๋ `config.yaml` ๋๋ `extensions_config.json`์ `extensions.middlewares` ์๋์ `AgentMiddleware` ํด๋์ค๋ฅผ ์ ์ธํ์ฌ ์์ด์ ํธ ๋ฐํ์ ์์ฒด๋ฅผ ํ์ฅํ ์๋ ์์ต๋๋ค. ๊ฐ ํญ๋ชฉ์ `module.path:ClassName` ๋ฌธ์์ด(์ธ์ ์๋ ์์ฑ์) ๋๋ ๊ฐ์ฒด `{class, kwargs}`์ด๋ฉฐ, ๊ฐ์ฒด์ `kwargs`๋ ์์ฑ์์ ์ ๋ฌ๋ฉ๋๋ค. `kwargs` ๊ฐ์ JSON ํ์
(๊ฐ์ฒด, ๋ฐฐ์ด, ๋ฌธ์์ด, ์ซ์, ๋ถ๋ฆฌ์ธ, null)์ด์ด์ผ ํ๋ฉฐ, YAML ๋ ์ง์ ํ์์คํฌํ๋ JSON๊ณผ ์ผ์นํ๋๋ก ISO ๋ฌธ์์ด๋ก ๋ณํ๋ฉ๋๋ค. DeerFlow๋ ์ค์ ๋ ๊ฐ์ ๋ชฉ๋ก์ ๋ฆฌ๋ ์์ด์ ํธ์ ์๋ธ์์ด์ ํธ ํ์ดํ๋ผ์ธ์ ๋ถ๋ฌ์ค๋ฉฐ, ๊ทธ ์์น๋ ๊ธฐ๋ณธ ์ ๊ณต ๋ฐํ์ ๋ฏธ๋ค์จ์ด์ ๋ฃจํ/ํ ํฐ ๊ฐ๋ ๋ค, ๊ทธ๋ฆฌ๊ณ terminal-response/safety/clarification ๊ผฌ๋ฆฌ ์์
๋๋ค. ๋ฐ๋ผ์ ์ํฐํ๋ผ์ด์ฆ ํฌํฌ๋ ๊ธฐ๋ณธ ์ ๊ณต ๋ฏธ๋ค์จ์ด ๋น๋๋ฅผ ํจ์นํ์ง ์๊ณ ๋ ๋๋ฉ์ธ ๊ฐ๋๋ ์ผ, ๋๊ตฌ ํธ์ถ ๊ฑฐ๋ฒ๋์ค, ๊ด์ธก์ฑ ํ
์ ์ถ๊ฐํ ์ ์์ต๋๋ค. ํจํค์ง ๋๋ฝ, ์๋ชป๋ ํด๋์ค, ์์๋ ๋ชจ๋, ์์ฑ์ ์ค๋ฅ๋ ์์ด์ ํธ ์์ฑ ์์ ์ ๋ช
ํํ ์ค๋ฅ๋ก ์คํจํฉ๋๋ค. `config.yaml`๊ณผ `extensions_config.json`์ ์ด์์๊ฐ ์ ์ดํ๋ ์ ๋ขฐ๋ ํ์ผ๋ก ์ทจ๊ธํ์ธ์. ์ปค์คํ
๋๊ตฌ, ๋ชจ๋ธ, ์๋๋ฐ์ค, ๊ฐ๋๋ ์ผ, MCP ์๋ฒ, MCP ์ธํฐ์
ํฐ ์ ์ธ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ฏธ๋ค์จ์ด ๊ฒฝ๋ก๋ ๊ณง ์ฝ๋ ์คํ์
๋๋ค. Gateway์ ์คํฌ/MCP ํ ๊ธ ์๋ํฌ์ธํธ๋ ์ด ํ๋๋ฅผ ๋ณด์กดํ์ง๋ง `extensions.middlewares`์ ๋ํ API ์ฐ๊ธฐ ๊ฒฝ๋ก๋ ์ ๊ณตํ์ง ์์ต๋๋ค. ๋ฆฌ๋ ์์ด์ ํธ ์ ์ฉ/์๋ธ์์ด์ ํธ ์ ์ฉ ๋ฏธ๋ค์จ์ด ๋ชฉ๋ก์ ๋ฐ๋ก ์ง์ ํ๋ ๊ธฐ๋ฅ์ ์์ง ์ง์๋์ง ์์ต๋๋ค.
ํจํค์งํ๋๊ณ ์ค์ ๊ฐ๋ฅํ ๋ฐํ์ ํตํฉ์๋ DeerFlow์ ํ์ฅ ๊ด๋ฆฌ์๋ฅผ ์ฌ์ฉํ์ธ์. ํ์ฅ ๊ด๋ฆฌ์๋ Python ํจํค์ง ์๊ตฌ ์ฌํญ, ๊ณต๊ฐ HTTPS Git URL, ๋๋ ๋ก์ปฌ ๋๋ ํฐ๋ฆฌ๋ฅผ ๋ฐ์ ๋ฐฑ์๋ ์ ์ฉ `extensions` ์์กด์ฑ ๊ทธ๋ฃน์ ํจํค์ง๋ฅผ ์ค์นํ๊ณ , `backend/uv.lock`์ ์
๋ฐ์ดํธํ๋ฉฐ, ์์ ์์๋ง ์ฝ๋ `config.yaml`์ ์ต์์ `plugins:` ๋ชฉ๋ก์ ํ์ฑํ๋ ํญ๋ชฉ์ ์ถ๊ฐํฉ๋๋ค.
```bash
# PyPI โ pin a version for a reproducible deployment
make extension-install SOURCE="deerflow-extension-acme==1.2.3"
# Public HTTPS Git โ pin an immutable commit
make extension-install \
SOURCE="git+https://github.com/acme/deerflow-extension-acme.git@0123456789abcdef0123456789abcdef01234567"
# Local package โ an absolute path avoids Make's backend-relative working directory
make extension-install SOURCE="$PWD/examples/deerflow-extension-example"
make extension-list
make extension-upgrade SOURCE="$PWD/examples/deerflow-extension-example"
make extension-disable NAME=acme
make extension-enable NAME=acme
make extension-remove NAME=acme
```
ํจํค์ง ์ค์น ๊ณผ์ ์์ Python ๋น๋ ํ
์ด ์คํ๋ ์ ์๊ณ , ๋ถ๋ฌ์จ ํ์ฅ์ ์ดํ Gateway ๊ถํ์ผ๋ก ์คํ๋๊ธฐ ๋๋ฌธ์ ์ค์น๋ ๋ํํ์ผ๋ก ์งํ๋ฉ๋๋ค. ์ด๋ฏธ ๊ฒํ ํ ์์ค๋ผ๋ฉด ์๋ํ์์ `cd backend && uv run --frozen --no-group extensions deerflow extensions install --yes`๋ก ์ด ๊ฒฝ๊ณ๋ฅผ ๋ช
์์ ์ผ๋ก ์ธ์ ํ ์ ์์ต๋๋ค. ํ์ฅ ๊ด๋ฆฌ์์๋ uv 0.8.0 ์ด์์ด ํ์ํ๋ฉฐ, ์ ๊ณต๋๋ Docker ์ด๋ฏธ์ง๋ uv 0.11.1๋ก ๊ณ ์ ๋์ด ์์ต๋๋ค. ๋๋จธ์ง ์ง์ ๋ช
๋ น์ `deerflow extensions upgrade SOURCE`, `list`, `enable NAME`, `disable NAME`, `remove NAME`์
๋๋ค. `NAME`์๋ ํ์ฅ ์ด๋ฆ, Python ๋ฐฐํฌํ, ๋๋ `module:install` ๊ฐ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์์ค URL์ ์๊ฒฉ ์ฆ๋ช
์ ๋ฃ์ง ๋ง์ธ์. URL์ ํฌํจ๋ userinfo๋ ์๊ฒฉ ์ฆ๋ช
์ฒ๋ผ ๋ณด์ด๋ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ด์ URL์ uv๊ฐ ์คํ๋๊ธฐ ์ ์ ๊ฑฐ๋ถ๋ฉ๋๋ค. ์๊ฒฉ Git ์์ค๋ ๊ณต๊ฐ HTTPS๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ๊ธฐ๋ณธ Docker ๋น๋๊ฐ ํธ์คํธ์ SSH ์๊ฒฉ ์ฆ๋ช
์ ์ ๋ฌํ์ง ์๊ธฐ ๋๋ฌธ์ SSH Git URL์ ๊ฑฐ๋ถ๋ฉ๋๋ค. ๋ฃจํ๋ฐฑ URL์์ ์ค์นํ๋ ๊ฒ์ ๋ก์ปฌ ๋๊ตฌ์ฉ์ผ๋ก ํ์ฉ๋์ง๋ง ๊ฒฝ๊ณ ๊ฐ ํ์๋ฉ๋๋ค. lock์ ๊ธฐ๋ก๋ `127.0.0.1`์ Docker ๋น๋ ์์์๋ ๋ค๋ฅธ ๋จธ์ ์ ๊ฐ๋ฆฌํค๊ธฐ ๋๋ฌธ์
๋๋ค.
๊ด๋ฆฌ๋๋ ํจํค์ง๋ ์ ํํ ํ๋์ ํ์ค PEP 621 ์ํธ๋ฆฌ ํฌ์ธํธ๋ฅผ ์ ์ธํฉ๋๋ค.
```toml
[project.entry-points."deerflow.extensions"]
acme = "acme_deerflow_extension:install"
```
์ด callable์ ๋
๋ฆฝํ `deerflow-extension-api` ๊ณ์ฝ์ ์ฌ์ฉํ๋ฉฐ ์ฌ๋ฌ ์ข
๋ฅ์ ๊ธฐ์ฌ๋ฅผ ๋ฑ๋กํ ์ ์์ต๋๋ค. ๋ฑ๋กํ ์ ์๋ ๊ธฐ์ฌ๋ ๋ฆฌ๋ ์์ด์ ํธ/์๋ธ์์ด์ ํธ์ ์๋ฏธ์ ๋ชจ๋ธ ์์น ๋๋ ๋๊ตฌ ์์น์ ๋์ด๋ ๊ฒฉ๋ฆฌ๋ ๋ฏธ๋ค์จ์ด, ๋ฆฌ๋ ์์ด์ ํธ ๋ฐ ์๋ธ์์ด์ ํธ ์์
์๋ช
์ฃผ๊ธฐ ํ
, ๋ฏธ๋ค์จ์ด ๋ชจ๋ธ ํธ์ถ ํ
์ผ๋ก ๊ฐ์ธ์ง์ง ์๋ DeerFlow ์์ฒด ๋ชจ๋ธ ํธ์ถ(๋ชฉํ, ๋ฉ๋ชจ๋ฆฌ, ์ ๋ชฉ, ์์ฝ)์ ๋ํ ์ต์ ๋ฒ, Gateway ์๋ช
๋์ ์ ์ง๋๋ ์๋น์ค, ๊ทธ๋ฆฌ๊ณ ์ฆ์ ๋ก๋๋๋ FastAPI HTTP ๋ผ์ฐํฐ์
๋๋ค. ๊ณ์ฝ ํจํค์ง์๋ ํ๋ ์์ํฌ ์์กด์ฑ์ด ์์ผ๋ฏ๋ก, ํ์ฅ์ ์์ ์ด importํ๋ FastAPI, LangChain, LangGraph ๋๋ ๊ธฐํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ง์ ์ ์ธํด์ผ ํฉ๋๋ค. [๊ฐ์ ธ์จ ์ฝํ
์ธ ๊ฒ์ฌ ์์ ](examples/deerflow-extension-jev-screening/README.md)๋ ์ด๋ฌํ ๋ฏธ๋ค์จ์ด ํ๋๋ฅผ ๊ฐ์ ๋๊ตฌ ์์น์ ๊ธฐ์ฌํฉ๋๋ค. ์ด์์๊ฐ ๋ช
์์ ์ผ๋ก ์ผ๋ฉด ์๊ฒฉ ๋๊ตฌ ๊ฒฐ๊ณผ๊ฐ ๋ชจ๋ธ์ ๋ณด์ฌ ์ฃผ๋ ์ ์ ๋ ํ
์คํธ(`pii_redaction`์ด ํ์ฑํ๋ ๊ฒฝ์ฐ PII๊ฐ ๋ง์คํน๋ ํ
์คํธ)๋ฅผ ๋ถ๋ฅํ๊ณ , ์๋ช
์ฃผ๊ธฐ ์ํ ์
๋ฐ์ดํธ๋ฅผ ํตํด ๊ถ๊ณ ์ฑ ๊ฒฝ๊ณ ๋ฅผ ์ถ๊ฐํฉ๋๋ค. ์ด ์์ ๋ ํ์ฅ ๊ณ์ฝ๋ง importํฉ๋๋ค.
ํ์คํ ๊ธฐ์ฌ๋ [ํ๋ฌ๊ทธ์ธ API](docs/full-stack-plugins.md)๋ฅผ ํตํด ๋ธ๋ผ์ฐ์ ํ์ด์ง, ๋ํ ์ก์
, ์ธ์ฆ๋ ๋ฐฑ์๋ ์์
, ๋ชจ๋ธ ๋๊ตฌ๋ฅผ ์ถ๊ฐ๋ก ์ ๊ณตํ ์ ์์ต๋๋ค. ๋
๋ฆฝ๋ [๋ถ๋งํฌ ์์ ](examples/deerflow-extension-bookmarks/README.md)๋ ์์ ์ฌ์ฉ์ ๋ฐ์ดํฐ, ์์ฒด ์ฌ์ด๋๋ฐ ํ์ด์ง, ์ฝ๊ธฐ ์ ์ฉ ๊ฒ์ ๋๊ตฌ๋ฅผ ๊ฐ์ถ ํ๋์ ํจํค์ง๋ฅผ ๋ณด์ฌ ์ค๋๋ค. ๋ชจ๋ธ ๋๊ตฌ๋ `response_format="content_and_artifact"`์ `PluginToolResult`(extension-api 0.2.6)๋ก ๋ณ๋์ ๊ตฌ์กฐํ๋ ์ํฐํฉํธ๋ฅผ ์ตํธ์ธํ ์ ์์ต๋๋ค. ์ํฐํฉํธ ๊ฐ์ฒด์ ํค๋ ๋ชจ๋ ๊น์ด์์ ๋ฌธ์์ด์ด์ด์ผ ํฉ๋๋ค. ๊ธฐ์กด ๋๊ตฌ๋ JSON ํ
์คํธ ์ถ๋ ฅ์ ๊ทธ๋๋ก ์ ์งํฉ๋๋ค. [๋ก์ปฌ ๊ฒ์ ์์ ](examples/deerflow-extension-retrieval/README.md)๋ ์ธ๋ถ ์ง์ ์๋น์ค ์์ด ๋ฒ์๊ฐ ์ ํ๋ ์ฝ๊ธฐ ์ ์ฉ ๊ฒฐ๊ณผ์ ์ฒดํฌํฌ์ธํธ ์ฌ์์ ๋ณด์ฌ ์ค๋๋ค. ์ํฐํฉํธ๊ฐ ์ธ์ฉ์ ์๋์ผ๋ก ํ์ฑํํ์ง๋ ์์ต๋๋ค. ์ด ์์ ๋ ์ง์ญํ๋ ์ค์น ์๋ด ๋ฉํ๋ฐ์ดํฐ์ ํจ๊ป ํ์ฅ ์นดํ๋ก๊ทธ์๋ ํ์๋ฉ๋๋ค. ๋ถ๋งํฌ๋ฅผ ๋ค์ ์ด๋ฉด ํธ์คํธ๋ฅผ ํตํด ๋ํ์ ํ์ฌ ์์ด์ ํธ๊ฐ ํด์๋๋ฏ๋ก, ์ปค์คํ
์์ด์ ํธ ๋ํ๋ ์ด์ ๋ถ๋งํฌ๋ฅผ ํฌํจํด ์๋์ ์ฑํ
์ง์
์ ์ ์ ์งํฉ๋๋ค. ๋
๋ฆฝ๋ [์์ด์ ํธ ํ ์์ ](examples/deerflow-extension-agent-teams/README.md)๋ ์์ ํ ์ปค์คํ
์์ด์ ํธ๋ค์ด ๋ค์ดํฐ๋ธ `@` ๋ฉ์
, ๊ณต์ ๋ฉ์์ง, ๋น๋๊ธฐ ํผ์ด ์์ฒญ์ ํตํด ํ์
ํ๋๋ก ํ๋ฉฐ, ๋ณ๋์ ํ ํ์ด์ง์ ์์ ๋ฉค๋ฒ ๋ํ๋ฅผ ์ ๊ณตํฉ๋๋ค. Capability Center๋ ์ค์น ์ ์๋ ์ด ์์ ๋ฅผ ์ง์ญํ๋ ์ค์น ์ ๋ณด์ ํจ๊ป ๋์ดํฉ๋๋ค. ์ค์น์ ํ์ฑํ๋ ๊ณ์ ๋ฐฐํฌ ์ธก์์ ์ ์ดํ๋ฉฐ, Capability Center๋ ํ๋ฌ๊ทธ์ธ ์ ๋ณด์ ์ํ๋ฅผ ๋ณด์ฌ ์ค๋๋ค. ๋ธ๋ผ์ฐ์ ์ฝ๋๋ ์ ๋ขฐ๋ ๋์ผ ์ถ์ฒ(same-origin) ์ฝ๋๋ก ์คํ๋ฉ๋๋ค. ๋ธ๋ผ์ฐ์ API์ ์ธ๋ผ์ธ `BrowserModule.code` ์ ์ก ๋ฐฉ์์ ์คํ์ ์
๋๋ค. ํ๋ฌ๊ทธ์ธ ๊ฐ์ด๋๋ ๋งค๋ํ์คํธ์ ํจํค์งํ๋ ์ ์ ๋ฆฌ์์ค๋ก ๋์๊ฐ๋ ์ถ๊ฐ ๊ฒฝ๋ก๋ฅผ ์ค๋ช
ํฉ๋๋ค.
DeerFlow๋ ๋ฏธ๋ค์จ์ด, ์๋ช
์ฃผ๊ธฐ, ์์คํ
๋ชจ๋ธ ๊ด์ฐฐ์ ๋ํด์๋ง ์์
๋ฒ์์ ํ์ฅ ์ ์ฅ์๋ฅผ ํ ๋นํฉ๋๋ค. ์๋น์ค๋ Gateway ์์์ฑ ๊ณ์ธต์ด ์ค๋น๋ ํ ์ฑ ๋ฒ์์ ๋ฐํ์ ์์กด์ฑ์ ๋ฐ๊ณ , ํ์ฑ ์คํ์ด ๋ชจ๋ ๋๋ ํ ์ญ์์ผ๋ก ์ค์ง๋ฉ๋๋ค. ์ ํ ์ฌํญ์ธ `ExtensionRuntimeDeps.run_evidence_reader`๋ ๊ฐ์ฌ, ํ๊ฐ, ๋๊ธฐํ, ๊ด์ธก์ฑ ์๋น์ค๋ฅผ ์ํ ์์ ์ ์ธ ์ฝ๊ธฐ ์ ์ฉ ์ธํฐํ์ด์ค์
๋๋ค. ๋ถํฌ๋ช
ํ๊ณ ์ฌ๊ฐ ๊ฐ๋ฅํ ์ปค์๋ก ๋ณ๊ฒฝ๋ ์คํ์ ์ฐพ๊ณ , `after_seq`๋ก ์๋ ค์ง ์คํ์ ์ ์ฅ๋ ์ด๋ฒคํธ๋ฅผ ํ์ด์ง ๋จ์๋ก ๊ฐ์ ธ์ค๋ฉฐ, ๊ถ์ ์๋ ์คํ ์ํ๋ฅผ ์ด๋ฒคํธ ๊ทผ๊ฑฐ์ ๋ณ๋๋ก ์ฝ์ต๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ธฐ๋ฐ ์คํ ์ ์ฅ์๋ Gateway๋ฅผ ์ฌ์์ํด๋ ํ์ ์ปค์๋ฅผ ์ ํจํ๊ฒ ์ ์งํ๋ฉฐ, ๋ฉ๋ชจ๋ฆฌ ์คํ ์ ์ฅ์๋ ํ์ฌ ํ๋ก์ธ์ค ์๋ช
๋์์๋ง ๊ฐ์ ์์๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด๋ฒคํธ ๋ฉํ๋ฐ์ดํฐ๋ ์ด ๊ฒฝ๊ณ์์ ์ํฌ๋ฆฟ์ด ๋ง์คํน๋์ง๋ง, ์ด๋ฒคํธ ๋ด์ฉ์ ๋ณ๊ฒฝ ์์ด ๋ฐํ๋ฉ๋๋ค. ๋ ํ์ด๋ก๋ ๋ชจ๋ ๋ถ๋ฆฌ๋ ์ค๋
์ท์ด๋ฏ๋ก, ์ค์ฒฉ๋ ๊ฐ์ ์์ ํด๋ ํธ์คํธ์ ์ ์ฅ๋ ๊ทผ๊ฑฐ๋ ๋ฐ๋์ง ์์ต๋๋ค. ํ๋ก๋์
Gateway๋ ์ ๋ขฐ๋ ์ด์์ ํ์ฅ์ ์ฑ ๋ฒ์์ ์ฌ์ฉ์ ๊ฐ(cross-user) ๋ฆฌ๋๋ฅผ ์ ๊ณตํ๋ฉฐ, ์๋ฒ ๋๋ ํธ์คํธ๋ ๊ฐ์ ์ด๋ํฐ๋ฅผ ํ ์ฌ์ฉ์์๊ฒ ๋ฐ์ธ๋ฉํ ์ ์์ต๋๋ค. ๋ณ๊ฒฝ๋ ์คํ ํ์ด์ง์๋ ๋ณด์กด๋ ํ์ ์์ฑ๊ณผ ๋ณ๊ฒฝ์ด ๋ด๊ธฐ๋ฉฐ, ์ญ์ ํผ์คํค์ ํฌํจ๋์ง ์์ต๋๋ค. ์ญ์ ๋ฅผ ์กฐ์ (reconciliation)ํด์ผ ํ๋ ์๋น์๋ ์๋ ค์ง ์คํ์ ์ํ๋ฅผ ํด๋งํ๊ณ ๊ฒฐ๊ณผ๊ฐ ์์ผ๋ฉด ์กด์ฌํ์ง ์๋ ๊ฒ์ผ๋ก ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค. ํ์ฅ์ ์ฌ์ ํ Gateway ๊ถํ์ผ๋ก ์คํ๋๊ณ ๋ ๊ฑฐ์ `session_factory`๋ฅผ ์ ์งํ๋ฏ๋ก, ์ด ๋ฆฌ๋๋ API ์์ ์ฑ๊ณผ ์๋์น ์์ ๊ถํ์ ์ต์ํํ๊ธฐ ์ํ ๊ฒฝ๊ณ์ผ ๋ฟ, ์ ๋ขฐํ ์ ์๋ Python ํจํค์ง๋ฅผ ์ํ ์๋๋ฐ์ค๊ฐ ์๋๋๋ค. ํ์ฅ HTTP ๋ผ์ฐํฐ๋ ๋ชจ๋ ํธ์คํธ ๋ผ์ฐํธ ๋ค์์ ๋ง์ดํธ๋ฉ๋๋ค. ํ์คํ๊ฒ ๊ฐ๋ ค์ง๋(shadow) ๋ผ์ฐํธ์ ํธ์คํธ์ ์ธ์ฆ ์์ธ ๊ฒฝ๋ก ๋๋ CSRF ์์ธ ๊ฒฝ๋ก๋ก ๋ค์ด๊ฐ๋ ๋ผ์ฐํธ๋ ์ถ์ฒ๊ฐ ๋ช
์๋ ์ง๋จ๊ณผ ํจ๊ป ๊ฑฐ๋ถ๋๋ฉฐ, ๊ด๋ จ ์๋ ๋ผ์ฐํฐ๋ ๊ณ์ ๋ก๋๋ฉ๋๋ค. ํธ์คํธ์ ๊ณต๊ฐ ๊ฒฝ๋ก๋ ํ์ฅ์ด ์ง์
ํ ์ ์๋ ์์ฝ๋ ์ ๋์ฌ ๋ชฉ๋ก์ด๋ฏ๋ก **๊ธฐ์ฌ๋ ๋ชจ๋ ์๋ํฌ์ธํธ์๋ ์ธ์ฆ๋ ์ธ์
์ด ํ์ํฉ๋๋ค**. ํ์ฌ ํ์ฅ์ด ์ธ์ฆ๋์ง ์์ ๋ผ์ฐํธ๋ฅผ ๋
ธ์ถํ ๋ฐฉ๋ฒ์ ์์ผ๋ฏ๋ก, ์์ ํ๋ก๋ฐ์ด๋ ์นํ
๊ณผ ๊ณต๊ฐ ์ํ ์๋ํฌ์ธํธ๋ ์ด๋ฒ ๋ฆด๋ฆฌ์ค์ ๋ฒ์์ ํฌํจ๋์ง ์์ต๋๋ค. ๊ทธ ์์์ ํ์ฅ์ `deerflow_extension_api.auth`๋ฅผ ํตํด ์ผ๋ฐ ์ฌ์ฉ์์ ๊ด๋ฆฌ์๋ฅผ ๊ตฌ๋ถํฉ๋๋ค. `resolve_principal(request)`๋ ํธ์ถ์๋ฅผ ๋ฐํํ๊ณ , `require_admin(request)`๋ ๊ด๋ฆฌ์๊ฐ ์๋ ๋ชจ๋ ํธ์ถ์์ ๋ํด `PermissionError`๋ฅผ ๋ฐ์์ํค๋ฉฐ ์๋ณ ์ ๋ณด๋ฅผ ํ์ธํ ์ ์์ผ๋ฉด ์คํจ ์ ์ฐจ๋จ(fail closed)ํฉ๋๋ค. ํ์ฅ์ ํธ์คํธ์ ์ธ์ฆ ์ปจํ
์คํธ๊ฐ ์๋๋ผ ์ฌ์ฉ์ ID, ๊ด๋ฆฌ์ ํ๋๊ทธ, ๋ด๋ถ ํ๋๊ทธ, ์ญํ ๋ก ๊ตฌ์ฑ๋ ํฌ์(projection)๋ง ๋ฐ์ต๋๋ค. ๋ผ์ฐํฐ startup/shutdown ํ
, ์ปค์คํ
lifespan, Mount, WebSocket ๋ผ์ฐํธ๋ ํ์ฉ๋์ง ์์ต๋๋ค. ์๋ช
๋์ ์ ์ง๋๋ ๋ฆฌ์์ค๋ `ExtensionService`์ ๋์ด์ผ ํ๋ฉฐ, WebSocket ๊ธฐ์ฌ์๋ ํฅํ ํธ์คํธ๊ฐ ์์ ํ๋ ์ธ์ฆ/Origin ๋ํผ๊ฐ ํ์ํฉ๋๋ค. ์๋ช
์ฃผ๊ธฐ ์ฝ๋ฐฑ๊ณผ ์์คํ
๋ชจ๋ธ ์ฝ๋ฐฑ์ ๊ฒฉ๋ฆฌ๋ ๋ฃจํ์์ ์คํ๋๋ ์๋ธ์์ด์ ํธ๋ฅผ ํฌํจํด Gateway์ ์ ๊ท ์๋ฆผ ๋ฃจํ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์ฌ์ฉ์ ๋์ ํ์ฅ ๋ผ์ฐํธ๋ `deerflow_extension_api.require_run_evidence_reader(request)`(extension API 0.2.2+)๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค. Gateway๋ ์ธ์ฆ๋ `runs:read` ๊ถํ์ ์๊ตฌํ๊ณ , ๊ด๋ฆฌ์์ ๋ด๋ถ ํธ์ถ์๋ฅผ ํฌํจํด ๋ฆฌ๋์ ๋ฒ์๋ฅผ ํด๋น ์ฌ์ฉ์๋ก ๊ณ ์ ํฉ๋๋ค. ํธ์ถ์๊ฐ ์ ๊ณตํ ID๋ก๋ ์ด ๋ฒ์๋ฅผ ๋ฐ๊ฟ ์ ์์ต๋๋ค. ๋ณผ ์ ์๋ ์คํ๊ณผ ์กด์ฌํ์ง ์๋ ์คํ์ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ฉฐ, ๋ณ๊ฒฝ๋ ์คํ ์ปค์๋ ์ฌ์ฉ์ ๊ฐ์ ์ง์ ์ฌ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ ํ ์ฌํญ์ธ `resolve_run_evidence_reader(request)`๋ ํธ์คํธ๊ฐ ์ด ๊ธฐ๋ฅ์ ์ง์ํ์ง ์์ผ๋ฉด `None`์ ๋ฐํํ๊ณ , ํ์ ํฌํผ๋ ๋์ `NotImplementedError`๋ฅผ ๋ฐ์์ํต๋๋ค. ์ ๊ทผ์ด ๊ฑฐ๋ถ๋๋ฉด `PermissionError`๊ฐ ๋ฐ์ํฉ๋๋ค. ๋ผ์ฐํธ๋ ์ด ์์ธ๋ค์ ๊ฐ๊ฐ HTTP 503๊ณผ 403์ผ๋ก ๋งคํํด์ผ ํ๋ฉฐ, ๋ฆฌ์กธ๋ฒ๊ฐ ์คํจํด๋ ์ ๋ ์ ์ญ ์๋น์ค ๋ฆฌ๋๋ก ํด๋ฐฑํ์ง ์์ต๋๋ค.
ํ์ฅ ์๋น์ค๋ ์ ํ์ ์ผ๋ก [ํธ์คํธ ๋ชจ๋ธ ํธ์ถ๊ธฐ](backend/docs/extension-model-invocation.md)(extension API 0.2.4+)๋ฅผ ๋ฐ์ ์ ์์ต๋๋ค. ์ด์์๋ `plugins[].host_access.model_invocation` ์๋์ ํ์ฉํ ๋
ผ๋ฆฌ์ ์ญํ ์ ๋ช
์์ ์ผ๋ก ๋งคํํ๋ฉฐ, ํธ์คํธ๊ฐ ์๊ฒฉ ์ฆ๋ช
, ๋์์ฑ, ํ์์์, ์คํค๋ง ๊ฒ์ฆ๋ ์ถ๋ ฅ์ ์ฒ๋ฆฌํฉ๋๋ค. ์น์ธ์ ์ํ์ด ์์ผ๋ฉฐ, ํ์์์๋ ํ๋ก๋ฐ์ด๋ ์์
์ ์๋ฃ๋ ๋๊น์ง ๋์์ฑ ์ฌ๋กฏ์ ๊ณ์ ์ ์ ํ๊ณ , ์คํค๋ง ๊ฒ์ฆ์ ์ข
๋ฃ ๊ฐ๋ฅํ ์์ ํ๋ก์ธ์ค์์ ์คํ๋ฉ๋๋ค. ํ๋ก๋ฐ์ด๋ ์์ฒด์ ์ทจ์๋ `ModelInvocationFailed`๊ฐ ๋์ง๋ง, ํธ์ถํ๋ ํ์ฅ ์์
์ ์ทจ์๋ ์ฌ์ ํ ์ ์์ ์ผ๋ก ์ ํ๋ฉ๋๋ค. ๊ถํ์ด ๋ถ์ฌ๋์ง ์์ผ๋ฉด ์ด ๊ธฐ๋ฅ์ `None`์
๋๋ค.
ํ๋ฌ๊ทธ์ธ ์์๋ ๊ฒฐ์ ์ ์ด๋ฉฐ, ํ๋ฌ๊ทธ์ธ๋ณ ์ค์ ์ `install()`์ ์ ๋ฌ๋๊ณ , `required: true`์ด๋ฉด ๋ก๋ ์คํจ ์ ์์์ด ์ค๋จ๋ฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์คํจ๊ฐ ๋ณด๊ณ ๋๊ณ ํด๋น ํ๋ฌ๊ทธ์ธ์ ๊ฑด๋๋๋๋ค. `enabled: false`์ด๋ฉด ํด์๊ณผ import๋ฅผ ๊ฑด๋๋๋๋ค. ํ์ฅ ๊ด๋ฆฌ์๋ ํ์ฅ์ ํ ๊ธํ ๋ ํ์ฅ์ ๋น๊ณต๊ฐ `config`๋ฅผ ๋ณด์กดํ๋ฉฐ, ๊ด๋ฆฌ๋๋ ์ค์น์ ๋ํด `name`, `package`, `use`, `enabled`, `required` ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋กํฉ๋๋ค. ์ค์น๋ `required: false`๋ก ๊ธฐ๋ก๋๋ฏ๋ก, ๋์ค์ ๊ณ ์ฅ ๋ ํ์ฅ์ Gateway ์์์ ๋ง๋ ๋์ ๋ณด๊ณ ๋ฉ๋๋ค. ํจํค์ง๊ฐ ์์ ๋ ์์์ ์ค๋จํด์ผ ํ๋ค๋ฉด `extensions install --required`๋ฅผ ์ ๋ฌํ์ธ์. ํ๋ฌ๊ทธ์ธ์ Gateway ์ฑ์ด ์์ฑ๋ ๋ ํ ๋ฒ ๋ก๋๋๋ฏ๋ก, ์ค์น, ํ์ฑํ, ๋นํ์ฑํ, ์ ๊ฑฐ, ๊ทธ๋ฆฌ๊ณ `plugins:`๋ฅผ ์๋์ผ๋ก ํธ์งํ๋ ๊ฒฝ์ฐ ๋ชจ๋ Gateway๋ฅผ ์ฌ์์ํด์ผ ํฉ๋๋ค. ์ด๋ Python ์ฝ๋๋ฅผ importํ๋ ์์
์ด๋ฏ๋ก, `plugins:`๋ ์๋์ ์ผ๋ก API๋ก ์ธ ์ ์๋ `extensions_config.json`์ ํตํด์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๊ด๋ฆฌ ๋ช
๋ น์ `uv run --frozen --no-group extensions`๋ฅผ ํตํด ํ์ฅ ๊ทธ๋ฃน ์์ด ์ฒดํฌ์์ ํ๊ฒฝ์ ๋ถํธ์คํธ๋ฉํฉ๋๋ค. frozen ๋ชจ๋ ๋๋ถ์ ์ค์น๋ ํ์ฅ์ ์๊ฒฉ ์์ค๋ ๊ด๋ฆฌ ์ค๋
์ท์ ์ฌ์ฉํ ์ ์๊ฒ ๋ ๊ฒฝ์ฐ์๋ `disable`๊ณผ `remove`๋ฅผ ์์ํ ์ ์์ผ๋ฉฐ, ์๋ก์ด ์ฒดํฌ์์์์๋ ๊ธฐ์กด lock์ผ๋ก ํ์ฅ ์ด์ธ์ ํ๊ฒฝ์ ๋ง๋ค ์ ์์ต๋๋ค. ์ดํ์ ์ ๊ธด(locked) ์์กด์ฑ ํธ๋์ญ์
์ ํ์ฅ ๊ด๋ฆฌ์๊ฐ ์ง์ ๋ด๋นํฉ๋๋ค. ํ๋์ ์ฒดํฌ์์์ ๋ํ ๋ณ๊ฒฝ ์์
์ ํ๋ก์ธ์ค ์ ๊ธ์ผ๋ก ์ง๋ ฌํ๋ฉ๋๋ค. ํ์ฅ ์์
์ด ์คํจํ๋ฉด ์์กด์ฑ ํ์ผ๊ณผ ์ค์ ์ด ์๋ ํ์ผ ๊ถํ๊ณผ ํจ๊ป ์์์ ์ผ๋ก ๋ณต์๋๋ฏ๋ก, ๊ทธ๋ฃน ๊ถํ์ผ๋ก ํ์ผ์ ์ฝ๋ Gateway์ ์ ๊ทผ์ด ์ ์ง๋ฉ๋๋ค. ์ด๊ธฐ ํ์ฅ ๊ด๋ฆฌ์ ๊ธฐ๋ฅ์ ์ ์๋ฆฌ ์
๊ทธ๋ ์ด๋๊ฐ ์๋๋ผ ์์ฑ/์ ๊ฑฐ ๋ฐฉ์์
๋๋ค. ์ค์น๋ ์์ค๋ฅผ ๋ณ๊ฒฝํ๋ ค๋ฉด ๋น๊ณต๊ฐ `plugins[].config`๋ฅผ ์ ์ฅํด ๋๊ณ , ํ์ฅ์ ์ ๊ฑฐํ ๋ค, ์๋ก ๊ณ ์ ํ ๋ฒ์ ์ ๋ค์ ์ค์นํ๊ณ , ์ ์ฅํ ์ค์ ์ ๋ณต์ํ์ธ์.
๋ก์ปฌ ๋๋ ํฐ๋ฆฌ ์ค์น๋ `backend/extensions/sources//`์ ๋ณต์ฌ๋๋ฉฐ, ์๋ ๋๋ ํฐ๋ฆฌ๊ฐ ์๋๋ผ ์ด ๋ฐฐํฌ ๊ฐ๋ฅํ ์ค๋
์ท์ด lock์ ๊ธฐ๋ก๋ฉ๋๋ค. Git ๋ฉํ๋ฐ์ดํฐ, ๊ฐ์ ํ๊ฒฝ, ๋ฐ์ดํธ์ฝ๋ ์บ์, ์ฌ๋ณผ๋ฆญ ๋งํฌ, ์๊ฒฉ ์ฆ๋ช
์ผ๋ก ๋ณด์ด๋ ํ์ผ์ ์ค๋
์ท ๋ด์ฉ์ผ๋ก ํ์ฉ๋์ง ์์ต๋๋ค. ๊ทธ๋๋ ์ค์นํ๋ ๋ด์ฉ์ ์ง์ ๊ฒํ ํ์ธ์. ์ค์๋ก ํฌํจ๋ ํ์ผ์ ๊ฑธ๋ฌ๋ธ๋ค๊ณ ํด์ ํ์ฅ์ด๋ ๊ทธ ๋น๋ ๋ฐฑ์๋, ๋ฐํ์ ์ฝ๋๊ฐ ์๋๋ฐ์ค์ ๊ฒฉ๋ฆฌ๋๋ ๊ฒ์ ์๋๋๋ค.
๋ก์ปฌ `make dev`/`make start`, Docker ๊ฐ๋ฐ ํ๊ฒฝ, ํ๋ก๋์
Gateway ์ด๋ฏธ์ง๋ ๋ชจ๋ ๊ฐ์ `backend/pyproject.toml`๊ณผ `backend/uv.lock`์ ์ฌ์ฉํฉ๋๋ค. ๋ก์ปฌ ๋ฐ Docker ๊ฐ๋ฐ ๋ฐ์ฒ๋ ์์ ์ ์ ์ ๊ธด ๋๊ธฐํ๋ฅผ ์ํํ๋ฉฐ, ํ๋ก๋์
์ด๋ฏธ์ง๋ ๋น๋ ์ค์ ์ด ๋๊ธฐํ๋ฅผ ์ํํ๊ณ ๊ด๋ฆฌ๋๋ ๋ก์ปฌ ์ค๋
์ท์ ๋น๋ ์ปจํ
์คํธ์ ํฌํจํฉ๋๋ค. ์ดํ Gateway ๋ฐํ์ ๋ช
๋ น์ ํจํค์ง๋ฅผ ํด์ํ๊ฑฐ๋ ์ค์นํ์ง ์๊ณ ์ด๋ฏธ ์์ฑ๋ ํ๊ฒฝ์ ์ฌ์ฉํฉ๋๋ค. ๋ก์ปฌ ๋ฐ Docker ๊ฐ๋ฐ ํ๊ฒฝ์ ์์ ์ ๋๊ธฐํ๋ ๋๋ฝ๋ ์ ๊ธด ์ํฐํฉํธ๋ฅผ ๋ค์ด๋ก๋ํ ์ ์์ต๋๋ค. ๋ฐ๋ฉด ํ๋ก๋์
๋ฐฐํฌ๋ ๋ช
์์ ์ธ ์ค์น๋ ์ด๋ฏธ์ง ๋น๋ ์ค์๋ง ์ด๋ฅผ ๋ค์ด๋ก๋ํ๋ฉฐ, ๊ทธ ๊ฒฐ๊ณผ๋ก ๋ง๋ค์ด์ง ํ๋ก๋์
Gateway ์ปจํ
์ด๋๋ฅผ ์์ํ ๋๋ ์ ๋ ๋คํธ์ํฌ์์ ํ์ฅ์ ํด์ํ๊ฑฐ๋ ์ค์นํ์ง ์์ต๋๋ค. ๋ก์ปฌ wheel์ด๋ `file://` Git URL์ Docker ๋น๋ ์ปจํ
์คํธ์ ์กด์ฌํ์ง ์์ผ๋ฏ๋ก ๊ฑฐ๋ถ๋ฉ๋๋ค. ๋์ ์์ค ๋๋ ํฐ๋ฆฌ๋ฅผ ์ ๋ฌํด ๊ด๋ฆฌ ์ค๋
์ท์ ๋ง๋์ธ์. ํ๊ฒฝ ์ค์ (์: `UV_FIND_LINKS` wheelhouse)์ ๋ฐ๋ผ ์ผ๋ฐ ํจํค์ง ์ด๋ฆ์ด ์ฌ์ ํ ๋ก์ปฌ wheel๋ก ํด์๋ ์ ์์ผ๋ฏ๋ก, ํ์ฅ ๊ด๋ฆฌ์๋ ํ์ฅ์ ํ์ฑํํ๊ธฐ ์ ์ ๋ชจ๋ ์ lock์ ๊ฐ์ฌํฉ๋๋ค. ๊ธฐ๋ณธ ์ด๋ฏธ์ง ๋น๋๊ฐ ์ฌํํ ์ ์๋ ๋ก์ปฌ ์ฐธ์กฐ๊ฐ ํ๋๋ผ๋ ์์ผ๋ฉด ์ค์น ๋๋ ์ ๊ฑฐ ์ ์ฒด๊ฐ ๋กค๋ฐฑ๋ฉ๋๋ค. ๊ด๋ฆฌ๋๋ ํ์ฅ ๊ตฌ์ฑ์ ๋ณ๊ฒฝํ ํ์๋ `make up`์ผ๋ก ๋ค์ ๋น๋ํ์ธ์. ์ ์ฒด ์์๋ `config.example.yaml`๊ณผ [์ฐธ์กฐ ํ์ฅ](examples/deerflow-extension-example/)์ ์ฐธ๊ณ ํ์ธ์.
Gateway๊ฐ ์์ฑํ๋ ํ์ ์ง๋ฌธ ์ ์์ ์ด์ JSON ๋ฐฐ์ด ์๋ต์ ํ์ฑํ๊ธฐ ์ ์ ์ผ๋ฐ ๋ฌธ์์ด ๋ชจ๋ธ ์ถ๋ ฅ๊ณผ ๋ธ๋ก/๋ฆฌ์คํธ ํ์์ ๋ฆฌ์น ์ฝํ
์ธ ๋ฅผ ๋ชจ๋ ์ ๊ทํํ๋ฏ๋ก, ํ๋ก๋ฐ์ด๋๋ณ ์ฝํ
์ธ ๋ํผ ๋๋ฌธ์ ์ ์์ด ์กฐ์ฉํ ๋๋ฝ๋์ง ์์ต๋๋ค. ํ์ ์ง๋ฌธ ์ ์๊ณผ ์
๋ ฅ ๋ค๋ฌ๊ธฐ๋ ๋ฌธ์์ด์ด ์๋ ํ์
์ ์ฝํ
์ธ ๋ธ๋ก์ ๊ฑด๋๋ฐ์ด, ์์ฒญ์ ์คํจ์ํค๋ ๋์ ์ฃผ๋ณ ํ
์คํธ๋ฅผ ๋ณด์กดํฉ๋๋ค
๊ฐ์ ์ฝํ
์ธ ๊ฐ์ง(empty-response, terminal-response, model-length ๋ฏธ๋ค์จ์ด๊ฐ ๊ณต์ ํ๋ `has_visible_content`)์ ์๋ธ์์ด์ ํธ ๋์คํจ์น ์ค๋
์ท(`ParentContextSnapshot.from_state`)์ ์ฝํ
์ธ ๋ธ๋ก ํ์
์ ์งํฉ ํฌํจ ์ฌ๋ถ๊ฐ ์๋๋ผ ๋๋ฑ ๋น๊ต๋ก ๊ฒ์ฌํฉ๋๋ค. ๋ฐ๋ผ์ ํ๋ก๋ฐ์ด๋๊ฐ `type: []`์ฒ๋ผ ํด์ํ ์ ์๋ ํ์
์ ๋ธ๋ก์ ๋ด๋ณด๋ด๋๋ผ๋ ๋ฏธ๋ค์จ์ด ์ฒด์ธ ๋ฐ์ผ๋ก TypeError๋ฅผ ๋ฐ์์ํค๋ ๋์ ํด๋น ๋ธ๋ก๋ง ๊ฑด๋๋ฐ๊ณ ์ฃผ๋ณ ๊ธฐ๋ก์ ์ ์งํฉ๋๋ค
๋ฐฑ์๋ ์๋ต ์ ๋ฆฌ๋ ํ์ ์ง๋ฌธ ์ ์๊ณผ ๋ค๋ฌ์ ์ด์์์ ``, `` ๊ฐ์ ๊ด๋ จ ์๋ ํ๊ทธ ์ด๋ฆ์ ๋ณด์กดํฉ๋๋ค. ์ ํํ ``๋ผ๋ ์ด๋ฆ(์ ํ์ ์ผ๋ก ๋ค์ ์์ฑ์ด ๋ถ์ ์ ์์)๋ง ์ถ๋ก ๋ธ๋ก์ ์์ํฉ๋๋ค. ์์ฒด ๋ซํ ํ๊ทธ ``์ ``๋ ๋น ์ถ๋ก ๋ธ๋ก์ด๋ฉฐ ๋ค๋ฐ๋ฅด๋ ๋ต๋ณ์ ๊ทธ๋๋ก ๋ก๋๋ค. ``์ฒ๋ผ ๋ฐ์ดํ๋ก ๋ฌถ์ธ ์์ฑ ์์ ๊ตฌ๋ถ ๊ธฐํธ๋ ๋ค๋ฐ๋ฅด๋ ๋ต๋ณ์ ๊ทธ๋๋ก ๋ก๋๋ค.
์น UI ์
๋ ฅ์ฐฝ์ ์ ์ก ์ ์ ์ด์ ์
๋ ฅ์ ๋ค๋ฌ์ ์ ์์ต๋๋ค. ๋ค์ ์ฐ๊ธฐ๋ `input_polish` ๋ชจ๋ธ ์ค์ ์ ์ฌ์ฉํ๋ ์งง์ Gateway LLM ์์ฒญ์ผ๋ก ์คํ๋๋ฉฐ, `/data-analysis` ๊ฐ์ ์ฌ๋์ ์คํฌ ์ ๋์ฌ๋ฅผ ์ ์งํ๊ณ , ์ฌ์ฉ์๊ฐ ๋ค๋ฌ๊ธฐ ๋ฒํผ์ ํด๋ฆญํ ํ์๋ง ๋ก์ปฌ ์ด์์ ๊ต์ฒดํฉ๋๋ค. ์ค๋ ๋ ์คํ์ ๋ง๋ค๊ฑฐ๋ ๋ฉ์์ง๋ฅผ ์์ ์ ์ฅํ์ง๋ ์์ต๋๋ค.
์์ด์ ํธ๊ฐ ํ์ธ ์ง๋ฌธ์ ์์ฒญํ๋ฉด ์น UI๋ ๊ตฌ์กฐํ๋ ์๋ต ์นด๋๋ฅผ ํ์ํ๋ ์ผ๋ฐ ์
๋ ฅ์ฐฝ๋ ๊ณ์ ์ฌ์ฉํ ์ ์๊ฒ ๋ก๋๋ค. ์ฌ์ฉ์๋ ์นด๋๋ฅผ ์์ฑํ๊ฑฐ๋, ์์ ํ์์ ์ฑํ
๋ฉ์์ง๋ฅผ ๋ณด๋ด ์นด๋๋ฅผ ๊ฑด๋๋ธ ์ ์์ต๋๋ค. ์ด ๋ฉ์์ง๋ ๊ฐ์ฅ ์ต๊ทผ์ ๋๊ธฐ ์ค์ธ ํ์ธ ์ง๋ฌธ์ ๋ซ๊ณ ์์ด์ ํธ์ ๋ค์ ์
๋ ฅ์ด ๋ฉ๋๋ค. ํจ๊ป ์ค๋ ๋ต๋ณ ํ
์คํธ๋ ์คํ ๋จ๊ณ ํจ๋ ๋ฐ์ ํ์๋๋ฉฐ, ์์ฒญ์ ๋ตํ๋ฉด ์์ด์ ํธ๊ฐ ์์
์ ๊ณ์ํ๋ ๋์ ์ด์ ์ ์๋ฃ๋ ํ
์คํธ๊ฐ ๋ํ์ ๊ทธ๋๋ก ๋จ์ต๋๋ค.
์น UI ์
๋ ฅ์ฐฝ์์ ๋ณด๋ด์ง ์์ ์ด์์ ํ์ด์ง๋ฅผ ๋ค์ ๋ถ๋ฌ์ค๊ฑฐ๋ ๊ฐ์ ๋ธ๋ผ์ฐ์ ํญ ์์์ ๋ํ๋ฅผ ์ ํํด๋ ์ ์ง๋ฉ๋๋ค. ์ด์์ ์ฌ์ฉ์, ์์ด์ ํธ, ๋ํ๋ณ๋ก ๊ฒฉ๋ฆฌ๋๋ฉฐ, ์ ํํ ์คํฌ๊ณผ ๋ช
์์ ๋ํ ์ฐธ์กฐ๋ฅผ ํฌํจํ๊ณ , ์ ์ก์ด ์๋ฝ๋๋ฉด ์ง์์ง๋๋ค. ์ค๋ ๋์ ์ด๋ฏธ ์ฒจ๋ถ๋ ํ๋ก์ ํธ ๋ฌธ์๋ ๋ค์ ๋ถ๋ฌ์จ ํ์ ์ ์ง๋์ง๋ง, ๋ธ๋ผ์ฐ์ ๋ก์ปฌ ์
๋ก๋์ ์ธ์ฉํ ๋ฉ์์ง ๋ฐ์ท๋ฌธ์ ์์ ์ ์ฅ๋์ง ์์ต๋๋ค.
์น UI ์
๋ ฅ์ฐฝ์ ์ปค์ ์์น์์ ๋๋ `@` ๋ฒํผ์ ํตํด `@` ์ฐธ์กฐ๋ฅผ ์ง์ํฉ๋๋ค. ๊ทธ๋ฃนํ๋ ์ ํ๊ธฐ์์ ํ์ฑํ๋ ์คํฌ, ํ์ฌ ํ๋ก์ ํธ์ ๋ฌธ์, ๋ค๋ฅธ ๋ํ๋ฅผ ๊ฒ์ํ ์ ์์ผ๋ฉฐ, ์ ํํ ์ฐธ์กฐ๋ ์ด์ ํ
์คํธ์ ํจ๊ป ์ธ๋ผ์ธ์ผ๋ก ํ์๋๊ณ ์ผ๋ฐ์ ์ธ ํธ์ง์ผ๋ก ์ ๊ฑฐํ ์ ์์ต๋๋ค. ํ๋์ ๋ฉ์์ง์์ ์ฌ๋ฌ ์คํฌ์ ์ ํํ ์ ์์ผ๋ฉฐ(๊ณ ์ ์คํฌ ์ต๋ 16๊ฐ), ์ฒดํฌ๋ ์คํฌ์ ๋ค์ ์ ํํ๋ฉด ์ ๊ฑฐ๋ฉ๋๋ค. ๊ฐ ์ ํ์ ํ์ฌ ์ฌ์ฉ์ ๋ ์ง์คํธ๋ฆฌ์ ์์ด์ ํธ ํ์ฉ ๋ชฉ๋ก์ ๋ํด ๊ฒ์ฌ๋ฉ๋๋ค. ํ๋ก์ ํธ ํ์ผ์ ์์ง(ingestion)์ด ์ฑ๊ณตํ ํ์๋ง ์ฒจ๋ถ๋ฉ๋๋ค. ๋ํ ์ฐธ์กฐ์๋ `read_conversation` ๊ธฐ๋ฅ์ด ํ์ํ๋ฉฐ ํด๋น ๊ธฐ๋ฅ์ ์คํ๋ณ ์ ํ์ด ๊ทธ๋๋ก ์ ์ฉ๋ฉ๋๋ค. ๊ธฐ๋ฅ ํ์์ ์คํจํ๋ฉด ์ ์ฅ๋ ๋ํ ์ฐธ์กฐ๋ ๊ทธ๋๋ก ์ ์ง๋๋ฉฐ, ์ ์ก์ ์ฌ์๋๊ฐ ์ฑ๊ณตํ ๋๊น์ง ๋๊ธฐํฉ๋๋ค. ๋ค๋ฌ๊ธฐ๋ ์ง์ ์ฌํญ์ ์์๊ฐ ๋ฐ๋์ด๋ ์ฐธ์กฐ ๋ ์ด๋ธ ์ ์ฒด๋ฅผ ๋ณด์กดํฉ๋๋ค. ํ์ผ ๊ทธ๋ฃน์์๋ ๋ก์ปฌ ์
๋ก๋๋ ์ ๊ณตํฉ๋๋ค. `/goal`, `/compact`, ๋ ๊ฑฐ์ `/skill-name` ์
๋ ฅ๋ ๊ณ์ ์ง์๋ฉ๋๋ค.
์ธ๋ผ์ธ ์ฐธ์กฐ๋ฅผ ๊ณ ๋ฅธ ํ์๋ ๊ทธ ๋ฐ๋ก ๋ค์์ ์ด์ด์ ์
๋ ฅํ ์ ์์ต๋๋ค. ์ปค์๋ฅผ ์ฎ๊ธฐ๋ฉด ์ฐธ์กฐ ์์ ํ
์คํธ๋ฅผ ํธ์งํ ๋๋ฅผ ํฌํจํด ์ ํํ ์์น๊ฐ ์ ์ง๋ฉ๋๋ค.
์น UI ์
๋ ฅ์ฐฝ์ ๋ธ๋ผ์ฐ์ ๊ฐ Web Speech API๋ฅผ ์ ๊ณตํ๋ ๊ฒฝ์ฐ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ฐ ์์ฑ ๋ฐ์์ฐ๊ธฐ๋ ์ง์ํฉ๋๋ค. ๋ง์ดํฌ ๋ฒํผ์ ์์ฑ์ ๋ก์ปฌ ์ด์์ผ๋ก๋ง ์ ์ฌํ๋ฉฐ, DeerFlow๋ ์ ์ฌ๋ ํ
์คํธ๋ง ๋ฐ์ต๋๋ค. ์ค๋์ค ์ฒ๋ฆฌ๋ ํด๋น ํ๊ฒฝ์ ์ ์ฑ
์ ๋ฐ๋ผ ๋ธ๋ผ์ฐ์ ๋๋ ์ด์ ์ฒด์ ์ ์์ฑ ์ธ์ ์๋น์ค์ ์์๋ฉ๋๋ค. ์ฌ์ฉ์๋ ์ ์ก ์ ์ ํ
์คํธ๋ฅผ ๊ฒํ ํ๊ฑฐ๋ ํธ์งํ ์ ์์ต๋๋ค. ๋ฐ์์ฐ๊ธฐ๋ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ฌ ๊ตฌ๊ฐ์ ์๋ผ๋ผ ๋๋ ๋จ์ด๋ฅผ ๋์ด์ ์ ์งํ๊ณ , ์ค๊ตญ์ด์ ์ผ๋ณธ์ด์ ๋ถ์ฌ ์ฐ๊ธฐ๋ฅผ ๋ณด์กดํ๋ฉฐ, ์์ ์ค๋ ๋ฌธ์ฅ ๋ถํธ์ ํผ์ผํธ ๊ธฐํธ๋ ๊ณต๋ฐฑ ์์ด ๋ถ์
๋๋ค.
์น UI๋ ํ์ค ๋ํ์ ์ปค์คํ
์์ด์ ํธ ๋ํ ๋ชจ๋์์ ์
๋ ฅ์ฐฝ ์๋์ ์ง์ญํ๋ AI ์์ฑ ์ฝํ
์ธ ๋ฉด์ฑ
๋ฌธ๊ตฌ๋ฅผ ํ์ํ์ฌ, ์ฌ์ฉ์์๊ฒ ์ค์ํ ์ ๋ณด๋ฅผ ํ์ธํ๋๋ก ์๋ดํฉ๋๋ค.
์ค๋จ๋ ์ฒซ ํด ์คํ๋ ํด๋ฐฑ ๋ํ ์ ๋ชฉ์ ์ ์ฅํ๋ฏ๋ก, ์คํธ๋ฆฌ๋ฐ ์๋ต์ ์ค์งํด๋ ์๋ก ๊ณ ์น ํ ์ค๋ ๋๊ฐ "Untitled"๋ก ๋จ์ง ์์ต๋๋ค.
์คํธ๋ฆฌ๋ฐ๋๋ Markdown ์๋ต์ ์๋ก ๋์ฐฉํ ๋จ์ด์๋ง ์ ๋๋ฉ์ด์
์ ์ ์ฉํฉ๋๋ค. ๋ค์ ์ฒญํฌ๊ฐ ๊ฐ์ ๋ธ๋ก์ ์ด์ด ๋ถ์ผ ๋ ์ด๋ฏธ ๋ณด์ด๋ ํ
์คํธ๊ฐ ์ฌ๋ผ์ก๋ค๊ฐ ๋ค์ ์ฌ์๋์ง ์์ต๋๋ค.
์น UI์์๋ ์๋ฃ๋ ์ด์์คํดํธ ํด์ ์ ๋ฉ์ธ ๋ํ๋ก ๋ถ๊ธฐํ ์ ์์ต๋๋ค. ์๋์ผ๋ก ์์๋๋ ๋ถ๊ธฐ ์ ๋ชฉ์ ์ฌ์ฉ ๊ฐ๋ฅํ ๋ค์ ์ธ์ด ์ค๋ฆฝ ์ซ์ ์ ๋ฏธ์ฌ(`Title (2)`, ๊ทธ๋ฆฌ๊ณ ๋ค๋ฅธ ํ์ ๋ํ๋ ๋ฒํธ๊ฐ ๋ถ์ ๋ํ์ ๋ถ๊ธฐ์๋ `Title (3)`)๋ฅผ ์ฌ์ฉํ๋ฏ๋ก, ๋ก์ผ์ผ๋ณ ๋ ์ด๋ธ์ ์ ์ฅํ์ง ์๊ณ ๋ ์์ฑ๋ ํ์ ์ ๋ชฉ์ด ์๋ก ๊ตฌ๋ณ๋ฉ๋๋ค. ๋ช
์์ ์ผ๋ก ์ง์ ํ๊ฑฐ๋ ์ด๋ฆ์ ๋ฐ๊พผ ํ์ ์ ๋ชฉ์ด ์ผ์นํ๋ ๊ฒฝ์ฐ์๋, ์์ฑ ์๋ฒ ๋ฉํ๋ฐ์ดํฐ๊ฐ ์๋๋ผ๋ ํ์๋ ์ ๋ฏธ์ฌ๋ฅผ ์์ฝํฉ๋๋ค. ๋ช
์์ ์ธ API ์ ๋ชฉ์ ๋ณด์กด๋ฉ๋๋ค. ๋ถ๊ธฐ์ ์ด๋ฆ์ ๋ฐ๊พธ๋ฉด ์์ฑ ์๋ฒ์ด ์ง์์ง๋ฏ๋ก, ๊ทธ ๋ถ๊ธฐ์ ๋ค์ ์๋ ๋ถ๊ธฐ๋ ๋ฐ๋ ์ ๋ชฉ์์ `(2)`๋ถํฐ ์์ํฉ๋๋ค. Recent chats๋ ๋ํ ๋ถ๋ฌ์จ ๋ถ๊ธฐ๋ฅผ ๋ถ๋ฌ์จ ๋ถ๋ชจ ๋ฐ๋ก ์๋์ ์์ํ ํธ๋ฆฌ ์ฐ๊ฒฐ์ ๊ณผ ํจ๊ป ๋ฌถ์ด ํ์ํฉ๋๋ค. ๋ถ๋ชจ๊ฐ ์๊ฑฐ๋, ๊ณ๋ณด๊ฐ ์๋ชป๋์๊ฑฐ๋ ์ํํ๊ฑฐ๋, ๊ณ ์ (pinned) ์ํ๊ฐ ๋ค๋ฅธ ๋ถ๊ธฐ๋ ์จ๊ฒจ์ง๊ฑฐ๋ ๊ณ ์ ๊ฒฝ๊ณ๋ฅผ ๋์ด ์ด๋ํ์ง ์๊ณ ์ต์์ ์์ค์ ๊ณ์ ํ์๋ฉ๋๋ค. ์ ์ค๋ ๋๋ ํด๋น ํด์ ์ฒดํฌํฌ์ธํธ์์ ์์ํ๊ณ ๊ทธ ์์ ์ฌ์ ์ฒดํฌํฌ์ธํธ๋ฅผ ์ ์งํ๋ฏ๋ก, ๋ถ๊ธฐ๋ ์๋ต์ ์ฆ์ ์ฌ์์ฑํ ์ ์์ต๋๋ค. ์ต์ ์๋ต์ ์คํธ๋ฆฌ๋ฐ๋ ๋ถ๋ถ ํ
์คํธ๊ฐ ์ฒดํฌํฌ์ธํธ์ ๋๋ฌํ์ง ๋ชปํ๋๋ผ๋ ์ค๋จ ํ ์ฌ์์ฑํ ์ ์์ต๋๋ค. ์ต์ ์๋ต์ ์ฌ์์ฑํด๋ ์ค๋ ๋์ ํ์ฌ ์ ๋ชฉ์ ์ ์ง๋๋ฉฐ, ์๋ ์๋ต ์ดํ ์ง์ ๋ฐ๊พผ ์ ๋ชฉ๋ ๋ง์ฐฌ๊ฐ์ง์
๋๋ค. ์ฒดํฌํฌ์ธํธ ๋ถ๋ชจ ๋งํฌ๊ฐ ์๋ ๋ ๊ฑฐ์ ๊ธฐ๋ก์ด๋ ๊ฐ์ ธ์จ ๊ธฐ๋ก์ ๋ฒ์๊ฐ ์ ํ๋ ์๊ฐ์ ํด๋ฐฑ์ ์ฌ์ฉํฉ๋๋ค. ์ด์ ์ฌ์ ์ฒดํฌํฌ์ธํธ๊ฐ ์์ผ๋ฉด ๋ถ๊ธฐ๋ ๋ ๊ฑฐ์ ๋จ์ผ ์ฒดํฌํฌ์ธํธ ํํ๋ก ์ฌ์ ํ ์ฑ๊ณตํ์ง๋ง, ์์๋ ํด๋น ์๋ต์ ์ฌ์์ฑํ ์ ์์ต๋๋ค. ๊ธฐ์กด ๋จ์ผ ์ฒดํฌํฌ์ธํธ ๋ถ๊ธฐ๋ ์์ ํ์ง ์์ ์ฒดํฌํฌ์ธํธ ๋ณต์ฌ๋ฅผ ์๋ํ์ง ์๊ณ ๊ทธ๋๋ก ๋ก๋๋ค. ์ํฌ์คํ์ด์ค ํ์ผ์ ์ฒดํฌํฌ์ธํธ์ ํฌํจ๋์ง ์์ผ๋ฏ๋ก, ์ต์ ํด์์ ๋ถ๊ธฐํ ๋๋ง ๋ถ๊ธฐ๊ฐ ํ์ฌ ์ํฌ์คํ์ด์ค์ ์ต์ ๋
ธ๋ ฅ(best-effort) ์ฌ๋ณธ์ ๋ฐ์ต๋๋ค. ์ด์ ํด์์ ๋ถ๊ธฐํ๋ฉด ๋ณต์๋ ๋ฉ์์ง ๊ธฐ๋ก๋ง ์ ์ง๋๋ฏ๋ก, ๋ถ๊ธฐ๊ฐ ๋ํ์ ์ดํ ๋ถ๋ถ์์ ์์ฑ๋ ํ์ผ์ ์์ํ๋ ์ผ์ ์์ต๋๋ค.
์น UI๋ ์๋ฃ๋ ์์
์๊ฐ์ ์คํ๋ง๋ค ํ ๋ฒ ๋ณด๊ณ ํฉ๋๋ค. ์ด๋ ๋ชจ๋ธ ์ถ๋ก , ๋๊ตฌ ํธ์ถ, ๋๊ธฐ ์๊ฐ์ ๋ชจ๋ ํฌํจํ ์ ์ฒด ๊ฒฝ๊ณผ ์๊ฐ(wall-clock time)์ด๋ฉฐ, ๋จ๊ณ๋ณ ์๊ฐ์ด๋ ๋ชจ๋ธ๋ง์ ์ฌ๊ณ ์๊ฐ์ด ์๋๋๋ค. ์ถ๋ก ๋ด์ฉ์ ๋ณ๋์ ํผ์นจ ์์ญ์์ ๊ณ์ ํ์ธํ ์ ์์ต๋๋ค.
์๋ต์ด ์คํธ๋ฆฌ๋ฐ๋๋ ๋์ Anthropic thinking ๋ธ๋ก์ ํฌํจํด ์ถ๋ก ๋ง ๋ด๊ธด ๋ฉ์์ง๋ ์ฒ๋ฆฌ ํจ๋์ ๋จธ๋ญ
๋๋ค. ์ถ๋ก ๊ณผ ํจ๊ป ๋ต๋ณ ๋ด์ฉ์ด ๋์ฐฉํ๋ฉด ์ด์์คํดํธ ๋งํ์ ์ ํ์๋ฉ๋๋ค.
ํ์ค ์ฝ๋, ๋ค์ฌ์ด ์ฝ๋, ์ธ๋ผ์ธ ์ฝ๋ ์์ ๋ฆฌํฐ๋ด `` ํ๊ทธ๋ ์ถ๋ก ํผ์นจ ์์ญ์ผ๋ก ์ฎ๊ฒจ์ง์ง ์๊ณ ๋ต๋ณ๊ณผ ๋ณต์ฌ๋ ํ
์คํธ์ ์ผ๋ถ๋ก ๋จ์ต๋๋ค. ๋ฆฌ์คํธ ํญ๋ชฉ ์ค์์ ์ด๋ฆฐ ํ์ค๋ ๋ง์ฐฌ๊ฐ์ง์ด๋ฉฐ, ์ฝ๋ ๋ค์ ์ค๋ ์ค์ ์ถ๋ก ์ ์ฌ์ ํ ์ถ์ถ๋ฉ๋๋ค. ๋๋์ง ์์ ์ธ๋ผ์ธ ์ฝ๋ ๊ตฌ๊ฐ์ ํ ๋ฌธ๋จ ์์์ ์คํธ๋ฆฌ๋ฐ๋๋ ๋์ ๋ณด์กด๋์ง๋ง, ๋น ์ค์ด๋ ์ค๊ฐ์ ๋ผ์ด๋๋ ์ ๋ชฉ, ๋ฆฌ์คํธ, ๊ตฌ๋ถ์ , ํ์ค์์ ๋๋ฉ๋๋ค. ๋ค์ฌ์ด ๋ฌธ๋จ ์ฐ์ ์ค์ ์ฝ๋ ๋ธ๋ก์ ์์ํ์ง ์์ต๋๋ค.
์น UI์์๋ ๊ฐ์ฅ ์ต๊ทผ์ ์๋ฃ๋ ์ฌ์ฉ์ ํด์ ๋ฉ์์ง ๋๊ตฌ ๋ชจ์์์ ํธ์งํ๊ณ ๋ค์ ์คํํ ์๋ ์์ต๋๋ค. DeerFlow๋ ํด๋น ์ฌ์ฉ์ ๋ฉ์์ง ์ด์ ์ ๋ํ ์ฒดํฌํฌ์ธํธ๋ฅผ ๋ณต์ํ๊ณ , ํธ์งํ ํ
์คํธ๋ฅผ ์ ์ฌ์ฉ์ ๋ฉ์์ง๋ก ์ ์ถํ๋ฉฐ, ์ฌ์์ด ์งํ ์ค์ด๊ฑฐ๋ ์ฑ๊ณตํ๋ฉด ๋์ฒด๋ ํด์ ์จ๊น๋๋ค. ์ด๋ ๋ํ ์ํ์ ์ฌ์์ผ ๋ฟ์ด๋ฉฐ, ํ์ผ, ๋ฉ๋ชจ๋ฆฌ ์
๋ฐ์ดํธ, ์ธ๋ถ ๋๊ตฌ์ ๋ถ์ ํจ๊ณผ๋ ๋๋๋ฆฌ์ง ์์ต๋๋ค.
์น UI ์ฑํ
๋งํฌ๋ ์ปค์คํ
์ค๋ ๋ ์๋ณ์๋ฅผ ๋ผ์ฐํธ ์ธ๊ทธ๋จผํธ์ ๋ฃ๊ธฐ ์ ์ ํผ์ผํธ ์ธ์ฝ๋ฉํ๋ฏ๋ก, `#`์ด๋ `?` ๊ฐ์ URL ์์ฝ ๋ฌธ์ ๋๋ฌธ์ ์ด๋ฆฌ๋ ๋ํ๊ฐ ๋ฐ๋์ง ์์ต๋๋ค.
### ์ฑํ
๋ณด๊ดํจ
์ฌ์ด๋๋ฐ์์ ์ฑํ
์ ์ญ์ ํ๋ ค๋ฉด ์ฑํ
์ ๋ชฉ์ด ํ์๋ ํ์ธ ์ ์ฐจ๋ฅผ ๊ฑฐ์ณ์ผ ํฉ๋๋ค. ์ญ์ ํ๋ฉด ๋ํ์ ํด๋น ํ์ผ์ด ์ ๊ฑฐ๋๋ฉฐ ๋๋๋ฆด ์ ์์ต๋๋ค.
์ต๊ทผ ์ฑํ
์ ์ฌ์ด๋๋ฐ ๋ฉ๋ด์์ **Archive chat**์ ์ฌ์ฉํ๋ฉด ๋ฉ์์ง, ํ์ผ, ์๋ ๋งํฌ๋ฅผ ์ ์งํ ์ฑ ์๋ฃ๋ ์์
์ ์จ๊ธธ ์ ์์ต๋๋ค. ์ฑ๊ณต ๋ฉ์์ง์๋ **Undo**๊ฐ ํจ๊ป ํ์๋ฉ๋๋ค. **Chats โ Archived**๋ฅผ ์ด๋ฉด ๋ณด๊ด๋ ๋ํ๋ฅผ ์ฐพ์ ๊ฐ๋ณ์ ์ผ๋ก ๋ณต์ํ ์ ์์ผ๋ฉฐ, ๋ณด๊ด๋ ๋ํ๋ฅผ ์ด๋ฉด ํค๋์๋ ๋ณต์ ๋ฒํผ์ด ํ์๋ฉ๋๋ค. ๊ฒ์์ ๋ถ๋ฌ์จ ๋ํ์ ์ ๋ชฉ์ ํํฐ๋งํ๋ฉฐ, ์ด์ ํญ๋ชฉ์ **Load more**๋ก ๋ถ๋ฌ์ฌ ์ ์์ต๋๋ค.
๋ณด๊ด๊ณผ ๋ณต์์ ์ฑํ
์ ํ๋ ์๊ฐ๊ณผ ๊ณ ์ ์ํ๋ฅผ ๋ณด์กดํฉ๋๋ค. ๋ณด๊ดํด๋ ์คํ ์ค์ธ ์์
์ด ์ค์ง๋๊ฑฐ๋ ํด๋น ์ผ์ ์ด ์ผ์ ์ค์ง๋์ง ์์ผ๋ฉฐ, ์ ํ๋์ด ์๊ฒจ๋ ์๋์ผ๋ก ๋ณต์๋์ง ์์ต๋๋ค. ๋ํ์ ํด๋น ํ์ผ์ ์ ๊ฑฐํ๋ ค๋ ๊ฒฝ์ฐ์๋ ๊ธฐ์กด Delete ์์
์ ์ฌ์ฉํ์ธ์.
### ์ธ์
๋ชฉํ
`/goal `์ ์ฌ์ฉํ๋ฉด ํ์ฌ ์ค๋ ๋์ ํ์ฑ ์๋ฃ ์กฐ๊ฑด ํ๋๋ฅผ ์ฐ๊ฒฐํ ์ ์์ต๋๋ค. ๋ชฉํ๋ ์คํฌ ํ์ฑํ๊ฐ ์๋๋ผ ์ค๋ ๋ ๋ฒ์์ ์ํ์ด๋ฏ๋ก, DeerFlow๊ฐ ๋ชฉํ๊ฐ ์ถฉ์กฑ๋์๋ค๊ณ ํ๋จํ๊ฑฐ๋ ์ฌ์ฉ์๊ฐ ๋ชฉํ๋ฅผ ์ง์ธ ๋๊น์ง ์ฌ๋ฌ ํด์ ๊ฑธ์ณ ํ์ฑ ์ํ๋ก ์ ์ง๋ฉ๋๋ค. ์์ด์ ํธ๋ ๋ชจ๋ ๋ชจ๋ธ ํธ์ถ์์ ํ์ฑ ๋ชฉํ๋ฅผ ๋ณด๋ฏ๋ก, ์ปจํ
์คํธ ์์ถ์ผ๋ก ๋ชฉํ๋ฅผ ์ธ๊ธํ ๋ฉ์์ง๊ฐ ์ ๊ฑฐ๋ ํ์๋ ๊ณ์ ๋ชฉํ๋ฅผ ํฅํด ์์
ํฉ๋๋ค.
์ง์๋๋ ๋ช
๋ น:
```text
/goal finish the implementation and make all tests pass
/goal # show the active goal
/goal clear # clear it
```
Gateway ๊ธฐ๋ฐ ์คํ(run)์ด ๋๋ ๋๋ง๋ค DeerFlow๋ thinking์ ์ฌ์ฉํ์ง ์๋ ํ๊ฐ ๋ชจ๋ธ๋ก ์ด์์คํดํธ์ ๋๊ตฌ ํธ์ถ๊ณผ ์ถ์ฝ๋ ๋๊ตฌ ๊ฒฐ๊ณผ๋ฅผ ํฌํจํ ๊ฐ์ ๋ํ๋ฅผ ํ์ฑ ๋ชฉํ์ ๋น์ถ์ด ํ๊ฐํฉ๋๋ค. ๋๊ตฌ ๊ฒฐ๊ณผ๊ฐ ์ฑ๊ณตํ๋ค๋ ์ฌ์ค๋ง์ผ๋ก๋ ๋ชฉํ๊ฐ ์ถฉ์กฑ๋์ง ์์ผ๋ฉฐ, ์ด์์คํดํธ๊ฐ ๋๋ฝ๋์๊ฑฐ๋ ๋ชจํธํ ์ ๋ณด๋ฅผ ์ถ์ธกํด์ผ ํ๋ ๊ฒฝ์ฐ ํ๊ฐ ๋ชจ๋ธ์ `needs_user_input`์ ๋ณด๊ณ ํฉ๋๋ค. ํ๊ฐ ๋ชจ๋ธ์ ํ์
์ด ์ง์ ๋ ์ฐจ๋จ ์์ธ(`missing_evidence`, `needs_user_input`, `run_failed`, `external_wait`, ๋๋ `goal_not_met_yet`)๊ณผ ๊ฐ์์ ์ธ ๊ทผ๊ฑฐ๋ฅผ ํจ๊ป ๋ฐํํด์ผ ํฉ๋๋ค. DeerFlow๋ ์ต์ ์ด์์คํดํธ ํด์ด ์์์ ์ผ๋ก ์ฒดํฌํฌ์ธํธ์ ์ ์ฅ๋์๊ณ , ์ฐจ๋จ ์์ธ์ด `goal_not_met_yet`์ด๋ฉฐ, ํ๊ฐ ์ค์ ์ค๋ ๋๊ฐ ๋ณ๊ฒฝ๋์ง ์์๊ณ , ์ง์ ์์ ์ฐจ๋จ๊ธฐ๊ฐ ์๋ํ์ง ์์ ๊ฒฝ์ฐ์๋ง ์จ๊ฒจ์ง ์ฐ์ ์คํ์ ์ฃผ์
ํฉ๋๋ค. ์์ ์ํ์ ๊ธฐ๋ณธ์ ์ผ๋ก ์จ๊ฒจ์ง ์ฐ์ ์คํ 8ํ์ด๋ฉฐ, ์ง์ ์๋ ๋์ผํ ํ๊ฐ๊ฐ ๋ฐ๋ณต๋๋ฉด 2ํ ์๋ ํ ์ค์งํฉ๋๋ค. `/goal clear`์ ์ฌ์ฉ์๊ฐ ์์ฑํ ๋ชจ๋ ์ ์
๋ ฅ์ ๋๊ธฐ ์ค์ธ ์ฐ์ ์คํ๋ณด๋ค ์ฐ์ ํฉ๋๋ค. ํ๊ฐ ๋ชจ๋ธ์ด ๋ชฉํ๊ฐ ์ถฉ์กฑ๋์๋ค๊ณ ํ๋จํ๋ฉด DeerFlow๋ ์คํ์ด ์ฑ๊ณต์ ์ผ๋ก ๋ง๋ฌด๋ฆฌ๋๊ณ ์
๋ฐ์ดํธ๋ ์ค๋ ๋ ์ํ๋ฅผ ๊ฒ์ํ ํ ๋ชฉํ๋ฅผ ์ง์๋๋ค. ๊ฐ์ ์ฒดํฌํฌ์ธํธ์ ์๋ฃ ์ฌ์ค์ด `goal_outcome`์ผ๋ก ๊ธฐ๋ก๋๋ฉฐ, ์ด๋ ๋ค์ ๋ชฉํ ๋ณ๊ฒฝ ์๊น์ง ์ ์ง๋ฉ๋๋ค. ํ์ ์ํฐํฉํธ ์ ๋ฌ์ด๋ ๊ทธ ์์์ฆ ์์ ์ ์ฅ์ ์คํจํ๋ฉด ์คํ์ ์ค๋ฅ๋ฅผ ๋ณด๊ณ ํ๊ณ ๋ชฉํ๋ ์ดํ ์ฌ์๋๋ฅผ ์ํด ํ์ฑ ์ํ๋ก ๋จ์ต๋๋ค. ์ด ๊ฒฝ์ฐ ๋ ๋ค๋ฅธ ์จ๊ฒจ์ง ์ฐ์ ์คํ์ ์์๋์ง ์์ต๋๋ค.
์ด์ ์๋ต์ ์ฌ์์ฑํด๋ ์ฑํ
์ ํ์ฌ ์ค์ ๋ ๋ชฉํ์ ์ด๋ฏธ ์ฌ์ฉํ ์ฐ์ ์คํ ์์ฐ์ ์ ์ง๋ฉ๋๋ค. ์ง์์ก๊ฑฐ๋ ๋ฌ์ฑ๋ ๋ชฉํ๋ ๋ณต์๋์ง ์์ต๋๋ค. ์ด์ ๋ต๋ณ์ ์๋ฃ ๊ธฐ๋ก์ ํด๋น ๊ณผ๊ฑฐ ์ฒดํฌํฌ์ธํธ๊ฐ ์ฌ์๋ ๋ ์ ๊ฑฐ๋ฉ๋๋ค.
์น UI๋ ์
๋ ฅ์ฐฝ(composer) ์์ ํ์ฑ ๋ชฉํ๋ฅผ ํ์ํ๊ณ , ์๋ ๊ณ์์ด ์ค์ง๋ ์ด์ ๋ฅผ ์๋ ค ์ฃผ๋ฉฐ, ๋ชฉํ๊ฐ ์ถฉ์กฑ๋๋ฉด "Goal met" ์๋ฆผ์ ํ์ํฉ๋๋ค. ๋ชฉํ๊ฐ ์ค์ ๋์ด ์๋ ๋์์๋ ๋ง์ง๋ง ๋ฉ์์ง ํธ์ง์ด ๊บผ์ง๋๋ค. ๊ฐ์ ๋ช
๋ น์ TUI์ ์ง์๋๋ IM ์ฑ๋์์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์น UI์ ์ง์๋๋ IM ์ฑ๋์์ `/goal `์ ์ค์ ํ๋ฉด ํด๋น ์กฐ๊ฑด์ ์์
์ผ๋ก ํ๋ ์คํ๋ ์์๋๋ฉฐ, ์ํ ํ์ธ ๋ช
๋ น๊ณผ ์ง์ฐ๊ธฐ ๋ช
๋ น์ ๋ชฉํ ์ํ๋ง ๊ด๋ฆฌํฉ๋๋ค. ํด๋น ์ค๋ ๋์ ์งํ ์ค์ธ ์คํ์ด ์์ผ๋ฉด(๋ค๋ฅธ Gateway ์์ปค๊ฐ ์์ ํ ์คํ ํฌํจ) ๋ชฉํ ์ค์ ์ด๋ ์ง์ฐ๊ธฐ๊ฐ ๊ฑฐ๋ถ๋๋ฏ๋ก, ๋ชฉํ ์ฒดํฌํฌ์ธํธ๊ฐ ํ์ฑ ์คํ์ ์ฒดํฌํฌ์ธํธ ๊ณ๋ณด์์ ๊ฐ๋ผ์ ธ ๋๊ฐ ์ ์์ต๋๋ค.
์ญํ ์ `runs:create`๊ฐ ์์ผ๋ฉด ์น UI๋ ์ค๋ ๋๋ฅผ ์ค๋นํ๊ฑฐ๋ ๋ชฉํ๋ฅผ ์ ์ฅํ๊ธฐ ์ ์ ์ ์์
์ด๋ `/goal `์ ๊ฑฐ๋ถํ๊ณ , ์ฌ์๋ํ ์ ์๋๋ก ์ด์์ ์ ์งํฉ๋๋ค. ๋ชฉํ ์ํ ํ์ธ, ๋ชฉํ ์ง์ฐ๊ธฐ, `/compact`๋ ๊ณ์ ๊ฐ์์ ์๋ํฌ์ธํธ ๊ถํ์ ๋ฐ๋ผ ๊ด๋ฆฌ๋ฉ๋๋ค.
### ์๋ ์ปจํ
์คํธ ์์ถ
`task_continuity.enabled`๋ฅผ ์ฌ์ฉํ๋ฉด `history_search`๊ฐ ํ์ฌ ์์
์ ํ์ฑ ๊ธฐ๋ก๊ณผ ์์ถ๋ ๊ธฐ๋ก์ ๊ฒ์ํฉ๋๋ค. ์ ํ ์ฌํญ์ธ `role`์ `user`, `assistant`, `tool`์ ๋ฐ์ผ๋ฉฐ 8๊ฐ ๊ฒฐ๊ณผ ์ ํ์ ์ ์ฉํ๊ธฐ ์ ์ ํํฐ๋งํฉ๋๋ค. ์ด๋ฅผ ์๋ตํ๊ฑฐ๋ `null`์ ์ ๋ฌํ๋ฉด ๋ชจ๋ ์ญํ ์ ๊ฑธ์น ๊ฒ์์ด ์ ์ง๋ฉ๋๋ค.
๊ฒ์ ๋ฐ์ท๋ฌธ์ ๋ค์ด๊ฐ ์ ์๋ ๊ฐ์ฅ ์์ชฝ์ ์ฐพ์ ์ ์๋ ์ผ์น ํญ๋ชฉ ์ฃผ๋ณ์ผ๋ก ์ต๋ 600์๋ฅผ ๋ด์ผ๋ฉฐ, ์๋ณธ ์์ค์์์ 0๋ถํฐ ์์ํ๋ ๋ฐ์ด๋ฆฐ(half-open) ๋ฌธ์ ๋ฒ์์ธ `excerpt_start` / `excerpt_end`๋ฅผ ํฌํจํฉ๋๋ค. ๋๋ฌด ํฐ ์ผ์น ํญ๋ชฉ์ ๊ฑด๋๋ฐ๊ณ ๋ค์ ์ค๋ ๋ค์ด๊ฐ ์ ์๋ ์ผ์น ํญ๋ชฉ์ ์ฌ์ฉํฉ๋๋ค. ๋ฐ์ท๋ฌธ ์์์ ์์ ํ ์ผ์น ํญ๋ชฉ์ ์ฐพ์ ์ ์์ผ๋ฉด ๋ฐ์ท๋ฌธ์ `excerpt_match=false`์ ํจ๊ป ์์ค์ ์์ ๋ถ๋ถ์ผ๋ก ํด๋ฐฑํฉ๋๋ค. ๊ณ์ ์ฝ์ผ๋ ค๋ฉด ์์ ์์น๋ฅผ `offset`์ผ๋ก ํ์ฌ `history_read`์ ์ ๋ฌํ์ธ์.
์๋ณธ ์์ค๋ฅผ ํ์ธํ๋ ค๋ฉด `history_read`๋ฅผ ์ฌ์ฉํ์ธ์. ๊ณผ๊ฑฐ ์ฌ์ฉ์ ๋ฉ์์ง๊ฐ ํ์ฌ์ ๊ถํ์ ๋ถ์ฌํ์ง๋ ์์ต๋๋ค. [์์
์ฐ์์ฑ](docs/task-continuity.md)์ ์ฐธ๊ณ ํ์ธ์.
์๋ ์์ถ๊ณผ ์๋ ์์ถ ๋ชจ๋ ์ค๋๋ ํ ์ผ(todo) ๋ฆฌ๋ง์ธ๋ ๋ฉ์์ง๋ฅผ ์์ฝ ์
๋ ฅ๊ณผ ์ ์ง๋๋ ์ปจํ
์คํธ์์ ์ ์ธํฉ๋๋ค. ํ์ฌ ํ ์ผ ๋ชฉ๋ก์ ์ค๋ ๋ ์ํ์ ๋จ์ ์์ต๋๋ค. ๊ณํ ๋ชจ๋์์ ์๋์ `write_todos` ํธ์ถ์ด ๋ ์ด์ ๋ณด์ด์ง ์์ผ๋ฉด, DeerFlow๋ ๋ค์ ๋ชจ๋ธ ํธ์ถ ์ ์ ์ต์ ์์
์ํ๋ฅผ ์ฌ์ฉํด ๋ฆฌ๋ง์ธ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค. ์์ถ์ ๊ฑด๋๋ฐ๊ฑฐ๋ ์์ถ์ ์คํจํ๋ฉด ๊ธฐ์กด ๋ฉ์์ง๋ ๋ณ๊ฒฝ๋์ง ์์ต๋๋ค.
์ ํ ์ฌํญ์ธ `pii_redaction.enabled`๋ ์ฌ์ฉ์ ๋ฉ์์ง, ์๊ฒฉ ๋๊ตฌ ๊ฒฐ๊ณผ, ์์ถ ์
๋ ฅ, ๋ค์ ์ฃผ์
๋๋ ์์ฝ, ์ค์ ๋ LLM ์ ๋ชฉ ์
๋ ฅ, `/goal` ํ๊ฐ ๋ชจ๋ธ์ ์
๋ ฅ์์ ๊ฐ์ง๋ ์๋ณ์๋ฅผ ๋ง์คํนํฉ๋๋ค. ์์ถ ์ ํ๋ฌ์๋ฅผ ํฌํจํ ๋ฉ๋ชจ๋ฆฌ ์น์ธ(admission)์์๋ ์ง์๋๋ ํ
์คํธ/JSON ์ฝํ
์ธ , ํ์ฑ๋ ํธ์ถ ์ธ์์ ์ ํจํ์ง ์์ ํธ์ถ ์ธ์/์ค๋ฅ ํ
์คํธ, ํ๋ก๋ฐ์ด๋ ์์/๋ ๊ฑฐ์ ํจ์ ํธ์ถ, ์ง์๋๋ ์ฌ์ฉ์ ์ฝํ
์ธ ์ถ์ฒ(provenance)์์ ๊ฐ์ง๋ ์๋ณ์๋ฅผ ๋ง์คํนํฉ๋๋ค. ์ด ๊ธฐ๋ฅ์ ๊ธฐ๋ณธ์ ์ผ๋ก ๊บผ์ ธ ์์ผ๋ฉฐ, ํ์ฑํํ ๋ฐฐํฌ์์๋ ๊ฐ์์ ํ์๋๋ ์์ ์ ์ธ ํค ๊ธฐ๋ฐ ์๋ฆฌ ํ์์๋ฅผ ์ํด ์ํฌ๋ฆฟ์ ์ ๊ณตํฉ๋๋ค. ํ ํฐ๊ณผ ์์ ๊ฐ ๊ฐ์ ๋งคํ์ ์ ์ฅ๋์ง ์์ต๋๋ค. ์์ ์ค๋ ๋ ํ
์คํธ์ ๋ก์ปฌ ํด๋ฐฑ ์ ๋ชฉ์ ํ์์ฉ์ผ๋ก ๊ณ์ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ๋ฉ๋ชจ๋ฆฌ ๋ง์คํน์ ํธ์ถ์์ ๊ธฐ๋ก์ด๋ ๋๊ตฌ ์คํ์ ๋ณ๊ฒฝํ์ง ์๊ณ ๋ฉ์์ง๋ฅผ ๋ณต์ฌํด์ ์ฒ๋ฆฌํฉ๋๋ค. ์จ๊ฒจ์ง `/goal` ์ฐ์ ์คํ์ ์ ์ฅ๋๊ธฐ ์ ์ ๋ง์คํน๋ฉ๋๋ค.
์น UI๋ ๊ธฐ๋ก์ ์ค์๊ฐ ์
๋ฐ์ดํธ์ ๋ณํฉํ ๋ ์ ์ฅ๋ ๋ฉ์์ง ์์๋ฅผ ๋ณด์กดํฉ๋๋ค. ๋ถ๋ฌ์จ ๊ธฐ๋ก ์์์ ์ ์ฅ๋ ๊ฒฐ๊ณผ ์ฃผ๋ณ์ ์๋ ์คํธ๋ฆฌ๋ฐ ๋จ๊ณ๋ ๊ฒฐ๊ณผ๋ณด๋ค ๋ฆ๊ฒ ๋์ฐฉํ ๋จ๊ณ๊น์ง ํฌํจํด ํจ๊ป ๋ฌถ์ฌ ์ ์ง๋ฉ๋๋ค. ๊ธฐ๋ก์ด ์๋ก ๊ณ ์ณ์ง์ง ์์๊ณ UI๊ฐ ์์ง ๋ ๋๋งํ์ง ์์ ๊ฒฝ์ฐ, ์์ถ ์ค์ ์์ง๋ ๋จ๊ณ๋ ์ ์ฅ๋ ๊ฒฐ๊ณผ ์์ ๊ณ์ ํ์๋ฉ๋๋ค.
์์ถ์ ํ์ฌ ์ฌ์ฉ์ ์์ฒญ์ ์ ์งํ๊ณ ์ค๋๋ ์ด์์คํดํธ/๋๊ตฌ ํ๋์ ์์ฝํฉ๋๋ค. ๊ทธ ์์ฒญ์ ์ด๋ ค ๋๋ฉด ์ด์์คํดํธ/๋๊ตฌ๋ง ๋จ์ ์์ฝ ๊ตฌ๊ฐ์ด ์๊ธฐ๋ ๊ฒฝ์ฐ, ์
๋ ฅ ํธ๋ฆฌ๋ฐ์ ๊ฐ์ฅ ์ต๊ทผ ๋ด์ฉ์ ์ฐ์ ํฉ๋๋ค. ์ฌ์ฉ์ ๋ฉ์์ง ๊ธฐ์ค์ ์ด ํธ๋ฆฌ๋ฐ ์์ฐ ๋ฐ์ ์๋ ํผํฉ ๊ธฐ๋ก์ ๊ฒฝ์ฐ, ์์ถ์ ๊ธฐ์กด์ ๋ง์ง๋ง ๋ฉ์์ง ํด๋ฐฑ์ ์ ์งํฉ๋๋ค. `summarization.trim_tokens_to_summarize`(๊ธฐ๋ณธ๊ฐ 4000)๋ ์์ ์์ฝ ์
๋ ฅ์ ํธ๋ฆฌ๋ฐ์ ์ ์ดํ๋ฉฐ, ์ด์ค์ผ์ดํ์ ํ๋กฌํํธ ์์ ๋๋ฌธ์ ๊ทธ ์์ฐ์ ๋๋ ์ค๋ฒํค๋๊ฐ ์ถ๊ฐ๋ฉ๋๋ค. ์ด ์ต์
์ `null`๋ก ์ค์ ํ๋ฉด ์์ฝ ๋ชจ๋ธ์ ์
๋ ฅ ํธ๋ฆฌ๋ฐ์ด ๋นํ์ฑํ๋ฉ๋๋ค. ๋ชจ๋ธ์ด ์์ถ ๋์์ธ ์ ์ฒด ๊ธฐ๋ก์ ๋ฐ์๋ค์ผ ์ ์๋ ๊ฒฝ์ฐ์๋ง ์ด ์ค์ ์ ์ ํํ์ธ์.
๋ ๋๋ง๋ ์์ฝ ํ๋กฌํํธ์ ๋ชจ๋ธ ํ๋ณด๊ฐ ๋์ผํ๊ฒ ๋ฐ๋ณต๋๋ฉด, DeerFlow๋ ์ฒซ ๋ฒ์งธ ํ๋ณด๊ฐ ์ด์ ์ ๊ธฐ์กด ์์ฝ์ ๋ณ๊ฒฝ ์์ด ๋ฐํํ๋ ๊ฒฝ์ฐ ๊ทธ ์์ฝ์ ์ฌ์ฌ์ฉํฉ๋๋ค. ๋ณ๊ฒฝ ์๋ ํด๋ฐฑ ์๋ต์ ์บ์๋์ง ์์ผ๋ฏ๋ก, ์ฌ์ฌ์ฉ ๋๋ฌธ์ ํธ์ถ ์คํจ ํ ๊ธฐ๋ณธ ๋ชจ๋ธ์ ์ฌ์๋๊ฐ ๋งํ๋ ์ผ์ ์์ต๋๋ค. ์บ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด ์ผ๋ฐ ์์ฑ์ผ๋ก ํด๋ฐฑํฉ๋๋ค. ์์ฝ ๊ฒฐ๊ณผ์ ์ฌ์ฌ์ฉ ์นด์ดํฐ๋ [์์ฝ ํ
๋ ๋ฉํธ๋ฆฌ](backend/docs/summarization.md#reuse-and-telemetry)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
์น UI ์
๋ ฅ์ฐฝ(composer)์์ `/compact`๋ฅผ ์ฌ์ฉํ๋ฉด ํ์ฌ ์ค๋ ๋์ ์ค๋๋ ์ปจํ
์คํธ๋ฅผ ์์ฝํฉ๋๋ค. DeerFlow๋ ์ ์ฒด ์ฑํ
์ ๊ณ์ ํ์ํ์ง๋ง, ์ดํ ๋ชจ๋ธ ํธ์ถ์๋ ์์ถ๋ ์์ฝ๊ณผ ์ต๊ทผ ๋ฉ์์ง๊ฐ ์ฌ์ฉ๋ฉ๋๋ค. ์์ถํ ๊ธฐ๋ก์ด ์ถฉ๋ถํ์ง ์์ผ๋ฉด ์ด ๋ช
๋ น์ ๋ฌด์๋๋ฉฐ, ์ค๋ ๋์ ์งํ ์ค์ธ ์คํ(run)์ด ์์ผ๋ฉด(๊ทธ ์คํ์ ๋ค๋ฅธ Gateway ์์ปค๊ฐ ์์ ํ ๊ฒฝ์ฐ ํฌํจ) ์ฐจ๋จ๋ฉ๋๋ค. ๋ฉํฐ ์์ปค ์์ฝ์ด ๋ฆฌ์ค๋ฅผ ์์ผ๋ฉด, DeerFlow๋ ๋์ฒด ์คํ์ด ์งํ๋๊ธฐ ์ ์ ์ฒดํฌํฌ์ธํธ ์์ฑ๊ธฐ๋ฅผ ์ทจ์ํ๊ณ ์ ๋ฆฌ ํ ์ฌ์๋ ๊ฐ๋ฅํ ์ถฉ๋์ ๋ฐํํฉ๋๋ค. ์ค๋ ๋ ์ ๋ชฉ ํธ์ง๋ ๊ฐ์ ์ํ ์ฐ๊ธฐ ๊ฒฝ๊ณ๋ฅผ ํตํด ์ง๋ ฌํ๋๋ฉฐ, ์คํ์ด ํ์ฑ ์ํ์ด๋ฉด ์ด๋ฆ ๋ณ๊ฒฝ ๋ํ ์์๋ฅผ ๋ซ์ง ์๊ณ ์ถฉ๋์ ํ์ํฉ๋๋ค.
์ ํํ ๋ชจ๋ธ์ ์์์ `context_window`๊ฐ ์ค์ ๋์ด ์์ผ๋ฉด ์ฑํ
ํค๋์ ์ปจํ
์คํธ ์๋์ฐ ๊ฒ์ด์ง๋ ํ์๋ฉ๋๋ค. ๊ฒ์ด์ง๋ ๊ฐ์ฅ ์ต๊ทผ์ ๊ตฌ์ฒดํ๋ ์ฒดํฌํฌ์ธํธ์ ๋ฉ์์ง ํ ํฐ์ ์ถ์ ํ๋ฉฐ, ๋ฐ์ดํฐ๋ฅผ ๋ค์ ๊ฐ์ ธ์ค๋ ๋์์๋ ๊ฐ์ ์ค๋ ๋์ ์ด์ ๋ฐฑ๋ถ์จ์ ๊ณ์ ํ์ํฉ๋๋ค. ์ด๋ ๋์ ํ ํฐ ์ฌ์ฉ๋ ์ค์ ๊ณผ๋ ๋
๋ฆฝ์ ์
๋๋ค.
`token_budget.enabled`์ `token_usage.enabled`๊ฐ ๋ชจ๋ ํ์ฑํ๋์ด ์์ผ๋ฉด, ๊ฐ ๋ฆฌ๋ ์์ด์ ํธ ์คํ ์์ฐ์๋ ๋ง์ง๋ง ๋ฐฐ์น๋ฅผ ํฌํจํด ์๋ฃ๋ ์๋ธ์์ด์ ํธ ์ฌ์ฉ๋์ด ํฌํจ๋ฉ๋๋ค. ์จ๊ฒจ์ง ๋ชฉํ ์ฐ์ ์คํ์ ์์ฐ์ ๊ณต์ ํ๋ฉฐ, ์ฌ์ฉ์๊ฐ ์๋ก ์์ํ ์คํ์ ์ ์์ฐ์ผ๋ก ์์ํฉ๋๋ค.
### ์๋ธ์์ด์ ํธ
์๋ธ์์ด์ ํธ๊ฐ `return_direct=True` ๋๊ตฌ(ํ์ฅ ๋ฏธ๋ค์จ์ด๊ฐ ์ ๊ณตํ๋ ๋๊ตฌ ํฌํจ)๋ก ์ข
๋ฃ๋๋ฉด, ํด๋น ๋๊ตฌ์ ์ถ๋ ฅ์ ๋๊ตฌ ํธ์ถ ์์๋๋ก ๋ฐํ๋ฉ๋๋ค. ๋๊ตฌ ํ๋๊ฐ ์คํจํ๋ฉด ๋ฐฐ์น ์ถ๋ ฅ์ ๋ณด์กดํ ์ฑ ์์
์ ์คํจ๋ก ํ์ํฉ๋๋ค.
์ผ๋ฐ `task` ํธ์ถ์ `context_mode="isolated"`(๊ธฐ๋ณธ๊ฐ) ๋๋ `context_mode="snapshot"`์ ๋ฐ์ต๋๋ค. ๊ฒฉ๋ฆฌ(isolated) ์์
์ ์ด์ ๊ณผ ๊ฐ์ด ์์๋ ํ๋กฌํํธ๋ฅผ ๋ฐ์ต๋๋ค. ์ค๋
์ท(snapshot) ์์
์ ์ฌ๊ธฐ์ ๋ํด ๋ถ๋ชจ๊ฐ ๋ณด์กดํ๊ณ ์๋ ๋ํ์ ์์ถ ์์ฝ๋ ๋ฐ์ผ๋ฉฐ, ์ด๋ ๋์คํจ์น ์์ ์ ์บก์ฒ๋์ด ๊ณผ๊ฑฐ ๋ฐฐ๊ฒฝ ์ ๋ณด๋ก ์ ๊ณต๋ฉ๋๋ค. ์ด ๋ฐฉ์์ ์ถ๊ฐ ์
๋ ฅ ํ ํฐ์ ๋๊ฐ๋ก, ์์ ์๊ตฌ์ฌํญ์ด๋ ์คํจํ ์ ๊ทผ ๋ฐฉ์์ ์์กดํ๋ ์ธ๊ณ(handoff)์ ๋์์ด ๋ฉ๋๋ค. ๋ณด์กด๋ ํ
์คํธ, ๋๊ตฌ ํธ์ถ ์ค๋ช
/๊ฒฐ๊ณผ, JSON์ผ๋ก ์ง๋ ฌํํ ์ ์๋ ๋ฏธ๋์ด ์
๋ ฅ ๋ธ๋ก์ด ๋์ด๊ฐ๋๋ค. ๋ฐ์ด๋๋ฆฌ์ด๊ฑฐ๋ ๊ทธ ๋ฐ์ ์ด์ ๋ก ์ง๋ ฌํํ ์ ์๋ ๋ฏธ๋์ด ๋ธ๋ก์ ๋ช
์์ ์ธ ์๋ต ์๋ด๋ก ๋ฐ๋๋ฉฐ, ์ฃผ๋ณ ๋ํ๋ ๊ทธ๋๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ถ๋ชจ์ ์์คํ
ํ๋กฌํํธ, ์จ๊ฒจ์ง ํ๋ ์์ํฌ ๋ฉ์์ง(์ฃผ์
๋ ๋ฉ๋ชจ๋ฆฌ ๋ฐ ํ ์ผ ์๋ฆผ ๋ฑ), ์ถ๋ก ๋ธ๋ก, ๋๊ตฌ ์คํ ๋ฉํ๋ฐ์ดํฐ, ๋๊ธฐ ์ค์ธ ๋๊ตฌ ํธ์ถ์ ์ ์ธ๋ฉ๋๋ค. ๋๊ตฌ ํธ์ถ ์ค๋ช
์ ์ง์ด ๋ง๋ ๊ฒฐ๊ณผ๊ฐ ๋ณด์กด๋์ด ์์ด์ผ ํ๋ฉฐ, ํ์ฌ ์์
๊ณผ ํจ๊ป ์ด๋ฃจ์ด์ง ํธ์ถ๋ ๋ง์ฐฌ๊ฐ์ง์
๋๋ค. ์ ํจํ ์จ๊ฒจ์ง ์ฌ์ฉ์ ํ์ธ ์ง๋ฌธ(clarification) ์๋ต์ ๋ํ์ ์ผ๋ถ๋ก ๋จ์ต๋๋ค. ์์์ ์์ ์ ์ญํ , ๋ชจ๋ธ, ๋๊ตฌ, ์คํฌ ์ ํ์ ๊ทธ๋๋ก ์ ์งํฉ๋๋ค. ๋ถ๋ชจ์ ๋๊ตฌ ๊ธฐ๋ก์ผ๋ก๋ ์์์ ์คํ ๊ฒ์ฌ๋ฅผ ์ถฉ์กฑํ ์ ์์ต๋๋ค. ์ดํ ๋ถ๋ชจ์ ์์์ ๊ธฐ๋ก์ ๋
๋ฆฝ์ ์ผ๋ก ์งํ๋๋ฉฐ, ๊ณต์ ์๋๋ฐ์ค/ํ์ผ ์์คํ
๋์์ ๋ณํ์ง ์์ต๋๋ค. ์ค๋
์ท ๋ชจ๋๋ ์ด๋ฏธ ์์ถ๋ ๋ฉ์์ง๋ฅผ ๋ณต์ํ์ง ์์ผ๋ฉฐ ํ๋กฌํํธ ์บ์ ์ฌ์ฌ์ฉ์ ๋ณด์ฅํ์ง๋ ์์ต๋๋ค. ์์(durable) `batch_task` ํญ๋ชฉ์๋ ์ฌ์ ํ ์์ฒด์ ์ผ๋ก ์๊ฒฐ๋ ํ๋กฌํํธ๊ฐ ํ์ํฉ๋๋ค.
๋ค์ดํฐ๋ธ ๋ฌธ์ ๋ธ๋ก์ ์ค๋
์ท์ ๋ณด์กด๋ฉ๋๋ค. ์ด ๋ธ๋ก์ ํ
์คํธ ๋ด์ฉ, ์ ๋ชฉ, ์ปจํ
์คํธ์๋ ๋ค๋ฅธ ๊ณผ๊ฑฐ ํ
์คํธ์ ๋์ผํ ์์ฝ ํ๊ทธ ๋ฐ ์
๋ ฅ ๊ฒฝ๊ณ ๋ฌด๋ ฅํ๊ฐ ์ ์ฉ๋๋ฉฐ, ์ธ์ฝ๋ฉ๋ ๋ฏธ๋์ด์ URL ์์ค๋ ๋์ฝ๋ฉํ์ง ์๊ณ ๋ณด์กด๋ฉ๋๋ค.
์ ์ฒด ์ธ๊ณ์ ์ค๋
์ท์ ์๋ยทํฉ์ฑ ๋ฐฉ์์ผ๋ก ๋น๊ตํ ๊ฒฐ๊ณผ๋ [์ปจํ
์คํธ ์ค๋
์ท ํ๊ฐ](backend/scripts/benchmark/context_snapshot/README.md)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
์ปค์คํ
์์ด์ ํธ๋ ์ค๊ตญ์ด์ ์ด๋ชจ์ง๋ฅผ ํฌํจํ ์ ๋์ฝ๋ ํ์ ์ด๋ฆ์ ์ ํ์ ์ผ๋ก ์ง์ ํ ์ ์์ต๋๋ค. ์์ด์ ํธ์ **Agent settings โ Display name**์ ์ด์ด ์ค์ ํ๊ฑฐ๋(์ต๋ 100๊ฐ ์ ๋์ฝ๋ ์ฝ๋ ํฌ์ธํธ), ๋น์ ๋๋ฉด ๊ธฐ์กด ์๋ณ์๊ฐ ํ์๋ฉ๋๋ค. ์ ์ด ๋ฌธ์์ ์๋ฐฉํฅ ์์ ์ ์ด ๋ฌธ์๋ ๊ฑฐ๋ถ๋๋ฉฐ, ์ผ๋ฐ์ ์ธ ๋ค๊ตญ์ด ํ
์คํธ์ ์ด๋ชจ์ง๋ ์ง์๋ฉ๋๋ค. ๋ณด์ด์ง ์๋ ๋ฌธ์๋ก๋ง ์ด๋ฃจ์ด์ง ์ด๋ฆ๊ณผ ๋๋น ์๋ ๊ณต๋ฐฑ(zero-width space) ๊ฐ์ ๋ณด์ด์ง ์๋ ์์ ๋ฌธ์๋ ๊ฑฐ๋ถ๋ฉ๋๋ค. ์ด์ ๋ฒ์ ์ด๊ฑฐ๋ ์ง์ ํธ์งํ ์ ์ฅ ๋ฐ์ดํฐ์ ์๋ ์๋ชป๋ ํ์ ์ด๋ฆ์ ์ฝ์ ๋ ์์ด์ ํธ ์๋ณ์๋ก ํด๋ฐฑ๋๋ฉฐ, ๊ฒฝ๊ณ ์ ํด๋น ์์ด์ ํธ๊ฐ ํ์๋ฉ๋๋ค. ๋ค์ ๋ถํธ์คํธ๋ฉํด๋ ์ ํจํ ํ์ ์ด๋ฆ์ ๋ณด์กด๋ฉ๋๋ค. ๊ฐค๋ฌ๋ฆฌ, ์ฑํ
ํค๋, ํ์ ํ์ด์ง๋ ์ด ๋ผ๋ฒจ์ ์ฌ์ฉํ๋ฉฐ, URL๊ณผ API ํธ์ถ์ ๊ณ์ํด์ ๊ณ ์ ๋ ์๋ฌธ `name`์ ์ฌ์ฉํฉ๋๋ค. API ํธ์ถ์๋ ์์ด์ ํธ ์์ฑ ๋๋ ์
๋ฐ์ดํธ ์์ฒญ์ `display_name`์ ์ ๋ฌํ ์ ์์ผ๋ฉฐ, ์
๋ฐ์ดํธ์์ ์๋ตํ๋ฉด ๊ธฐ์กด ๊ฐ์ด ์ ์ง๋๊ณ `null`์ ์ ๋ฌํ๋ฉด ์ง์์ง๋๋ค. ๊ฐ์ ์ ํ ํ๋๋ ์์ด์ ํธ์ `config.yaml`์์๋ ์ง์๋ฉ๋๋ค.
`agent_storage.backend: db`๋ก ๋ง์ด๊ทธ๋ ์ด์
๋ ์ปค์คํ
์์ด์ ํธ๋ ๊ฐ์ ธ์ค๊ธฐ ๋๊ตฌ(importer)๊ฐ ๋กค๋ฐฑ์ ์ํด ๊ธฐ์กด ํ์ผ์ ๋ณด๊ดํ๋ ๋์์๋ Agent settings์ `update_agent`๋ฅผ ํตํด ๊ณ์ ํธ์งํ ์ ์์ต๋๋ค. ๋ง์ด๊ทธ๋ ์ด์
์ ์ฐจ๋ [์์ด์ ํธ ์ ์ฅ์](backend/docs/CONFIGURATION.md#agent-storage)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
์ปค์คํ
์์ด์ ํธ๋ Agents ๊ฐค๋ฌ๋ฆฌ์์ DeerFlow ์ฌ์ฉ์ ๊ฐ ๋๋ ๋ฐฐํฌ ๊ฐ์ ์ฎ๊ธธ ์๋ ์์ต๋๋ค. **Export Agent**๋ ๋ฒ์ ์ด ์ง์ ๋ `*.deerflow-agent.json` ํจํค์ง๋ฅผ ๋ค์ด๋ก๋ํ๋ฉฐ, ์ด ํจํค์ง์๋ ์ด์ ๊ฐ๋ฅํ ์ ์์ `SOUL.md`๊ฐ ๋ด๊ฒจ ์์ต๋๋ค. **Import Agent**๋ ํด๋น ํจํค์ง๋ฅผ ๊ฒ์ฆํ ๋ค ๋ฐ๋ ์ฌ์ฉ์๊ฐ ๋ก์ปฌ ์ด๋ฆ์ ์ ํ ์ ์๊ฒ ํฉ๋๋ค. ์๋ชป๋ ํจํค์ง์๋ ๊ฒ์ฆ ๋ฉ์์ง๊ฐ ํ์๋๋ฏ๋ก ํจํค์ง๋ฅผ ์์ ํด ๋ค์ ์๋ํ ์ ์์ต๋๋ค. ๊ฐ์ ธ์ค๊ธฐ๋ ๊ธฐ์กด ์์ด์ ํธ๋ฅผ ์ ๋ ๋ฎ์ด์ฐ์ง ์์ต๋๋ค. ํจํค์ง์๋ ๋ชจ๋ธ, ๋๊ตฌ/MCP, ์คํฌ, ์ง์, ์๋ธ์์ด์ ํธ, ์ถ๋ก , ๋ฉ๋ชจ๋ฆฌ ์ ์ฑ
์ค์ ์ด ํฌํจ๋์ง๋ง, ๋ฉ๋ชจ๋ฆฌ ๋ด์ฉ, ๋ํ, ์๊ฒฉ ์ฆ๋ช
, ์ด์์ ์์ ์ GitHub ๋ฐ์ธ๋ฉ์ ์๋์ ์ผ๋ก ์ ์ธ๋ฉ๋๋ค.
์๋ธ์์ด์ ํธ๋ ์ต์ ํ ์๋จ์ด๋ฉฐ, ๋ณต์กํ ์์ฒญ์ ๋ํ ๊ธฐ๋ณธ ๋์์ด ์๋๋๋ค.
์์๋ ์์
์ด ์๋ต์ ๋ฐํํ๊ธฐ ์ ์ Stop์ผ๋ก ์ค๋จ๋๋ฉด, ๋ค์ ์ฌ์ฉ์ ํด์์ ์์ด์ ํธ์ ์์ ์ปจํ
์คํธ์ ๊ทธ ์ด์ ์์
์ ์ทจ์๋จ์ผ๋ก ํ์ํ์ฌ ์ฌ์๋ํ ์ ์๊ฒ ํฉ๋๋ค. ๊ธฐ์กด ์๋ต์ ๋ณด์กด๋ฉ๋๋ค. ์ํ ๋ฉํ๋ฐ์ดํฐ๊ฐ ์๋ ์ด์ ์๋ต์ ์ฌ์ ํ ์งํ ์ค์ผ๋ก ๋ณด์ผ ์ ์์ผ๋ฉฐ, ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์๋ต ํ
์คํธ๋ก๋ถํฐ ์ถ๋ก ํ์ง ์์ต๋๋ค. ์์ ์์ ์์ฅ์ ์คํ(run)๊ณผ ํ๋ก๋ฐ์ด๋ ๋๊ตฌ ํธ์ถ ID๋ก ํธ์ถ์ ๊ตฌ๋ถํ๋ฏ๋ก, ์ดํ์ ์ฌ์ฉ์ ํด์ด ๊ฐ์ ID๋ฅผ ์ฌ์ฌ์ฉํ๋๋ผ๋ ์ด์ ์์
์ ๋์ฒดํ๊ฑฐ๋ ํด๋น ํด์ ์คํ๋ณ ์์ ํ์๋ฅผ ์์ง ์์ต๋๋ค.
๋ฆฌ๋ ์์ด์ ํธ๋ ์ค์ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ก ์ธํ ์ง์ฐ ์๊ฐ ๋จ์ถ, ์ ๋ฌธ ๊ธฐ๋ฅ, ์ปจํ
์คํธ ๊ฒฉ๋ฆฌ๋ฅผ ํตํด ์์์ ์์ด์ต์ด ๋ถ๋ช
ํ ๋, ๊ฐ์ ๋ฒ์๊ฐ ์ง์ ๋ ์ปจํ
์คํธ, ๋๊ตฌ, ์ข
๋ฃ ์กฐ๊ฑด์ ๊ฐ์ถ ์๋ธ์์ด์ ํธ๋ฅผ ์ฆ์์์ ์์ฑํ ์ ์์ต๋๋ค. ์๋ก ์์กดํ๋ ๋ฒ์์ ๋ถ์ ํจ๊ณผ๊ฐ ๊ฒน์น๋ ์์
์ ๋ณ๋ ฌ ๋์คํจ์น์์ ์ ์ธํ๋ฉฐ, ์ ๋ฌธ์ฑ์ด๋ ์ปจํ
์คํธ ๊ฒฉ๋ฆฌ์ ์ด์ ์ด ๋ถ๋ช
ํ ๋ ํด ๋๋ ๋ฒ์๊ฐ ํ์ ๋ ์์ฐจ ์์
์ฒด์ธ์ ํ๋์ ์๋ธ์์ด์ ํธ์์ ์คํํ ์๋ ์์ต๋๋ค. ๋ฆฌ๋ ์์ด์ ํธ๋ ์ ์ฉํ ์ต์ํ์ ์๋ธ์์ด์ ํธ๋ง ์ฌ์ฉํ๊ณ , ์์
์ด ํฌ๊ฑฐ๋ ์ฌ๋ฌ ๋จ๊ณ๋ก ์ด๋ฃจ์ด์ก๋ค๋ ์ด์ ๋ง์ผ๋ก ์์
์ ๋ถ์ฐ(fan-out)ํ์ง ์๊ณ ์ดํ ๋ฐฐ์น๋ฅผ ๋ค์ ํ๊ฐํฉ๋๋ค. ์๋ธ์์ด์ ํธ๋ ๊ตฌ์กฐํ๋ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ํ๊ณ , ๋ฆฌ๋ ์์ด์ ํธ๋ ์ด๋ฅผ ๊ฒ์ฆํ๊ณ ์ข
ํฉํด ์ผ๊ด๋ ๊ฒฐ๊ณผ๋ฌผ์ ๋ง๋ญ๋๋ค. ๊ฒฐ์ ์ (deterministic) ๋๊ตฌ ์์์ฆ์ ์ง์ ์ ์ธ ๋๊ตฌ ๋ฉ์์ง์, ์ํ๋ฅผ ๊ฐฑ์ ํ๋ `Command` ๊ฒฐ๊ณผ(์์๋ `task` ์๋ต ๋ฑ)๋ฅผ ๋ชจ๋ ๋ค๋ฃจ๋ฉฐ, ์์์ฆ ์์ฅ์ด ์ปจํ
์คํธ ์์ฐ์ ๋๋ฌํ๋ฉด ๊ฐ์ฅ ์ต๊ทผ์ ์์
๊ณผ ๊ทธ ์๋ ์์์ฆ ID๋ฅผ ์ ์งํฉ๋๋ค. ์ด์์๋ `verification.receipts_enabled: false`๋ก ์ด ์ถ์ฒ(provenance) ๊ณ์ธต์ ๋ ์ ์์ต๋๋ค. ์๋ธ์์ด์ ํธ์ ์ค์ ๋ ์คํฌ์ ๋ฆฌ๋ ์์ด์ ํธ์ ๋์ผํ ์ฌ์ฉ์ ๋ฒ์ ์นดํ๋ก๊ทธ์์ ํด์๋๋ฏ๋ก, ์ฌ์ฉ์ ์์ ์ ์ปค์คํ
์คํฌ์ ๋ค๋ฅธ ์ฌ์ฉ์์ ๋ฒ์ ์ ๋
ธ์ถํ์ง ์์ผ๋ฉด์ ๊ณ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์๋ธ์์ด์ ํธ ๋ด๋ถ์ AI ๋ฐ ๋๊ตฌ ๋ฉ์์ง๋ ๋ถ๋ชจ ์ฑํ
์คํธ๋ฆผ์ ๋ค์ด๊ฐ์ง ์๊ณ ์์๋ ๊ทธ๋ํ ๋ฒ์ ์์ ๋จธ๋ญ
๋๋ค. ๋ค์ ๋ถ๋ฌ์จ ์ค๋ ๋ ๊ธฐ๋ก๋ ๊ฐ์ ๊ฒฝ๊ณ๋ฅผ ์ ์ฉํฉ๋๋ค. ์ฝ๋ฐฑ์ผ๋ก ์บก์ฒ๋ ์๋ธ์์ด์ ํธ AI ์๋ต์ ์คํ ์ด๋ฒคํธ ์ง๋จ์์๋ ๊ณ์ ๋ณผ ์ ์์ง๋ง ๋ถ๋ชจ ๋ํ ๊ธฐ๋ก์์๋ ์ ์ธ๋๋ฉฐ, ๋ถ๋ชจ์ `task` ๊ฒฐ๊ณผ๋ ํด๋น ํ์ ์์
์นด๋์ ๊ณ์ ์ฐ๊ฒฐ๋ฉ๋๋ค. ์ค๋ ์คํ๋๋ ์๋ธ์์ด์ ํธ๋ ์์ฝ์ด ํ์ฑํ๋ ๊ฒฝ์ฐ ์ค๋๋ ๊ธฐ๋ก์ ์์ถํ๊ณ , ๊ณ์ ์งํํ๊ธฐ ์ ์ ์์ฝ์ ๋ณดํธ๋ ์จ๊ฒจ์ง ์์ ์ปจํ
์คํธ๋ก ๋ค์ ์ฃผ์
ํ๋ฏ๋ก ์ต๊ทผ์ ์ด์์คํดํธ/๋๊ตฌ ํ๋์ด ์์
์ ๊ทผ๊ฑฐ๋ฅผ ๋๊ณ ์ ์ง๋ฉ๋๋ค. ์ญํ ๊ณผ ๋ณด๊ณ ๊ณ์ฝ์ ํฌํจํ ์๋ธ์์ด์ ํธ์ ์์คํ
์ง์๋ ์์ถ ํ์๋ ์ ์ง๋๋ฉฐ, ์์ฝ ๋์์ด ์ด ์ง์์ ํ์ฌ ์์ฒญ๋ฟ์ด๋ผ๋ฉด ์์ถ์ ๊ฑด๋๋๋๋ค. ํ๋ก๋ฐ์ด๋/๋ชจ๋ธ ์์ฒญ ์คํจ๋ ์ฑ๊ณตํ ๊ฒฐ๊ณผ๊ฐ ์๋๋ผ ์คํจํ ์๋ธ์์ด์ ํธ ์์
์ผ๋ก ๋ณด๊ณ ๋๋ฏ๋ก, ๋ฆฌ๋ ์์ด์ ํธ์ ์น UI๊ฐ ์ด์ ์ฌ๋ฐ๋ฅด๊ฒ ๋์ํ ์ ์์ต๋๋ค. ๋์์ ์งํ๋๋ ๋ถ๋ชจ ์คํ๋ ์๋ก ๋
๋ฆฝ๋ ์๋ฒ ์ธก ์๋ธ์์ด์ ํธ ์คํ ID๋ฅผ ๋ฐ์ผ๋ฏ๋ก, ํ๋ก๋ฐ์ด๋๊ฐ ๋๊ตฌ ํธ์ถ ID๋ฅผ ์ฌ์ฌ์ฉํ๋๋ผ๋ ํ ์คํ์ด ๋ค๋ฅธ ์คํ์ ๋ฐฑ๊ทธ๋ผ์ด๋ ์์
์ ํด๋งํ๊ฑฐ๋ ์ทจ์ํ๊ฑฐ๋ ์ ๋ฆฌํ๊ฒ ๋ง๋ค ์ ์์ต๋๋ค. ์ ํ ์๋ธ์์ด์ ํธ ์นด๋์๋ ์ค์ ์ ์ฉ๋ ๋ชจ๋ธ์ด ํ์๋๊ณ , ํ๋ก๋ฐ์ด๋๊ฐ ์ฌ์ฉ๋ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ๋ ๊ฒฝ์ฐ ๋์ ํ ํฐ ํฉ๊ณ๋ ํ์๋ฉ๋๋ค. ์ด ํฉ๊ณ๋ ์๋ธ์์ด์ ํธ์ LLM ํธ์ถ์ด ์๋ฃ๋ ๋๋ง๋ค ๊ฐฑ์ ๋๋ฉฐ ์๋ก๊ณ ์นจ ํ์๋ ์ ์ง๋ฉ๋๋ค. ํ ํฐ ์ฌ์ฉ๋ ์ถ์ ์ด ํ์ฑํ๋ ๊ฒฝ์ฐ, ์๋ฃ๋ ์๋ธ์์ด์ ํธ ์ฌ์ฉ๋์ ํ๋ก์ธ์ค ์ ์ญ ํ๋ก๋ฐ์ด๋ ID ์บ์๊ฐ ์๋๋ผ ํด๋น ์คํ์ ์ข
๋ฃ ๋๊ตฌ ๋ฉ์์ง ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๊ธฐ์ค์ผ๋ก, ๋์คํจ์นํ ๋จ๊ณ์ ๋ค์ ๊ท์๋ฉ๋๋ค.
์๋ธ์์ด์ ํธ ์นด๋๋ ์ธ์๋์ง ์๋ ๊ตฌ์กฐํ๋ ์์
์ํ๋ฅผ ์งํ ์ค์ผ๋ก ์ ์งํฉ๋๋ค. ํจ๊ป ์ ๋ฌ๋ ๊ฒฐ๊ณผ ํ
์คํธ๊ฐ ์์ด๋ ์ ์ ์๋ ์ํ๋ฅผ ์ฑ๊ณต์ด๋ ์คํจ๋ก ๋ฐ๊พธ์ง ์์ต๋๋ค.
์ทจ์๋์๊ฑฐ๋ ํ์์์๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ์๋ธ์์ด์ ํธ ์คํ์ ์๋ฃ๋ ๋ชจ๋ธ ํธ์ถ์์ ํ๋ก๋ฐ์ด๋๊ฐ ๋ณด๊ณ ํ ํ ํฐ ์ฌ์ฉ๋์ ์ ์งํ๋ฉฐ, ๋ค์ ์งํ ์ํฉ ์
๋ฐ์ดํธ ์ ์ ๋ฐ์ ์๋ต๋ ์ด์ ํฌํจ๋ฉ๋๋ค. ๋ถ๋ชจ ์คํ์ ์ต์ข
์ฌ์ฉ๋์ ์ ๋ฌํ ๋ ์ด์ ์งํ ์ค๋
์ท์ ๋ ๋ฒ ๊ณ์ฐํ์ง ์์ต๋๋ค.
`tests_passed:go test ./...`์ ๊ฒฝ์ฐ, `[no test files]` ๋๋ `[no tests to run]`์ผ๋ก ํ์๋ ํจํค์ง๊ฐ ๋ค๋ฅธ ํจํค์ง์ ํต๊ณผ ์์ฝ์ ๋ฌดํจํํ์ง ์์ต๋๋ค. ํ
์คํธ๊ฐ 0๊ฐ์ธ ํจํค์ง ์์ฝ๋ง ์๋ ์คํ์ `UNVERIFIED`๋ก ๋จ๊ณ , ์คํจ๋ ์ฌ์ ํ ์ฐ์ ํฉ๋๋ค. ์ด๋ ๊ธฐ๋ก๋ ์คํ ์ฆ๊ฑฐ๋ฅผ ํ์ธํ๋ ๊ฒ์ด์ง, ์ฃผ์ฅ์ ์ ํ์ฑ์ ํ์ธํ๋ ๊ฒ์ด ์๋๋๋ค.
`tests_passed:cargo test`์ ๊ฒฝ์ฐ, ์์ ํ ํต๊ณผ ๋์(target) ์์ฝ์ ๋น์ด ์๋ ๋จ์, ํตํฉ ๋๋ ๋ฌธ์ ๋์๊ณผ ํจ๊ป ์์ ์ ์์ต๋๋ค. ํต๊ณผ ์๊ฐ 0์ธ ์์ ํ ์ฑ๊ณต ์์ฝ์ ์ด๋ฌํ ํ์ ์ฆ๊ฑฐ๋ฅผ ๋ฌดํจํํ์ง ์์ต๋๋ค. ๋ชจ๋ ๋์์ด ๋น์ด ์๊ฑฐ๋ ๋ชจ๋ ๋ฌด์๋(ignored) ์คํ๊ณผ `test result: ok` ๋ฐฐ๋๋ง ์๋ ๊ฒฝ์ฐ๋ `UNVERIFIED`๋ก ๋จ์ต๋๋ค. ํ
์คํธ๊ฐ 0๊ฐ์ธ ๋ถ์์ ํ ์์ฝ์ ๊ณ์ ๋ฌดํจํ ์์ธ์ผ๋ก ์ ์ง๋๋ฉฐ, ์คํจ๋ ์ฌ์ ํ ์ฐ์ ํฉ๋๋ค.
Maven ๋ฐ Gradle ํ
์คํธ ์๋ฝ ๊ธฐ์ค์ ๊ฒฝ์ฐ, `BUILD SUCCESS` / `BUILD SUCCESSFUL` ๋ฐฐ๋๋ง ์์ผ๋ฉด `UNVERIFIED`๋ก ๋จ์ต๋๋ค. ํ
์คํธ๋ฅผ ์คํํ์ง ์๊ณ ๋ ๋น๋๋ ์ฑ๊ณตํ ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค. ์์ ํ `Tests run: N, Failures: F, Errors: E, Skipped: S` ๋๋ `N tests completed` ์์ฝ์ ๋ณด๊ณ ๋ ์คํจ ์์ด ์ต์ ํ๋์ ํ
์คํธ๊ฐ ์คํ๋ ๊ฒฝ์ฐ์๋ง ๊ธฐ์ค ์ถฉ์กฑ(hold)์ ์ฑ๋ฆฝ์ํต๋๋ค. ํ
์คํธ๊ฐ 0๊ฐ์ด๊ฑฐ๋ ๋ชจ๋ ๊ฑด๋๋ด ๋ชจ๋์ ๊ธ์ ์ ์ฆ๊ฑฐ๋ฅผ ์ ๊ณตํ์ง ์์ผ๋ฉฐ, ์ด๋ ๋ชจ๋์์๋ ์คํจ๊ฐ ์์ผ๋ฉด ํต๊ณผ ํ์๋ณด๋ค ์ฐ์ ํฉ๋๋ค.
ํ์ผ ์๋ฝ ๊ธฐ์ค์ ๊ฒฝ์ฐ, ๊ณต์ ์ํฌ์คํ์ด์ค์ ์๋ ๋น ์ผ๋ฐ ํ์ผ์ ์๊ฒฉ ์๋๋ฐ์ค๋ฅผ ํฌํจํด `file: exists`์ `file_written:`๋ฅผ ์ถฉ์กฑํ ์ ์์ต๋๋ค. ํ์ง๋ง `file: non-empty`์์๋ ๊ฒฐ์ ์ ์ธ ๋น ํ์ผ ๊ฒฐ๊ณผ๋ก ์คํจํฉ๋๋ค.
CSV ํค๋ ์ด์ ์๊ตฌํ๋ ค๋ฉด `task` ๋๋ `batch_task` ํญ๋ชฉ์ ๊ธฐ์ค์ `file:../outputs/report.csv csv-columns:["id","name"]`๋ก ์ค์ ํ์ธ์. JSON ๋ฐฐ์ด์๋ ์ค๋ณต๋์ง ์๊ณ ๋น์ด ์์ง ์์ผ๋ฉฐ UTF-8๋ก ์ธ์ฝ๋ฉํ ์ ์๋ ์ด ์ด๋ฆ์ด ๋ค์ด ์์ด์ผ ํฉ๋๋ค. ์ด๋ฆ์ ์์์ ๊ด๊ณ์์ด ์ ํํ(๋์๋ฌธ์์ ๊ณต๋ฐฑ ํฌํจ) ์ผ์นํด์ผ ํ๋ฉฐ, ์ถ๊ฐ ์ด์ ํ์ฉ๋ฉ๋๋ค. ๊ฒ์ฌ๋ ์ ํ๋ ์๋ถ๋ถ๋ง ์ฝ๊ณ ์ผํ๋ก ๊ตฌ๋ถ๋ ์ฒซ ๋ฒ์งธ ๋
ผ๋ฆฌ ๋ ์ฝ๋๋ฅผ ํ์ฑํ๋ฉฐ, ํฐ๋ฐ์ดํ๋ก ๋ฌถ์ธ ํ๋, ์ฐ๋ฌ์ ์ด ๋ ๊ฐ์ ๋ฐ์ดํ, ํ๋ ์์ ์ค๋ฐ๊ฟ, ์ ํ์ ์ธ UTF-8 BOM์ ์ง์ํฉ๋๋ค. ๋ฐ์ดํฐ ํ์ ๊ฒ์ฆํ์ง ์์ต๋๋ค. ๋น ํ์ผ, ํ์ ์ด ๋๋ฝ, ํ์์ด ์๋ชป๋์๊ฑฐ๋ ์ ํจํ์ง ์์ UTF-8 ํค๋, ๋น์ด ์๊ฑฐ๋ ์ค๋ณต๋ ํค๋ ์ด๋ฆ์ `does not hold`๋ฅผ ๋ฐํํฉ๋๋ค. **50,000๋ฐ์ดํธ**๋ฅผ ๋๋ ํค๋, ๋ถ์์ ํ ์ฝ๊ธฐ, ์ ํจํ์ง ์์ ๊ธฐ์ค, ์ํฌ์คํ์ด์ค ์ ๊ทผ ๋ถ๊ฐ, ์ฝ๊ธฐ ์์ฐ ์์ง์ `UNVERIFIED`๋ฅผ ๋ฐํํฉ๋๋ค. ํฐ ํ์ผ์ด๋ผ๋ ์ ์ฒด ํค๋๊ฐ ์์ฐ ์์ ๋ค์ด๊ฐ๋ฉด ๊ฒ์ฌ๋ฅผ ์ถฉ์กฑํ ์ ์์ต๋๋ค. ํด๋น ํค๋ ์์ ๋ช
ํํ ๊ตฌ๋ฌธ ์ค๋ฅ๋ ์ดํ ๋ฐ์ดํฐ ํ๊ณผ ๊ด๊ณ์์ด ๊ฒ์ฌ๋ ๋ถ์ ๊ฒฐ๊ณผ๋ก ๋จ์ผ๋ฉฐ, ์๋ฆฐ ๋ฐ์ดํ ์ฒ๋ฆฌ๋ `UNVERIFIED`๋ก ๋จ์ต๋๋ค. ์ฝ๊ธฐ์๋ ์๋ JSON ๊ฒ์ฌ์ ๋์ผํ ๊ถํ ํ์ธ ๋ฐ ๋ฒ์ ์ง์ ์ ์ก ๋ฐฉ์์ด ์ฌ์ฉ๋ฉ๋๋ค. ์ต๋ 50,001๋ฐ์ดํธ์ด๋ฉฐ, ์๊ฒฉ ์ฝ๊ธฐ์๋ 5์ด ๋ช
๋ น ํ์์์(ํ๋ก๋ฐ์ด๋ ํธ์ถ์ 10์ด)์ด ์ ์ฉ๋ฉ๋๋ค. ๋ก์ปฌ ์ฝ๊ธฐ์ ํ์ฑ์ ํ๋ ฅ์ ์ธ 5์ด ๋ง๊ฐ ์๊ฐ์ ๊ณต์ ํ๋ฉฐ, ์๊ฒฉ ํ์ฑ์ ์ฝ๊ธฐ๊ฐ ๋ฐํ๋ ๋ค๋ถํฐ ์์ํ๋ ๋ณ๋์ 5์ด ๋ง๊ฐ ์๊ฐ์ ๊ฐ์ง๋๋ค. ์ด ๊ฒ์ฌ๋ ์งํ ์ค์ธ ํ์ผ ์์คํ
ํธ์ถ์ด๋ ํ์ ํธ์ถ์ ์ค๋จํ์ง ์์ต๋๋ค. ๋์ ์ฐ๊ธฐ๋ ์์์ ์ค๋
์ท์ด ๋์ง ์์ต๋๋ค. ์ด ๊ฒ์ฌ๋ ๋ฐ์ดํฐ ํ์
, ํ ์, ๋น์ฆ๋์ค ์๋ฏธ๋ฅผ ๊ฒ์ฆํ์ง ์์ต๋๋ค.
JSON ๊ตฌ๋ฌธ ๊ฒ์ฆ์ ์์ฒญํ๋ ค๋ฉด `task` ๋๋ `batch_task` ํญ๋ชฉ์ `acceptance_criteria`๋ฅผ ๋ช
์์ ์ผ๋ก `["file:../outputs/report.json json-valid"]`๋ก ์ค์ ํ์ธ์. ๊ฒ์ฌ๋ ๊ณต์ ์ํฌ์คํ์ด์ค ์์ ์๋ **50,000๋ฐ์ดํธ** ์ดํ์ ์์ ํ UTF-8 JSON ํ์ผ๋ง ๋์์ผ๋ก ํฉ๋๋ค. ์ ํจํ ๊ตฌ๋ฌธ์ `holds`๋ฅผ ๋ฐํํ๊ณ , ๋น ํ์ผ, ๊ตฌ๋ฌธ ์ค๋ฅ, UTF-8์ด ์๋ ๋ด์ฉ, `NaN`/`Infinity`๋ `does not hold`๋ฅผ ๋ฐํํฉ๋๋ค. ํฌ๊ธฐ ์ด๊ณผ ํ์ผ, ๋ถ์์ ํ ์ฝ๊ธฐ, ๋ฒ์๋ฅผ ๋ฒ์ด๋ ๊ฒฝ๋ก, ํ์ ๋ฆฌ์์ค ์ ํ์ `UNVERIFIED`๋ฅผ ๋ฐํํฉ๋๋ค. ํฌ๊ธฐ ์ด๊ณผ ๋ด์ฉ์ ๊ฐ์งํ๊ธฐ ์ํด ์ฝ๊ธฐ๋ 50,001๋ฐ์ดํธ๋ก ์ ํ๋ฉ๋๋ค. ์๊ฒฉ ๊ฒฐ๊ณผ๋ ์๋ฃ ๋ง์ปค, ์ฝ๊ธฐ ์ข
๋ฃ ์ฝ๋, ํ์ธํ ํฌ๊ธฐ๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ฒ์ฌํฉ๋๋ค. ํ์ํ ํ์ธ ๋๊ตฌ๊ฐ ์๋ ์๊ฒฉ ํ๋ก๋ฐ์ด๋๋ ์ ์ฒด ๋ด์ฉ ์ฝ๊ธฐ๋ก ํด๋ฐฑํ์ง ์๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋ฏธ๊ฒ์ฆ ์ํ๋ก ๋ก๋๋ค. ํฌ๊ธฐ๊ฐ ๊ฐ์ ๋์ ์ฐ๊ธฐ๋ ์์์ ์ค๋
์ท์ ๋ง๋ค์ง ์์ต๋๋ค. ๋ก์ปฌ ๊ฒ์ฌ๋ ๊ฒฝ๋ก๋ฅผ ํด์ํ๊ฑฐ๋ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ํ์ธํ๊ธฐ ์ ์ ์๋๋ฐ์ค ์ ๊ทผ ๊ถํ์ ํ์ธํ๊ณ , ๋ด์ฉ์ ์ฝ๊ธฐ ์ ์ ๋ค์ ํ์ธํฉ๋๋ค. ๊ถํ์ด ํ์๋๋ฉด ํ์ผ ์กด์ฌ ์ฌ๋ถ๋ฅผ ๋๋ฌ๋ด์ง ์๊ณ `UNVERIFIED`๋ฅผ ๋ฐํํฉ๋๋ค. ์๊ฒฉ ํ์ธ์ ๊ฒ์ ๊ฐ๋ฅํ ์์ ๋๋ ํฐ๋ฆฌ์ ๋ฒ์ ์์ ์ ๊ท ๊ฒฝ๋ก๊ฐ ์์ ๋์๋ง ํ์ผ์ด ์๋ค๊ณ ๋ณด๊ณ ํ๋ฉฐ, ์ ๊ทผํ ์ ์๋ ๋๋ ํฐ๋ฆฌ๋ `UNVERIFIED`๋ก ๋จ์ต๋๋ค. UTF-8 BOM์ ๊ฑฐ๋ถ๋ฉ๋๋ค. ์ต์์ ์ค์นผ๋ผ ๊ฐ, ์ค๋ณต ํค, ๊ตฌ๋ฌธ์ ์ ํจํ ํฐ ์ซ์๋ ํต๊ณผํ ์ ์์ผ๋ฉฐ, ์คํค๋ง, ํ๋, ๋น์ฆ๋์ค ์๋ฏธ๋ ๊ฒ์ฆํ์ง ์์ต๋๋ค. ๋ค๋ฅธ ํ์ผ ๊ธฐ์ค์ ๋ณ๊ฒฝ๋์ง ์์ผ๋ฉฐ, `.json` ํ์ผ์ ์๋์ผ๋ก ๊ฒ์ฌ๋์ง ์์ต๋๋ค. ์ด ๊ธฐ์ค์ ์์๋ฐฉํธ์ ์ธ bash/Python ๊ฒ์ฌ๋ฅผ ์๊ตฌํ๋ ๋์ ํ์ , ๊ฒฝ๋ก ๊ฒฝ๊ณ, ์ฝ๊ธฐ ์ ํ์ ํ์คํํ๊ณ , ์ฆ๊ฑฐ๊ฐ ๋ถ์ถฉ๋ถํ๋ค๋ ์ฌ์ค์ ๋ช
์์ ์ผ๋ก ๋๋ฌ๋
๋๋ค. ์คํ ์๋ฃ ์ํ์ ์๋ ์ฌ์๋ ์ ์ฑ
์ ๋ณ๊ฒฝ๋์ง ์์ต๋๋ค.
๋ด์ฉ์ด ์๋ ์๋ธ์์ด์ ํธ ์ต์ข
๋ฉ์์ง๋ `No response generated`๋ฅผ ๋ณด๊ณ ํ๋ฉฐ, ๋ฆฌํฐ๋ด ํ
์คํธ `None`์ ๋ณด๊ณ ํ์ง ์์ต๋๋ค. ๋ด์ฉ์ด ์๋ ํ๋ก๋ฐ์ด๋ ์ค๋ฅ ํด๋ฐฑ์ ๊ตฌ์กฐํ๋ ์ค๋ฅ ์ธ๋ถ ์ ๋ณด๊ฐ ์์ผ๋ฉด ์ด๋ฅผ ๋ณด๊ณ ํฉ๋๋ค.
์ผ๋ฐ `task`๋ ๋์คํจ์นํ ์คํ์ ํ์ฌ ์
๋ก๋์ ๋ํ ๋ฐฉ์ด์ ์ค๋
์ท๋ ๋ฐ์ต๋๋ค. ์ด๋ฅผ ํตํด ์กฐ๊ฑด์ ์ถฉ์กฑํ๋ ์๋ธ์์ด์ ํธ๋ `list_uploaded_files`๋ก ์ด์ ํด์ ํ์ผ์ ์ฐพ์ ์ ์์ผ๋ฉฐ, ๊ฐ์ ํด์ ์ฒจ๋ถ ํ์ผ์ ๊ณผ๊ฑฐ ํ์ผ๋ก ๋ฐํํ์ง ์์ต๋๋ค. ์ง์ฐ๋์๊ฑฐ๋ ๋ณต๊ตฌ๋ `batch_task` ์์ปค๋ ์ ํจํ ํด ๋ก์ปฌ ์
๋ก๋ ๊ฒฝ๊ณ๊ฐ ์์ผ๋ฏ๋ก ์ด ๋๊ตฌ๋ฅผ ๋นํ์ฑํํ ์ํ๋ก ๋ก๋๋ค.
์๋ฒ ๋๋ Python ์
๋ก๋๋ ์
๋ก๋ ๋์ค ํธ์ถ์์ ์์ค๊ฐ ๋ฐ๋๋๋ผ๋, ์ ์ฅ๋ ๋ฌธ์์ ๊ทธ Markdown ๋ณํ์ ๋์ผํ๊ฒ ์บก์ฒ๋ ๋ด์ฉ์ ์ฌ์ฉํฉ๋๋ค.
๊ณผ๊ฑฐ ์
๋ก๋ ํ์์ ์์ ์ ์ธ ํ์ด์ง ์ด์ด ๋ณด๊ธฐ๋ฅผ ์ง์ํฉ๋๋ค. `list_uploaded_files`๋ ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ด์ง๋น 20๊ฐ, ์ต๋ 100๊ฐ ํญ๋ชฉ์ ๋ฐํํฉ๋๋ค. ๋ฐํ๋ `next_cursor`๋ฅผ ๋ค์ ํธ์ถ์ `cursor`๋ก ์ ๋ฌํ๊ณ ๊ฐ์ ํํฐ ์กฐ๊ฑด์ ์ ์งํ๋ฉด์, ๋ง์ง๋ง ํ์ด์ง์์ ๋ ์ด์ ์ปค์๊ฐ ๋ฐํ๋์ง ์์ ๋๊น์ง ๊ณ์ํ์ธ์. ๋๋ ํฐ๋ฆฌ ๋ฉํ๋ฐ์ดํฐ๋ ํธ์ถ ์ปจํ
์คํธ๊ฐ ๋ฐ๋๋ฉด ๋ค์ ์ด๊ฑฐํ๋ผ๋ ์๊ตฌ๊ฐ ๋ช
์์ ์ผ๋ก ๋ฐํ๋ฉ๋๋ค. ์์ธํ ๋ด์ฉ์ [ํ์ผ ์
๋ก๋ ๋ฌธ์](backend/docs/FILE_UPLOAD.md)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
์์ `batch_task` ์์ปค๋ ๋๊ตฌ ์กฐ๋ฆฝ๊ณผ ์คํ์ ์ฑ์ด ์์ ํ ๋จ์ผ ํ๋ฌ๊ทธ์ธ ์ค๋
์ท์ ์ฌ์ฉํฉ๋๋ค. ๋ณต๊ตฌ๋ ์์
์ Gateway ์ฌ์์ ํ ์ ์์ปค์ ํ๋ฌ๊ทธ์ธ ์ค๋
์ท์ ์ฑํํ๋ฉฐ, ํ๋ฌ๊ทธ์ธ ๊ฐ์ฒด๋ ์์ ์์
๋ ์ฝ๋์ ์ ๋ ์ ์ฅ๋์ง ์์ต๋๋ค.
์ผ๋ฐ `task` ์์๊ณผ ๋ช
์์ ์ธ ์์ `batch_task` ์คํ์ ์์ ์์ ๋ฒ์์ `subagent_runtime` ํ๋ก์ธ์ค ์ฉ๋์ ๊ณต์ ํฉ๋๋ค. ๋ฐฐ์น ๋ชจ๋๋ ์๋ก ๋
๋ฆฝ์ ์ธ ๋๋ ํญ๋ชฉ ์งํฉ์ SQL์ ๋ณด๊ดํ๋ฉฐ, ์ ์ฒดยทํ์ฑยท์คํ ์ค ํญ๋ชฉ์ ๋ํ ๋ณ๋์ ์ ํ, ์ฌ์์ ๋ณต๊ตฌ, ํฌ๊ธฐ๊ฐ ์ ํ๋ ๊ฒฐ๊ณผ, ์ค๋ ๋ ๋ฒ์์ ์น UI ํจ๋์ ์ ๊ณตํฉ๋๋ค. ํจ๋์ ํ์ํ ๋ ํฌ๊ธฐ๊ฐ ์ ํ๋ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ฅผ ํ์ด์ง ๋จ์๋ก ๋ถ๋ฌ์ค๋ฉฐ, ์ ์ฅ๋ ๊ฒฐ๊ณผ ์ ์ฒด๋ ์์ ์ ๋ฒ์์ JSONL ๋ด๋ณด๋ด๊ธฐ๋ก ๋ฐ์ ์ ์์ต๋๋ค. ๋ด๋ถ ์คํ ๋ฐ ๊ถํ ๋ถ์ฌ ์ปจํ
์คํธ๋ ์์ ์์๊ฒ ๋ณด์ด๋ ์๋ต์ ์ ๋ ํฌํจ๋์ง ์์ต๋๋ค. ๋์ค์ ๋ฐฐ์น ์์ปค๊ฐ ์ค์ง๋๊ฑฐ๋ ๋นํ์ฑํ๋๋๋ผ๋, ์ ์ฅ๋ ๋ฐฐ์น๊ฐ ์๋ ์ค๋ ๋์์๋ ์ฝ๊ธฐ ์ ์ฉ ํญ๋ชฉ ์กฐํ์ JSONL ๋ด๋ณด๋ด๊ธฐ๋ฅผ ๊ณ์ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ์คํ ์ ์ด๋ ์์ปค๊ฐ ๋ค์ ์คํ๋ ๋๊น์ง ๋นํ์ฑํ๋ ์ํ๋ก ๋จ์ต๋๋ค. ์ ํ๊ณผ ๋ณต๊ตฌ ์๋ฏธ๋ `config.example.yaml`๊ณผ [๊ตฌํ ๊ณ์ฝ](docs/plans/2026-08-24-subagent-batch-capacity-implementation.md)์ ์ฐธ๊ณ ํ์ธ์.
์์ ๋ฐฐ์น ๋๊ตฌ๋ฅผ ์ฌ์ฉํ ์ ์๋ ๋์, ์ดํ์ ์์ ์ ํด์์๋ `read_batch_result(batch_id, position=0, offset=0, max_chars=4000)`๋ก ์ ํํ ๊ฒฐ๊ณผ๋ฅผ ๋ช
์์ ์ผ๋ก ์กฐํํ ์ ์์ต๋๋ค. ์ด ๋ฆฌ๋๋ ๋ช
์์ ์ผ๋ก ๋ฐ์ธ๋ฉ๋ SDK ๊ทธ๋ํ๋ฅผ ํฌํจํด ํ์ฌ ์ฌ์ฉ์์ ์ค๋ ๋๋ก ์ ํ๋ฉ๋๋ค. ๋ฆฌ๋๋ ์ ์ฅ๋ ๋ณด๊ณ ์, ์คํ/์ค๋ฅ ์ํ, ๋ณ๋์ ์๋ฝ ๊ธฐ์ค/ํ์ ์ ๋ด์ JSON ๋ฌธ์์ ํ ์๋์ฐ๋ฅผ ๋ฐํํ๋ฉฐ, ์์
์ ์์ํ๊ฑฐ๋ ๊ธฐ๋ค๋ฆฌ์ง๋ ์์ต๋๋ค. ํ์ฑํ๊ธฐ ์ ์ `content` ์๋์ฐ๋ฅผ ์ด์ด ๋ถ์ด์ธ์. `next_offset`์ ์ ๋ฌํ๊ณ ๋ฐํ๋ `revision`์ `expected_revision`์ผ๋ก ์ ๋ฌํ๋ ๊ณผ์ ์ `next_offset`์ด null์ด ๋ ๋๊น์ง ๋ฐ๋ณตํ๋ฉด ๋ฉ๋๋ค. ํญ๋ชฉ์ด ๋ณ๊ฒฝ๋๋ฉด `restart_required`๊ฐ ๋ฐํ๋๋ฏ๋ก, ์ด์ ์๋์ฐ๋ฅผ ๋ฒ๋ฆฌ๊ณ 0๋ถํฐ ๋ค์ ์์ํ์ธ์. `next_position`์ ์ฌ์ฉํด `batch_status.total_items` ๋ฒ์ ์์์ ์ ํํ ๋ค์ ํญ๋ชฉ์ผ๋ก ๋์ด๊ฐ์ธ์. ์ต๋ ์๋์ฐ ํฌ๊ธฐ๋ 8,192์์ด๋ฉฐ, ๋ฉํ๋ฐ์ดํฐ๋ ์๋์ฐ ์์ฐ์ ํจ๊ป ์ฌ์ฉํ๊ณ JSON ์๋ต ํ๋ ์ด๋ฐ์ผ๋ก ์ธํ ์ค๋ฒํค๋๊ฐ ์ถ๊ฐ๋ฉ๋๋ค. `result_truncated`๋ ์ ์ฅ ๋จ๊ณ์์ ์ด๋ฏธ ๋ณด๊ณ ์๊ฐ ์๋ ธ๋ค๋ ์๋ฏธ์ด๋ฉฐ, ์ด์ด ์ฝ๊ธฐ๋ก ๋ฒ๋ ค์ง ๋ด์ฉ์ ๋ณต๊ตฌํ ์๋ ์์ต๋๋ค. ์ฑ๊ณตํ ํญ๋ชฉ์ด ๊ณง ์๋ฝ๋ ์์
์ ์๋๋ฉฐ, ๊ฒ์ฌ๋์ง ์์ ๊ธฐ์ค์ UNVERIFIED๋ก ๋จ์ต๋๋ค. ์๋ ๊ฒฐ๊ณผ ์์ง, ๋๊ธฐ ๋ฃจํ, UI ๋ณ๊ฒฝ์ ์ถ๊ฐ๋์ง ์์ต๋๋ค.
์ด์ค์ผ์ดํ๋ ์ ์ฒด ์๋ต๋ 10,000์ ์ด๋ด์ด๋ฉฐ ๋ฐ์ธ๋ฉ๋ ํธ์คํธ์ ์์ `tool_output` ์ธ๋ถํ/ํด๋ฐฑ ์ ํ ์์๋ ๋ค์ด๊ฐ๋ฏ๋ก, ์ผ๋ฐ์ ์ธ ์์ฐ ๊ด๋ฆฌ์์ ์ด์ด ์ฝ๊ธฐ์ฉ JSON์ด ๋ณด์กด๋ฉ๋๋ค. ์ ํ์ด ๋ ์์ผ๋ฉด ์๋์ฐ๊ฐ ์งง์์ง ์ ์์ต๋๋ค. `budget_too_small`์ ๊ธธ์ด๊ฐ 0์ธ ํ์ด์ง๋ฅผ ์ฌ์๋ํ๋ ๋์ ์ด์์๊ฐ ์์ฐ์ ๋๋ ค์ผ ํ๋ค๋ ๋ป์
๋๋ค. ์ด ์ค๋ฅ ๋ดํฌ(envelope)์กฐ์ฐจ ๋ด์ ์ ์์ ๋งํผ ์์ ์ ํ์์๋ ์ฌ์ฉํ ์ ์๋ ๊ตฌ์กฐํ๋ ์๋ต์ ์ ๊ณตํ ์ ์์ต๋๋ค. ์ปค์คํ
์ถ๋ ฅ ์์ฐ ๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ์ฉํ๋ ๋ช
์์ SDK ๊ทธ๋ํ๋ ๊ฐ์ `AppConfig`๋ฅผ `SubagentRuntime`์ ํตํด ์ ๋ฌํด์ผ ํ๋ฉฐ, ๊ธฐ๋ณธ ๊ทธ๋ํ๋ ๊ธฐ๋ณธ ๋ฆฌ๋ ์ ํ์ ์ฌ์ฉํฉ๋๋ค.
์คํ๋ผ์ธ ์๋ฝ ๊ฒ์ฆ: `cd backend && PYTHONPATH=. uv run --locked pytest tests/test_batch_result_reader.py -k 'real_submission_worker or sdk_factory_graph' -q`. ์ด ๋ช
๋ น์ ์ค์ ์ ์ถ, ๊ฒฐ์ ์ ์ธ ์์ปค ์๋ฃ, ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฌ์ด๊ธฐ, ๋ฑ๋ก๋ ๊ทธ๋ํ์ ๊ฒฐ๊ณผ ์๋น๋ฅผ ์คํํ๋ฉฐ, ์ธ๋ถ ๋ชจ๋ธ ์คํ์ ๊ฐ์ง ๋ชจ๋ธ/์คํ๊ธฐ๋ก ๋์ฒด๋ฉ๋๋ค.
์์ ์ง์ ๋ฆฌ์์น ๊ฒฐ๊ณผ๋ null์ผ ์ ์๋ `result_artifact.knowledge_sources` ์ค๋
์ท๋ ๋ด๋ณด๋
๋๋ค. ๋ณด์กด๋ ๊ฐ ์์ค๋ ์ ์ฅ๋ ๋ณด๊ณ ์์ ์ธ์ฉ ID์ `knowledge_search` ๋๋ ์์๋ `task`๊ฐ ์บก์ฒํ ์ ํํ ๋ฐ์ท๋ฌธ์ ์ง์ง์ผ๋ฉฐ, RAGFlow ๋ฐ์ดํฐ์
/๋ฌธ์/์ฒญํฌ ์์น ์ ๋ณด์ ํ์ด์ง๋ ํจ๊ป ๋ด์ต๋๋ค. ์ง์
์ ์ ๊ธฐ์กด์ ์ธ์ฆ๋ `GET /api/threads/{thread_id}/subagent-batches/{batch_id}/results.jsonl`๋ก ๋์ผํฉ๋๋ค. Gateway ์ฌ์์์ด๋ ํ๋ก๋ฐ์ด๋ ๋ณ๊ฒฝ ํ ์ฆ๊ฑฐ๋ฅผ ํ์ธํ๋ ค๋ฉด, ๋ณด๊ณ ์์ `#knowledge-` ๋งํฌ๋ฅผ ํด๋น ํ์ `sources`์์ `id`๋ก ์ฐพ์ผ์ธ์. ๊ฐ๋ตํ ํญ๋ชฉ ์กฐํ์ ๋ฐฐ์น ํจ๋์๋ ์ด ์ค๋
์ท์ด ํฌํจ๋์ง ์์ผ๋ฉฐ, ๋ฐฐ์น ๋ฏธ๋ฆฌ๋ณด๊ธฐ์ ํด๋ฆญ ๊ฐ๋ฅํ ์ธ์ฉ์ด ์ถ๊ฐ๋์ง๋ ์์ต๋๋ค.
์ค๋
์ท์ ํ๋ก๋ฐ์ด๋์์ ์๋ก ๊ฐ์ ธ์จ(fetch) ๋ด์ฉ์ด ์๋๋ผ ๋ฐ์ท๋ฌธ ์ ์ฒด๋ฅผ ๋ณด์กดํฉ๋๋ค. ์ค๋
์ท์ ์์ค 100๊ฐ/ํ
์คํธ 1,000,000์ ์ ๋ฌ ์ ํ์ ๊ทธ๋๋ก ๋ฐ๋ฅด๋ฉฐ, ์ง๋ ฌํ๋ ์ค๋
์ท์๋ ๋ณด๊ณ ์์ ๊ธฐ์กด ์์ฐ๊ณผ ๋ณ๋๋ก `subagent_batches.max_result_chars`์ ๊ฐ์ ํฌ๊ธฐ์ ๋ฌธ์ ์์ฐ์ด ์ ์ฉ๋ฉ๋๋ค. `knowledge_sources.omitted_count`๋ ์ ๋ฌ, ์ค๋
์ท ํฌ์(projection) ๊ฒ์ฌ, ์ค๋
์ท ์์ฐ ๊ด๋ฆฌ ๊ณผ์ ์์ ์๋ต๋ ์ฐธ์กฐ ๋ ์ฝ๋ ์๋ฅผ ๋ณด๊ณ ํ๋ฉฐ, ํ๋ณด ์ ์ ์ ์ ๊ฑธ๋ฌ์ง ํ์์ด ์๋ชป๋์๊ฑฐ๋ ์ง์๋์ง ์๋ ์์ฐ์ ์ํฐํฉํธ๋ ์ง๊ณํ์ง ์์ต๋๋ค. ๋ณด๊ณ ์๊ฐ ์๋ฆฌ๋ฉด ์ ์ฅ๋ ํ
์คํธ ์์ ์์ ํ ์ธ์ฉ๋ง ์ ํ ๋์์ด ๋ฉ๋๋ค. ์ด์ /์ผ๋ฐ ๊ฒฐ๊ณผ์๋ ์ค๋
์ท์ด ์์ผ๋ฉฐ(`null`), ๊ณผ๊ฑฐ ์ฆ๊ฑฐ๋ฅผ ์ฌ๊ตฌ์ฑํ์ง ์์ต๋๋ค. Gateway ์์ ์ ๋ง์ด๊ทธ๋ ์ด์
`0033_batch_result_artifact`๋ฅผ ํตํด null์ ํ์ฉํ๋ JSON ์ด์ด ์ถ๊ฐ๋ฉ๋๋ค. ๋ง์ด๊ทธ๋ ์ด์
์ ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๋ฐฑ์
ํ์ธ์. ๋ค์ด๊ทธ๋ ์ด๋ํ๋ฉด ๋ณด๊ณ ์ ํ
์คํธ๋ ๋ณด์กด๋์ง๋ง ์ฆ๊ฑฐ ์ค๋
์ท์ ์ญ์ ๋ฉ๋๋ค. ์ทจ์๋์๊ฑฐ๋ ์คํจํ๊ฑฐ๋ ์ค๋๋(stale) ์๋๋ ์ฆ๊ฑฐ๋ฅผ ๊ฒ์ํ์ง ์์ผ๋ฉฐ, ๋ช
์์ ์ฌ์๋๋ ์ด์ ์ค๋
์ท์ ์ง์๋๋ค.
๋ช
์์ ์ผ๋ก ํ์ฑํ๋ ์ค์ฒฉ `task` ์์์ ์บก์ฒ๋ ์ํฐํฉํธ์์ ์๋ต๋ ๋ถํฌ๋ช
(opaque) ์์ค ID๋ฅผ ์ ํํฉ๋๋ค. ๊ฐ ๋ฐ๊นฅ์ชฝ ๋ณด๊ณ ์๋ ์ด ID๋ฅผ ํํฐ๋งํ๊ณ ์ค๋ณต์ ์ ๊ฑฐํ๋ฉฐ, ๋
๋ฆฝ์ ์ผ๋ก ์บก์ฒ๋ ์ฆ๊ฑฐ๋ก ์๋ต๋ ์์ค๋ฅผ ๋ณต์ํ ์ ์์ต๋๋ค. ์์ ์ค๋
์ท์๋ ์ต์ข
๊ฐ์๋ง ๊ฒ์๋ฉ๋๋ค. ์๋ต ID๊ฐ ์๋ ๋ ๊ฑฐ์ ์์
์ํฐํฉํธ๋ก๋ ์ด์ ์ ๋ฌ ๊ณผ์ ์ ์์ค์ ์ฌ๊ตฌ์ฑํ ์ ์์ผ๋ฉฐ, ์ ์ ์๋ ์ฐ๋ฌธ ์ธ์ฉ์ ์บก์ฒ๋ ์ฆ๊ฑฐ๋ก ์ทจ๊ธํ์ง ์์ต๋๋ค.
์ฌ์๋ ์์ฐ์ ๋ชจ๋ ์์งํ ๋ค ํญ๋ชฉ์ ๋ง์ง๋ง ๋ฆฌ์ค๊ฐ ๋ง๋ฃ๋๋ฉด, ๋ชจ๋ ํญ๋ชฉ์ด ์ข
๋ฃ ์ํ๊ฐ ๋๋ ์์ ์ ๋ฐฐ์น๋ ์ข
๋ฃ ์ํ๊ฐ ๋ฉ๋๋ค. ์ฑ๊ณตํ ํญ๋ชฉ์ด ํ๋๋ ์์ผ๋ฉด `failed`, ํ๋ ์ด์ ์ฑ๊ณตํ์ผ๋ฉด `completed`๊ฐ ๋ฉ๋๋ค. ๋ ๊ฒฝ์ฐ ๋ชจ๋ ํด๋น ํญ๋ชฉ์ `failed`๋ก ๋จ์ผ๋ฏ๋ก ๋ถ๋ถ ๊ฒฐ๊ณผ๋ฅผ ๊ณ์ ๋ณผ ์ ์์ต๋๋ค.
`create_deerflow_agent(...)`๋ฅผ ์ง์ ์ฌ์ฉํ๋ ํตํฉ์ Gateway ์์์ ์์กดํ๋ ๋์ ๊ฐ์ ๊ฒฝ๊ณ๋ฅผ ๋ช
์์ ์ผ๋ก ์์ ํ ์ ์์ต๋๋ค. `SubagentRuntime` ํ๋๋ฅผ ์์ฑํด ํด๋น ์ ํ๋ฆฌ์ผ์ด์
์ ๋ชจ๋ ๊ทธ๋ํ์์ ๊ณต์ ํ์ธ์. ๊ทธ๋ฌ๋ฉด `max_running`, ์ผ๋ฐ ์คํ๋ณ ์ด๋, ๋ฐ์ธ๋ฉ๋ `task` ๋๊ตฌ, ์ ํ์ ์ธ ์์ ๋ฐฐ์น ๋๊ตฌ๊ฐ ํธ์ถ์๊ฐ ์์ ํ ๋์ผํ ์ค๋
์ท๊ณผ ์คํ ์ปจํธ๋กค๋ฌ๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ฐฐ์น ์ ์ฅ์(repository)๊ฐ ์๋ ๋ฐํ์์ ์์ปค๋ฅผ ์์ ํ๋ฏ๋ก, ๊ทธ๋ํ ์์ฑ ์ ์ ์์ํ๊ณ ์ ํ๋ฆฌ์ผ์ด์
์ข
๋ฃ ์ค์ ์ค์งํด์ผ ํฉ๋๋ค.
```python
from deerflow.agents import RuntimeFeatures, create_deerflow_agent
from deerflow.subagents import SubagentRuntime
runtime = SubagentRuntime.from_app_config(app_config, batch_repository=batch_repository)
async with runtime:
graph = create_deerflow_agent(
model,
features=RuntimeFeatures(subagent=True),
subagent_runtime=runtime,
)
# Serve or invoke graph while the durable worker is running.
```
`SubagentRuntime.stop()`์ ๋ฐ๋ณต๋ ์ทจ์๋ฅผ ํฌํจํด ํธ์ถ์์ ์ทจ์๋ฅผ ์ ํํ๊ธฐ ์ ์, ์์ ์ด ์์ ํ ๋ฐฐ์น ์๋น์ค๊ฐ ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค. ์ด ๋๋ ์ธ(drain)์๋ ํ์์์์ด ์์ผ๋ฏ๋ก ์ ์ฅ์ ์์
๊ณผ ์์ ์ ๋ฆฌ๊ฐ ๋ฐ๋์ ์ข
๋ฃ๋์ด์ผ ํฉ๋๋ค. ์๋น์ค ์ข
๋ฃ๋ ์คํจํ๊ฑฐ๋ ์ทจ์๋๋ฉด, ์ฒซ ๋ฒ์งธ ํธ์ถ์ ์ทจ์๊ฐ ๋ณด์กด๋๊ณ ์๋น์ค ์คํจ๊ฐ ๊ทธ ์์ธ์ผ๋ก ์ฐ๊ฒฐ๋ฉ๋๋ค.
ํฉํ ๋ฆฌ๋ ์ฌ์ ํ YAML์ ๋ถ๋ฌ์ค๊ฑฐ๋ SQL ์ธํ๋ผ๋ฅผ ๋ง๋ค์ง ์์ต๋๋ค. ์ค์ ์ค๋
์ท, ์ ์ฅ์, ์๋ช
์ฃผ๊ธฐ๋ ํธ์ถ์๊ฐ ์ ๊ณตํฉ๋๋ค. ํฉํ ๋ฆฌ๊ฐ ํธ์ถ์ ์์ ์ `system_prompt`๋ฅผ ๋ฐ๊ธฐ ๋๋ฌธ์, ์ง์ ํตํฉํ๋ ์ชฝ์์๋ ์ด๋ฌํ ์ ํ์ ๊ดํด ๋ชจ๋ธ์ ๋ณด์ด๋ ๋ฌธ๊ตฌ๋ ์ง์ ์ฑ
์์ ธ์ผ ํฉ๋๋ค. ๊ทธ์ ๊ด๊ณ์์ด ๊ธฐ๋ณธ ๋ฏธ๋ค์จ์ด๊ฐ ๋ฐํ์ ์ ํ์ ๊ฐ์ ํฉ๋๋ค. ํฉํ ๋ฆฌ๋ Gateway์ ์์ ์ ๋ฒ์ HTTP ๋ผ์ฐํธ๋ ์น UI๋ฅผ ๋ง์ดํธํ์ง ์์ผ๋ฏ๋ก, ์ง์ ํตํฉํ ์ ํ๋ฆฌ์ผ์ด์
์์ ์ด๋ฌํ ํ๋ฉด์ด ํ์ํ๋ค๋ฉด ์์ฒด ๊ฒฐ๊ณผ API/UI๋ฅผ ๋
ธ์ถํด์ผ ํฉ๋๋ค. ์ผ๋ฐ ์์๋ง ์ฌ์ฉํ ๋๋ `SubagentRuntime(...)`์ ๋น๋๊ธฐ ์์์ด ํ์ํ์ง ์์ต๋๋ค.
๊ด๋ฆฌ์๋ **Settings โ Subagents**์์ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์์ปค ์ ์๋ฅผ ์ถ๊ฐ, ํธ์ง, ๋นํ์ฑํ, ์ญ์ ํ ์ ์์ต๋๋ค. ๊ธฐ๋ณธ ์ ๊ณต ์ ์์ `config.yaml` ์ ์๋ ์ด๊ณณ์ ์ฝ๊ธฐ ์ ์ฉ ํญ๋ชฉ์ผ๋ก ๊ณ์ ํ์๋ฉ๋๋ค. ๊ธฐ๋ณธ ๋ฆฌ๋ ์์ด์ ํธ(Lead Agent)๋ ํ์ฑํ๋ ๋ชจ๋ ๋ฐํ์ ์๋ธ์์ด์ ํธ๋ฅผ ์ฌ์ฉํ ์ ์๊ณ , ํ์ด์ง์์ ๋ง๋ ๊ฐ ์ปค์คํ
์์ด์ ํธ๋ ๋์ ์ ์ฒด, ์์, ๋๋ ์ ํํ ์ผ๋ถ๋ง ํ์ฉํ ์ ์์ต๋๋ค. ์ด ์ ํ์ ๋ชจ๋ธ์ ๋ณด์ด๋ ๋๋ ํฐ๋ฆฌ์ ์๋ฒ ์ธก `task` ๋๊ตฌ ์์ชฝ์์ ๋ชจ๋ ๊ฐ์ ๋ฉ๋๋ค. ๊ด๋ฆฌ๋๋ ์ ์๋ ์ด๋ฒ ๋ฒ์ ์์ ๋ฐฐํฌ ์ ์ฒด์ ์ ์ฉ๋๋ฉฐ `agent_storage.backend`๋ฅผ ๋ฐ๋ฆ
๋๋ค. ๋ก์ปฌ ๋ฐฐํฌ์์๋ ์์์ ํ์ผ์, ์ฌ๋ฌ ์ธ์คํด์ค์์๋ ๊ณต์ ์ ํ๋ฆฌ์ผ์ด์
๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์๋ฅผ ๋ค์ด, ์๋ก ๋
๋ฆฝ์ ์ธ ์ฝ๊ธฐ ์ ์ฉ ๋ฆฌ์์น๋ ์ค์ ์์ ์๊ฐ ์ ๊ฐ์ด ์ค๋ณต๋๋ ํ์ ๋ฐ ์ข
ํฉ ๋น์ฉ๋ณด๋ค ํด ๋ ๋์์ ์คํํ ์ ์์ง๋ง, ๊ณต์ ํ์ผ๊ณผ ์์ฐจ์ ์ธ ํ
์คํธ ํผ๋๋ฐฑ์ด ์๋ ์ ์ฅ์ ๋ฆฌํฉํฐ๋ง์ ๋ฆฌ๋ ์์ด์ ํธ๊ฐ ๊ณ์ ๋งก์ต๋๋ค. `max_concurrent_subagents`๊ฐ `1`์ด๋ฉด ๋ณ๋ ฌ ๋ฐ ๋ค์ค ๋ฐฐ์น ๋ผ์ฐํ
์๋ด๊ฐ ๋นํ์ฑํ๋๋ฉฐ, ์์์ ์ ๋ฌธ์ฑ์ด๋ ์ปจํ
์คํธ ๊ฒฉ๋ฆฌ์ ์ค์ง์ ์ธ ์ด์ ์ด ์์ ๋์๋ง ์ฌ์ฉํ ์ ์์ต๋๋ค.
### ์๋๋ฐ์ค์ ํ์ผ ์์คํ
AIO ์๋๋ฐ์ค๋ ์๋ฌต์ ์
ธ ์คํ์ด๋ ์ธ์
์์ฑ์ ๊ฒฐ๊ณผ๊ฐ ๋ถํ์คํ๋ฉด ์ฌํ์ฉ(recycle)๋ฉ๋๋ค. ํ์ธ๋ `hard_timeout`์ ์ ์ฌ์ฌ์ฉ ๋์์ผ๋ก ๋จ์ต๋๋ค. Gateway๋ ๋ช
๋ น ์ธ์
์ ๋ฆฌ๋ฅผ ํฌํจํด ๋ชจ๋ ์คํ ๋ฐ ์
๋ก๋ ์ ์ ์๊ฐ ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค. ์งํ ์ค์ธ ์ธ์
์์ฑ๋ง์ผ๋ก๋ ์ฌํ์ฉ์ด ์ผ์ด๋์ง ์์ผ๋ฉฐ, ๋์์ ์งํ ์ค์ธ ์คํ(run)์ ์ค๋จํ์ง๋ ์์ต๋๋ค. ์ฌํ์ฉํ๊ธฐ ์ ์ Gateway๋ ์ปจํ
์ด๋ ID ๋๋ Pod UID๋ฅผ `{DEER_FLOW_HOME}/sandbox-quarantine` ์๋์ ๊ธฐ๋กํฉ๋๋ค. ์ด ๊ธฐ๋ก์ ์ค์ง ์คํจ์ Gateway ์ฌ์์ ํ์๋ ์ ์ง๋ฉ๋๋ค. AIO ์ปจํ
์ด๋๋ฅผ ๊ณต์ ํ๋ Gateway๋ค์ ์์ ๊ถ ์ ์ฅ์๋ฟ ์๋๋ผ ์ด ํ ๋๋ ํฐ๋ฆฌ๋ ๊ณต์ ํด์ผ ํฉ๋๋ค. ์ ๋ฐํ์ ์ธ์คํด์ค๋ ์ค๋ ๋์ ์๋๋ฐ์ค ID๋ฅผ ์ฌ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ๊ฒ์ฆํ ์ ์๋ ์ธ๋(generation)๋ ๊ธฐ์กด ๊ธฐ๋ก์ ๋ํด ์คํจ ์ ์ฐจ๋จ(fail closed)๋ฉ๋๋ค. ๊ฒฉ๋ฆฌ(quarantine)๋ ID๋ฅผ ๋ค์ ์์ฑํ๊ธฐ ์ ์ Gateway๋ ์ผ๋ฐ ํด์ฒด(teardown) ํ์ค๋ฅผ ์ ์งํ ์ํ์์, ๋จ์ ์๋ ์ปจํ
์ด๋๋ Pod๊ฐ ์๋ค๊ณ ๋ฐฑ์๋๊ฐ ํ์ธํ ๋ค์๋ง ์ด์ ๊ธฐ๋ก์ ํ๊ธฐํฉ๋๋ค. ๋ฐ๋ผ์ ๋ฐํ์์ด ์ธ๋๋ฅผ ๋ณด๊ณ ํ ์ ์๋ ๊ฒฝ์ฐ์๋ ๋ณต๊ตฌํ ์ ์์ต๋๋ค. ๋ถ๋ถ ์ญ์ ๋ก ์ปจํ
์ด๋๋ Pod๊ฐ ๋จ์ผ๋ฉด Gateway๋ ํฌ์ค ์ฒดํฌ ๋ฐ Service ๊ฐ์ฉ์ฑ๊ณผ ๋ฌด๊ดํ๊ฒ ์ด๋ฅผ ๊ฒ์ฌํ ๋ค, ๊ฒฉ๋ฆฌ๋ ์ธ๋์ ๋ํด์๋ง ์ ๋ฆฌ๋ฅผ ์ฌ์๋ํฉ๋๋ค. ๊ต์ฒด๋ ์ธ๋๋ ์์ ์ ๋ฆฌ์์ค๋ฅผ ์ ์งํฉ๋๋ค. ์ญ์ ํ์ธ ์๋ต์ด๋ ํฌ์ค ์ฒดํฌ ์คํจ๋ง์ผ๋ก๋ ๊ธฐ๋ก์ ์ง์ฐ๊ธฐ์ ์ถฉ๋ถํ์ง ์์ต๋๋ค.
๋ณต๊ตฌ๋ ์ฌ์์ฑ ์ ์ ๋จ์ ์๋ ๋ก์ปฌ ํ๋ก์์ ๋คํธ์ํฌ ๋ฆฌ์์ค๋ ์ ๋ฆฌํฉ๋๋ค.
Lark ๋ธ๋ก์ปค ํ๋ก๋น์ ๋์๋ ํ์ธ๋ ๊ธฐ๋ฅ(capability)์ด ํ์ํฉ๋๋ค. ํ๋ก๋ธ ์คํจ๋ก๋ ์๊ฒฉ ์ฆ๋ช
๋ง์ดํธ๋ฅผ ์ ํํ๊ฑฐ๋ ์ด๋ฏธ ์๋ ค์ง ๋ธ๋ก์ปค ์๊ตฌ ์ฌํญ์ ๋ฎ์ด์ธ ์ ์์ต๋๋ค. Gateway์ Provisioner๋ ํจ๊ป ์
๋ฐ์ดํธํ์ธ์. Provisioner๋ ๊ฐ Pod์ ์ค์ ๋ธ๋ก์ปค ๋ชจ๋๋ฅผ ๋ณด๊ณ ํ๋ฉฐ, ํธํ๋์ง ์๋ Pod๋ ์ฌ์ฌ์ฉ ์ ์ ์ผ๋ฐ ์์ ๊ถ ํ์ค๋ฅผ ๊ฑฐ์ณ ๊ต์ฒด๋ฉ๋๋ค. Lark ๋ช
๋ น์ ๊ทธ๋ ๊ฒ ์น์ธ(admission)๋ ๋ชจ๋๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์ด์ ๋ฒ์ ์ Provisioner๊ฐ Pod์ ๋ธ๋ก์ปค ๋ชจ๋๋ฅผ ์๋ตํ๋ฉด Gateway๋ ๋ช
์์ ์ธ ์
๊ทธ๋ ์ด๋ ์ค๋ฅ์ ํจ๊ป ์ฌ์ฌ์ฉ์ ๊ฑฐ๋ถํ๊ณ ํด๋น Pod๋ฅผ ๋ณด์กดํฉ๋๋ค. ๋ชจ๋๊ฐ ์๋ต๋์๋ค๋ ์ฌ์ค์ ๊ธฐ์กด ๋ฐํ์์ ๊ต์ฒดํด์ผ ํ๋ค๋ ๊ทผ๊ฑฐ๊ฐ ์๋๋๋ค.
๊ธฐ๋ฅ ํ๋ก๋ธ๋ Provisioner๋ง๋ค ํ๋์ ์์ฒญ์ ๊ณต์ ํ๋ฉฐ, ์คํจ ํ์๋ ์ ์ ๋ฐฑ์คํํฉ๋๋ค. ์บ์์ ๋ชจ์๋๋ Pod ๋ชจ๋๋ ๊ต์ฒด ์ ์ ์๋ก์ด ๊ด์ธก์ ํธ๋ฆฌ๊ฑฐํฉ๋๋ค. ์์ฑ ํ ์น์ธ์ ์คํจํ๋ฉด ์์ ๊ถ ํ์ค๊ฐ ์ ์ฉ๋ ์ ๋ฆฌ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
Lark ํ๋ก๋น์ ๋ ๋ชจ๋๊ฐ Provisioner์ ํ์ฌ ์ค์ ๊ณผ ์ถฉ๋ํ๋ ์์ฑ ์์ฒญ์ ๊ธฐ๋ฅ ๊ฐฑ์ ์ผ๋ก ํ์๋ฉ๋๋ค. Gateway๋ ์บ์๋ ๊ด์ธก์ ๋ฒ๋ฆฌ๋ฏ๋ก, ๋ค์ ํ๋(acquire) ์ ์บ์ ํญ๋ชฉ์ด ๋ง๋ฃ๋ ๋๊น์ง ๊ฐ์ ์คํจ๋ฅผ ๋ฐ๋ณตํ์ง ์๊ณ ๋ค์ ํ๋ก๋ธํฉ๋๋ค.
๋ธ๋ก์ปค ๋ชจ๋๊ฐ ์ฆ๋ช
(attest)๋์ง ์์ ์๋๋ฐ์ค์์๋ lark-cli ๋ช
๋ น์ด ์ธ์ฆ๋์ง ์์ ํ๋กํ๋ก ์คํ๋์ง ์๊ณ , ๋ช
์์ ์ธ ๋ฏธ๊ฒ์ฆ ๋ชจ๋ ์ค๋ฅ์ ํจ๊ป ์คํจํฉ๋๋ค.
ํธ์คํธ๋ก ์ธ๋ถํ๋ ๋๊ตฌ ์ถ๋ ฅ์ Gateway์ ์ผ๋ฐ ํ์ผ ์์ฑ umask๋ฅผ ์ฌ์ฉํฉ๋๋ค.
ํธ์คํธ์ ์๋๋ฐ์ค ์ถ๋ ฅ์ ์๋ณธ ๋๊ตฌ ํธ์ถ ID์ ์ถ๋ ฅ ๋ด์ฉ์ผ๋ก ํด์ํ ๊ฒฐ์ ์ (deterministic) ํ์ผ ์ด๋ฆ์ ์ฌ์ฉํฉ๋๋ค. ID๊ฐ ์๊ฑฐ๋, ์ถฉ๋ํ๊ฑฐ๋, ์ง๋์น๊ฒ ๊ธธ๋๋ผ๋ ๋ค๋ฅธ ์ถ๋ ฅ์ ๋ฎ์ด์ฐ๊ฑฐ๋ ํ์ผ ์ด๋ฆ์ ๋๋ฌด ๊ธธ๊ฒ ๋ง๋ค ์ ์์ผ๋ฉฐ, ๋์ผํ ์ถ๋ ฅ์ ๊ฐ์ ๊ฒฝ๋ก๋ฅผ ์ฌ์ฌ์ฉํ ์ ์์ต๋๋ค.
ํ์ผ ์ด๋ฆ ํด์ฑ ์ค์ ์๋ชป๋ Unicode๋ฅผ ํฌํจํด ํธ์คํธ ๋ฐ ์๊ฒฉ ์๋๋ฐ์ค์ ์์ ์ ์ฅ ์คํจ์๋ ์ค์ ๋ ์ธ๋ผ์ธ ํด๋ฐฑ์ด ์ฌ์ฉ๋ฉ๋๋ค.
๋๊ตฌ๋ณ ์ฌ์ ์๋ฅผ ํฌํจํ `tool_output` ๋ฌธ์ ์/๊ฐ์ ์์ฐ์ ์์ด ์๋ ์ ์์ฌ์ผ ํ๋ฉฐ, YAML ๋ถ๋ฆฌ์ธ์ 0์ด๋ 1๋ก ์ทจ๊ธ๋์ง ์๊ณ ๊ฑฐ๋ถ๋ฉ๋๋ค.
๋๊ตฌ๋ณ ์ฌ์ ์๋ฅผ ๋ช
์์ ์ผ๋ก 0์ผ๋ก ์ง์ ํ๋ฉด ์ธ๋ถํ๊ฐ ๋นํ์ฑํ๋๋ฉฐ, ์์์ธ ์ ์ญ ํด๋ฐฑ ์ ํ์ ๊ทธ๋๋ก ์ ์ง๋ฉ๋๋ค.
๊ตฌ์กฐํ๋ JSON ๋๊ตฌ ๊ฒฐ๊ณผ๋ ๋ฏธ๋์ด์ ์์ธ ๊ฒฐ๊ณผ๋ฅผ ํฌํจํด ์ด ์์ฐ์ ๋ฐ๋ฅด๋ฉฐ, ์ธ๋ถํ ์์๋ ํ์ผ ์ฐธ์กฐ๋ฅผ ํตํด ์ ์ฒด JSON์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
MindIE๋ JSON ๋๊ตฌ ๊ฒฐ๊ณผ๋ฅผ ์ด์ค์ผ์ดํ๋ ํ
์คํธ๋ก ๋ ๋๋งํ๋ฉฐ, ์ค์ ๋ ๋๊ตฌ ์์ธ๋ ์ ์ง๋ฉ๋๋ค. PII ๋ง์คํน์ด ํ์ฑํ๋์ด ์์ผ๋ฉด ๋ ๋๋ง ์ ์ ์ค์ฒฉ๋ JSON ํค์ ๊ฐ์ ๊ฒ์ฌํฉ๋๋ค.
๋ค๋ฅธ UID๋ก ์คํ๋๋ ๋ง์ดํธ๋ ์๋๋ฐ์ค๋ ๊ณต์ ์ ์ฅ์ ๊ถํ์ ํตํด ์ฝ๊ธฐ ๊ถํ์ ๊ฐ์ ธ์ผ ํฉ๋๋ค. ๋น์ ์ ์ข
๋ฃ ์ `.tool-output-*.tmp` ํ์ผ์ด ์ค๋ ๋ ์ถ๋ ฅ ์๋์ `tool_output.storage_subdir`(๊ธฐ๋ณธ๊ฐ `.tool-results`)์ ๋จ์ ์ ์์ต๋๋ค.
๋จ์ ํ์ผ์ ๋ชจ๋ Gateway ์ฐ๊ธฐ ํ๋ก์ธ์ค๋ฅผ ์ค์งํ ์ํ์์ ์ค๋ ๋ ๋ฐ์ดํฐ ์ ์ง ๋ณด์ ์ค์ ์ ๊ฑฐํ๊ฑฐ๋, ํด๋น ๋นํ์ฑ ์ค๋ ๋์ ๋ฐ์ดํฐ๋ฅผ ์ญ์ ํ ๋ ์ ๊ฑฐํ์ธ์.
`E2BSandboxProvider`๋ ๊ธฐ๋ณธ ์ค๋ฒํ๋ก ์ ์ฑ
์ผ๋ก `wait`๋ฅผ ์ฌ์ฉํฉ๋๋ค. `acquire_timeout` ๋์ ๊ธฐ๋ค๋ฆฐ ๋ค ์์ด์ ํธ ํด์ ์คํจ์ํต๋๋ค. DeerFlow๋ ํด์ ์๋์ผ๋ก ์ฌ์๋ํ์ง ์์ต๋๋ค. ํด๋ผ์ด์ธํธ๋ ๊ตฌ์กฐํ๋ ์ค๋ฅ๋ฅผ ์ฌ์ฉํด ์ฌ์๋๋ฅผ ์์ฝํ ์ ์์ต๋๋ค.
์ ํด์ง ํ๋ ์์์ ์ถ๊ฐ VM์ ํ์ฉํ๋ ค๋ฉด `burst`์ `burst_limit`์ ํจ๊ป ์ฌ์ฉํ์ธ์. `wait`์ `reject` ์ ์ฑ
์ `replicas`๋ง ์ฌ์ฉํฉ๋๋ค. `reject` ์ ์ฑ
์ ์ค๋ฅ๋ฅผ ๋ฐํํ๊ธฐ ์ ์ ์ VM ํ๋๋ฅผ ์ ๊ฑฐํ ์ ์์ต๋๋ค.
์ธ๋ฉ๋ชจ๋ฆฌ ์์ ๊ถ์์๋ `replicas`๊ฐ Gateway ํ๋ก์ธ์ค ํ๋ ๋จ์๋ก๋ง ์ ์ฉ๋๋ ์ ํ์
๋๋ค. Redis ์์ ๊ถ์์๋ E2B๊ฐ ๊ฐ์ `sandbox.ownership.key_prefix`๋ฅผ ์ฌ์ฉํ๋ ์์ปค๋ค ์ฌ์ด์์ ํ๋์ ์ฉ๋ Hash๋ฅผ ๊ณต์ ํ๋ฉฐ, ์ด๋ `replicas`(์ค์ ๋ burst ํฌํจ)๋ ๋ฐฐํฌ ์ ์ฒด์ ํ๋ ์ ํ์ด ๋ฉ๋๋ค. ๋ฐฐํฌ๋ง๋ค ๊ณ ์ ํ ์ ๋์ฌ ํ๋์ ๋์ผํ ์ ํจ ์ ํ์ ์ฌ์ฉํ์ธ์. ์ ํ์ ๋ณ๊ฒฝํ๋ ค๋ฉด ํด๋น ๋ฐฐํฌ์ Gateway๋ค์ ์ค์งํ๊ณ , ์ฉ๋ Hash๋ฅผ ์ญ์ ํ ๋ค ๋ค์ ์์ํ์ธ์. ์ค์ ์ด ์ผ์นํ์ง ์๋ ์์ปค๋ ์คํจ ์ ์ฐจ๋จ๋ฉ๋๋ค.
์ด Hash๋ ์๊ฒฉ VM๊ณผ ์งํ ์ค์ธ ์์ฑ ์์
์ ์ง๊ณํ๊ณ , ์ค๋จ๋ ์์ฑ์ E2B ๋ฉํ๋ฐ์ดํฐ๋ก ๋ณต๊ตฌํ๋ฉฐ, ์ค๋๋ ์ธ๋ฒคํ ๋ฆฌ ๋๋ฝ์ ์ ์ ๊ธฐ๊ฐ ๋ณดํธ๋ฅผ ์ ์ฉํ๊ณ , Redis๋ ์ด๊ธฐ ์ธ๋ฒคํ ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์๋ ๋์์๋ ์ ์์ฑ์ ์ฐจ๋จํฉ๋๋ค. Redis๋ ์์์ฑ, ์ถ์ถ(eviction)ํ์ง ์๋ ๋ฉ๋ชจ๋ฆฌ ์ค์ , HA ๊ตฌ์ฑ์ผ๋ก ์ด์ํ์ธ์.
E2B ์กฐ์ (reconciliation)์ `idle_timeout`์ด 0์ด๊ฑฐ๋ ์ค์ ๋ ์ฃผ๊ธฐ๋ณด๋ค ์งง์ ๊ฒฝ์ฐ์๋, ๊ทธ ์ฃผ๊ธฐ๋ฅผ ํฌ๊ดํ๋ ์์ ํ์์์์ผ๋ก ํ์ฑ VM์ ๊ฐฑ์ ํฉ๋๋ค. ์ VM์ ์ค์ ๋ ์ ํด ํ์์์ ๋์์ ์ ์งํฉ๋๋ค. ๋ง๋ฃ๋ ๋ก์ปฌ ์ ํญ๋ชฉ์ด ๊ณต์ ์ฉ๋์ ์ง์ ํด์ ํ์ง๋ ์์ต๋๋ค. ์๊ฒฉ ์ธ๋ฒคํ ๋ฆฌ๊ฐ ๊ธฐ์กด ์ ์ ๊ธฐ๊ฐ์ ๊ฑฐ์ณ ๋จผ์ ์๋ฉธ์ ํ์ธํด์ผ ํฉ๋๋ค.
ํ์ฑ ๊ฐฑ์ ์ ํด์ (release)๊ฐ ์ ํ์์์์ ์ค์ ํ๊ธฐ ์ ์ ์๋ฃ๋๋ฏ๋ก, ๋์์ ์คํ๋๋ ์ ์ง ๋ณด์ ํจ์ค๊ฐ ์ ํด VM์ ์๋ช
์ ์ฐ์ฅํ ์ ์์ต๋๋ค. ์ ํญ๋ชฉ ์ ๋ฆฌ ์ญ์ ์ ๋ฆฌ ๋์ค ์ ์์ฒญ์ด ํ๋ํ ์์ ๊ถ์ ๋ณด์กดํฉ๋๋ค.
์์ ๊ถ ํํธ๋นํธ๋ ๋๋ฆฐ E2B ํ์์์ ์์ฒญ๊ณผ ๋
๋ฆฝ์ ์ผ๋ก ๋์ํ๋ฏ๋ก, ์ปจํธ๋กค ํ๋ ์ธ ์ง์ฐ์ผ๋ก ์ธํด ํ์ฑ ์๋๋ฐ์ค ๋ฆฌ์ค๊ฐ ๋ง๋ฃ๋์ง ์์ต๋๋ค.
E2B๋ ํ๋ก๋ฐ์ด๋๊ฐ ์์๋ ๋ `skills.container_path`์ ์ค๋
์ท์ ๋ง๋ค๊ณ , ์ ๊ทํ๋ ๋ฃจํธ๋ฅผ ์ค๋ ๋ ์๋ณ ์ ๋ณด, ์ ํ ์๋, ์๊ฒฉ ๋ฉํ๋ฐ์ดํฐ์ ํฌํจํฉ๋๋ค. ๋ค๋ฅธ ๋ฃจํธ์ฉ์ผ๋ก ์์ฑ๋ VM์ ์ ๋ ์ธ์๋์ง ์์ผ๋ฉฐ, ์ด์ ์๋ ํผ์ด๊ฐ ์์ ํ์ง ์๊ฒ ๋๋ฉด ์ค์ ๋ ์ ์ ๊ธฐ๊ฐ ํ ์กฐ์ ๊ณผ์ ์์ ํ์๋ฉ๋๋ค. ๋ฃจํธ๋ฅผ ๋ณ๊ฒฝํ ํ์๋ Gateway๋ฅผ ์ฌ์์ํ์ธ์.
E2B ํ๋์ ํฌ๊ธฐ๊ฐ ์ ํ๋ ์คํ๊ธฐ(executor)๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋๊ธฐ ์ค์ธ ํ๋์ ๊ธฐ๋ณธ asyncio ์คํ๊ธฐ๋ฅผ ์ฌ์ฉํ์ง ์์ต๋๋ค.
๋ํ ํด ์ฌ์ด์ E2B ์๋๋ฐ์ค๊ฐ ๋ง๋ฃ๋๋ฉด, ๋์ฒด ์๋๋ฐ์ค๋ ๋๊ตฌ๊ฐ ์ฌ์ฉํ๊ธฐ ์ ์ ๊ฐ์ ์ฌ์ฉ์์ ์ ์ฅ๋ ์ค๋ ๋ ํ์ผ์ `workspace`, `uploads`, `outputs` ๋ฐ ACP ์ํฌ์คํ์ด์ค์์ ๋ณต์ํฉ๋๋ค. ์คํ ์ค์ธ ์๋๋ฐ์ค๋ฅผ ์ฌ์ฌ์ฉํ ๋๋ ์๊ฒฉ ํ์ผ์ ๋ ์ค๋๋ ์ ์ฅ๋ณธ์ผ๋ก ๋ฎ์ด์ฐ์ง ์์ต๋๋ค. ๋ณต์์ ์คํจํ๊ฑฐ๋ ์
๋ก๋ ์ ํ์ ์ด๊ณผํ๋ฉด ์ ์๋๋ฐ์ค๊ฐ ๊ฑฐ๋ถ๋ฉ๋๋ค. ์ผ์์ ์ธ ์คํจ๋ ์ดํ ์๋์์ ์ฑ๊ณตํ ์ ์์ต๋๋ค.
์ฉ๋ ์ด๊ณผ ์์๋ ๋ฆฌ์์ค ํธ๋ฆฌ์ ์ด๊ณผ๋ ์ํ์ด ๋ณด๊ณ ๋ฉ๋๋ค. ์ํ์ ํ์ผ๋น 100 MiB, ํธ๋ฆฌ๋น 2,000๊ฐ ํ์ผ / 512 MiB, ์์ฑ ํจ์ค ์ ์ฒด์์ 2,000๊ฐ ํ์ผ / 512 MiB์
๋๋ค.
์ฌ์๋ํ๊ธฐ ์ ์ ์ด์์๊ฐ Gateway์ ์์ ์ค๋ ๋ ๋๋ ํฐ๋ฆฌ์์ ๋ถํ์ํ ํ์ผ์ ๋ณด๊ดํ๊ฑฐ๋ ์ ๊ฑฐํด ์ด ์ ํ์ ๋ง์ถฐ์ผ ํฉ๋๋ค. ๋ฐ์ดํฐ๋ฅผ ๋ฐ๊พธ์ง ์๊ณ ์ฌ์๋ํด์๋ ์ฉ๋ ์ด๊ณผ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค. ์๊ฒฉ ์ฌ๋ณธ๋ง ์ญ์ ํ๋ ๊ฒ์ผ๋ก๋ ์ถฉ๋ถํ์ง ์์ต๋๋ค.
๊ทธ ๋ฐ์ ๋ณต์ ์ค๋ฅ๋ ๋ฆฌ์์ค ํธ๋ฆฌ์ ์์ธ ๋ฒ์ฃผ๋ฅผ ์๋ ค ์ฃผ๋ฉฐ, Gateway ๋ก๊ทธ์๋ ์ง๋จ์ ์ํด ๊ทผ๋ณธ ์์ธ๊ฐ ๋จ์ต๋๋ค.
๋ณต๊ตฌํ๋ ค๋ฉด Gateway์ ์์ ์ค๋ ๋ ๋๋ ํฐ๋ฆฌ๋ฅผ ๊ณ์ ์ฌ์ฉํ ์ ์์ด์ผ ํฉ๋๋ค. VM์ด ์ฌ๋ผ์ง๊ธฐ ์ ์ ํ ๋ฒ๋ ๋๊ธฐํ๋์ง ์์ ํ์ผ์ ๋ณต๊ตฌํ ์ ์์ต๋๋ค.
๊ธฐ์กด ํด์ ๋๊ธฐํ๋ ์ํฌ์คํ์ด์ค/์ถ๋ ฅ ํ์ผ์ ์ ์ฅํ์ง๋ง ํ์ผ ์ญ์ ๋ ๋ฐ์ํ์ง ์์ผ๋ฏ๋ก, ์๊ฒฉ์์ ์ญ์ ํ ํ์ผ์ ์ ์ฅ๋ณธ์ด ์ฌ์์ฑ ์ ๋ค์ ๋ํ๋ ์ ์์ต๋๋ค.
E2B ๋ง์ดํธ ์
๋ก๋ ํจ์ค ํ ๋ฒ์ ์ต๋ 512 MiB, 2,000๊ฐ ํ์ผ๊น์ง ํ์ฉํฉ๋๋ค. ๊ฐ ํจ์ค์๋ ํ์กฐ์ (cooperative) 120์ด ๊ธฐํ๋ ์์ต๋๋ค. ์ค๋ ๋ ๋ณต์์ด ๋จผ์ ์คํ๋๋ฉฐ, ์คํฌ ํฌ์(projection) ๋ฐ ์ค์ ๋ ๋ง์ดํธ์ ์ด ์ ํ์ ๊ณต์ ํฉ๋๋ค. ํ๋ก๋ฐ์ด๋๋ ๊ฐ ๋ง์ดํธ ์ ๊ณผ ๋๋ ํฐ๋ฆฌ ์ฌ์ ์ ๊ฒ ์ค์ ๊ธฐํ์ ํ์ธํฉ๋๋ค. ๊ธฐํ์ด ์ง๋๋ฉด ์ ํ์ผ ์
๋ก๋๊ฐ ์ค์ง๋ฉ๋๋ค. ์งํ ์ค์ธ ํ์ผ ์์คํ
ํธ์ถ์ด๋ E2B SDK ํธ์ถ์ ์ค๋จํ์ง๋ ์์ต๋๋ค.
E2B VM์ E2B๊ฐ ํ๊ธฐ๋ฅผ ํ์ธํ ๋๊น์ง ์์ ์ ์ฌ๋กฏ์ ์ ์งํฉ๋๋ค. ์ด ๊ท์น์ ์์ฑ๊ณผ ํ์ ์์
์ ์ ์ฉ๋ฉ๋๋ค. ํ์(discovery)์ ํตํด ๋ค๋ฅธ Gateway์ VM์ด ๋ฐ๊ฒฌ๋ ์ ์์ต๋๋ค.
์ข
๋ฃ ์์๋ ์์ ํ์ง ์์ ํ์ ํด๋ผ์ด์ธํธ๋ฅผ ํด๋น VM์ ํ๊ธฐํ์ง ์๊ณ ๋ซ์ต๋๋ค.
ํด์ ๋ VM์ด ์ ํ์ ๋ค์ด๊ฐ๋ฉด ์ ํ ์ง๊ณ๋ฅผ ์ค๋จํฉ๋๋ค.
์ข
๋ฃ ๊ฒฝ์ ์ํฉ์์๋ ์ผ์์ ์ธ kill ์คํจ ํ ์๊ฒฉ ์ ๋ฆฌ๋ฅผ ์ฌ์๋ํฉ๋๋ค.
๋ฆฌ์
์ ์ถ์ ์ค์ธ ํ์ฑ ๋ฐ ์ E2B VM์ ํ๊ธฐํฉ๋๋ค. ์ด์ ํ๋ก๋ฐ์ด๋ ์ธ์คํด์ค๋ ์ ํ๋์ ๋ฐ์ ์ ์์ต๋๋ค.
DeerFlow๋ ๋ฌด์ธ๊ฐ๋ฅผ ํ๊ฒ ๋ค๊ณ *๋ง*๋ง ํ์ง ์์ต๋๋ค. ์๊ธฐ๋ง์ ์ปดํจํฐ๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
๊ฐ ์์
์ ์คํฌ, ์ํฌ์คํ์ด์ค, ์
๋ก๋, ์ถ๋ ฅ์ ํฌํจํ ์ ์ฒด ํ์ผ ์์คํ
๋ทฐ๋ฅผ ๊ฐ์ถ ๋
๋ฆฝ๋ ์คํ ํ๊ฒฝ์ ๋ฐ์ต๋๋ค. ์์ด์ ํธ๋ ํ์ผ์ ์ฝ๊ณ , ์ฐ๊ณ , ํธ์งํฉ๋๋ค. ์ด๋ฏธ์ง๋ฅผ ๋ณผ ์ ์์ผ๋ฉฐ, ์์ ํ๊ฒ ์ค์ ๋ ๊ฒฝ์ฐ ์
ธ ๋ช
๋ น๋ ์คํํ ์ ์์ต๋๋ค.
์ฝ๊ธฐ ํ ์ฐ๊ธฐ(read-before-write) ๊ฒ์ดํธ๋ ๊ฐ ์ฝ๊ธฐ ํ์๋ฅผ ํด๋น `read_file` ํธ์ถ์ ๊ฒฐ๊ณผ์ ์ฐ๊ฒฐํ๋ฉฐ, ์ฌ๋ฌ ๋ฉ์์ง๋ก ๋ `Command` ์
๋ฐ์ดํธ๋ฅผ ๋ฐํํ๋ ์ปค์คํ
๋๊ตฌ๋ ํฌํจํฉ๋๋ค. ๊ด๋ จ ์๋ ๊ฒฐ๊ณผ๋ก๋ ์ฝ๊ธฐ ์คํจ ํ์ ์ฐ๊ธฐ๋ฅผ ํ๊ฐํ๊ฑฐ๋ ์ฑ๊ณตํ ์ฝ๊ธฐ๋ฅผ ๊ฐ๋ฆด ์ ์์ต๋๋ค.
๋ฃจํ ๊ฒฝ๊ณ ๊ฐ ๋ฐ์ํ๋ฉด ์์ด์ ํธ๋ ์ต์ข
๋ต๋ณ ์ ์ ์์งํ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ ์ ์์ต๋๋ค. ์ ์ฅ์ด ์ฝ๊ธฐ ํ ์ฐ๊ธฐ ๊ฒ์ดํธ์ ๋งํ๋ฉด ์์ด์ ํธ๋ ๋์ ํ์ผ์ ์ฝ์ ๋ค ์ ์ฅ์ ํ ๋ฒ ์ฌ์๋ํ ์ ์์ต๋๋ค. ๋ฃจํ์ ๋น ์ก๊ฑฐ๋ ์ค์ง๋ ๋๊ตฌ๋ ์ฌ์ฉ ๊ฐ๋ฅํ ๋์์ผ๋ก ๋์ฒดํด์ผ ํฉ๋๋ค. ํ์ฉ๋ ์ ์ฅ ๊ฒฝ๋ก๊ฐ ์๊ฑฐ๋ ์ฌ์๋๊ฐ ์คํจํ๋ฉด ์ต์ข
๋ต๋ณ์ ์์งํ ๊ฒฐ๊ณผ๋ฅผ ํฌํจํ๊ณ ํ์ผ์ด ์ ์ฅ๋์ง ์์์์ ์๋ฆฝ๋๋ค. ๋ณต๊ตฌ๋ฅผ ์ํ ํธ์ถ๋ ๋ฃจํ ์ ํ์ ๊ณ์ ์ง๊ณ๋๋ฉฐ, ํ๋ ์คํฑ์ด ๊ฑธ๋ฆฌ๋ฉด ์ดํ ๋๊ตฌ ์คํ์ด ์ฐจ๋จ๋ฉ๋๋ค.
๋ฒ์๋ฅผ ์ง์ ํ `read_file` ํธ์ถ์ ๋ชจ๋ ์๋๋ฐ์ค ํ๋ก๋ฐ์ด๋์์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ค์ ์
๋๋ค. ์ค์ ๊ฐํ ๋ฌธ์์์๋ง ๋๋ฉ๋๋ค. ๋ฐ๋ผ์ E2B, BoxLite, Tenki, OpenSandbox์์๋ ๋จ๋
์บ๋ฆฌ์ง ๋ฆฌํด(์: ์ ์ฅ๋ ์งํ ๋ก๊ทธ), ํผ ํผ๋, Unicode ์ค ๊ตฌ๋ถ์๊ฐ ํฌํจ๋ ํ์ผ์ด ๋ก์ปฌ ์๋๋ฐ์ค์ ๊ฐ์ ์ค์ ๋ฐํํ๋ฉฐ, ์๋ฆฐ ์ฝ๊ธฐ๊ฐ ์ ์ํ๋ `start_line`์ ์์ง ์ฝ์ง ์์ ๋ค์ ์ค์ ๊ฐ๋ฆฌํต๋๋ค.
๊ฐ์ ํ์ผ์ ๋ํ ๋์ ์ฝ๊ธฐ์ ์ฐ๊ธฐ๋ ๋๊ธฐ ๋ฐ ๋น๋๊ธฐ ๋๊ตฌ ํธ์ถ ์ ๋ฐ์ ๊ฑธ์ณ ํ๋์ ๊ฒ์ดํธ๋ฅผ ๊ณต์ ํฉ๋๋ค. ํด๋น ๊ฒ์ดํธ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ๋น๋๊ธฐ ํธ์ถ์๋ ํ์ฌ ์ฝ๊ธฐ ๋๋ ์ฐ๊ธฐ๋ฅผ ๋ง์น๋ ๋ฐ ํ์ํ ์์ปค ์ค๋ ๋๋ฅผ ์ ์ ํ์ง ์์ต๋๋ค. ๋๊ธฐ ์ค์ธ ํธ์ถ์ ์ทจ์ํด๋ ํ์ฌ ์์
์ ๊ณ์ ์คํ๋ฉ๋๋ค. ์ด๋ฏธ ํ์ผ ๊ฒ์ฌ๋ฅผ ์์ํ ํธ์ถ์ ๊ฒ์ดํธ๋ฅผ ํด์ ํ๊ธฐ ์ ์ ๊ทธ ์์
์ด ๋๋๊ธฐ๋ฅผ ๊ณ์ ๊ธฐ๋ค๋ฆฝ๋๋ค.
๊ธฐ๋ณธ ์ ๊ณต `grep` ๋๊ตฌ๋ ํ
์คํธ ํ์ผ ํ๋ ๋๋ ๋๋ ํฐ๋ฆฌ ์๋์์ ์ผ์นํ๋ ๋ชจ๋ ํ
์คํธ ํ์ผ์ ๊ฒ์ํ๋ฏ๋ก, ์์ด์ ํธ๋ ์์ฒญ์ ์
๋ก๋ ๋๋ ํฐ๋ฆฌ ์ ์ฒด๋ก ๋ํ์ง ์๊ณ ๋ ์
๋ก๋๋ ๋ฌธ์๋ฅผ ์ง์ ๊ฒ์ํ ์ ์์ต๋๋ค.
E2B์ `glob` ํํฐ๋ ํ์ผ ์ด๋ฆ ํจํด์ ๊ณต๋ฐฑ, ๋ฐ์ดํ, ๋ฌ๋ฌ ๊ธฐํธ๋ฅผ ๋ณด์กดํ๋ฉฐ, ์์ผ๋์นด๋ ๋งค์นญ๊ณผ ๋ฃจํธ ๊ธฐ์ค ๋๋ ํฐ๋ฆฌ ๋ฒ์ ์ง์ ์ ๊ทธ๋๋ก ์ ์ง๋ฉ๋๋ค.
E2B `grep`์ ์ผ์นํ๋ ๊ฒฝ๋ก์ ์ค ๋ฒํธ๋ฅผ ๋ณด๊ณ ํ ๋ ํ์ผ ๋ฐ ๋๋ ํฐ๋ฆฌ ์ด๋ฆ์ ์ฝ๋ก ๋ ๋ณด์กดํฉ๋๋ค.
`glob`๊ณผ `grep`์ E2B, BoxLite, Tenki, OpenSandbox์์ ๋ฐํ๋ ๊ฒฝ๋ก ์์ ์์ง ํญ์ด๋ Unicode ์ค ๊ตฌ๋ถ์ ๊ฐ์ LF ์ด์ธ์ ๊ตฌ๋ถ ๋ฌธ์๋ฅผ ๋ณด์กดํ๋ฉฐ, `grep`์ ์ผ์นํ ํ
์คํธ ์์์๋ ์ด๋ฅผ ๋ณด์กดํฉ๋๋ค.
์๊ฒฉ `ls`๋ 500๊ฐ ํญ๋ชฉ ๋ชฉ๋ก ์ ํ์ ์ ์ฉํ๊ธฐ ์ ์ ๋ฌด์ ๋์ ํ์ ํญ๋ชฉ์ ์ ์ธํ๋ฏ๋ก, ์์กด์ฑ ๋ฐ ๋น๋ ํธ๋ฆฌ๊ฐ ๋ณด์ด๋ ํ์ผ์ ๋ฐ์ด๋ด์ง ์์ต๋๋ค. ๋ฌด์ ๋์ ๋๋ ํฐ๋ฆฌ๋ฅผ ๋ช
์์ ์ผ๋ก ๋์ดํ๋ฉด ์ฌ์ ํ ๊ทธ ๋ด์ฉ์ด ๋์ด๋๋ฉฐ, ์ผ๋ฐ์ ์ธ ๊น์ด ๋ฐ ์ถ๋ ฅ ์ ํ์ ๊ณ์ ์ ์ฉ๋ฉ๋๋ค.
AIO ๋๋ ํฐ๋ฆฌ ๋ชฉ๋ก ์กฐํ๋ ์ฌ๋ผ์ง ์
ธ ์ธ์
์ ๋ฒ๋ฆฌ๋ฏ๋ก ๋ค์ ์์ฒญ์ด ๋ณต๊ตฌ๋ ์ ์์ต๋๋ค.
์ฐ๊ฒฐ์ด ๋๊ธด ํ์๋ ๋๋ ํฐ๋ฆฌ ๋ชฉ๋ก ์กฐํ์ ์์ ์
ธ ๋ช
๋ น์ด ์์
์ ์ฌ์(replay)ํ์ง ์๊ณ ๊ฒฐ๊ณผ๋ฅผ ์ ์ ์์์ผ๋ก ๋ณด๊ณ ํ๋ฉฐ, ์ดํ ํธ์ถ์ ์ ์ธ์
์ ์ฌ์ฉํฉ๋๋ค.
์
๋ก๋๋ Markdown์ ๊ฐ์๋ ATX ์ ๋ชฉ ๋ฌธ๋ฒ์ ์ธ์ํ๊ณ , ์ ํ ์ ๋ฏธ์ฌ ์ค์บ์ผ๋ก ๋ซ๋ ๋ง์ปค๋ฅผ ์ ๋ฆฌํ๋ฉฐ, HTML ์ฃผ์ ๋ธ๋ก๊ณผ ํ์ค ๋ฐ ๋ค์ฌ์ฐ๊ธฐ ์ฝ๋ ์์ ๋ฅผ ๊ฑด๋๋๋๋ค. ๋ฐ๋ผ์ ํด์ํ๊ทธ์ ์ฝ๋ ์ฃผ์์ด ์์ด์ ํธ์ ์ ๋ชฉ ๋ฏธ๋ฆฌ๋ณด๊ธฐ์์ ์ค์ ๋ฌธ์ ์น์
์ ๋ฐ์ด๋ด์ง ์์ต๋๋ค. ๋ค์ฌ์ฐ๊ธฐ๋ ๊ตต์ ๊ธ์จ ์์ ๋ ์ ์ธ๋๋ฉฐ, ์์ชฝ ๊ณต๋ฐฑ์ด ์ต๋ 3๊ฐ์ธ PDF ์คํ์ผ์ ๊ตต์ ๊ธ์จ ์ ๋ชฉ์ ๊ณ์ ์ง์๋ฉ๋๋ค.
๊ดํธ๋ก ๋ฌถ์ธ ์ฐ๋, ๋ถํธ๊ฐ ์๋ ๊ฐ, ํตํ ๊ธฐํธ๊ฐ ์์ ๋ถ์ ๊ธ์ก์ ํฌํจํด, ๊ตต์ ๊ธ์จ๊ฐ ๋๋ ์ซ์ ํ ํ์ ์น์
๋ฒํธ ๋ค์ ๋ธ๋ก ์ค ํ๋๋ผ๋ ์ซ์ ์ด์ด๋ฉด ์ ์ธ๋๋ฏ๋ก ๊ฐ์์ ์ ๋ชฉ ์์ฐ์ ์๋ชจํ์ง ์์ต๋๋ค.
๋ฐ์ดํธ ์์ ํ์(BOM)๊ฐ ์๋ ์๋ UTF-8 Markdown ํ์ผ์ ์๋ ์ค ๋ฒํธ๋ฅผ ์ ์งํ ์ฑ ๋์ผํ ๊ฐ์์ ํด๋ฐฑ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ฅผ ์์ฑํฉ๋๋ค.
๊ฐ์ ์ ๋ชฉ์ 200์, ํด๋ฐฑ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ํ์ผ๋น 2,000์๋ก ์ ํ๋๋ฉฐ ์๋ฆผ ํ์๊ฐ ๋ถ์ต๋๋ค. ์
๋ก๋๋ ์ ์ฒด ํ์ผ์ ๋์ ์ง์ ์ฝ๊ธฐ์ ๊ณ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ณํ๋ ์
๋ก๋์ ๊ฐ์์ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ์์ ํ์์คํฌํ๋ฅผ ํฌํจํด ์์ค ๋ฒ์ ์ด ์ผ์นํด์ผ ํฉ๋๋ค. ์์ค ๋ฒ์ ๋ณ๊ฒฝ์ด ๊ฐ์ง๋๋ฉด ๊ธธ์ด๊ฐ ๊ฐ์ ํธ์ง์ ํฌํจํด ์ด์ ๋ณํ์ด ๋ฌดํจํ๋ฉ๋๋ค. ์์ค ํ์์คํฌํ๊ฐ ์๋ ์ด์ ์์ ๊ถ ๊ธฐ๋ก๋ ๊ฑฐ๋ถ๋ฉ๋๋ค. ๋ณํ ๊ธฐ๋ฐ ๊ฐ์๋ฅผ ๋ณต์ํ๋ ค๋ฉด `uploads.auto_convert_documents: true`๋ก ์์ค๋ฅผ ๋ค์ ์
๋ก๋ํ์ธ์. ํ์ผ์ ๊ณ์ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ๊ฒ์ฆ๋์ง ์์ Markdown ๋ณํ๋ณธ์ ์์ด์ ํธ์ ๊ณผ๊ฑฐ ๋ชฉ๋ก์ ๋
๋ฆฝ๋ ํ์ผ๋ก ํ์๋ฉ๋๋ค.
Windows์์๋ `st_ctime_ns`๊ฐ ์์ฑ ์๊ฐ์ ๋ํ๋ผ ์ ์์ผ๋ฏ๋ก, ์๋ `mtime`์ ๋ณต์ํ๋ ๊ฐ์ ํฌ๊ธฐ์ ์ฌ์์ฑ์ ๊ฒ์ฆ์ ํผํ ์ ์์ต๋๋ค. ํ์์คํฌํ ๊ฒ์ฌ๋ ๋ณด์์ ์ธ ๋ฉํ๋ฐ์ดํฐ ๊ฒ์ฆ์ด๋ฉฐ, ๋ด์ฉ์ด ๋์ผํ๋ค๋ ๋ณด์ฅ์ด ์๋๋๋ค.
์๋๋ฐ์ค ์ด๋ฏธ์ง ๋ค์ด๋ก๋๋ ๋ชจ๋ธ ์ปจํ
์คํธ ์ฌ์ฝ๊ธฐ๋ฅผ ํฌํจํด ์ฝ๋ ๋์ 20 MiB ๋น์ ์ ํ์ ์ ์ฉํฉ๋๋ค. ํฌ๊ธฐ๋ฅผ ์ด๊ณผํ๋ ์คํธ๋ฆผ์ ์ ํ์ ๋๋ ์ฒซ ์ฒญํฌ์์ ์ค์ง๋ฉ๋๋ค. ์ปค์คํ
์๋๋ฐ์ค ํ๋ก๋ฐ์ด๋๋ `download_file(..., max_bytes=...)` ํค์๋ ์ธ์๋ฅผ ๋ฐ์ ์ ์ฉํด์ผ ํฉ๋๋ค. ์ด๋ฅผ ์ง์ํ์ง ์๋ ์ด์ ๊ตฌํ์์๋ ์ ํ ์๋ ๋ค์ด๋ก๋๋ก ํด๋ฐฑํ์ง ์๊ณ ์ด๋ฏธ์ง ์ฝ๊ธฐ๊ฐ ์คํจํฉ๋๋ค.
๋น์ ๋ชจ๋ธ ํธ์ถ์ ์ํด ๋ถ๋ฌ์จ ์ด๋ฏธ์ง ๋ฐ์ดํธ๋ ์ผ์์ ์
๋๋ค. DeerFlow๋ ๋ชจ๋ธ์ด ์ด๋ฅผ ์๋นํ ๋ค ์จ๊ฒจ์ง base64 ๋ฉ์์ง๋ฅผ ์ ๊ฑฐํ๋ฏ๋ก, ์ดํ ์ฒดํฌํฌ์ธํธ๊ฐ ํด๋น ํ์ด๋ก๋๋ฅผ ๊ณ์ ์ค๋ณต ์ ์ฅํ์ง ์์ต๋๋ค.
๊ฐ ์คํ(run)์ด ๋๋๋ฉด DeerFlow๋ ์คํ์ด ์์ ํ `workspace` ๋ฐ `outputs` ๋๋ ํฐ๋ฆฌ์ ๋ํ ์ํฌ์คํ์ด์ค ๋ณ๊ฒฝ ์์ฝ์ ๊ธฐ๋กํฉ๋๋ค. ์น UI๋ ์ด์์คํดํธ ํด์ ๊ฐ๊ฒฐํ "files changed" ๋ฐฐ์ง๋ฅผ ํ์ํ๋ฉฐ, ์ด๋ฅผ ์ด๋ฉด ์์ฑ, ์์ , ์ญ์ ๋ ํ์ผ์ ๋ณด์ฌ ์ฃผ๊ณ ํ์ํด๋ ์์ ํ ๊ฒฝ์ฐ ํ
์คํธ diff๋ ํจ๊ป ๋ณด์ฌ ์ค๋๋ค. ์
๋ก๋๋ ์์ด์ ํธ๊ฐ ๋ง๋ ๋ณ๊ฒฝ์ด ์๋๋ผ ์ฌ์ฉ์ ์
๋ ฅ์ด๋ฏ๋ก ์ ์ธ๋ฉ๋๋ค. DeerFlow๊ฐ ์์ ํ `.mcp/` ๋ค์์คํ์ด์ค ์๋์ stdio MCP ์์/๋๋ฒ๊ทธ ํ์ผ๋ ํ๋ก์ธ์ค ๋ด๋ถ ์ํ์ด๋ฏ๋ก ์ ์ธ๋ฉ๋๋ค(`.git/`, `node_modules/`์ ๋ง์ฐฌ๊ฐ์ง๋ก `.mcp`๋ผ๋ ์ด๋ฆ์ ๋๋ ํฐ๋ฆฌ๋ ๊น์ด์ ๊ด๊ณ์์ด ๋ชจ๋ ์ ์ธ๋ฉ๋๋ค). ํฌ๊ฑฐ๋, ๋ฐ์ด๋๋ฆฌ์ด๊ฑฐ๋, ๋ฏผ๊ฐํด ๋ณด์ด๋ ํ์ผ์ ๋ฉํ๋ฐ์ดํฐ๋ง ํ์๋ฉ๋๋ค.
`present_files`๋ฅผ ํตํด ์ ์๋ ํ์ผ์ ์ค๋ ๋์ ์ํฐํฉํธ ์ํ์ ๊ณ์ ํฌํจ๋๋ฉฐ, ์น UI๋ ํ์ด์ง๋ฅผ ์๋ก ๊ณ ์น ํ์๋ ์ํฐํฉํธ ํจ๋๊ณผ ์ ํ๋ ๋ฌธ์๋ฅผ ๋ณต์ํฉ๋๋ค. ์๋ฃ๋ ์๋ต์ด 2๊ฐ ์ด์ 50๊ฐ ์ดํ์ ํ์ผ์ ์ฑ๊ณต์ ์ผ๋ก ์ ์ํ๋ฉด, ๋ง์ง๋ง ํ์ผ ์นด๋์์ ZIP ๋ค์ด๋ก๋ ํ๋๋ ์ ๊ณตํฉ๋๋ค. ์์ถ ํ์ผ์ ํฌํจ๋๋ ํญ๋ชฉ์ ๋ธ๋ผ์ฐ์ ๊ฐ ๋ณด๋ธ ๊ฒฝ๋ก๊ฐ ์๋๋ผ ์ต์ข
์ ๋ฌ ์์์ฆ(terminal delivery receipt)์์ ๊ฒฐ์ ๋๋ฉฐ, ZIP์๋ ์๋ต ์ดํ ๋ณ๊ฒฝ๋์์ ์ ์๋ ํ์ฌ ํ์ผ ๋ฒ์ ์ด ๋ด๊น๋๋ค. ํ์ฌ ์ ํ๋ ์ ์ ์ํฐํฉํธ๋ ์คํ์ด ๋๋ ๋ ํ ๋ฒ ์๋ก ๊ณ ์ณ์ง๋ฏ๋ก, ์๋์ผ๋ก ๋ค์ ๋ถ๋ฌ์ค์ง ์์๋ ํธ์ง ๋ด์ฉ์ด ๋ณด์
๋๋ค. `/mnt/user-data/outputs` ์๋์ ๊ธฐ์กด UTF-8 ํ
์คํธ ์ํฐํฉํธ๋ Unix์ Windows ๋ชจ๋์์, ์ค๋ ๋๊ฐ ์ ํด ์ํ์ผ ๋ ํจ๋์์ ํธ์งํ๊ณ ๋ช
์์ ์ผ๋ก ์ ์ฅํ ์๋ ์์ต๋๋ค. ์ ์ฅ ์์๋ ์ฝํ
์ธ ๋ฆฌ๋น์ ์ ์ฌ์ฉํด ์์ด์ ํธ์ ๋ณ๊ฒฝ์ ๋ฎ์ด์ฐ์ง ์๋๋ก ํฉ๋๋ค. ์์ค ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ํ์ฅ์๊ฐ ์๋ `Dockerfile` ๋ฐ `Makefile` ์ํฐํฉํธ๋ ํ์ผ ์ด๋ฆ์ผ๋ก ์ธ์ํฉ๋๋ค. `constructor`, `__proto__` ๊ฐ์ ์ด๋ฆ์ ํฌํจํด ์ ์ ์๋ ํ์ผ ํ์์ ๋ค์ด๋ก๋ ํด๋ฐฑ์ ์ ์งํฉ๋๋ค.
์ ์ฅํ์ง ์์ ์ํฐํฉํธ ํธ์ง ๋ด์ฉ์ ๊ฐ์ ๋ธ๋ผ์ฐ์ ํญ์์ ์ฑํ
์ด๋ ์ํฌ์คํ์ด์ค ํ์ด์ง๋ฅผ ์ ํํ๊ฑฐ๋, ํ ํ์ด์ง๋ฅผ ๋ฐฉ๋ฌธํ๋ค๊ฐ ๋์์๋ ์ ์ง๋ฉ๋๋ค. ์ด์์ ์ ์ฅํ๊ฑฐ๋ ํ๊ธฐํ ๋๊น์ง ํ์ฌ ๊ณ์ ์ ๋ฉ๋ชจ๋ฆฌ์ ๋จ์ผ๋ฉฐ, ๊ณ์ ์ ๋ฐ๊พธ๊ฑฐ๋ ๋ก๊ทธ์์ํ๋ฉด ์ง์์ง๋๋ค.
๊ณต๊ฐ ์ผ์ผ์ด์ค ๋ฐฉ๋ฌธ ์ค์ด๊ฑฐ๋ Gateway ์ธ์ฆ ํ๋ก๋ธ๋ฅผ ์ฌ์ฉํ ์ ์์ ๋๋ ์ธ์ฆ ์ํ๊ฐ ํ์ธ๋ ๋๊น์ง ์จ๊ฒจ์ง ์ด์์ ์ ์งํฉ๋๋ค. ๋ค๋ฅธ ๊ณ์ ์ผ๋ก ๋ณต๊ตฌ๋๊ฑฐ๋ ๋ก๊ทธ์์์ด ํ์ธ๋๋ฉด ์ ์ง๋๋ ๋ด์ฉ์ด ์ง์์ง๋๋ค.
์ ์ฅํ์ง ์์ ํธ์ง์ด ์๋ ์ฑํ
์ด ํ๋๋ผ๋ ์์ผ๋ฉด ํญ์ ์๋ก ๊ณ ์น๊ฑฐ๋ ๋ซ์ ๋ ๊ฒฝ๊ณ ๊ฐ ํ์๋ฉ๋๋ค. ์ด์ ํ์ผ ๋ด์ฉ์ ๋ธ๋ผ์ฐ์ ์ ์ฅ์์ ์ ์ฅ๋์ง ์์ผ๋ฉฐ ๋ค์ ๋ถ๋ฌ์ค๋ฉด ์ ์ง๋์ง ์์ต๋๋ค.
์ถ๋ ฅ ํ์ผ์ด ์์์ ์ผ๋ก ๊ต์ฒด๋๋ฉด, ํฌ๊ธฐ์ ์์ ์๊ฐ์ด ๊ทธ๋๋ก์ฌ๋ ์ํฐํฉํธ ์ฝํ
์ธ ๋ฆฌ๋น์ ์ด ๊ฐฑ์ ๋ฉ๋๋ค. ์ดํ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ฅผ ์๋ก ๊ณ ์น๋ฉด ์ ์ฅ์ ์ฌ์ฉํ ์ ๋ฆฌ๋น์ ์ด ์ ๊ณต๋๋ฉฐ, ์ด์ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ์ฌ์ ํ ๋ค์ ๋ถ๋ฌ์์ผ ํฉ๋๋ค.
2 MiB ํธ์ง ์ ํ์ ๋๋ ์ผ๋ฐ ํ์ผ์ ์ ์ฒด ํ์ผ์ ํด์ฑํ์ง ์๊ณ ํ์ผ ์๋ณ ์ ๋ณด์ ๋ณ๊ฒฝ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๋ฒ์ ๊ฒ์ฆ์(validator)๋ก ์ฌ์ฉํฉ๋๋ค. ์ผ๋ฐ ํ์ผ์ ๋ํ ์กฐ๊ฑด๋ถ ๋ฐ์ดํธ ๋ฒ์ ์์ฒญ์๋ ์ผ์นํ๋ ETag๊ฐ ํ์ํ๋ฉฐ, ๋ ์ง ํ์์ `If-Range` ์์ฒญ์๋ ํ์ฌ ํ์ผ ์ ์ฒด๊ฐ ๋ฐํ๋ฉ๋๋ค.
์ ์ฅ ์์๋ ๊ธฐ์กด ํ์ผ ์ฝ๊ธฐ๋ 2 MiB์ ๊ฐ์ง์ฉ 1๋ฐ์ดํธ๋ฅผ ๋ํ ํฌ๊ธฐ๋ก ์ ํํ๋ฏ๋ก, ํฌ๊ธฐ ํ์ธ ํ ์ปค์ง๊ฑฐ๋ ๊ต์ฒด๋ ํ์ผ์ ํฌ๊ธฐ๋ฅผ ์ด๊ณผํ ํ์ผ ์ ์ฒด๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ๋ถ๋ฌ์ค์ง ์๊ณ ๊ฑฐ๋ถ๋ฉ๋๋ค.
CSV ๋ฐ TSV ์ํฐํฉํธ๋ ์ํฐํฉํธ ํจ๋๊ณผ ๋ณ๋ ์ฐฝ์์ ํ๋ก ์ด๋ฆฝ๋๋ค. ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ํ
์คํธ ๊ฐ(์์๋ฆฌ 0 ํฌํจ)์ ๋ณด์กดํ๊ณ , ์ ํ์ ์ธ ํค๋ ํ์ ์ง์ํ๋ฉฐ, ์ด๊ธฐ ์ํ์์ ์ต๋ 200ํ, 50์ด๊น์ง ํ์ด์ง ๋จ์๋ก ๋๊ฒจ ๋ณผ ์ ์์ต๋๋ค. ๊ธธ๊ฑฐ๋ ์ฌ๋ฌ ์ค์ธ ์
์ ์ด์ด์ ์ ์ฒด ๋ด์ฉ์ ๋ณต์ฌํ ์ ์์ต๋๋ค. ํ์ผ์ ๊ฒ์ฌํ๊ฑฐ๋ ํธ์งํ๋ ค๋ฉด ์์ค ๋ณด๊ธฐ๋ก ์ ํํ์ธ์. ๋ค์ด๋ก๋์ ๋ณ๋ ์ฐฝ์ ์ ์ฅ๋ ๋ฒ์ ์ ์ฌ์ฉํฉ๋๋ค.
HTML ์ํฐํฉํธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ๋ฌธ์์ ์ค์ `` ์์๊ฐ ์๋ ํ ์ํฐํฉํธ ๋๋ ํฐ๋ฆฌ๋ฅผ ๊ธฐ์ค์ผ๋ก ์๋ ๊ฒฝ๋ก ์์
์ ํด์ํฉ๋๋ค. ์ฃผ์์ด๋ ์คํฌ๋ฆฝํธ ํ
์คํธ ์์ base ํ๊ทธ ์์๋ ์ด ํด์ ๋ฐฉ์์ ๋ฐ๊พธ์ง ์์ต๋๋ค.
์ธ์ฆ์ด ํ์ฑํ๋์ด ์์ผ๋ฉด ๊ฐ์ ์ค๋ ๋์ ์ํฐํฉํธ ๊ฒฝ๋ก์ ์๋ ์ ์ ๋ฆฌ์์ค(์ด๋ฏธ์ง, ๋ฐ์ํ ์ด๋ฏธ์ง, ํด๋์ ์คํฌ๋ฆฝํธ์ CSS, ์ค์ฒฉ๋ import ํฌํจ)๋ ๋ถ๋ชจ ํ์ด์ง๊ฐ ๊ฐ์ ธ์ ์ธ๋ผ์ธ์ผ๋ก ์ฝ์
ํ๋ฉฐ, ๋ถํฌ๋ช
(opaque) iframe ์๋๋ฐ์ค๋ฅผ ์ฝํ์ํค์ง ์์ต๋๋ค. ์ค๋น ๊ณผ์ ์๋ ๋ฆฌ์์ค ์, ๋ฐ์ดํธ, CSS ๊น์ด, ์๊ฐ ์ ํ์ด ์์ผ๋ฉฐ, ์ผ๋ถ๋ง ์ค๋น๋ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ๊ทธ ์ฌ์ค์ ์๋ฆฝ๋๋ค. ๋์ JavaScript ์์ฒญ, ES ๋ชจ๋ import, ์ค์ฒฉ iframe, ํ์(navigation)์ ์ฌ์ ํ ์๋๋ฐ์ค ์ ํ์ ๋ฐ์ต๋๋ค. ์ง์ ๋ฒ์์ ์ ํ์ [ํ๋ก ํธ์๋ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋
ธํธ](frontend/README.md#development-notes)๋ฅผ ์ฐธ๊ณ ํ์ธ์. 401 ์๋ต์ ํฌํจํด ์ ํ์ ๋ฆฌ์์ค๋ฅผ ๋ถ๋ฌ์ค์ง ๋ชปํด๋ ๋ํ๋ ์ด๋ฆฐ ์ํ๋ก ์ ์ง๋๋ฉฐ ๋ถ๋ถ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์๋ด๊ฐ ํ์๋ฉ๋๋ค. HTML doctype๊ณผ doctype์ด ์๋ ๋ ๋๋ง ๋ชจ๋๋ ๋ณด์กด๋๊ณ , ์ธ๋ผ์ธ SVG ์คํ์ผ ์์ CSS ์ฐธ์กฐ๋ ํจ๊ป ์ค๋น๋ฉ๋๋ค.
์ํฐํฉํธ ํจ๋๊ณผ ๋ณ๋ ์ฐฝ์ Markdown ๋ณด๊ณ ์ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ๋ก์ปฌ ์ด๋ฏธ์ง๋ฅผ ๋ณด๊ณ ์ ์์ฒด์ ๋๋ ํฐ๋ฆฌ์ ๋ํ๋ฅผ ๊ธฐ์ค์ผ๋ก ํด์ํฉ๋๋ค. `./charts/summary.png` ๊ฐ์ ์๋ ๊ฒฝ๋ก์ ์ ๋ `/mnt/...` ๊ฒฝ๋ก๋ฅผ ๋ชจ๋ ์ง์ํ๋ฉฐ, ์ธ๋ถ ์ด๋ฏธ์ง URL์ ๊ธฐ์กด ๋์์ ์ ์งํฉ๋๋ค.
์ํ์ด CRLF ์ค ๋์ ์ค๊ฐ์์ ์๋ฅด๋ฉด, ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ์์ชฝ์ ์์ ํ ํ์ ์ ์งํ๊ณ ๋ถ์์ ํ ๋ง์ง๋ง ๋ ์ฝ๋๋ ์๋ตํฉ๋๋ค. ๋ง์ง๋ง ํ๋๊ฐ ๋ฐ์ดํ๋ก ๋ฌถ์ธ ๊ฒฝ์ฐ๋ ๋ง์ฐฌ๊ฐ์ง์
๋๋ค.
ํ
์คํธ ์ํฐํฉํธ๋ HTTP ๋ฐ์ดํธ ๋ฒ์๋ฅผ ์ง์ํ๋ ๋ฐฉ์์ผ๋ก ์คํธ๋ฆฌ๋ฐ๋ฉ๋๋ค. ์น UI๋ ์ฒ์์ ์ต๋ 1 MiB๋ง ๋ถ๋ฌ์ค๊ณ , ํ์ผ์ด ๋ ํฌ๋ฉด ๋ฏธ๋ฆฌ๋ณด๊ธฐ ํฌ๊ธฐ๋ฅผ ํ์ํ๋ฉฐ, ๋๋จธ์ง๋ฅผ ๊ฐ์ ธ์ค๊ฑฐ๋ ์ ์ฒด ์ฝ๋ ํธ์ง๊ธฐ๋ฅผ ๋ง์ดํธํ๊ธฐ ์ ์ ๋ช
์์ ์ธ **Load full file** ๋์์ ๊ธฐ๋ค๋ฆฝ๋๋ค. ์ ์ฒด ํ์ผ์ ๋ถ๋ฌ์จ ๋ค์์ผ ํธ์งํ ์ ์์ต๋๋ค. ์ ์ฅํ์ง ์์ ๋ณ๊ฒฝ ๊ฐ์ง๋ ํธ์ง์ ๋๋๋ฆฌ๊ฑฐ๋ ์ด๊ธฐ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ดํ ๋ถ๋ถ์ ์ญ์ ํ๋ ๊ฒฝ์ฐ๋ฅผ ํฌํจํด ์ ์ฒด ๋ด์ฉ์ ๊ธฐ์ค์ผ๋ก ํฉ๋๋ค. ๋ค์ ๋ถ๋ฌ์ค๊ธฐ๊ฐ ์คํจํ๊ฑฐ๋ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ง ๋ฐํ๋๋๋ผ๋, ์ฌ์ฉ์๋ ์ ์ฅํ์ง ์์ ์ด์์ ์ ์งํ ์ฑ ํธ์ง์ ์ข
๋ฃํ ์ ์์ต๋๋ค.
ํ์ฑ HTML, XHTML, SVG ์ํฐํฉํธ๋ Gateway ๊ฒฝ๊ณ์์ ๊ณ์ ๊ฐ์ ๋ค์ด๋ก๋๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค.
์ํฐํฉํธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ์ ๋ค์ด๋ก๋๋ ํ์ผ ์ด๋ฆ์ ํฌํจ๋ ๋ฆฌํฐ๋ด ํผ์ผํธ ์ํ์ค๋ฅผ ๋ณด์กดํฉ๋๋ค. `report%20final.md`์ `report final.md`๋ ์๋ก ๋ค๋ฅธ ํ์ผ๋ก ์ ์ง๋ฉ๋๋ค. Markdown ๋งํฌ๋ ๊ณ์ URL ์ธ์ฝ๋ฉ๋ ๊ฒฝ๋ก๋ฅผ ํ์ฉํฉ๋๋ค.
`write_file` ์๋ด๋ ์ปค์คํ
์์ด์ ํธ ๋ฐ thinking ๋ชจ๋ ์ฌ์ ์๋ฅผ ํฌํจํด ํ์ฑ ๋ชจ๋ธ์ ์ถ๋ ฅ ํ ํฐ ์ ํ์ ๋ฐ์ํฉ๋๋ค. ๋ ๊ธด ๋ฌธ์์ ๊ฒฝ์ฐ ์์ด์ ํธ๋ `append=True`๋ก ์น์
๋จ์๋ก ์์ฑํ๋๋ก ์๋ด๋ฐ์ผ๋ฉฐ, ์ ํ์ด ์๋ ค์ง์ง ์์ ๋ชจ๋ธ์ ์์น ์์ฐ ํํธ๋ฅผ ๋ฐ์ง ์์ต๋๋ค.
`AioSandboxProvider`์์๋ ์
ธ ์คํ์ด ๊ฒฉ๋ฆฌ๋ ์ปจํ
์ด๋ ์์์ ์ด๋ฃจ์ด์ง๋๋ค. `LocalSandboxProvider`์์๋ ํ์ผ ๋๊ตฌ๊ฐ ์ฌ์ ํ ํธ์คํธ์ ์ค๋ ๋๋ณ ๋๋ ํฐ๋ฆฌ์ ๋งคํ๋์ง๋ง, ํธ์คํธ `bash`๋ ์์ ํ ๊ฒฉ๋ฆฌ ๊ฒฝ๊ณ๊ฐ ์๋๊ธฐ ๋๋ฌธ์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋นํ์ฑํ๋์ด ์์ต๋๋ค. ํธ์คํธ bash๋ ์์ ํ ์ ๋ขฐํ ์ ์๋ ๋ก์ปฌ ์ํฌํ๋ก์์๋ง ๋ค์ ํ์ฑํํ์ธ์. ํธ์คํธ bash ๋ช
๋ น์๋ ์ค์ ๊ฒฝ๊ณผ ์๊ฐ(wall-clock) ๊ธฐ์ค ํ์์์์ด ์์ผ๋ฉฐ, ์ค๋ ์คํ๋๋ ํ๋ก์ธ์ค๋ ์ถ๋ ฅ์ ์ํฌ์คํ์ด์ค ๋ก๊ทธ๋ก ๋ฆฌ๋๋ ์
ํด ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์์ํด์ผ ํฉ๋๋ค. Windows์์๋ Git Bash/MSYS ์ธ์ ๋ณํ ์ ์ธ ๋์์ด ์์ ํ ๋น๋ฃจํธ ๊ฐ์ ๊ฒฝ๋ก ์ ๋์ฌ๋ก ํ์ ๋๋ฏ๋ก, ํธ์คํธ ๋ค์ดํฐ๋ธ CLI ๋ฐ์ฒ๋ ์ผ๋ฐ์ ์ธ MSYS ํธํ์ฑ์ ์ ์งํฉ๋๋ค. ๋ก์ปฌ ์๋๋ฐ์ค๊ฐ PowerShell๋ก ํด๋ฐฑํ ๋๋ ์ถ๋ ฅ์ UTF-8๋ก ์บก์ฒํ๋ฏ๋ก CJK ํ
์คํธ๊ฐ Gateway ํธ์คํธ์ ๋ก์บ์ ์ข์ฐ๋์ง ์์ต๋๋ค.
Docker AIO ์๋๋ฐ์ค๋ ํธํ์ฑ์ ์ํด ๊ธฐ๋ณธ์ ์ผ๋ก ๊ธฐ์กด์ ๊ฐ๋ฐฉํ ์ด๊ทธ๋ ์ค(egress) ๋์์ ์ฌ์ฉํฉ๋๋ค. ์ด์์๋ `sandbox.network.mode`๋ฅผ `isolated` ๋๋ `allowlist`๋ก ์ค์ ํ ์ ์์ต๋๋ค. ํ์ฉ ๋ชฉ๋ก ๋ชจ๋๋ ์ด์์๊ฐ ์ ์ํ ๋๋ฉ์ธ๊ณผ, ์ผ์์ ๋๋ ์๋๋ฐ์ค ์๋ช
๋์์ HTTP(S) ์น์ธ์ ์ํ ๋ํํ Human Input ์นด๋๋ฅผ ์ง์ํฉ๋๋ค. ์ฌ์ค, ๋ฃจํ๋ฐฑ, ๋งํฌ ๋ก์ปฌ, ๋ฉํฐ์บ์คํธ, ํด๋ผ์ฐ๋ ๋ฉํ๋ฐ์ดํฐ ์ฃผ์๋ ๊ณ์ ์น์ธํ ์ ์์ต๋๋ค. ๊ฑฐ๋ถ๋ ํธ์คํธ ์ด๋ฆ์ DNS ์กฐํ ์ ์ ๊ฑฐ๋ถ๋ฉ๋๋ค.
`scheduled`, `webhook`, `autonomous` ์ํธ์์ฉ ๋ชจ๋์ ์คํ์ ์นด๋๋ฅผ ์ด์ง ์๊ณ ์๋์ผ๋ก ๊ฑฐ๋ถ๋ฉ๋๋ค. ์ด๋ฌํ ๋ฌด์ธ ์คํ์ ์ํ์ด ๋ฎ๊ณ ๋๋๋ฆด ์ ์๋ ์์
์ ํํด์๋ง ์ต์ํ์ ๊ฐ์ ์ผ๋ก ์งํํฉ๋๋ค. ์ถฉ๋ถํ ๊ถํ ์์ด ์ํ์ด ๋๊ฑฐ๋ ๋๋๋ฆด ์ ์๋ ์์
์, ๋ชจ๋ธ์ด ํ์ธ ์ง๋ฌธ(clarification)์ ์๋ํ๋๋ผ๋ ๋๋ฝ๋ ๊ฒฐ์ ์ ๋ช
์ํ ๊ตฌ์กฐํ๋ `BLOCKED` ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํฉ๋๋ค.
์ ๋ขฐํ ์ ์๋ ์ฌ์ด๋์นด๋ Docker์ ๊ณต์ ๊ธฐ๋ณธ ๋ธ๋ฆฌ์ง ๋์ ์๋๋ฐ์ค๋ณ ์ ์ฉ ์ด๊ทธ๋ ์ค ๋ธ๋ฆฌ์ง๋ฅผ ์ฌ์ฉํ๋ฉฐ, ์ ๋ฌํ๊ธฐ ์ ์ ๋ชจํธํ HTTP ํ๋ ์ด๋ฆ์ ๊ฑฐ๋ถํฉ๋๋ค. ๋ฐํ์ ์๊ตฌ ์ฌํญ๊ณผ ์ ์ฒด ์ ์ฑ
๋ชจ๋ธ์
[์๋๋ฐ์ค ์ค์ ](backend/docs/CONFIGURATION.md#sandbox-network-policy)์ ์ฐธ๊ณ ํ์ธ์.
`AioSandboxProvider`๋ ์ผ๋ฐ์ ์ผ๋ก ๋ฐฑ์๋์ ๋ฐ๋ผ ์ค๋ ๋ ๋ฐ์ดํฐ ๋ง์ดํธ ์ฌ๋ถ๋ฅผ ๊ฐ์งํฉ๋๋ค. ๋ก์ปฌ ์ปจํ
์ด๋๋ ๋ง์ดํธ๋ Gateway ๋๋ ํฐ๋ฆฌ๋ฅผ ์ฌ์ฉํ๊ณ , ์๊ฒฉ/Provisioner ์๋๋ฐ์ค๋ ๋ช
์์ ์ธ ๋๊ธฐํ๋ฅผ ํตํด ์
๋ก๋๋ ํ์ผ์ ๋ฐ์ต๋๋ค. ์์ชฝ์ด ๋์ผํ ์ค๋ ๋ ์ฌ์ฉ์ ๋ฐ์ดํฐ ๋๋ ํฐ๋ฆฌ๋ฅผ ๊ณต์ ํ๋ค๋ ๊ฒ์ด ๋ณด์ฅ๋๋ ๋ฐฐํฌ์์๋ `sandbox.thread_data_mounts: true`๋ฅผ ์ค์ ํด ์
๋ก๋๋ง๋ค ์ํ๋๋ ์๋๋ฐ์ค ํ๋๊ณผ ๋๊ธฐํ๋ฅผ ๊ฑด๋๋ธ ์ ์์ต๋๋ค. ์๋ ๊ฐ์ง๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์ด ํ๋๋ฅผ ์ค์ ํ์ง ๋ง์ธ์. ์๋ชป ์ค์ ํ๋ฉด ์๋๋ฐ์ค ์์์ ์
๋ก๋๋ ํ์ผ์ ์ฌ์ฉํ ์ ์๊ฒ ๋ ์ ์์ต๋๋ค.
์
๋ก๋ ์ปค๋ฐ์ด ์คํจํ๋ฉด, ์๋ฅผ ๋ค์ด Windows ๊ณต์ ์๋ฐ ๋๋ฌธ์ ์์ ํ์ผ ์ ๋ฆฌ๊น์ง ์คํจํ๋๋ผ๋ ์๋ ์ค๋ฅ๊ฐ ๋ณด๊ณ ๋ฉ๋๋ค.
ํ์ผ์ด ๊ฒ์๋ ํ์๋ ์์ ํ์ผ ์ ๋ฆฌ ์คํจ๊ฐ ๋ก๊ทธ์ ๊ธฐ๋ก๋ ๋ฟ ์
๋ก๋๋ฅผ ์คํจ์ํค์ง ์์ผ๋ฉฐ, ์จ๊ฒจ์ง ์คํ
์ด์ง ํ์ผ์ ์์ ์ ์ ๋ฆฌ ์์
์ ๋งก๊ฒจ์ง๋๋ค.
์ด ์ ๋ฆฌ ์์
์ด ์
๋ก๋ ๋๋ ํฐ๋ฆฌ๋ฅผ ์ค์บํ ์ ์์ผ๋ฉด ๊ฒฝ๊ณ ๋ฅผ ๋ก๊ทธ์ ๋จ๊ธฐ๊ณ ํด๋น ๋๋ ํฐ๋ฆฌ์ ํ์ผ์ ๋ณด์กดํ ์ฑ ๋ค๋ฅธ ๊ณณ์ ์ ๋ฆฌ๋ฅผ ๊ณ์ํฉ๋๋ค. ์ ๋ฆฌ ๋์ค ์ฌ๋ผ์ง ๋๋ ํฐ๋ฆฌ๋ ์กฐ์ฉํ ๊ฑด๋๋๋๋ค.
์
๋ก๋, ์ ์คํฌ ์ง์ ํ์ผ, ์ ๋ก์ปฌ ์๋๋ฐ์ค ๊ฒฝ๋ก๋ ๋ชจ๋ ํ๋ซํผ์์ Windows ์์ฝ ์ฅ์น ์ด๋ฆ์ ๊ฑฐ๋ถํฉ๋๋ค. ์ฌ๊ธฐ์๋ `COMยน`, `LPTยฒ`, ์ฝ์ ๋ณ์นญ `CONIN$` ๋ฐ `CONOUT$`, ๊ทธ๋ฆฌ๊ณ `comยณ.txt`์ฒ๋ผ ํ์ฅ์๊ฐ ๋ถ์ ์ด๋ฆ์ด ํฌํจ๋ฉ๋๋ค.
ํ์ฅ์ ์์ ASCII ๊ณต๋ฐฑ์ ๋ฃ์ด๋ ์ฅ์น ์ด๋ฆ์ด ์ด์ ๊ฐ๋ฅํด์ง์ง๋ ์์ต๋๋ค. `NUL .txt`์ `COM1 .log`๋ ๊ฑฐ๋ถ๋ฉ๋๋ค. `report .txt` ๊ฐ์ ์ผ๋ฐ ์ด๋ฆ์ ๋ณ๊ฒฝ ์์ด ๋ณด์กด๋ฉ๋๋ค.
๊ฐ์ ํ์ผ ํธ๋ฆฌ๋ฅผ Windows์์๋ ๊ณ์ ์ฌ์ฉํ ์ ์๋๋ก, ์ด๋ฌํ ํ์ผ์ ์์ฑํ๊ฑฐ๋ ์
๋ก๋ํ๊ธฐ ์ ์ ์ด๋ฆ์ ๋ฐ๊พธ์ธ์.
`.upload-*.part`์ ์ผ์นํ๋ ์
๋ก๋ ํ์ผ ์ด๋ฆ์ ํด๋น ํจํด์ด ์์ ์คํ
์ด์ง ํ์ผ์ฉ์ผ๋ก ์์ฝ๋์ด ์์ผ๋ฏ๋ก ๊ฑฐ๋ถ๋ฉ๋๋ค. ๊ทธ๋ฐ ํ์ผ์ ์
๋ก๋ํ๊ธฐ ์ ์ ์ด๋ฆ์ ๋ฐ๊พธ์ธ์.
์ด ์ ํ์ ๋ชจ๋ ํธ์คํธ์์ `.upload-notes.part.`, `.upload-notes.part `, `.UPLOAD-NOTES.PART`์ฒ๋ผ ๋์ ์ ์ด๋ ๊ณต๋ฐฑ์ด ๋ถ์ Windows ๋ณ์นญ๊ณผ ๋์๋ฌธ์ ๋ณํ์๋ ์ ์ฉ๋ฉ๋๋ค.
HTTP ๊ฒ์ฌ๋ basename์ ์ถ์ถํ ๋ Linux์์๋ `/`์ `\`๋ฅผ ๋ชจ๋ ๊ฒฝ๋ก ๊ตฌ๋ถ์๋ก ์ธ์ํฉ๋๋ค. ์์ฝ๋ ์ด๋ฆ์ด ํฌํจ๋ ๋ฐฐ์น์์๋ ์๋ํฌ์ธํธ๊ฐ ์ด๋ค ํ์ผ๋ ๊ฒ์ํ๊ธฐ ์ ์ ์ด๋ฆ ๋ณ๊ฒฝ ํํธ์ ํจ๊ป `400`์ ๋ฐํํ๋ฏ๋ก, ์ฑํ
์ ์ฒจ๋ถ ํ์ผ ์์ด ๊ณ์ ์งํํ๋ ๋์ ์
๋ก๋ ์ค๋ฅ๋ฅผ ๋ณด๊ณ ํฉ๋๋ค. SDK๋ ํ์ผ์ ๋ณต์ฌํ๊ธฐ ์ ์ ๋ฐฐ์น ์ ์ฒด์ ํ์ผ ์ด๋ฆ์ ๊ฒ์ฆํฉ๋๋ค. ์ ํ๋ก์ ํธ ๋ฌธ์ ์ด๋ฆ๋ ์์ค์์ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ ํด์ง๋ , ์
๋ก๋ ๋๋ ์๊ฐ๋ก ์น๊ฒฉํ ๋ ๋ช
์์ ์ผ๋ก ์ง์ ๋๋ ๊ฐ์ ์ ํ์ ๋ฐ๋ฆ
๋๋ค. ์์ฝ๋ ์ด๋ฆ์ ๊ฐ์ง ์ด์ ์๊ฐ ๋ฌธ์๋ ๊ณ์ ๋ค์ด๋ก๋ํ ์ ์์ง๋ง ์ง์ ์ฒจ๋ถํ ์๋ ์์ต๋๋ค. ๋ค์ด๋ก๋ํ ๋ค ์ด๋ฆ์ ๋ฐ๊ฟ ์ค๋ ๋์ ์
๋ก๋ํ์ธ์. ์ด ๋ณ๊ฒฝ์ ์ด๋ฏธ ์คํ
์ด์ง ํจํด๊ณผ ์ผ์นํ๋ ์ด์ ์ค๋ ๋ ์
๋ก๋๋ฅผ ๋ณต๊ตฌํ๊ฑฐ๋ ๋ง์ด๊ทธ๋ ์ด์
ํ์ง ์์ต๋๋ค.
์
๋ก๋ ๋ชฉ๋ก์ ๋์ ์ ๋ฆฌ ์ค์๋ ๊ณ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ ๊ฑฐ๋ ํ์ผ์ ์๋ต๋๋ฉฐ, ์
๋ก๋ ๋๋ ํฐ๋ฆฌ๊ฐ ์ฌ๋ผ์ง๊ฑฐ๋ ํ์ผ๋ก ๊ต์ฒด๋๋ฉด ๋ชฉ๋ก ์กฐํ๋ ์ด๋ฏธ ์์งํ ํญ๋ชฉ์ ๋ฐํํฉ๋๋ค. ๊ถํ ์ค๋ฅ ๋ฐ ๊ธฐํ ์ด์์ ์ค๋ฅ๋ ์ฌ์ ํ ํ์๋ฉ๋๋ค.
์ด๊ฒ์ด ๋๊ตฌ์ ์ ๊ทผํ ์ ์๋ ์ฑ๋ด๊ณผ ์ค์ ์คํ ํ๊ฒฝ์ ๊ฐ์ถ ์์ด์ ํธ์ ์ฐจ์ด์
๋๋ค.
```
# Paths inside the sandbox container
/mnt/user-data/
โโโ uploads/ โ your files
โโโ workspace/ โ agents' working directory
โโโ outputs/ โ final deliverables
```
### ์์ด์ ํธ ๋ธ๋ผ์ฐ์ ์ ์ด
๋ธ๋ผ์ฐ์ ์คํฌ๋ฆฐ์ท๊ณผ Browserless ์บก์ฒ/๊ฐ์ ธ์ค๊ธฐ(fetch) ๊ฒฐ๊ณผ๋ฌผ์ ํ์ผ ์ ์ฒด๊ฐ ๊ธฐ๋ก๋ ๋ค์๋ง ๊ฒ์๋ฉ๋๋ค. ์ ํ์ผ์ ํธ์คํธ์ ์ผ๋ฐ์ ์ธ ์์ฑ ๊ถํ(์ผ๋ฐ์ ์ผ๋ก `0644`)์ ์ฌ์ฉํ๊ณ , ๊ต์ฒด๋๋ ํ์ผ์ ๊ธฐ์กด ๊ถํ์ ์ ์งํ๋ฏ๋ก, ํด๋น ๊ถํ์ด ํ์ฉํ๋ ๊ฒฝ์ฐ ์๋๋ฐ์ค ์ฝ๋๊ฐ ์บก์ฒ๋ฅผ ์ฝ์ ์ ์์ต๋๋ค.
๋ธ๋ผ์ฐ์ ์์กด์ฑ ์๋ ๊ฐ์ง๋ ๋๊ตฌ ํญ๋ชฉ ์์์ `name`, `group`, `use`๊ฐ ์ด๋ค ์์๋ก ์ค๋ ๋ฐ์๋ค์ด๋ฉฐ, ๋ค์ฌ์ด YAML ๋ชฉ๋ก๊ณผ ๋ค์ฌ์ฐ์ง ์์ YAML ๋ชฉ๋ก์ ๋ชจ๋ ์ง์ํฉ๋๋ค.
ํ์ด์ง๋ฅผ ์ฝ๋ ๊ฒ๊ณผ ํ์ด์ง๋ฅผ *์ฌ์ฉํ๋* ๊ฒ์ ๋ค๋ฆ
๋๋ค. DeerFlow๋ ์ฝ๊ธฐ ์ ์ฉ `web_fetch` ๋ฐ `web_capture` ๋๊ตฌ์ ํจ๊ป, ๋ํ๋ณ๋ก ์ด์ ์๋ ๋ธ๋ผ์ฐ์ ์ธ์
์ ์ ์งํ๋ ์ ํ ์ฌํญ์ธ ์์ด์ ํธ ๋ธ๋ผ์ฐ์ ๋๊ตฌ ๊ทธ๋ฃน์ ์ ๊ณตํฉ๋๋ค. ์ด๋ฅผ ํตํด ์์ด์ ํธ๋ JavaScript ๋น์ค์ด ํฐ ์ฌ์ดํธ์์ ํ์ด์ง ์ด๋, ์ํธ์์ฉ ์์ ์ฝ๊ธฐ, ํด๋ฆญ, ์
๋ ฅ, ํผ ์ ์ถ, ์ฌ๋ฌ ๋จ๊ณ๋ก ์ด๋ฃจ์ด์ง ํ๋ฆ ๋ฐ๋ผ๊ฐ๊ธฐ ๋ฑ ์ค์ ๋ก ํ์ด์ง๋ฅผ ์กฐ์ํ ์ ์์ต๋๋ค.
๊ฐ ๋์์ ํ์ด์ง์ ์ํธ์์ฉ ์์์ ๋ํ ์ ์ค๋
์ท์ ๋ฐํํ๋ฉฐ, ๊ฐ ์์๋ ์์ ์ ์ธ `[ref]` ๋ฒํธ๋ก ์ง์ ๋๋ฏ๋ก ์์ด์ ํธ๋ ์
๋ ํฐ๋ฅผ ์ถ์ธกํ๋ ๋์ ๋ฐฉ๊ธ ๊ด์ฐฐํ ๋ด์ฉ์ ๋ฐํ์ผ๋ก ๋์ํฉ๋๋ค. ์ธ๋ถ๋ก ๋๊ฐ๋ URL์ ๊ธฐ๋ณธ์ ์ผ๋ก SSRF ๊ฒ์ฌ๋ฅผ ๊ฑฐ์น๋ฉฐ, ๋ธ๋ผ์ฐ์ ์ TCP ์ฐ๊ฒฐ์ ๊ฐ ์ฐ๊ฒฐ์ ๊ฒ์ฌ๋ ์ฃผ์์ ๊ณ ์ ํ๋ ๋ก์ปฌ ํ๋ก์๋ฅผ ๊ฑฐ์น๋ฏ๋ก, ๊ฒ์ฌ ์ดํ์ ๋ฐ๋ DNS ์๋ต์ด ์ฐ๊ฒฐ์ ์ฌ์ค ํธ์คํธ๋ก ์ฐํ์ํฌ ์ ์์ต๋๋ค(WebRTC UDP๋ ์ ์ฉ ๋์์ด ์๋๋๋ค). ์ด ๊ธฐ๋ฅ์ Playwright๋ก ๊ตฌ๋๋๋ฉฐ, ์ฝ์ด ์ค์น๋ฅผ ๊ฐ๋ณ๊ฒ ์ ์งํ๊ธฐ ์ํด ์ ํ์ extra๋ก ์ ๊ณต๋ฉ๋๋ค.
```bash
cd backend
uv sync --extra browser
uv run playwright install chromium
```
๊ทธ๋ฐ ๋ค์ `config.yaml`์์ `group: browser` ๋๊ตฌ ํญ๋ชฉ(`browser_navigate`, `browser_snapshot`, `browser_click`, `browser_type`, `browser_get_text`, `browser_back`, `browser_screenshot`, `browser_close`)์ ์ฃผ์์ ํด์ ํ์ธ์. `make dev` / Docker ์์ ๊ณผ์ ์ ํ์ฑํ๋ `browser_navigate` ๋๊ตฌ๋ฅผ ๊ฐ์งํ๊ณ , ์์กด์ฑ ๋๊ธฐํ ์ `browser` extra๋ฅผ ์ ์งํฉ๋๋ค. ๋ธ๋ผ์ฐ์ ์ ์ด๊ฐ ์ค์ ๋์ด ์๋๋ฐ Playwright๊ฐ ์์ผ๋ฉด Gateway๋ ์์์ ์คํจํ๋ฉฐ, `/api/features`๋ ๋ฐฑ์๋๊ฐ ์ค์ ๋ก Browser UI๋ฅผ ์ ๊ณตํ ์ ์์ ๋๋ง ์ด๋ฅผ ํ์ํฉ๋๋ค. ๋ก์ปฌ์ ์ ๋ขฐํ ์ ์๋ ๋๋ฒ๊น
์ด ์๋ ๋ชจ๋ ๊ฒฝ์ฐ์๋ `headless: true`์ `allow_private_addresses: false`๋ฅผ ์ ์งํ์ธ์. `cdp_url`๋ก ๊ธฐ์กด Chrome์ ์ฐ๊ฒฐํ๋ฉด DeerFlow์ ํ์ ๋ฆฌ์์ค/๋ฆฌ๋๋ ์
SSRF ๋ณดํธ๋ฅผ ์ ์ฉํ ์ ์์ผ๋ฏ๋ก, `allow_unguarded_cdp: true`๋ก ๊ทธ ์ํ์ ๋ช
์์ ์ผ๋ก ์ธ์ ํ์ง ์๋ ํ ์คํจ ์ ์ฐจ๋จ(fail closed)๋ฉ๋๋ค. ์ด ์ต์
์ ์ ๋ขฐํ ์ ์๋ ๋ก์ปฌ ๋ธ๋ผ์ฐ์ ์์๋ง ์ฌ์ฉํ์ธ์. ๋ธ๋ผ์ฐ์ ์ธ์
์ ํ๋ก์ธ์ค ๋ก์ปฌ์ด๋ฏ๋ก, ์ด ๋๊ตฌ ๊ทธ๋ฃน์ด ํ์ฑํ๋์ด ์๋ ๋์์๋ Gateway๋ฅผ ๋จ์ผ ์์ปค ํ๋ก์ธ์ค๋ก ์ ์งํ์ธ์. ์ผ๋ฐ์ ์ธ uvicorn ์์ปค ๋ถ๋ฐฐ๋ ์ค๋ ๋ ์นํ์ฑ(thread affinity)์ ์ ๊ณตํ์ง ์๊ธฐ ๋๋ฌธ์
๋๋ค. ์ฆ `GATEWAY_WORKERS=1`์ด์ด์ผ ํ๋ฉฐ, uvicorn์ ์์ปค ์๋ฅผ ์ ํ ์ ๋ฌํ์ง ์๋ ์คํ ๋ฐฉ์(`backend/Dockerfile`, `scripts/serve.sh`)์์๋ uvicorn์ด ํ๋ก์ธ์ค ์๋ฅผ `WEB_CONCURRENCY`์์ ๊ฐ์ ธ์ค๋ฏ๋ก ์ด ๊ฐ๋ ์ค์ ํ์ง ์๊ฑฐ๋ `1`๋ก ๋์ด์ผ ํฉ๋๋ค.
๋ธ๋ผ์ฐ์ ์ ์ด๋ฅผ ์ฌ์ฉํ ์ ์๊ณ ์์ด์ ํธ๊ฐ `tool_groups`๋ฅผ ์ ํํ์ง ์๊ฑฐ๋ `browser` ๊ทธ๋ฃน์ ํฌํจํ๋ ๊ฒฝ์ฐ, ๋ชฉ(mock)์ด ์๋ ๊ธฐ์กด ์ปค์คํ
์์ด์ ํธ ์ฑํ
์๋ ๋์ผํ Browser Live ์ปจํธ๋กค์ด ํ์๋ฉ๋๋ค. `browser`๊ฐ ์๋ ๋ช
์์ ์ธ ๋๊ตฌ ๊ทธ๋ฃน ํ์ฉ ๋ชฉ๋ก์ ์ฌ์ฉํ๋ฉด ํด๋น ์ปจํธ๋กค์ ์จ๊ฒจ์ง ์ํ๋ก ์ ์ง๋ฉ๋๋ค.
์ํฌ์คํ์ด์ค Browser Live ํด๋ผ์ด์ธํธ๋ ๋ฐ์ด๋๋ฆฌ JPEG WebSocket ํ๋ ์์ ํ์ํ๊ณ , ๋์คํ๋ ์ด ๊ฐฑ์ ๋ง๋ค ๊ฐ์ฅ ์ต๊ทผ์ ๋๊ธฐ ํ๋ ์ ํ๋๋ง ์ ์งํ๋ฉฐ, ๊ต์ฒด๋ ๊ฐ์ฒด URL์ ํด์ ํฉ๋๋ค. Gateway ์ ์ด ๋ฉ์์ง๋ ๊ณ์ JSON์ด๋ฉฐ, ๋ฐ์ด๋๋ฆฌ ๊ธฐ๋ฅ(capability)์ ์์ฒญํ์ง ์๋ ํด๋ผ์ด์ธํธ๋ ๊ธฐ์กด JSON/base64 ํ๋ ์ ํ๋กํ ์ฝ์ ๊ทธ๋๋ก ์ฌ์ฉํฉ๋๋ค.
### ์ปจํ
์คํธ ์์ง๋์ด๋ง
**ํ ํ์ ๋๊ตฌ ์ถ๋ ฅ ๊ฐ์(synopsis)**: CSV/TSV ํ ์๋ ๋
ผ๋ฆฌ์ ๋ ์ฝ๋๋ฅผ ๊ธฐ์ค์ผ๋ก ํ๋ฏ๋ก, ๋ฐ์ดํ๋ก ๋ฌถ์ธ ํ๋ ์์ ์ค๋ฐ๊ฟ์ ํ์ ๋๋ฆฌ์ง ์์ต๋๋ค. ํ์ฑ์ ์คํจํ๊ฑฐ๋ ํ๋ ์ ํ์ ์ด๊ณผํ๋ฉด ๊ฐ์๋ ํ ์๋ฅผ ํ์ ํ ์ ์๋ค๊ณ ๋ณด๊ณ ํฉ๋๋ค. ์
๋ ฅ ํฌ๊ธฐ ์ ํ์ ๋๋ ์ถ๋ ฅ์ ์ฌ์ ํ ๊ตฌ์กฐํ๋ ํ์ฑ์ ๊ฑด๋๋๋๋ค.
**๊ฒฉ๋ฆฌ๋ ์๋ธ์์ด์ ํธ ์ปจํ
์คํธ**: ๊ฐ ์๋ธ์์ด์ ํธ๋ ์์ฒด์ ์ผ๋ก ๊ฒฉ๋ฆฌ๋ ์ปจํ
์คํธ์์ ์คํ๋ฉ๋๋ค. ์ฆ ์๋ธ์์ด์ ํธ๋ ๋ฉ์ธ ์์ด์ ํธ๋ ๋ค๋ฅธ ์๋ธ์์ด์ ํธ์ ์ปจํ
์คํธ๋ฅผ ๋ณผ ์ ์์ต๋๋ค. ์ด๋ ์๋ธ์์ด์ ํธ๊ฐ ๋ฉ์ธ ์์ด์ ํธ๋ ๋ค๋ฅธ ์๋ธ์์ด์ ํธ์ ์ปจํ
์คํธ์ ๋ฐฉํด๋ฐ์ง ์๊ณ ๋น๋ฉดํ ์์
์ ์ง์คํ ์ ์๋๋ก ํ๊ธฐ ์ํด ์ค์ํฉ๋๋ค.
**์์ฝ**: ์ธ์
๋ด์์ DeerFlow๋ ์๋ฃ๋ ํ์ ์์
์ ์์ฝํ๊ณ , ์ค๊ฐ ๊ฒฐ๊ณผ๋ฅผ ํ์ผ ์์คํ
์ผ๋ก ๋ด๋ณด๋ด๊ณ , ๋น์ฅ ๊ด๋ จ์ด ์์ด์ง ๋ด์ฉ์ ์์ถํ๋ ๋ฑ ์ปจํ
์คํธ๋ฅผ ์ ๊ทน์ ์ผ๋ก ๊ด๋ฆฌํฉ๋๋ค. ๋๋ถ์ ์ปจํ
์คํธ ์๋์ฐ๋ฅผ ์ด๊ณผํ์ง ์๊ณ ๋ ๊ธธ๊ณ ์ฌ๋ฌ ๋จ๊ณ๋ก ์ด๋ฃจ์ด์ง ์์
๋ด๋ด ์ ํํจ์ ์ ์งํ ์ ์์ต๋๋ค.
**๋๊ตฌ ์ถ๋ ฅ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์์ฐ**: ์ธ๋ถํ๋ ๊ฒฐ๊ณผ์ ๊ตฌ์กฐํ๋ ๊ฐ์์๋ ๋ฌธ์ ์ ์์ฐ์ด ์์ต๋๋ค. ๊ธด JSON ํค์ ๊ฒฝ๋ก๋ `...`๋ก ์ค์ฌ์ง๋ฉฐ, ์ง๋์น๊ฒ ํฐ ๊ฐ์ ๋ณธ๋ฌธ์๋ ์๋ฆผ ์๋ด๊ฐ ํฌํจ๋ฉ๋๋ค. ์๋ณธ ์๋ถ๋ถ/๋ท๋ถ๋ถ ์ํ, ์ ์ฒด ํ์ผ ์ฐธ์กฐ, `read_file` ์๋ด๋ ๋ณด์กด๋ฉ๋๋ค. ์ ํํ ํค๋ ์ ์ฒด ์ถ๋ ฅ์ด ํ์ํ๋ฉด ์ ์ฅ๋ ํ์ผ์ ์ฝ์ผ์ธ์.
**์๊ฒฉํ ๋๊ตฌ ํธ์ถ ๋ณต๊ตฌ**: ํ๋ก๋ฐ์ด๋๋ ๋ฏธ๋ค์จ์ด๊ฐ ๋๊ตฌ ํธ์ถ ๋ฃจํ๋ฅผ ์ค๋จํ๋ฉด, DeerFlow๋ ์ด์ ๊ฐ์ ์ค์ง๋ ์ด์์คํดํธ ๋ฉ์์ง์์ ํ๋ก๋ฐ์ด๋ ์์ค์ ์์ ๋๊ตฌ ํธ์ถ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ ๊ฑฐํ๊ณ , ๋ค์ ๋ชจ๋ธ ํธ์ถ ์ ์ ๋ฏธ์๋ฃ ํธ์ถ์ ๋ํ ์๋ฆฌ ํ์์ ๋๊ตฌ ๊ฒฐ๊ณผ๋ฅผ ์ฃผ์
ํฉ๋๋ค. ์ด๋ฅผ ํตํด `tool_call_id` ์์๋ฅผ ์๊ฒฉํ๊ฒ ๊ฒ์ฆํ๋ OpenAI ํธํ ์ถ๋ก ๋ชจ๋ธ์ด ์๋ชป๋ ํ์์ ๊ธฐ๋ก ์ค๋ฅ๋ก ์คํจํ์ง ์์ต๋๋ค.
**๋ณด์ด๋ ๋๊ตฌ ์คํ ์๋ฃ**: ๋ํํ ํด์์ DeerFlow๋ ๋๊ตฌ ์คํ ํ ์ต์ข
์๋ต์ด ๋น์ด ์์ผ๋ฉด ํ ๋ฒ ์ฌ์๋ํ๊ณ , ๊ทธ๋๋ ๋น์ด ์์ผ๋ฉด ์คํ(run)์ด ์กฐ์ฉํ ์ฑ๊ณตํ ๊ฒ์ผ๋ก ๋ณด๊ณ ํ๋ ๋์ ๋ณด์ด๋ ์ค๋ฅ๋ฅผ ํ์ํฉ๋๋ค.
**์คํ ๊ธฐ๋ก**: ์ด๋ฏธ์ง๋ง ์๋ ์ฌ์ฉ์ ์
๋ ฅ์ ์์ด์ ํธ๊ฐ ์ฌ๋ฌ ๋ฒ ๋ชจ๋ธ์ ํธ์ถํ๋๋ผ๋ ์คํ๋น ํ ๋ฒ๋ง ๊ธฐ๋ก๋ฉ๋๋ค. ํด๋น ๋ฏธ๋์ด ์ฝํ
์ธ ๋ ํ
์คํธ ์์ฝ ์์ด๋ ๊ธฐ๋ก์ ๋จ์ต๋๋ค.
### ์ฐธ์กฐํ ๋ํ ์ฝ๊ธฐ
Gateway API ํธ์ถ์๋ `read_conversation`์ ๋ช
์์ ์ผ๋ก ์ผ๊ณ ์คํ(run)๊ณผ ํจ๊ป `conversation_references` ๋ชฉ๋ก์ ์ ์ถํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ฉด ๋ฆฌ๋ ์์ด์ ํธ๋ ์์ ์ด ์์ ํ ํด๋น ๋ํ๋ค์ ํ์ฌ ๋ณด์ด๋ ํ
์คํธ๋ฅผ ์ ํ๋ ํฌ๊ธฐ์ ํ์ด์ง ๋จ์๋ก ์ฝ์ ์ ์์ต๋๋ค. ์ฝ๊ธฐ ๊ถํ์ ์คํ๊ณผ ํจ๊ป ๋ง๋ฃ๋๋ฉฐ, ์ด์ ๋ฉ์์ง์ ์๋ ํ
์คํธ๋ ์ ๊ทผ ๊ถํ์ ๋ถ์ฌํ์ง ์์ต๋๋ค. ์์ด์ ํธ๊ฐ ์ด๋ฏธ ์ฝ์ ํ
์คํธ๋ ์ ๊ทผ ๊ถํ์ด ๋ง๋ฃ๋๊ฑฐ๋ ์๋ณธ์ด ์ญ์ ๋ ๋ค์๋ ๋์ ๋ํ์ ๋จ์ต๋๋ค. ํ ๋ฒ์ ์ฝ๊ธฐ์ ๋๋ฌด ๊ธด ๋ฉ์์ง์๋ ์ด์ด ์ฝ๊ธฐ ์ ๋ณด๊ฐ ํฌํจ๋๋ฏ๋ก ์์ด์ ํธ๋ ๋๋จธ์ง๋ฅผ ์ฝ์ ์ ์์ผ๋ฉฐ, ๊ทธ ์ฝ๊ธฐ๋ฅผ ์ฌ์ฉํ ์ ์์ ๋๋ง ๋๋ฝ๋ ๋ถ๋ถ์ ์์ฒญํฉ๋๋ค.
์ต์์ ์์ฒญ ํ๋๋ฅผ ์ถ๊ฐํ ์ ์๋ SDK ํด๋ผ์ด์ธํธ๋ ๊ฐ์ ๋ชฉ๋ก์ `context.conversation_references`๋ก ๋ณด๋ผ ์ ์์ผ๋ฉฐ, `GET /api/features`๋ ์ด ๋๊ตฌ๊ฐ ํ์ฑํ๋์ด ์๋์ง ์๋ ค ์ค๋๋ค. ํ์ฑํ๋์ด ์์ผ๋ฉด ์น ์
๋ ฅ์ฐฝ(composer)์ ์ฒจ๋ถ ๋ฒํผ ์์ "Reference a conversation" ๋ฒํผ์ด ํ์๋ฉ๋๋ค. ์ต๊ทผ ๋ํ ์ค ์ต๋ ์ธ ๊ฐ๋ฅผ ์ ํํ๋ฉด ๋ค์ ๋ฉ์์ง์๋ง ์ฒจ๋ถ๋๋ฉฐ, ์
๋ ฅ์ฐฝ๊ณผ ๋ํ ๊ธฐ๋ก์ ์นฉ์ผ๋ก ํ์๋ฉ๋๋ค. ์๋ ๊ธฐ๋ก ๊ฒ์์ ์์ต๋๋ค. [์ค์ ](backend/docs/CONFIGURATION.md#reading-referenced-conversations)๊ณผ [์์ฒญ ๊ณ์ฝ](backend/docs/API.md#referencing-a-previous-conversation)์ ์ฐธ๊ณ ํ์ธ์.
### ํ์ฌ ์์
๋
ธํธ
`task_continuity.enabled: true`๋ก [์์
๋
ธํธ์ ๊ธฐ๋ก ํ์](docs/task-continuity.md)์ ํ์ฑํํ์ธ์.
ํ๋์ ์์
์ ์ต๋ 8๊ฐ์ ๋
ธํธ๋ฅผ ๋ณด๊ดํ ์ ์์ต๋๋ค. ๋จ์ ์ฌ๋กฏ์ ์ด๊ณผํ๋ ๋ณ๋ ฌ ์ถ๊ฐ ์์ฒญ์ `note_capacity`๋ฅผ ๋ฐํํ๋ฉฐ ๊ธฐ์กด ๋
ธํธ๋ ๋ณด์กด๋ฉ๋๋ค. ์ํฐํฉํธ ํธ๋ค ํด์์ด ํ์ฑํ๋์ด ์์ผ๋ฉด ์ฉ๋์ ํด์๋ ํค ๊ธฐ์ค์ผ๋ก ๊ณ์ฐ๋๋ฉฐ, ๊ฐ์ ๋
ธํธ์ ๋ํ ๋ณ์นญ์ ํ๋์ ์ฌ๋กฏ์ ๊ณต์ ํฉ๋๋ค.
์๋ชป๋ ํ์์ dict๊ฐ ์๋ ํ์ ์ธ์๋ ์ฌ๋กฏ์ ์๋นํ์ง ์์ผ๋ฉฐ ์ ํจํ ๋
ธํธ ํธ์ถ์ ๋ฐฉํดํ์ง ์์ต๋๋ค.
ํค๊ฐ ์ ํจํ์ง ์๊ฑฐ๋, ๋ด์ฉ์ด 750์๋ฅผ ๋๊ฑฐ๋, ์์ค๊ฐ 4๊ฐ๋ฅผ ๋๊ฑฐ๋, ์์ค ID ํ์์ด ์๋ชป๋ ๋
ธํธ๋ ์ฌ๋กฏ์ ์์ฝํ์ง ์์ต๋๋ค. ๊ธฐ์กด ํค๋ ์ฌ์ ํ ๊ต์ฒดํ๊ฑฐ๋ ์ญ์ ํ ์ ์์ต๋๋ค. ํ์ ํธ์ถ์ ์ญ์ ๋ ๋ฐํ์ ์คํจ(์ฌ์ฉํ ์ ์๋ ์์ค, ์ ์ฑ
๊ฑฐ๋ถ ๋ฑ)๋ก ๋น์์ง ์ฌ๋กฏ์ ๋ค์ ๋ฐฐ์น์์ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ฉฐ, ์ด๋ ๊ฑฐ๋ถ๋ ์ถ๊ฐ ์์ฒญ์ ์ฌ์๋ํ ์ ์์ต๋๋ค.
### ์ฅ๊ธฐ ๋ฉ๋ชจ๋ฆฌ
DeerMem์ ๋๊ธฐ ์ค์ธ ์
๋ฐ์ดํธ๋ฅผ ๋ํ, ์ฌ์ฉ์, ์์ด์ ํธ๋ณ๋ก ๋
๋ฆฝ์ ์ผ๋ก ๋๋ฐ์ด์คํฉ๋๋ค.
`memory.backend_config.debounce_seconds`๋ ๋๊ธฐ ์๊ฐ์ ์ค์ ํ๋ฉฐ(๊ธฐ๋ณธ๊ฐ 30์ด), `max_wait_seconds`๋ ์ฒซ ๋ฒ์งธ ๋๊ธฐ ์
๋ฐ์ดํธ๋ก๋ถํฐ ๋๋ฐ์ด์ค ์ง์ฐ์ ์ํ์ ์ ํฉ๋๋ค(๊ธฐ๋ณธ๊ฐ 300์ด). ๋ค๋ฅธ ๋ํ์ ํ๋์ ์ด ๋๊ธฐ ์๊ฐ์ ์ฐ์ฅํ ์ ์์ต๋๋ค.
์ถ์ถ์ ์ฌ์ ํ ์์ฐจ์ ์ผ๋ก ์งํ๋๋ฏ๋ก, ์ ์ฒด์ LLM ์ง์ฐ ์๊ฐ ๋๋ฌธ์ ์๋ฃ๊ฐ ๋ฆ์ด์ง ์ ์์ต๋๋ค.
์ตํธ์ธ ๋ฐฉ์์ [DeerMem ๋ฒ์ ๊ฒฉ๋ฆฌ ๋ฒค์น๋งํฌ](backend/scripts/benchmark/deermem_scope_isolation/README.md)๋ ํฉํธ์ ์์ฝ ์ ๋ฐ์ ์๋ฏธ์ ์์ ์ฑ, ๊ทธ๋ฆฌ๊ณ ์ฌ์ฉ์์ ์์ด์ ํธ ๊ฐ ํฉํธ ๋ผ์ฐํ
์ ๊ฒ์ฌํฉ๋๋ค. ์คํจํ ์ถ์ถ ์๋๋ ์์ ์ฑ ํต๊ณผ๊ฐ ์๋๋ผ ์ฌ์๋ ๊ฐ๋ฅํ ์คํ ์ค๋ฅ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค.
DeerMem์์ `memory.backend_config.storage_class: markdown`์ ์ง์ ํ๋ฉด JSON ์ฐ๊ธฐ์ ๊ธฐ์กด UI๋ ์ ์งํ๋ฉด์ ๊ด๋ํ ์์ฝ ์ฝ๊ธฐ๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ง์ ํธ์งํ `memory.json`์ JSON ๊ฐ์ฒด๋ฅผ ํ์ค๋ก ๊ฐ์ผ `memory-json` ๋ธ๋ก ์์ ๋ด์ ์ ์์ผ๋ฉฐ, ๋ด๋ถ์ ํฌํจ๋ ๋ฐฑํฑ๊ณผ ์ดํ์ ํ์ค ๋
ธํธ๋ ์ง์๋ฉ๋๋ค. ํ์ฑํ ์ ์๋ ์์ฝ ํ
์คํธ๋ ์ฌ๊ตฌ์ฑ ์ ์ ๋ณต๊ตฌ๋ฅผ ์ํด `memory.json.corrupt-`๋ก ์ฎ๊ฒจ์ง๋๋ค.
`storage_path`๋ ๊ธฐ์กด JSON ํ์ผ์ด ์๋๋ผ ๋ฐ์ดํฐ ๋ฃจํธ ๋๋ ํฐ๋ฆฌ๋ฅผ ๊ฐ๋ฆฌ์ผ์ผ ํฉ๋๋ค.
Gateway๋ ์ข
๋ฃ๊ฐ ์ทจ์๋๋๋ผ๋ ๋ฐฑ์๋๋ฅผ ๋ซ๊ธฐ ์ ์ ๋ฉ๋ชจ๋ฆฌ ์
๋ฐ์ดํธ๋ฅผ ๋ชจ๋ ์ฒ๋ฆฌ(drain)ํฉ๋๋ค. ์ค์ ๋ฆฌ๋ก๋ ์คํจ๋ ๋ก๊ทธ์ ๊ธฐ๋ก๋๋ฉฐ ๋ฐํ์ ์ ๋ฆฌ๋ฅผ ์ค๋จ์ํค์ง ์์ต๋๋ค. Kubernetes์์๋ `terminationGracePeriodSeconds`๋ฅผ ๋ชจ๋ ์ข
๋ฃ ํ
, ์ค์ /๋ฐฑ์๋ ํด์, `memory.shutdown_flush_timeout_seconds`, ๋ฐฑ์๋ ๋ซ๊ธฐ์ ์์ ์ฌ์ ๋ฅผ ๋ํ ๋งํผ ํ๋ณดํ์ธ์. ํ๋ฌ์ ํ์์์์ `close()`๋ฅผ ์ ํํ์ง ์์ต๋๋ค. ์ปค์คํ
๋ฐฑ์๋๋ close๋ฅผ ๋น ๋ฅด๊ฒ ๋๋ด๊ฑฐ๋ ๋ด๋ถ์ ์ผ๋ก ์ ํํด์ผ ํ๋ฉฐ, ๊ทธ๋ ์ง ์์ผ๋ฉด ํ๋ก์ธ์ค๊ฐ ๊ฐ์ ์ข
๋ฃ๋ ๋๊น์ง ์ข
๋ฃ๊ฐ ๋๊ธฐํ ์ ์์ต๋๋ค.
๋๋ถ๋ถ์ ์์ด์ ํธ๋ ๋ํ๊ฐ ๋๋๋ ์๊ฐ ๋ชจ๋ ๊ฒ์ ์์ด๋ฒ๋ฆฝ๋๋ค. DeerFlow๋ ๊ธฐ์ตํฉ๋๋ค.
DeerMem์ `memory.backend_config.fact_dedup_enabled: true`์ `fact_dedup_similarity_threshold`(๊ธฐ๋ณธ๊ฐ `0.7`, ๋ฒ์ `0.5`โ`1.0`)๋ก ๊ทผ์ฌ ์ค๋ณต ์ถ์ถ ํฉํธ๋ฅผ ์ ํ์ ์ผ๋ก ์ต์ ํ ์ ์์ต๋๋ค.
์ด ๋ก์ปฌ์ ๊ฒฐ์ ์ ๋จ์ด/CJK ๋ฐ์ด๊ทธ๋จ ํด๋ฆฌ์คํฑ์ ๊ฐ์ ์ฌ์ฉ์, ์์ด์ ํธ, ์นดํ
๊ณ ๋ฆฌ ์์์๋ง ํฉํธ๋ฅผ ๋น๊ตํ๋ฉฐ, ์๋ฏธ์ ๋๋ฑ์ฑ ํ์ง๊ฐ ์๋๋๋ค.
๋ณํฉ ์์๋ ๊ธฐ์กด ID, ํ
์คํธ, ์์ฑ ์๊ฐ์ ์ ์งํ๊ณ , ์ ๋ขฐ๋๋ฅผ ์ต๋๊ฐ์ผ๋ก ์ฌ๋ฆฌ๋ฉฐ, ์ ๋ขฐ๋๊ฐ ๋์์ง ๋๋ง ์์ค๋ฅผ ๊ฐฑ์ ํฉ๋๋ค. ๋ช
์์ ์ธ ์์ ๊ต์ฒด์ ์ญ์ ๊ฐ ์ ์๋ ํฉํธ๋ ๊ทผ์ฌ ์ค๋ณต ๋ณํฉ์ผ๋ก๋ถํฐ ๋ณดํธ๋ฉ๋๋ค. ๋ณํฉ์ ์ฌ์ฉ์ ํ์ธ์ผ๋ก ๊ฐ์ฃผ๋์ง ์์ต๋๋ค. ์ด ๊ฒ์ดํธ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๊บผ์ ธ ์์ผ๋ฉฐ, ๋์ ํฉํธ ์
๋ฐ์ดํธ์๋ ์ํฅ์ ์ฃผ์ง ์์ต๋๋ค.
DeerFlow์๋ ์ ํ ์ฌํญ์ธ `openviking` ๋ฉ๋ชจ๋ฆฌ ๋ฐฑ์๋๋ ํฌํจ๋์ด ์์ต๋๋ค. ์ด ๋ฐฑ์๋๋ ๊ณต์ `langchain-openviking` ํจํค์ง๋ฅผ ์ฌ์ฉํด ์๋ฃ๋ ํด์ ์์ ์ ์ธ OpenViking Session์ ๊ธฐ๋กํ๊ณ , ํ๋กฌํํธ ์ฃผ์
์ ์ํด ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ์ํ๋ฉฐ, DeerMem์ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ๊ทธ๋๋ก ๋ก๋๋ค. ์ด๊ธฐ ํตํฉ์ `memory.mode: middleware`์์ ์๊ฒฉ ์ฆ๋ช
์ ๋ฌถ์ธ OpenViking USER API ํค ํ๋๋ฅผ ๊ฐ์ง DeerFlow ์ฌ์ฉ์ ํ ๋ช
์ ์ง์ํ๋ฉฐ, `ovcli.conf`์ ์์ HTTP ํค๋๋ฅผ ์์ํ์ง ์์ต๋๋ค.
์ค์ , ๋์, ํ์ฌ์ ํ๊ณ๋ [OpenViking ๋ฉ๋ชจ๋ฆฌ ๋ฐฑ์๋](docs/OPENVIKING.md)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
DeerFlow๋ ์ธ์
์ ๋๋๋ค๋ฉฐ ์ฌ์ฉ์์ ํ๋กํ, ์ ํธ, ์ถ์ ๋ ์ง์์ ๋ํ ์์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ตฌ์ถํฉ๋๋ค. ๋ง์ด ์ฌ์ฉํ ์๋ก ์์ฑ ์คํ์ผ, ๊ธฐ์ ์คํ, ๋ฐ๋ณต์ ์ธ ์ํฌํ๋ก ๋ฑ ์ฌ์ฉ์๋ฅผ ๋ ์ ์๊ฒ ๋ฉ๋๋ค. ๋ฉ๋ชจ๋ฆฌ๋ ๋ก์ปฌ์ ์ ์ฅ๋๋ฉฐ ์ฌ์ฉ์์ ํต์ ์๋์ ์์ต๋๋ค.
DeerMem๊ณผ mem0๋ ์ฌ์ฉ์ ์
๋ ฅ๊ณผ ์ด์์คํดํธ์ ์ต์ข
์๋ต์ ๊ธฐ๋กํฉ๋๋ค. ๋๊ตฌ๋ฅผ ์์ฒญํ๋ ์ด์์คํดํธ ํด์ ์๋ชป๋ ํ์์ด๊ฑฐ๋ ํ๋ก๋ฐ์ด๋ ์์ ํธ์ถ์ธ ๊ฒฝ์ฐ๋ฅผ ํฌํจํ์ฌ, ๋ณด์ด๋ ํ
์คํธ๊ฐ ์๋๋ผ๋ ๋ฉ๋ชจ๋ฆฌ ์ถ์ถ์์ ์ ์ธ๋ฉ๋๋ค.
DeerMem์ ๊ณ์ ๊ธฐ๋ณธ ๋ก์ปฌ ๋ฐฑ์๋์
๋๋ค. ํธ์คํ
๋๋ mem0 Platform API ๋๋ API ํธํ ์์ฒด ํธ์คํ
์๋ฒ๋ฅผ ์ํ ์ตํธ์ธ `mem0` ๋ฐฑ์๋๋ ์ฌ์ฉํ ์ ์์ต๋๋ค. ํ ํฐ์ ์ ๋ฌํ๋ `base_url`์ ๊ธฐ๋ณธ์ ์ผ๋ก HTTPS๋ฅผ ์ฌ์ฉํด์ผ ํ๋ฉฐ, ํ๋ฌธ HTTP๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๋ก์ปฌ ๊ฐ๋ฐ์ฉ ์ตํธ์ธ์ ๋ช
์์ ์ผ๋ก ์ค์ ํด์ผ ํฉ๋๋ค. [mem0 ๋ฐฑ์๋ ๊ฐ์ด๋](backend/packages/harness/deerflow/agents/memory/backends/mem0/README.md)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
์์ฒด ํธ์คํ
๋๋ ํธ์คํ
Honcho(v3 API)๋ฅผ ์ํ ์ตํธ์ธ `honcho` ๋ฐฑ์๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด ๋ฐฑ์๋๋ ์ฅ๊ธฐ ์ ํธ์ ์ธ์
๊ฐ ์์
ํํ์ผ๋ก ๊ตฌ์ฑ๋ ์ฌ์ฉ์ ๋ชจ๋ธ ๋ฉ๋ชจ๋ฆฌ๋ฅผ Honcho ์๋ฒ ์ธก์์ ๊ตฌ์ถํ๋ฏ๋ก, ๋ฐฑ์๋๊ฐ ๋ก์ปฌ์์ LLM์ ํธ์ถํ์ง ์์ต๋๋ค. ๊ฐ ์ฌ์ฉ์๋ `user_id`์์ ํ์๋ ๊ฒฉ๋ฆฌ๋ ์ํฌ์คํ์ด์ค๋ฅผ ๋ฐ์ผ๋ฉฐ, ์ฌ์ฉ์ ID๊ฐ ์์ผ๋ฉด ๊ณต์ ์ํฌ์คํ์ด์ค๋ก ํด๋ฐฑํ๋ ๋์ ์คํจ ์ ์ฐจ๋จ(fail closed)๋ฉ๋๋ค.
์ด ๋ฐฑ์๋์์๋ ํฉํธ CRUD์ Settings ํ์ด์ง์ ํฉํธ ํธ์ง์ ์ฌ์ฉํ ์ ์์ต๋๋ค. [Honcho ๋ฐฑ์๋ ๊ฐ์ด๋](backend/packages/harness/deerflow/agents/memory/backends/honcho/README.md)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
์ด์ ๋ฉ๋ชจ๋ฆฌ ์
๋ฐ์ดํธ๋ ์ ์ฉ ์์ ์ ์ค๋ณต ํฉํธ ํญ๋ชฉ์ ๊ฑด๋๋ฐ๋ฏ๋ก, ๋ฐ๋ณต๋๋ ์ ํธ์ ์ปจํ
์คํธ๊ฐ ์ธ์
์ ๊ฑฐ์น๋ฉฐ ๋์์ด ์์ด์ง ์์ต๋๋ค.
๋ ๊ฑฐ์ ๋ฉ๋ชจ๋ฆฌ ํ์ผ์ ์ฝ๊ฑฐ๋ ๊ฐ์ ธ์ฌ ๋ ๋ณต๊ตฌ ๊ฐ๋ฅํ ํฉํธ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ํฌํจํ์ฌ ์ ๊ทํ๋๋ฏ๋ก, ์คํค๋ง๊ฐ ๋ฐ์ ํ๋๋ผ๋ ์ด์ ๋ก์ปฌ ๋ฐ์ดํฐ๋ฅผ ๊ณ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ํ๋ก ํธ์๋์ ๋ฐฑ์๋ ์ ๊ทํ๋ ์ ๋ขฐ๋๊ฐ ์๊ฑฐ๋ ์ ํจํ์ง ์์ผ๋ฉด `0.5`๋ฅผ ์ฌ์ฉํ๊ณ , ๋น์ด ์๋ ์์ค๋ ๊ธฐ๋ณธ์ ์ผ๋ก `unknown`์ผ๋ก ์ง์ ํ๋ฉฐ, ํฉํธ ๋ด์ฉ์ ์๋ค ๊ณต๋ฐฑ์ ์ ๊ฑฐํฉ๋๋ค.
๊ธฐ๋ณธ DeerMem `middleware` ๋ชจ๋์์ ์๋ ์ถ์ถ์ ์ด์ ์ ์๋ ๋ชจ๋ ํฉํธ๋ฅผ ๋ฒ์, ์ง์์ฑ, ๊ถํ(authority) ๊ธฐ์ค์ผ๋ก ๋ถ๋ฅํ ๋ค์์์ผ ๊ฒฐ์ ์ ์ฐ๊ธฐ ๊ฒ์ดํธ๊ฐ ์ด๋ฅผ ์๋ฝํ ์ ์์ต๋๋ค. ์์์ ์ด๊ณ ์์ ์ ์ธ ์ฌ์ฉ์ ์์ค ํฉํธ๋ง ์ ์ฅ๋๋ฉฐ, ํ์ฌ ์ค๋ ๋๋ ํ๋ก์ ํธ์ ์ ์ฝ๊ณผ ์ผํ์ฑ ๋์ ํ๊ฐ๋ ๋ํ ์ํ์ ๋จ์ต๋๋ค. ์ฌ์ฉ์ ์ ์ญ ์์ฝ์๋ ์ฌ์ฉ์ ๋ฒ์์ ์์ ์ ๊ถํ์ด ๋ชจ๋ ํ์ํ๊ณ , ๋ชจ์์ ๋ฐ๋ฅธ ์ญ์ ๋ ๋ฒ์ ๊ฒ์ดํธ๋ฅผ ๊ฑฐ์น๋ฉฐ, ๊ต์ฒด์ ์์กดํ๋ ์ญ์ ๋ ๊ทธ ๊ต์ฒด ํฉํธ๊ฐ ์ค์ ๋ก ๊ฒ์ฆ๊ณผ ์ ์ฅ์ ํต๊ณผํ์ ๋๋ง ์ ์ฉ๋ฉ๋๋ค. ์ด๋ฌํ ๋ถ๋ฅ ๋ ์ด๋ธ์ ์ถ์ถ ์ ์ฉ ๋ฉํ๋ฐ์ดํฐ๋ก, ์ถ๊ฐ LLM ํธ์ถ์ ์ผ์ผํค์ง ์์ผ๋ฉฐ ํฉํธ ํ์ผ์ ๊ธฐ๋ก๋์ง ์์ต๋๋ค. `memory.mode: tool`์ ๋ช
์์ CRUD ๋๊ตฌ๋ ์ฌ์ ํ ๋ชจ๋ธ์ด ์ฃผ๋ํ๋ ๋ณ๋ ๊ฒฝ๋ก์
๋๋ค. `memory.backend_config.prompts_dir`๋ก ๋ฒ๋ค๋ DeerMem ํ๋กฌํํธ๋ฅผ ์ฌ์ ์ํ๋ ๋ฐฐํฌ๋ ์ปค์คํ
ํ
ํ๋ฆฟ(`memory_update`์ ํฉํธ/์์ฝ/์ญ์ ํ์๊ณผ `consolidation`์ ํตํฉ ํฉํธ ์คํค๋ง)์ ์ ๋ถ๋ฅ ํ๋๋ฅผ ์ถ๊ฐํด์ผ ํฉ๋๋ค. ์ฐ๊ธฐ ๊ฒ์ดํธ๋ ์คํจ ์ ์ฐจ๋จ(fail closed)๋๋ฏ๋ก, ๋ง์ด๊ทธ๋ ์ด์
ํ์ง ์์ ํ
ํ๋ฆฟ์ ์ถ์ถ ๊ธฐ๋ฐ์ ๋ชจ๋ ํฉํธ, ์์ฝ, ์ญ์ ์ฐ๊ธฐ๋ฅผ ์ค๋จ์ํค๋ฉฐ, ์ด๋ `rejected_by_scope_gate` ์งํ์ ๋์ ๊ฑฐ๋ถ์จ ๊ฒฝ๊ณ ๋ฅผ ํตํด์๋ง ๋๋ฌ๋ฉ๋๋ค.
ํฉํธ ๋ฒ์๊ฐ `max_facts`์ ๋๋ฌํ๋ฉด DeerMem์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฌ์ ํ ๊ธฐ์กด์ ์ ๋ขฐ๋ ๊ธฐ๋ฐ ์ถ์ถ ์์๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ด์์๋ `memory.backend_config.fact_eviction_policy: hybrid-v1`์ ๋ช
์์ ์ผ๋ก ์ผค ์ ์์ผ๋ฉฐ, ์ด ์ ์ฑ
์ ์ ํ๋ ์ ๋ขฐ๋(65%), ๋ช
์์ ํ์ธ์ ์ต์ ์ฑ(25%), ์ฟผ๋ฆฌ ๊ธฐ๋ฐ ์ ๊ทผ ๋น๋(10%)๋ฅผ ๊ฒฐํฉํฉ๋๋ค. ํ์ด๋ธ๋ฆฌ๋ ์ ํธ ๋ฉํ๋ฐ์ดํฐ๋ hybrid-v1 ๋๋ ์๋ ๋ชจ๋๊ฐ ํ์ฑํ๋์ด ์๋ ๋์์๋ง ์์ง๋ฉ๋๋ค. ๋ช
์์ ํ์ธ์ ๊ธฐ์กด ๋ฉ๋ชจ๋ฆฌ ์
๋ฐ์ดํธ LLM ํธ์ถ์ด `factsToReinforce`๋ก ๋ฐํํ๋ฉฐ, ๊ฒฐ์ ์ ๋ฉ์์ง ์ฒ๋ฆฌ์์๋ ์ฌ์ฉ์์ ๊ฐํ ์ ํธ๊ฐ ๊ฐ์ง๋ ๊ฒฝ์ฐ์๋ง ์๋ฝ๋ฉ๋๋ค. ๋ํ ํด๋น ํฉํธ์ ๋
ธํ ๊ฒํ ์๊ณ๋ฅผ ์ด๊ธฐํํฉ๋๋ค. ์ด ๊ฒฐ์ ์ ๊ฒ์ดํธ๋ ๋ฐฐ์น ์์ค์ผ๋ก ๋์ํฉ๋๋ค. ์ฆ ํ์ฌ ์ถ์ถ ๋ฐฐ์น์์ ํํฐ๋ง๋ ๋ง์ง๋ง 6๊ฐ ๋ฉ์์ง ์ค ์ฌ๋์ ๋ฉ์์ง ํ๋๊ฐ ๊ฐํ ํจํด๊ณผ ์ผ์นํ๋ค๋ ์ฌ์ค๋ง ํ์ธํฉ๋๋ค. ํฉํธ์์ ์ฐ๊ฒฐ์ LLM์ด ์ ํํ `factsToReinforce` ID๊ฐ ์ ๊ณตํ๋ฉฐ, DeerMem์ ์ ํธ์ ํฉํธ ๊ฐ์ ๋์ ๊ด๊ณ๋ฅผ ๋
๋ฆฝ์ ์ผ๋ก ๊ฒ์ฆํ์ง ์์ต๋๋ค. ๋ฐ๋ณต ์ถ์ถ์ด๋ ์๋ ์ฃผ์
์ ๊ฒฐ์ฝ ํฉํธ๋ฅผ ํ์ธํ์ง ์์ต๋๋ค. ์ปค์คํ
`memory_update` ํ๋กฌํํธ๊ฐ ํ์ธ ์ต์ ์ฑ์ ์ฐธ์ฌํ๋ ค๋ฉด ์ ํ ์ฌํญ์ธ `factsToReinforce` ๋ฐฐ์ด์ ์ถ๊ฐํด์ผ ํฉ๋๋ค. ์ ๊ทผ ๋น๋๋ ๋ณ๋์ ๊ฐ์ ํ ์ฌ์ด๋์นด์ ์ ์ฅ๋๋ฉฐ, `memory_search`๊ฐ ์ค์ ๋ก ํด๋น ํฉํธ๋ฅผ ๋ฐํํ ๋๋ง ์ฆ๊ฐํ๋ฏ๋ก ์ฝ๊ธฐ๊ฐ ์ ์(canonical) Markdown์ด๋ ๊ทธ `updatedAt`์ ๋ค์ ์ฐ์ง ์์ต๋๋ค. ํ์ด๋ธ๋ฆฌ๋ ๋ชจ๋๋ ๋ํ ์ ํ๋ ์ต์ ์์ ์์ ์ฉ ์ฌ๋กฏ(์ํ์ 10%, ์ต๋ 10๊ฐ. ์ฌ์ฉํ์ง ์์ ์ฌ๋กฏ์ ์ผ๋ฐ ๊ฒฝ์์ผ๋ก ๋์๊ฐ๋๋ค)์ ์์ฝํฉ๋๋ค. ์ฉ๋์ ๋ฐ๋ฅธ ์ญ์ ๋ ์ฌ์ ํ ๋ฌผ๋ฆฌ์ ์ญ์ ์ด์ง๋ง, ์ ํ๋ ๋ฉํ๋ฐ์ดํฐ ์ ์ฉ ๊ฐ์ฌ ๊ธฐ๋ก์ด ํฉํธ ๋ด์ฉ์ ๋ณต์ฌํ์ง ์๊ณ ํฉํธ ID, ์นดํ
๊ณ ๋ฆฌ, ์ ์ฑ
์ ์, ์ฌ์ ๋ฅผ ๊ธฐ๋กํฉ๋๋ค. `fact_eviction_shadow_enabled: true`๋ ์ค์ ๋ณด์กด ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๊พธ์ง ์๊ณ ๊ธฐ๋ณธ ์ ์ฑ
๊ณผ ํจ๊ป hybrid-v1์ ํ๊ฐํฉ๋๋ค. ์ด ๊ธฐ๋ฅ์ LLM ํธ์ถ์ ์ถ๊ฐํ์ง ์์ผ๋ฉฐ, `confidence`๋ฅผ ์ ํํ์ฌ ๋กค๋ฐฑํ ์ ์์ต๋๋ค.
์ด์ ํ์ผ ๊ธฐ๋ฐ ๋ฉ๋ชจ๋ฆฌ๋ ์ ์ญ ์ฌ์ฉ์ ์ปจํ
์คํธ์ ์์ด์ ํธ ํฉํธ๋ฅผ ๋ถ๋ฆฌํฉ๋๋ค. ๊ฐ ์ฌ์ฉ์๋ `memory.json` ํ๋๋ฅผ ๊ฐ์ง๋ฉฐ ์ฌ๊ธฐ์๋ ํ๋ก์ ํธ์ ๋ฌด๊ดํ `user` ๋ฐ `history` ์์ฝ๋ง ๋ด๊น๋๋ค. ๋ชจ๋ ํฉํธ๋ `agents/{agent_name}/facts/` ์๋์ ์ ์ Markdown ํ์ผ์
๋๋ค. `agent_name`์ ์๋ตํ๋ ๊ธฐ์กด ๋ฆฌ๋ ์์ด์ ํธ ๋ฏธ๋ค์จ์ด, API, Settings, ๊ฐ์ ธ์ค๊ธฐ/๋ด๋ณด๋ด๊ธฐ, ์๋ฒ ๋๋ ํด๋ผ์ด์ธํธ ํธ์ถ์ DeerMem ๋ด๋ถ์์ ์์ฝ๋ `__default__` ๋ฒํท์ผ๋ก ํด์๋ฉ๋๋ค. ์ด ๋ฒํท์ ์ ํจํ ์ปค์คํ
์์ด์ ํธ ์ด๋ฆ ๋ฌธ๋ฒ ๋ฐ์ ์์ผ๋ฏ๋ก, `lead-agent`๋ผ๋ ์ด๋ฆ์ ์ค์ ์ปค์คํ
์์ด์ ํธ๋ ๋ณ๋์ ํฉํธ ์ ์ฅ์๋ฅผ ๊ฐ์ง๋ฉฐ, ์ปค์คํ
์์ด์ ํธ๋ฅผ ์ญ์ ํด๋ `config.yaml`์ด ์๋ ๋ฉ๋ชจ๋ฆฌ ์ ์ฉ ๋๋ ํฐ๋ฆฌ๋ ์ญ์ ๋์ง ์์ต๋๋ค. ๊ณต๊ฐ ์์ด์ ํธ ์๋ณ์๋ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ์ง ์์ผ๋ฉฐ ์๋ฌธ์๋ก ์ ๊ทํ๋ฉ๋๋ค. ๋ฐํ์/API ์ฝ๊ธฐ ์ธก์ ์ฌ์ ํ ์ ํ๋/๊ธฐ๋ณธ ์์ด์ ํธ์ ๋ํ ํธํ์ฉ `facts` ๋ฐฐ์ด์ ๋ฐ์ผ๋ฏ๋ก ํ๋ก ํธ์๋๋ `memory.json`์์ ์์ด์ ํธ ํฉํธ๋ฅผ ์ฝ์ง ์์ต๋๋ค. ๊ตฌ์กฐํ๋ Markdown `source` ๋ฉํ๋ฐ์ดํฐ๋ MemoryManager ๊ฒฝ๊ณ์์ ๊ธฐ์กด ๋ฌธ์์ด ํ๋๋ก ํฌ์๋ฉ๋๋ค. ๋ฒ์๋ฅผ ์ง์ ํ์ง ์์ Clear All์ ๋จผ์ ์ฝ์ง ์์ ๋ ๊ฑฐ์ ์์ด์ ํธ๋ณ JSON์์ ํฉํธ๋ฅผ ๋ง์ด๊ทธ๋ ์ด์
ํ๋ ๊ณง ์ง์์ง ์์ฝ์ ๊ฐ์ ธ์ค์ง ์๊ณ , ๊ทธ๋ค์ ์์ด์ ํธ ์ค์ ํ์ผ์ ๋ณด์กดํ๋ฉด์ ๊ณต์ ์์ฝ๊ณผ ๋ชจ๋ ์์ด์ ํธ ๋ฒํท์ ํฉํธ๋ฅผ ์ญ์ ํฉ๋๋ค. ๋ฐ๋ผ์ ์ดํ์ ์ฝ๊ธฐ๊ฐ ๊ฑด๋๋ด ๋ ๊ฑฐ์ ํฉํธ๋ฅผ ๋์ด๋ฆด ์ ์์ต๋๋ค. ๋ช
์์ ์ผ๋ก ์์ด์ ํธ ๋ฒ์๋ฅผ ์ง์ ํ ์ญ์ ๋ ํด๋น ์์ด์ ํธ์ ํฉํธ๋ง ์ญ์ ํฉ๋๋ค. ์ฒซ ๋ฒ์งธ ์ผ๋ฐ ์ฝ๊ธฐ ์, ์ฌ์ฉ์ JSON์ ํฌํจ๋ ์ด์ ํฉํธ๋ ์๋์ผ๋ก `__default__`๋ก ๋ง์ด๊ทธ๋ ์ด์
๋ฉ๋๋ค. ์ด์ ์ ์๋ฌต์ ์ธ `lead-agent` ๋ฒํท์ ๊ธฐ๋ก๋ ํฉํธ๋ ํด๋น ๋๋ ํฐ๋ฆฌ๊ฐ ์ค์ ์ปค์คํ
์์ด์ ํธ๊ฐ ์๋๋ฉด ํจ๊ป ์ด๋๋ฉ๋๋ค. ๋ง์ด๊ทธ๋ ์ด์
๊ณผ ์ผ๋ฐ ์ฐ๊ธฐ๋ ์์ ์ ์ฅ์ ์ ๊ธ์ด ํด์ ๋ ๋ค์๋ง ์ค์ ๋ ๊ฒ์(retrieval) ์ด๋ํฐ์ ์๋ฆฝ๋๋ค. DeerMem์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ฒ์๋ฅผ ์ธ์ํ๋ SQLite FTS5/BM25 ์ด๋ํฐ๋ฅผ ์ฌ์ฉํ๊ณ , ์ฌ๊ตฌ์ฑ ๊ฐ๋ฅํ ํ์ ์ธ๋ฑ์ค ๋ฐ์ดํฐ๋ง `.retrieval/` ์๋(๋๋ `memory.backend_config.retrieval_index_path`๊ฐ ์ค์ ๋ ๊ฒฝ์ฐ ๊ทธ ์๋. ์๋ ๊ฒฝ๋ก ๊ฐ์ `storage_path` ๊ธฐ์ค์ผ๋ก ํด์๋ฉ๋๋ค)์ ์ ์ฅํ๋ฉฐ, Gateway ์์ ์ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ๋๋ ๋ฒ์๊ฐ ์ง์ ๋ ์ฒซ ๊ฒ์ ์ ์ง์ฐ ๋ฐฉ์์ผ๋ก ์ธ๋ฑ์ค๋ฅผ ์ฌ๊ตฌ์ฑํฉ๋๋ค. ์์๋ ํ์ ์ธ๋ฑ์ค๋ ์๋์ผ๋ก ๋ค์ ์์ฑ๋ฉ๋๋ค. ์ฌ๋ฌ Gateway ์ธ์คํด์ค๊ฐ ํ๋์ `storage_path`๋ฅผ ๊ณต์ ํ๋ ๊ฒฝ์ฐ `retrieval_index_path`๋ฅผ ์ธ์คํด์ค ๋ก์ปฌ ๋์คํฌ๋ก ์ง์ ํ์ธ์. SQLite์ WAL ๋ชจ๋๋ ๋คํธ์ํฌ ํ์ผ ์์คํ
์์ ์ง์๋์ง ์๊ณ , ๊ฐ ์ธ์คํด์ค๋ ๋ค๋ฅธ ์ธ์คํด์ค๊ฐ ์ด ๋ค ๋ค์ ๊ฒ์ ์ ์ฌ์ฉ์์ ์ธ๋ฑ์ค๋ฅผ ๋ค์ ๋๊ธฐํํ๋ฉฐ, ๋ค์ค ์ธ์คํด์ค๋ก ์ ์ธ๋ ๋ฐฐํฌ(`deployment.multi_instance: true` / `DEER_FLOW_MULTI_INSTANCE=1`)์์ ์ธ๋ฑ์ค๋ฅผ ๋ฉ๋ชจ๋ฆฌ ๋ฃจํธ ์๋์ ๋๋ฉด ์์ ์ ๊ฒฝ๊ณ ๊ฐ ๊ธฐ๋ก๋ฉ๋๋ค. Helm ์ฐจํธ๋ ์ด๋ฅผ ์ํด Pod ๋ก์ปฌ `emptyDir`์ ๋ง์ดํธํฉ๋๋ค. ์ด๋ฅผ ๋นํ์ฑํํ๊ณ ๋ก์ปฌ ๋ถ๋ถ ๋ฌธ์์ด ํด๋ฐฑ์ ์ฌ์ฉํ๋ ค๋ฉด `memory.backend_config.retrieval_adapter`๋ฅผ ๋น ๋ฌธ์์ด๋ก ์ค์ ํ์ธ์. ์ค๊ตญ์ด ํ ํฐํ๋ ์ ํ ์ฌํญ์
๋๋ค. jieba ๊ธฐ๋ฐ ํ์ ๊ตฌ๋ฌธ ๊ฒ์์ ์ฌ์ฉํ๋ ค๋ฉด ๋ฐฑ์๋ `memory-zh` extra(`uv sync --extra memory-zh`)๋ฅผ ์ค์นํ์ธ์. ์ ๋๋ง๋ ์ฐ๊ธฐ, ๊ณต์ ์ฌ์ฉ์ ์ ๊ธ, ๋๊ด์ ์ฌ์ฉ์ ๋ฉ๋ชจ๋ฆฌ ๋ฆฌ๋น์ ์ด ์
๋ฐ์ดํธ๊ฐ ์กฐ์ฉํ ์ ์ค๋๋ ๊ฒ์ ๋ฐฉ์งํฉ๋๋ค.
๊ฒฐ์ ์ ๊ด๋ จ์ฑ/์ ๋ขฐ๋ ์์์ ์ฟผ๋ฆฌ ์ธ์ ์ฃผ์
์ ์ฌ์ฉํ๋ ค๋ฉด `memory.backend_config.retrieval_relevance_enabled: true`๋ฅผ ์ค์ ํ์ธ์. ์ด ์ค์ ์ ๊ธฐ๋ณธ FTS5/BM25์ ์ปค์คํ
์ด๋ํฐ๋ฅผ ํฌํจํ์ฌ **๊ฒ์ ์ `retrieval_adapter`๋ฅผ ์ฐํ**ํ๋ฉฐ, ์ธ๋ฑ์ฑ์ ์ค์ ๋ ๊ทธ๋๋ก ์ ์ง๋ฉ๋๋ค. `retrieval_relevance_weight`๋ ํผํฉ ๋น์จ์ ์ ์ดํ๊ณ , `retrieval_diversity_weight`๋ ๊ทผ์ฌ ์ค๋ณต ํ๋ํฐ๋ฅผ ํ์ฑํํฉ๋๋ค(๊ธฐ๋ณธ๊ฐ 0). ์ ์ ๊ณ์ฐ์ ์ฟผ๋ฆฌ/ํฉํธ๋ง๋ค ์ต๋ ์ฒ์ 4096์์ 128๊ฐ ํ ํฐ๋ง ์ฌ์ฉํฉ๋๋ค. ๊ฒ์์ `top_k`๊น์ง๋ง ๋ค์ํํ๋ฉฐ, ์ฃผ์
์ ๋ณด์ฅ ํฉํธ์ ์ผ๋ฐ ํฉํธ๋ฅผ ๊ฐ๊ฐ์ ํ ํฐ ์์ฐ์ ๋๋ฌํ ๋๊น์ง ๋
๋ฆฝ์ ์ผ๋ก ๋ค์ํํฉ๋๋ค. ๊ธฐ์กด ๊ฒ์ ๋ฐ ์ฃผ์
๋์์ ์ ์งํ๋ ค๋ฉด ์ด ๊ธฐ๋ฅ์ ๋นํ์ฑํ๋ ์ํ๋ก ๋์ธ์.
์ดํ์ ๊ด๋ จ์ฑ์ ์๋ก ๋ค๋ฅธ ์ฟผ๋ฆฌ ์ฉ์ด์ IDF ๊ฐ์ค ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ์ธก์ ํ๋ฏ๋ก, ๋ฐ๋ณต๋๋ ๋ถ๋ถ ์ผ์น๊ฐ ์ ์๋ฅผ ํฌํ์ํค๋ ๊ฒ๋ง์ผ๋ก ์์ ์ผ์น์ ๋์ ์ด ๋ ์ ์์ต๋๋ค. ์ ๋์ฌ ์ผ์น๋ ๋จ์ํ ๋ค ๊ธ์๋ฅผ ๊ณต์ ํ๋ ๊ฒ์ด ์๋๋ผ ํ ํ ํฐ ์ ์ฒด๊ฐ ๋ค๋ฅธ ํ ํฐ์ ์ ๋์ฌ์ฌ์ผ ํฉ๋๋ค. ์
๋ก๋์ ๊ฒฝ์ฐ ์ฟผ๋ฆฌ ์ธ์ ์ฃผ์
์ ์์ ๋ถ์ ํ์ผ ์ค๋ช
์ด ์๋๋ผ ๋ณด์กด๋ ์ฌ์ฉ์ ์์ฒญ์ ์ฌ์ฉํ๋ฉฐ, ์ฒจ๋ถ ํ์ผ๋ง ์๋ ๋ฉ์์ง๋ ์ฟผ๋ฆฌ ์๋ ์ฃผ์
์ ์ ์งํฉ๋๋ค. ์ด์ ์ปค์คํ
๋ฉ๋ชจ๋ฆฌ ๋ฐฑ์๋๋ ๊ธฐ์กด `get_context` ์๊ทธ๋์ฒ๋ฅผ ์ ์งํ ์ ์์ต๋๋ค. ํ๋กฌํํธ ์ฃผ์
๊ณผ ์์๋ ๋น๋๊ธฐ ๋ํผ๋ ํด๋น callable์ด ์ด ํค์๋๋ฅผ ์ง์ํ๊ณ ํํธ๊ฐ `None`์ด ์๋ ๋๋ง `query`๋ฅผ ์ ๋ฌํฉ๋๋ค.
๊ฒ์๊ณผ ์๋ ์ฃผ์
์ ๋์ผํ ์ฌ์ฉ์/์์ด์ ํธ ํ๋ณด ๋ฒ์์ ๋ํด ๋์ผํ IDF ๊ฐ์ค์น๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์นดํ
๊ณ ๋ฆฌ ํํฐ ๊ฒ์๊ณผ ์ฃผ์
์ ๋ณ๋ ๋ณด์ฅ/์ผ๋ฐ ํ ํฐ ์์ฐ ๋๋ฌธ์ ์ต์ข
์ ํ ๊ฒฐ๊ณผ๋ ์ฌ์ ํ ๋ค๋ฅผ ์ ์์ต๋๋ค.
๋ฉ๋ชจ๋ฆฌ ์ฃผ์
์ ์ค์ ๋ ์ด์ ๋ชจ๋๋ฅผ ๋ฐ๋ฆ
๋๋ค. `middleware` ๋ชจ๋์์ DeerMem์ ์ฌ์ฉ์ ์ ์ญ ์์ฝ๊ณผ ์ ํ๋ ์์ด์ ํธ์ ํฉํธ๋ฅผ ์ฃผ์
ํฉ๋๋ค. ์ปค์คํ
์์ด์ ํธ์ ๋ถํธ์คํธ๋ฉ ๋ํ๋ ํด๋น ์์ด์ ํธ์ ํฉํธ ๋ฒํท์ ์ฌ์ฉํ๋ฏ๋ก, ์ค์ ๊ณผ์ ์ ์ธ๋ถ ์ ๋ณด๊ฐ ๊ธฐ๋ณธ ์์ด์ ํธ์ ๋ฉ๋ชจ๋ฆฌ๋ก ์์ด ๋๊ฐ์ง ์์ต๋๋ค. `tool` ๋ชจ๋์์ ์๋ `` ๋ธ๋ก์๋ ์ ์ญ `user` ๋ฐ `history` ์์ฝ๋ง ํฌํจ๋๋ฉฐ, ์์ด์ ํธ ํฉํธ๋ `memory_search`๋ฅผ ํตํด ๋ช
์์ ์ผ๋ก ๊ฒ์๋๋ฏ๋ก ์๋ ์ฃผ์
๋ ํฉํธ ์ปจํ
์คํธ์ ๋๊ตฌ๊ฐ ๋ฐํํ ํฉํธ ์ปจํ
์คํธ๊ฐ ์ค๋ณต๋์ง ์์ต๋๋ค. `memory.injection_enabled: false`๋ฅผ ์ค์ ํ๋ฉด ๋ ๋ชจ๋ ๋ชจ๋์์ ์ฌ์ ํ ๋ธ๋ก ์ ์ฒด๊ฐ ๋นํ์ฑํ๋ฉ๋๋ค. ํฉํธ ID๋ฅผ ์ด๋ฏธ ์๊ณ ์์ผ๋ฉด `memory_get(fact_id)`๋ ๋ด์ฉ์ผ๋ก ๊ฒ์ํ์ง ์๊ณ ํ์ฌ ์ฌ์ฉ์์ ์์ด์ ํธ ๋ฒ์์์ ์ ํํ ๊ทธ ํฉํธ๋ฅผ ๋ฐํํฉ๋๋ค. ์กด์ฌํ์ง ์๊ฑฐ๋ ๋ฒ์ ๋ฐ์ ID๋ not-found ์ค๋ฅ๋ฅผ ๋ฐํํ๋ฉฐ, ํ์ํ ์ฝ๊ธฐ ๊ธฐ๋ฅ(capability)์ด๋ ์์ด์ ํธ ๋ฒ์ ๊ธฐ๋ฅ์ด ์๋ ๋ฐฑ์๋๋ unsupported ์ค๋ฅ๋ฅผ ๋ฐํํฉ๋๋ค.
๊ฐ๋ณ ์ปค์คํ
์์ด์ ํธ๋ ์ ์ญ ์ค์ ์ ๋ฐ๊พธ์ง ์๊ณ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋ ์ ์์ต๋๋ค. `memory_enabled: false`๋ฅผ ํด๋น ์์ด์ ํธ์ `users/{user_id}/agents/{name}/config.yaml`์ ์ถ๊ฐํ์ธ์. ์์ด์ ํธ๋ ์ฌ์ ํ ํ์ฌ ๋ ์ง ๋ฆฌ๋ง์ธ๋๋ฅผ ๋ฐ์ง๋ง, DeerFlow๋ ํด๋น ์์ด์ ํธ์ ๋ํด ํ์ํ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฃผ์
ํ์ง ์๊ณ , ์๋์ ์ด๊ฑฐ๋ ์์ฝ์ ์ํ ๋ฉ๋ชจ๋ฆฌ ์
๋ฐ์ดํธ(์๋ `/compact` ํฌํจ)๋ฅผ ๋๊ธฐ์ด์ ๋ฃ์ง ์์ผ๋ฉฐ, ๋ฉ๋ชจ๋ฆฌ ๋๊ตฌ๋ฅผ ๋
ธ์ถํ์ง ์๊ณ , ๋ฉ๋ชจ๋ฆฌ ๋๊ตฌ ์ง์นจ๋ ์ถ๊ฐํ์ง ์์ต๋๋ค. ๊ธฐ์กด ์์ด์ ํธ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋๋ฉด, ์ด์ ์ ์ฃผ์
๋ ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก์ ๋ค์ ๋ชจ๋ธ ํธ์ถ ์ ์ ์ฒดํฌํฌ์ธํธ ์ํ์์ ์ ๊ฑฐ๋๋ฉฐ ๋ ์ง ๋ฆฌ๋ง์ธ๋์ ๋ํ๋ ๊ทธ๋๋ก ๋จ์ต๋๋ค. ์ด ํ๋๋ฅผ ์๋ตํ๊ฑฐ๋ `true`๋ก ์ค์ ํ๋ฉด ๊ธฐ์กด ์ ์ญ `memory` ๋์์ด ์ ์ง๋ฉ๋๋ค.
๋จ์ผ ํฉํธ ์ ์ฅ์ ์์
์ ์ง์ ํ ์ฆ๋ถ ๋ฐฉ์์
๋๋ค. upsert/delete๋ ๋์ ํฉํธ ํ์ผ๋ง ์ฝ๊ณ , ์ ๋๋งํ๊ณ , ์ฐ๊ณ , ๋ค์ ์ธ๋ฑ์ฑํ๋ฉฐ, ์บ์์ ์์กดํ๋ ๊ฐ์ง ์ ์ฒด ๋ฌธ์ ๋์ ๋ช
์์ ์ธ ๋ถ์์ ๋ธํ๋ฅผ ๋ฐํํฉ๋๋ค. ์์ฝ ๋ณ๊ฒฝ ์ธํธ๋ ์ ๊ณต๋ `user`/`history` ํ์ ํค๋ฅผ ์ ์ฅ๋ ์น์
์์ ๋ณํฉํ๋ฏ๋ก ๋ถ๋ถ ์
๋ฐ์ดํธ๊ฐ ์๋ต๋ ํ์ ํค๋ฅผ ์ง์ธ ์ ์์ผ๋ฉฐ, ์ ์ฒด ๊ฐ์ ธ์ค๊ธฐ๋ ๊ต์ฒด ๊ฐ์ ์ ์ฉํ๊ธฐ ์ ์ ๋ ์น์
์ ์์ ํ ํธํ ์คํค๋ง๋ก ์ ๊ทํํฉ๋๋ค. ๊ฐ์ ธ์ค๊ธฐ๋ ์๋ชป๋ ํ์์ ํฉํธ ๋ชฉ๋ก์ด๋ ๋น์ด ์๊ฑฐ๋ ํ
์คํธ๊ฐ ์๋ ๋ด์ฉ์ ์ ์ฅ๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋ณ๊ฒฝํ๊ธฐ ์ ์ HTTP 400์ผ๋ก ๊ฑฐ๋ถํ๋ฉฐ, ๋ณต๊ตฌ ๊ฐ๋ฅํ ๋ ๊ฑฐ์ ๋ฉํ๋ฐ์ดํฐ์๋ ์ฌ์ ํ ๊ธฐ๋ณธ๊ฐ์ด ์ฑ์์ง๋๋ค. ๋ช
์์ ์ธ ๋น ํฉํธ ๋ชฉ๋ก์ ์ฌ์ ํ ์๋์ ์ธ ์ ์ฒด ์ญ์ ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค. Manager/API ํธํ ๋ฉ์๋๋ ๊ณต๊ฐ ์๋ต ๊ณ์ฝ์ด ์๊ตฌํ ๋๋ง ์๋ก์ด ์ ์ฒด ๋ฌธ์๋ฅผ ๊ตฌ์ฑํฉ๋๋ค. ํฉํธ ์์ค์ ๋จ๊ฑด ์์
์ ๊ธฐ๋ํ๋ ์ฌ์ฉ์ ๋ฉ๋ชจ๋ฆฌ ๋ฆฌ๋น์ ๊ณผ ํฉํธ ๋ฆฌ๋น์ ์ ๊ฐ๊ฐ ๋ฐ๋ก ์ฌ์ฉํ๋ฉฐ, ๋์ ํฉํธ์ ๋ชจ๋ ์ ์ ์กฐ๊ฑด์ด ์ฌ์ ํ ์ ํจํ๋ฉด ๋ช
์์ ์ผ๋ก ๋ฆฌ๋ฒ ์ด์คํ ์ ์์ต๋๋ค. ๋ฒ์ ์ง์ ์ญ์ , ์ํ์ด ์๋ ์์ฑ, ํตํฉ, ํธ๋ฆฌ๋ฐ๊ณผ ๊ฐ์ด ์ค๋
์ท์์ ํ์๋ ์์
์ ์ค๋๋ ์ญ์ /ํธ๋ฆฌ๋ฐ ์งํฉ์ ๊ฒฐ์ฝ ์ฌ์(replay)ํ์ง ์์ต๋๋ค. ๋งค๋ํ์คํธ ์ถฉ๋์ด ๋ฐ์ํ๋ฉด ์ ์ฒด ๋ฌธ์๋ฅผ ๋ค์ ๋ถ๋ฌ์ ์์
์ ๋ค์ ๊ณ์ฐํ๋ฉฐ, ์ฌ์๋ ํ์๋ ์ ํ๋ฉ๋๋ค. ํฉํธ ๊ฒฝ๋ก๋ `SHA-256(fact_id)`์ ์ฒ์ ๋ 16์ง์ ๋ฌธ์๋ฅผ ์ฌ์ฉํ๋ฏ๋ก, ์์ฑ๋ `fact_*` ID๊ฐ ์ค๋ ์ ์ฒด์ ๋ถ์ฐ๋ฉ๋๋ค. ์บ์ ํ ํฐ์ ๊ณต์ JSON์ ๋๋
ธ์ด ๋จ์ mtime, ํฌ๊ธฐ, ์ ์ฅ๋ ๋ฆฌ๋น์ ์ ๊ฒฐํฉํฉ๋๋ค. ์ด๋ฅผ ํตํด ํฉํธ ํ์ผ์ ์ค์บํ์ง ์๊ณ ๋, mtime ํด์๋๊ฐ ๋ฎ์ ํ๊ฒฝ์์ ๊ฐ์ ํฌ๊ธฐ๋ก ์ฐ์ธ ๊ฒฝ์ฐ ์ค๋๋ ๋ฐ์ดํฐ๊ฐ ๋ฐํ๋๋ ๊ฒ์ ๋ฐฉ์งํฉ๋๋ค. Markdown์ ์ธ๋ถ์์ ์ง์ ํธ์งํ ๊ฒฝ์ฐ์๋ ๋ช
์์ ์ผ๋ก ๋ค์ ๋ถ๋ฌ์์ผ ํฉ๋๋ค. ์ ์ฅ์๋ณ ์ถฉ๋๊ณผ ์์์ MemoryManager ๊ฒฝ๊ณ์์ ๋ณํ๋๋ฉฐ, Gateway๋ ์ถฉ๋์ HTTP 409๋ก, ๋ฏผ๊ฐ ์ ๋ณด๊ฐ ์๋ ์์ ์ ์ธ ์์ ์ค๋ฅ๋ฅผ HTTP 500์ผ๋ก ๋ฐํํฉ๋๋ค. ์ ์ฒด ๋ฌธ์ `save()`๋ ํธํ์ฉ API๋ก ๋จ์ ์์ผ๋ฉฐ ์ฐ๊ธฐ ์ ์ diff๋ฅผ ๊ณ์ฐํ๋ฏ๋ก, ์๋ชป๋ ํ์์ด๊ฑฐ๋ ๋๋ฝ๋ `facts`๊ฐ ๋ ์ด์ ์์ด์ ํธ์ Markdown ํ์ผ์ ์กฐ์ฉํ ์ง์ธ ์ ์์ต๋๋ค. ๋ ๊ฑฐ์ ๋ง์ด๊ทธ๋ ์ด์
์ ๋น์ด ์์ง ์์ `user`/`history`๋ฅผ ๋จผ์ ๋ณด์กดํ ๋ค์ ์์ด์ ํธ `memory.json`์ ์ญ์ ํ๋ฉฐ, ์์ฝ์ด ์ถฉ๋ํ๋ฉด ์ด๋ ์ชฝ์ ํํ๋ ๋์ ๋ ๊ฑฐ์ ํ์ผ์ ์ ์งํ๊ณ ๋ช
์์ ์ผ๋ก ์คํจํฉ๋๋ค.
`memory.json`์ ๋ ๊ฑฐ์ ํฉํธ๋ ์ฌ์ฉ์์ ์ฒซ ๋ฒ์งธ ์ผ๋ฐ ๋ฉ๋ชจ๋ฆฌ ์ฝ๊ธฐ ์ ์์ฝ๋ `__default__` Markdown ๋ฒํท์ผ๋ก ์๋ ๋ง์ด๊ทธ๋ ์ด์
๋ฉ๋๋ค. ํธ๋ํฝ์ ์ฒ๋ฆฌํ๊ธฐ ์ ์ ๋ง์ด๊ทธ๋ ์ด์
์ ๊ฐ์ฌํ๊ฑฐ๋ ์๋ฃํ๊ณ ์ถ์ ์ด์์๋ `backend/`์์ ์ ํ ์ฌํญ์ธ ๋ฉฑ๋ฑ CLI๋ฅผ ์คํํ ์ ์์ต๋๋ค.
```bash
PYTHONPATH=. python scripts/migrate_memory_markdown.py --all-users --dry-run
PYTHONPATH=. python scripts/migrate_memory_markdown.py --all-users
# A custom DeerMem root or original non-directory-safe identity can be explicit:
PYTHONPATH=. python scripts/migrate_memory_markdown.py --storage-path /path/to/deerflow-home --user-id 'test@example.com'
```
v1์์ v2๋ก์ ์ ์ฅ์ ๋ง์ด๊ทธ๋ ์ด์
์ ์คํ ์ค์ธ ์ ํ๋ฆฌ์ผ์ด์
๊ธฐ์ค์ผ๋ก ๋จ๋ฐฉํฅ์
๋๋ค. ํด๋น PR ์ด์ ์ ์ฝ๋๋ Markdown ํฉํธ๋ฅผ ์ฝ์ง ์์ต๋๋ค. ์์ ๋ฐฐํฌ๋ฅผ ์
๊ทธ๋ ์ด๋ํ๊ธฐ ์ ์ DeerFlow๋ฅผ ์ค์งํ๊ณ , ์ค์ ๋ ๋ฉ๋ชจ๋ฆฌ ์ ์ฅ์ ๋ฃจํธ์ ํ์ผ ์์คํ
์ค๋
์ท ๋๋ ์ ์ฒด ๋ฐฑ์
์ ๋ง๋์ธ์. ๋ง์ด๊ทธ๋ ์ด์
์ ๋ํ v2 ๋ฐ์ดํฐ๋ฅผ ์ฐ๊ธฐ ์ ์ ํ๊ดด์ ์ผ๋ก ๋ณ๊ฒฝ๋๋ ๊ฐ JSON ์์ค๋ฅผ ์๋ ๊ฒฝ๋ก ์์ `{manifest_filename}.v1.bak`์ผ๋ก ์์์ ์ผ๋ก ๋ณด๊ดํฉ๋๋ค. ์ผ์นํ์ง ์๋ ๊ธฐ์กด ๋ฐฑ์
์ด ์๊ฑฐ๋ ๋ฐฑ์
์ฐ๊ธฐ์ ์คํจํ๋ฉด v1 ์์ค๋ฅผ ์์ ํ์ง ์๊ณ ๋ง์ด๊ทธ๋ ์ด์
์ ์ค๋จํฉ๋๋ค. ์ด ๋ก์ปฌ ๋ฐฑ์
์ ๋ง์ด๊ทธ๋ ์ด์
์ด์ ๋ฐ์ดํฐ๋ฅผ ๋ณด์กดํ์ง๋ง ์ ์ฒด ์ค๋
์ท์ ๋์ฒดํ์ง ์์ผ๋ฉฐ, ์
๊ทธ๋ ์ด๋ ์ดํ์ ์์ฑ๋ ํฉํธ๋ ํฌํจํ์ง ์์ต๋๋ค.
`--user-id`๋ ์ฌ๋ฌ ๋ฒ ์ง์ ํ ์ ์์ต๋๋ค. `--all-users`๋ ์ ํํ ์ ์ฅ์ ๋ฃจํธ ์๋์ ์๋ ๊ธฐ์กด์ ๋๋ ํฐ๋ฆฌ ์์ ๋ฒํท์ ์ฐพ์ต๋๋ค. `@`์ ๊ฐ์ ๋ฌธ์๊ฐ ํฌํจ๋ ์์ ID๋ฅผ ์ ๋ฌํ๋ ๋
๋ฆฝํ ํตํฉ์ `--user-id`์ ์๋ ๊ฐ์ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ํ ์ฌ์ฉ์์ ๋ง์ด๊ทธ๋ ์ด์
์ด ์คํจํ๋ฉด ๋๋จธ์ง ๊ฐ์ฌ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ๋ฆฌ์ง ์๊ณ ๋ณด๊ณ ํ๋ฉฐ, ์ด๋ ํ ์ฌ์ฉ์๋ผ๋ ์คํจํ๋ฉด ๋ช
๋ น์ 0์ด ์๋ ์ฝ๋๋ก ์ข
๋ฃ๋ฉ๋๋ค. ์ฒซ ์ฝ๊ธฐ ์ ์๋ ๋ง์ด๊ทธ๋ ์ด์
๊ฒฝ๋ก๋ ๊ณ์ ํ์ฑํ๋์ด ์์ผ๋ฏ๋ก, ์์์ ์ํด ์ด CLI๋ฅผ ๋ฐ๋์ ์คํํ ํ์๋ ์์ต๋๋ค.
## ๊ถ์ฅ ๋ชจ๋ธ
DeerFlow๋ ํน์ ๋ชจ๋ธ์ ์ข
์๋์ง ์์ผ๋ฉฐ, OpenAI ํธํ API๋ฅผ ๊ตฌํํ๋ ๋ชจ๋ LLM๊ณผ ํจ๊ป ๋์ํฉ๋๋ค. ๋ค๋ง ๋ค์์ ์ง์ํ๋ ๋ชจ๋ธ์์ ๊ฐ์ฅ ์ข์ ์ฑ๋ฅ์ ๋
๋๋ค.
- ์ฌ์ธต ๋ฆฌ์์น์ ๋ค๋จ๊ณ ์์
์ ์ํ **๊ธด ์ปจํ
์คํธ ์๋์ฐ**(100k+ ํ ํฐ)
- ์ ์ํ ๊ณํ๊ณผ ๋ณต์กํ ๋ฌธ์ ๋ถํด๋ฅผ ์ํ **์ถ๋ก ๋ฅ๋ ฅ**
- ์ด๋ฏธ์ง ์ดํด์ ๋์์ ์ดํด๋ฅผ ์ํ **๋ฉํฐ๋ชจ๋ฌ ์
๋ ฅ**
- ์์ ์ ์ธ ํจ์ ํธ์ถ๊ณผ ๊ตฌ์กฐํ๋ ์ถ๋ ฅ์ ์ํ **๊ฐ๋ ฅํ ๋๊ตฌ ์ฌ์ฉ ๋ฅ๋ ฅ**
MindIE XML ๋๊ตฌ ํธ์ถ ์ธ์๋ ๋ถํธ๊ฐ ์๋ ์, ์์, ์ง์ ํ์์ JSON ์ซ์๋ฅผ ์ง์ํฉ๋๋ค. ์ซ์๊ฐ ์ค๋ฒํ๋ก๋๊ฑฐ๋, 0์ผ๋ก ์ธ๋ํ๋ก๋๊ฑฐ๋, Python์ ์ ์ ์๋ฆฟ์ ์ ํ์ ์ด๊ณผํ๋ฉด ์ค์ฒฉ๋ JSON ๋ชฉ๋ก๊ณผ ๊ฐ์ฒด๋ฅผ ํฌํจํ ์ธ์ ์ ์ฒด๊ฐ ๋ฌธ์์ด๋ก ์ ์ง๋๋ฏ๋ก, ํ์ฑ์ด ๊ฐ์ ์กฐ์ฉํ ๋ฐ๊พธ์ง ์์ต๋๋ค. ์ ํํ์ง ์์ ๋ถ๋์์์ ์๋ฅผ ํฌํจํ๋ Python ๋ฆฌํฐ๋ด set๊ณผ tuple๋ ๋ค๋ฅธ ์ปจํ
์ด๋ ์์ ์ค์ฒฉ๋ ๊ฒฝ์ฐ๋ฅผ ํฌํจํ์ฌ ์ธ์ ์ ์ฒด๋ฅผ ํ
์คํธ๋ก ์ ์งํฉ๋๋ค. ๋์
๋๋ฆฌ์ ํค์ ๊ฐ๋ ์ฌ๊ท์ ์ผ๋ก ๊ฒ์ฌ๋ฉ๋๋ค.
## ์๋ฒ ๋๋ Python ํด๋ผ์ด์ธํธ
`DeerFlowClient(agent_name="researcher")`์ ๊ฒฝ์ฐ, ์ง์ ๋ ์์ด์ ํธ์ `mcp_plugins` ์ ํ์ ๋ฆฌ๋ ์์ด์ ํธ์ ๊ทธ `task` / `batch_task` ์์ ๋ชจ๋์ ์ ์ฉ๋ฉ๋๋ค. `null`์ ํ์ฑํ๋ ๋ชจ๋ MCP ํ๋ฌ๊ทธ์ธ์ ์์ํ๊ณ , `[]`๋ ์๋ฌด๊ฒ๋ ์ ํํ์ง ์์ผ๋ฉฐ, ์ค์น ID๋ฅผ ์ง์ ํ๋ฉด ํด๋น ํ๋ฌ๊ทธ์ธ๋ง ์ ํํฉ๋๋ค. ์ ์ฅ๋ ์์ด์ ํธ ์ค์ ์ ํธ์งํ ๋ค์๋ `client.reset_agent()`๋ฅผ ํธ์ถํ์ฌ ์ ํ์ ์๋ก ๊ณ ์น์ธ์.
`DeerFlowClient.stream()`์ ๊ฐ `values` ์ด๋ฒคํธ์ `summary_text`๋ฅผ ํฌํจํฉ๋๋ค. ์ด๋ ํ์ฌ ์์ถ๋ ์ปจํ
์คํธ ์์ฝ์ด๋ฉฐ, ์์ฝ์ด ์์ผ๋ฉด `None`์
๋๋ค. ์๋น์๋ ์ฒดํฌํฌ์ธํธ ๋ด๋ถ๋ฅผ ์ฝ์ง ์๊ณ ๋ ๋ณ๊ฒฝ ์ฌํญ์ ๊ธฐ๋กํ ์ ์์ต๋๋ค. ๋ฐ๋ณต๋๋ ์ค๋
์ท์ ๊ฐ์ ์์ฝ์ ๋ด์ ์ ์์ผ๋ฉฐ, ์ด๊ธฐ ์ค๋
์ท์ ์ด์ ํด์ ์์ฝ์ด ์ด๋ฏธ ๋ค์ด ์์ ์๋ ์์ต๋๋ค.
DeerFlow๋ ์ ์ฒด HTTP ์๋น์ค๋ฅผ ์คํํ์ง ์๊ณ ๋ ์๋ฒ ๋๋ Python ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. `DeerFlowClient`๋ ๋ชจ๋ ์์ด์ ํธ ๋ฐ Gateway ๊ธฐ๋ฅ์ ํ๋ก์ธ์ค ๋ด์์ ์ง์ ์ ๊ทผํ ์ ์๊ฒ ํด ์ฃผ๋ฉฐ, HTTP Gateway API์ ๋์ผํ ์๋ต ์คํค๋ง๋ฅผ ๋ฐํํฉ๋๋ค. HTTP Gateway๋ ๋ํ LangGraph ์ค๋ ๋ ์์ฒด๊ฐ ์ญ์ ๋ ๋ค DeerFlow๊ฐ ๊ด๋ฆฌํ๋ ๋ก์ปฌ ์ค๋ ๋ ๋ฐ์ดํฐ๋ฅผ ์ ๊ฑฐํ๊ธฐ ์ํ `DELETE /api/threads/{thread_id}`๋ฅผ ์ ๊ณตํฉ๋๋ค.
๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ธฐ๋ฐ ์คํ(run) ์ด๋ฒคํธ์ ๊ฒฝ์ฐ, ์คํ์ ์ญ์ ํด๋ ํด๋น ์ค๋ ๋์ ์ํ์ค ์ํฐ๋งํฌ๋ ๋ณด์กด๋ฉ๋๋ค. ์ค๋ ๋ ์ญ์ ๋ ๋จ์ ์ด๋ฒคํธ๊ฐ ์์ ๋ ๊ทธ ์ํฐ๋งํฌ๋ฅผ ์ ๊ฑฐํ๋ฏ๋ก, ๋ค์ ์์ฑ๋ ์ค๋ ๋๋ ์ํ์ค 1๋ถํฐ ๋ค์ ์์ํ ์ ์์ต๋๋ค. ์์ ์ ๋ฒ์ ์ญ์ ์์๋ ๋ค๋ฅธ ์์ ์์ ์ด๋ฒคํธ๊ฐ ๋จ์ ์์ผ๋ฉด ์ํฐ๋งํฌ๋ฅผ ๋ณด์กดํฉ๋๋ค.
๋จ์ผ ํ๋ก์ธ์ค JSONL ์ด๋ฒคํธ ์ ์ฅ์๋ ์คํ ์ญ์ ์ ์ฌ์์์ ๊ฑฐ์ณ ์ค๋ ๋ ์ํ์ค ์ํฐ๋งํฌ๋ฅผ ์ ์งํ๋ฏ๋ก, `after_seq`๋ฅผ ์ฌ์ฉํ๋ ํด๋ผ์ด์ธํธ๊ฐ ์ดํ ๋ฉ์์ง๋ฅผ ๋์น์ง ์์ต๋๋ค. ์ด ๋ฐฑ์๋๋ฅผ ๋ฐฑ์
ํ ๋๋ `runs/.seq-watermark`๋ฅผ ์คํ ํ์ผ๊ณผ ํจ๊ป ๋ณด๊ดํ์ธ์. ์๋ก ์์ฑ๋๊ฑฐ๋ ๊ต์ฒด๋ ์ํฐ๋งํฌ๋ ์ญ์ ๋ ์คํ ํ์ผ์ ๊ถํ ๋นํธ๋ฅผ ์ด์ด๋ฐ์ต๋๋ค.
์ค๋ ๋ ์ ์ฒด๋ฅผ ์ญ์ ํ๋ฉด ์ํฐ๋งํฌ๊ฐ ์ ๊ฑฐ๋๊ณ ํ ๋น์ด ์ด๊ธฐํ๋ฉ๋๋ค.
์ค๋ ๋ ID๋ ํธ์ถ์๊ฐ ์ง์ ํ ์ ์์ผ๋ฉฐ UUID์ผ ํ์๋ ์์ต๋๋ค. ๋ช
์์ ์ธ ID๋ 1โ64๊ฐ์ ASCII ์๋ฌธ์, ์ซ์, ํ์ดํ, ๋ฐ์ค๋ก ๊ตฌ์ฑ๋์ด์ผ ํฉ๋๋ค(`^[A-Za-z0-9_-]{1,64}$`). DeerFlow๋ `thread_id`๊ฐ ์๋ต๋์๊ฑฐ๋ `None`์ผ ๋๋ง UUID๋ฅผ ์์ฑํ๋ฉฐ, ๋ช
์์ ์ผ๋ก ์ง์ ๋ ๋น ๋ฌธ์์ด์ ์ ํจํ์ง ์์ต๋๋ค.
์ด์ ์ ๋ ๋์จํ ๊ท์น์ผ๋ก ์์ฑ๋์ด ๋ผ์ฐํธ๋ก ์ ๊ทผ ๊ฐ๋ฅํ ๊ธฐ์กด ์ค๋ ๋๋ ๊ณ์ ์ฝ๊ณ ์ญ์ ํ ์ ์์ง๋ง, ์ ์คํ์ ์์ํ๊ฑฐ๋ ์๋ก์ด ํ์ผ ์์คํ
๋๋ ์๋๋ฐ์ค ์ํ๋ฅผ ๋ง๋ค ์๋ ์์ต๋๋ค. ๋ ๊ฑฐ์ ์ญ์ ๋ ID๊ฐ ์ ์ ๊ณ์ฝ์ ์์ ํ์ง ์์ผ๋ฉด ๋ก์ปฌ ๊ฒฝ๋ก ์ ๋ฆฌ๋ฅผ ๊ฑด๋๋๋๋ค. ๋ํ๊ฐ LangGraph ์ฒดํฌํฌ์ธํธ์๋ง ์กด์ฌํ๋ ์ ์ ํ์์ ๋ ๊ฑฐ์ ์ค๋ ๋์ ๊ฒฝ์ฐ, DeerFlow๋ ์ฒซ ๋ฒ์งธ ์ ์คํ ์ ์ ์ฒดํฌํฌ์ธํธ๋ก๋ถํฐ ๋น ์คํ ์ด๋ฒคํธ ํผ๋๋ฅผ ์๋ํ์ฌ `/messages/page`๊ฐ ์ด์ ํด๊ณผ ์ ํด์ ๋ชจ๋ ์ ์งํ๋๋ก ํฉ๋๋ค.
```python
from deerflow.client import DeerFlowClient
client = DeerFlowClient()
# Chat
response = client.chat("Analyze this paper for me", thread_id="my-thread")
# Streaming (LangGraph SSE protocol: values, messages-tuple, end)
for event in client.stream("hello"):
if event.type == "messages-tuple" and event.data.get("type") == "ai":
print(event.data["content"])
elif event.type == "messages-tuple" and event.data.get("type") == "tool" and "artifact" in event.data:
# Structured tool artifacts (for example, ask_clarification cards)
# are preserved when the ToolMessage provides one.
print(event.data["artifact"])
# Configuration & management โ returns Gateway-aligned dicts
models = client.list_models() # {"models": [...]}
skills = client.list_skills() # {"skills": [...]}
client.update_skill("web-search", enabled=True)
client.upload_files("thread-1", ["./report.pdf"]) # {"success": True, "files": [...]}
client.set_goal("thread-1", "finish the implementation and make all tests pass")
client.get_goal("thread-1") # {"goal": {...}} or {"goal": None}
client.clear_goal("thread-1")
```
์ค๋ ๋๋ฅผ ์ด์ด์ ์งํํ ๋ `values`๋ ์ฌ์ ํ ์ ์ฒด ๋ํ ์ํ๋ฅผ ๋ด์ง๋ง, `messages-tuple`๊ณผ `end.usage`๋ ํ์ฌ ํด๋ง ๋ค๋ฃน๋๋ค.
๋์์ ์คํ๋๋ `upload_files()` ํธ์ถ์ ๊ฐ ํธ์ถ ์์ ์์ ์ ์กด์ฌํ์ง ์๋ ํ์ผ ์ด๋ฆ์ ์ซ์ ์ ๋ฏธ์ฌ๋ฅผ ๋ถ์ฌ ๋ณด์กดํ๊ณ , ์ค์ ๋ก ์ ์ฅ๋ ์ด๋ฆ์ ๋ฐํํฉ๋๋ค. ์ Markdown ๋๋ฐ ํ์ผ์๋ ๊ฐ์ ๊ท์น์ด ์ ์ฉ๋ฉ๋๋ค. ์ด๋ฏธ ์กด์ฌํ๋ ์ ํํ ๊ฐ์ ์ด๋ฆ์ ๊ธฐ์กด์ฒ๋ผ ๊ต์ฒด ๋์์ ์ ์งํฉ๋๋ค. ๋ณํ ๊ฐ๋ฅํ ํ์ผ์ ๋ชจ๋ ํ์ผ ์ด๋ฆ ์ฌ์๋์ ๋ณํ ๊ณผ์ ์์ ํ๋์ ๋น๊ณต๊ฐ ์๋ณธ ์บก์ฒ๋ฅผ ์ฌ์ฉํ๋ฉฐ, ์๋ ๊ถํ๊ณผ ํ์์คํฌํ๋ฅผ ๋ณด์กดํฉ๋๋ค. ์คํ
์ด์ง ํ์ผ ๋ฐ๊ฟ์น๊ธฐ๊ฐ ๊ฐ์ง๋๋ฉด ๊ฑฐ๋ถ๋๋ฉฐ, ์คํ
์ด์ง ์ ๋ฆฌ ์คํจ๋ ์
๋ก๋ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ๋ฆฌ์ง ์๊ณ ๋ก๊ทธ์ ๊ธฐ๋ก๋ฉ๋๋ค.
HTTP Gateway๋ `values`, `messages-tuple`, `updates`, `debug`, `tasks`, `checkpoints`, `custom` ์คํธ๋ฆผ ๋ชจ๋๋ฅผ ๋ฐ์๋ค์
๋๋ค. `messages`์ `events` ๊ฐ์ ์ง์๋์ง ์๋ ๋ชจ๋, ์นํ
, ์ง์ฐ ์คํ, `multitask_strategy="enqueue"` ๊ฐ์ ์ง์๋์ง ์๋ ๊ธฐ๋ณธ๊ฐ์ด ์๋ ์คํ ์ต์
, ์ฒดํฌํฌ์ธํธ durability ์ฌ์ ์ ๊ฐ์ ์ ์ธ๋์ง ์์ SDK ์ต์
์ ์กฐ์ฉํ ๋ฌด์๋๊ฑฐ๋ ํํฅ ์ฒ๋ฆฌ๋๋ ๋์ ์คํ ์ ์ `422`๋ฅผ ๋ฐํํฉ๋๋ค.
dict๋ฅผ ๋ฐํํ๋ ๋ชจ๋ ๋ฉ์๋๋ CI์์ Gateway Pydantic ์๋ต ๋ชจ๋ธ์ ๋ํด ๊ฒ์ฆ๋๋ฏ๋ก(`TestGatewayConformance`), ์๋ฒ ๋๋ ํด๋ผ์ด์ธํธ๊ฐ HTTP API ์คํค๋ง์ ๋๊ธฐํ๋ ์ํ๋ก ์ ์ง๋ฉ๋๋ค. ์ ์ฒด API ๋ฌธ์๋ `backend/packages/harness/deerflow/client.py`๋ฅผ ์ฐธ๊ณ ํ์ธ์.
## ํ๋ก์ ํธ
ํ๋ก์ ํธ๋ ๊ด๋ จ ๋ํ๋ฅผ ๊ณต์ ์ด๋ฆ, ์ง์นจ, ๋ฌธ์ ์๊ฐ ์๋์ ๋ฌถ์ต๋๋ค.
๋ํ๋ ์์ฑ ์์ (ํ๋ก์ ํธ๊ฐ ์ ํ๋ ๊ฒฝ์ฐ)์ ๋๋ ์ดํ ์ด๋ ๋ฉ๋ด๋ฅผ ํตํด ํ๋ก์ ํธ์ ํฉ๋ฅํฉ๋๋ค. ์คํ(run)์ ์์์ ๊ฒฐ์ฝ ๋ณ๊ฒฝํ์ง ์์ต๋๋ค. ๋ฉ์์ง๋ฅผ ์ ์ถํด๋ ๋ํ๊ฐ ํ๋ก์ ํธ์ ๋ฐฐ์ ๋๊ฑฐ๋ ์ฌ๋ฐฐ์ ๋์ง ์์ต๋๋ค. ํ๋ก์ ํธ์์ ๋ํ๋ฅผ ๋นผ๋ด๋ฉด ๋ค์ ๋ช
์์ ์ผ๋ก ์ด๋ํ ๋๊น์ง ๋ฏธ๋ฐฐ์ ์ํ๋ก ๋จ์ต๋๋ค.
๋ํ๋ฅผ ์ด๋ํ๋ฉด ํ๋ก์ ํธ ๋ชฉ๋ก๋ฟ ์๋๋ผ ํค๋์ ์์ ํ์๋ ์๋ก ๊ณ ์ณ์ง๋ฉฐ, ์ด์ ๋ฉํ๋ฐ์ดํฐ ์์ฒญ์ด ์์ง ์งํ ์ค์ธ ๊ฒฝ์ฐ์๋ ๋ง์ฐฌ๊ฐ์ง์
๋๋ค.
ํ๋ก์ ํธ์๋ ์ต์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ
์ด๋ธ๊ณผ ์ปฌ๋ผ์ด ํ์ํฉ๋๋ค. ์ด์ 0018 ๊ธฐ๋ฐ ๋กค์์์์ `0019_thread_incarnations`๋ก ์คํฌํ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ํ๋ก์ ํธ ์คํค๋ง๊ฐ ์์ผ๋ฉด ์์ ์ ๊ฑฐ๋ถ๋ฉ๋๋ค. ํด๋น ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ด ๋น๋๋ฅผ ์์ํ๊ธฐ ์ ์ [์คํ๋ผ์ธ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ณต๊ตฌ ์ ์ฐจ](docs/database-forward-revision-recovery.md)๋ฅผ ๋ฐ๋ฅด์ธ์.
### ํ๋ก์ ํธ ์ง์นจ
๊ฐ ํ๋ก์ ํธ๋ ํ๋ก์ ํธ์ ๋ชจ๋ ๋ํ์ ์ ์ฉ๋๋ ๋ฐฐ๊ฒฝ, ๊ท์น, ์ ์ฝ ๊ฐ์ ์์ ํ์ ์ง์นจ์ ์ ์ฅํ๋ฉฐ, ์ด๋ ํ๋ก์ ํธ ํ์ด์ง์ Instructions ํญ์์ ์ค์๊ฐ ๋ฐ์ดํธ ์นด์ดํฐ์ ํจ๊ป ํธ์งํ ์ ์์ต๋๋ค. ์์ ์ค๋ ๋์์ ์คํ์ด ์์๋๋ฉด Gateway๋ ํ๋ก์ ํธ์ ํ์ฌ ์ํ๋ฅผ ํ ๋ฒ ๊ณ ์ ํ๊ณ , ํด๋น ์คํ์๋ง ์ ์ฉ๋๋ ํฌ๊ธฐ ์ ํ์ด ์๋ ์์ฒญ ๋ฒ์ `` ๋ธ๋ก์ผ๋ก ์ง์นจ์ ๋ ๋๋งํฉ๋๋ค. ์ด ๋ธ๋ก์ ์์คํ
ํ๋กฌํํธ๋ ์์ ์ ์ฅ๋ ๊ธฐ๋ก์ ์ ๋ ๋ค์ด๊ฐ์ง ์์ผ๋ฉฐ, ์ ์คํ๋ง๋ค ๊ฐ์ฅ ์ต๊ทผ์ ์ ์ฅ๋ ์ง์นจ์ ๋ด
๋๋ค. ์ง์นจ์ `projects.instructions_max_bytes` UTF-8 ๋ฐ์ดํธ(๊ธฐ๋ณธ๊ฐ 8192, ๋ฒ์ 256โ262144)๋ก ์ํ์ด ์ ํด์ง๋ฉฐ, ๋ฉํฐ๋ฐ์ดํธ ๋ฌธ์๋ UTF-8 ๋ฐ์ดํธ ๊ธธ์ด๋งํผ ๊ณ์ฐ๋ฉ๋๋ค. ํฌ๊ธฐ๋ฅผ ์ด๊ณผํ ์ง์นจ์ ์ฐ๊ธฐ ์์ ์ `422`๋ก ๊ฑฐ๋ถ๋๋ฉฐ ๊ฒฐ์ฝ ์กฐ์ฉํ ์๋ฆฌ์ง ์์ต๋๋ค.
### ๋ฌธ์ ์๊ฐ
๊ฐ ํ๋ก์ ํธ์๋ ํ๋ก์ ํธ ์ ์ฒด๊ฐ ๊ณต์ ํ๋ ํ์ผ์ ์ํ ๋ฌธ์ ์๊ฐ๊ฐ ์์ผ๋ฉฐ, ํ๋ก์ ํธ ํ์ด์ง์ Documents ์น์
์์ ๊ด๋ฆฌํฉ๋๋ค.
- ํ์ผ์ **์
๋ก๋**ํฉ๋๋ค(๋ฒํผ ๋๋ ๋๋๊ทธ ์ค ๋๋กญ, ์์ฒญ๋น ํ์ผ ํ๋). ์๊ฐ ํฌ๊ธฐ ์ ํ์ `uploads.max_file_size`(๊ธฐ๋ณธ๊ฐ 50 MiB)๋ฅผ ์ฌ์ฌ์ฉํ๋ฉฐ, ๋์ผํ ๋ด์ฉ์ ๋ค์ ์
๋ก๋ํ๋ฉด ์ค๋ณต ํญ๋ชฉ์ ๋ง๋๋ ๋์ ๊ธฐ์กด ํญ๋ชฉ์ ๋ฐํํฉ๋๋ค.
- ์ด๋ฆ, ํฌ๊ธฐ, ์์ ์๊ฐ, ์ถ์ฒ(provenance: ์
๋ก๋๋จ vs. ๋ํ์์ ์ ์ฅ๋จ)์ ํจ๊ป ํญ๋ชฉ์ **๋์ด**ํ๊ณ , ๋ชจ๋ ํญ๋ชฉ์ ๋ฏธ๋ฆฌ ๋ณด๊ฑฐ๋ ๋ค์ด๋ก๋ํ ์ ์์ต๋๋ค.
- ์ค๋ ๋ ํ์ผ์์ **ํ๋ก์ ํธ์ ์ ์ฅ(Save to project)**: ์๊ฐ ์๋์ ์ฝ๊ธฐ ์ ์ฉ ๋ํ ํ์ผ ๋ธ๋ผ์ฐ์ ๊ฐ ์์ ์ค๋ ๋์ ์
๋ก๋์ ์ถ๋ ฅ์ ๋์ดํ๋ฉฐ, ๊ฐ ํญ๋ชฉ์ Save to project ๋์์ด ์์ต๋๋ค.
- **์ค๋ ๋์ ์ฒจ๋ถ(Attach to thread)**: ์ผ๋ฐ ์์ง ํ์ดํ๋ผ์ธ์ ํตํด ์๊ฐ ํ์ผ์ ์ค๋ ๋์ ์
๋ก๋๋ก ๋ณต์ฌํ๋ฏ๋ก, ๋ํ์์ ํด๋น ํ์ผ์ ๋ฐ๋ก ๋ค๋ฃฐ ์ ์์ต๋๋ค.
๋ช
์์ ์ธ ์
๋ก๋ `name`๊ณผ ์น๊ฒฉ `shelf_name`์ ํฌํจํ ์ ์๊ฐ ์ด๋ฆ์ ์ผ๋ฐ ์
๋ก๋ ํ์ผ ์ด๋ฆ ๊ฒ์ฆ์ ๋ฐ๋ฆ
๋๋ค. NUL, Windows ์์ฝ ์ฅ์น ์ด๋ฆ(์: `CON.txt`), ๋์ ๋ถ์ ๋ง์นจํ๊ฐ ํฌํจ๋ ์ด๋ฆ์ ๋ฐ์ดํธ๊ฐ ์คํ
์ด์ง๋๊ธฐ ์ ์ `400`์ผ๋ก ๊ฑฐ๋ถ๋ฉ๋๋ค.
๋ค์ดํฐ๋ธ Windows์์ ๋ฌธ์ ์๊ฐ๋ ํ์ฅ ๊ธธ์ด ํ์ผ ์์คํ
๊ฒฝ๋ก๋ฅผ ์ฌ์ฉํ๋ฏ๋ก, ์์คํ
์ ์ฒด์ ๊ธด ๊ฒฝ๋ก ์ค์ ์ ์ผ์ง ์๊ณ ๋ ๊น์ ์ํฌ์คํ์ด์ค ๋๋ ํฐ๋ฆฌ์ ๊ธด ํ์ผ ์ด๋ฆ์ ์
๋ก๋, ๋ค์ด๋ก๋, ๋ณต์, ์๊ตฌ ์ญ์ ํ ์ ์์ต๋๋ค.
๊ฐ๋ณ ๊ฒฝ๋ก ๊ตฌ์ฑ ์์์ ๋ํ ํ์ผ ์์คํ
์ ํ์ ์ฌ์ ํ ์ ์ฉ๋ฉ๋๋ค.
์์ ์ค๋ ๋์ ์คํ์ ๊ณ ์ ๋ ์ค๋
์ท์ผ๋ก๋ถํฐ ์คํ๋ง๋ค ๋ ๋๋ง๋๋ ํฌ๊ธฐ ์ ํ์ด ์๋ `` ์ธ๋ฑ์ค๋ ๋ฐ์ผ๋ฉฐ(`projects.shelf_index_max_entries`์ `projects.shelf_index_max_bytes`๋ก ์ํ ์ง์ ), ์์ด์ ํธ๋ `list_project_documents` ๋ฐ `read_project_document` ๋๊ตฌ๋ก ์๊ฐ๋ฅผ ํ์ด์ง ๋จ์๋ก ํ์ํ๊ณ ๋ฌธ์๋ฅผ ์ฝ์ ์ ์์ต๋๋ค.
๋ฌธ์ ๋ฌธ์ ์ ๊ณ์ฐ์ ํฌ๊ธฐ๊ฐ ์ ํ๋ ์ค๋ ๋ ์์ ์บ์๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋์ ์ฝ๊ธฐ๋ ์บ์ ์ ๊ธ ๋ค์์ ์ ์ฒด ํ์ผ ์ค์บ์ ์ง๋ ฌํํ์ง ์์ต๋๋ค.
### ๋ณด๊ด ์ ์ฝ๊ธฐ ๋์
ํ๋ก์ ํธ๋ฅผ ๋ณด๊ดํ๋ฉด ์ฐ๊ธฐ๋ ๋๊ฒฐ๋์ง๋ง ์ฝ๊ธฐ๋ ์ ์ง๋ฉ๋๋ค. ๋ณด๊ด๋ ํ๋ก์ ํธ์ ์ค๋ ๋๋ ์ฌ์ ํ ์คํ๋๊ณ ํ๋ก์ ํธ์ ์ง์นจ๊ณผ ์๊ฐ ์ธ๋ฑ์ค๋ฅผ ๊ณ์ ๋ฐ์ผ๋ฉฐ, ์๊ฐ๋ ์์ ํ ์ฝ์ ์ ์์ต๋๋ค. ์ฆ ๋ชฉ๋ก ๋ณด๊ธฐ, ๋ฏธ๋ฆฌ ๋ณด๊ธฐ/๋ค์ด๋ก๋, ๋ํ ํ์ผ ๋ธ๋ผ์ฐ์ , ์ค๋ ๋์ ์ฒจ๋ถ ๊ธฐ๋ฅ์ด ๋ชจ๋ ๊ณ์ ๋์ํฉ๋๋ค. ์
๋ก๋, ํ๋ก์ ํธ์ ์ ์ฅ, ๊ฐ๋ณ ์๊ฐ ํ์ผ์ ํด์งํต์ผ๋ก ์ฎ๊ธฐ๋ ์์
์๋ ํ์ฑ ํ๋ก์ ํธ๊ฐ ํ์ํ๋ฉฐ, ํด์งํต์ ์๋ ๋ฌธ์๋ ๋ณด๊ด๋ ํ๋ก์ ํธ๋ก ๋ณต์ํ ์ ์์ต๋๋ค.
๋ณด๊ด๋ ํ๋ก์ ํธ์ ์ญ์ ๋ ๊ณ์ ํ์ฉ๋๋ฉฐ, ์ญ์ ํ๋ฉด ์๊ฐ ์ ์ฒด๊ฐ ํด์งํต์ผ๋ก ์ด๋ํฉ๋๋ค.
### ํด์งํต
์๊ฐ ๋ฌธ์๋ฅผ ์ญ์ ํ๋ฉด ์ง์์ง๋ ๋์ ํด์งํต์ผ๋ก ์ด๋ํฉ๋๋ค. ํด๋น ํญ๋ชฉ์ ๋ณด์กด ์ ๋ฆฌ ์์
์ด ์๊ตฌ์ ์ผ๋ก ์ ๊ฑฐํ ์ ์๊ฒ ๋๊ธฐ ์ ๊น์ง `projects.trash_retention_days`(๊ธฐ๋ณธ๊ฐ 30) ๋์ ๋ฐ์ดํธ์ ์๋ ํ๋ก์ ํธ์ ์ค๋
์ท์ ์ ์งํฉ๋๋ค. ํ๋ก์ ํธ ํ์ด์ง์ Documents ์น์
๊ณผ ์ฌ์ด๋๋ฐ์ Projects ํค๋์์ ์ ๊ทผํ ์ ์๋ `/workspace/trash` ํ์ด์ง๋ ํด์งํต์ ์๋ ๋ฌธ์๋ฅผ ์๋ ํ๋ก์ ํธ์ ๋จ์ ๋ณด์กด ๊ธฐ๊ฐ๊ณผ ํจ๊ป ๋์ดํ๋ฉฐ, ํญ๋ชฉ๋ณ Restore ๋ฐ Delete permanently ๋์๊ณผ ํจ๊ป, ํด์งํต์ ๋ชจ๋ ๋ฌธ์๋ฅผ ๋ณด์กด ๊ธฐ๊ฐ์ด ๋๋ ๋ค๊ฐ ์๋๋ผ ์ฆ์ ์๊ตฌ ์ญ์ ํ๋ Empty trash ๋์์ ์ ๊ณตํฉ๋๋ค. ๋ณด์กด ๊ธฐ๊ฐ์ ๋ณด์กด ์ ๋ฆฌ ์์
์ด ํญ๋ชฉ์ ํ์ํ๊ธฐ ์ ๊น์ง ํญ๋ชฉ์ด ํด์งํต์ ๋จธ๋ฌผ ์ ์๋ ๊ธฐ๊ฐ์ ์ํ์ผ ๋ฟ์
๋๋ค. Restore๋ ๋ฌธ์๋ฅผ ์๋ ํ๋ก์ ํธ๋ก ๋๋๋ฆฌ๋ฉฐ, ์๋ ํ๋ก์ ํธ๊ฐ ์๊ฑฐ๋ ๋ณด๊ด๋ ๊ฒฝ์ฐ์๋ ์ฌ์ฉ์๊ฐ ์ ํํ ํ๋ก์ ํธ๋ก ๋๋๋ฆฝ๋๋ค. ๋์ ํ๋ก์ ํธ์ ์ด๋ฏธ ๋์ผํ ํ์ฑ ํ์ผ์ด ์์ผ๋ฉด ๋ ํญ๋ชฉ์ ๋ณํฉ๋ฉ๋๋ค.
ํ๋ก์ ํธ๋ฅผ ์ญ์ ํ๋ฉด ๊ฐ์ ๋จ๊ณ์์ ํด๋น ํ๋ก์ ํธ์ ์๊ฐ ์ ์ฒด๊ฐ ํด์งํต์ผ๋ก ์ด๋ํฉ๋๋ค.
## ์์ฝ ์์
DeerFlow๋ ์ด์ ์ํฌ์คํ์ด์ค์ ์ผ๊ธ(first-class) ๊ธฐ๋ฅ์ผ๋ก ์์ฝ ์์
MVP๋ฅผ ์ ๊ณตํฉ๋๋ค.
์ผํ์ฑ ์์
์ ์ ๋ชฉ์ด๋ ํ๋กฌํํธ๋ฅผ ํธ์งํด๋ ์๋ ์คํ ์๊ฐ์ ์ ์ง๋๋ฉฐ, ์ฌ๊ธฐ์๋ ์ด ๋จ์ ๊ฐ๊ณผ ์๋จธํ์ ์ข
๋ฃ๋ก ์๊ณ๊ฐ ๋๋์๊ฐ๋ ๋์ ์ ํํ ํ์ฐจ๋ ํฌํจ๋ฉ๋๋ค. ๋ ์ง, ์๊ฐ ๋๋ ์๊ฐ๋๋ฅผ ๋ณ๊ฒฝํ๋ฉด ์คํ ์๊ฐ์ด ๋ค์ ๊ณ์ฐ๋ฉ๋๋ค. ํธ์ง ์ค์ ๋ค๋ฅธ ์์
์ผ๋ก ์ ํํ๋ฉด ์ ํํ ์์
์์ฒด์ ์ ๋ชฉ, ํ๋กฌํํธ, ์ผ์ ์ ๋ถ๋ฌ์ต๋๋ค.
๋ณ๊ฒฝํ์ง ์์ ์ผํ์ฑ ์คํ ์๊ฐ์ ์คํ๊น์ง `scheduler.min_once_delay_seconds` ์ด๋ด๋ก ๋จ์๋๋ผ๋ ๊ณ์ ์ ์ฅํ ์ ์์ต๋๋ค. ์ ์คํ ์๊ฐ๊ณผ ๋ค์ ํ์ฑํํ ์๋ฃ ์์
์ ์ด ์ต์ ์ง์ฐ ์๊ฐ์ ์ถฉ์กฑํด์ผ ํฉ๋๋ค.
ํ์ฌ MVP ๊ธฐ๋ฅ:
- `/workspace/scheduled-tasks`์์ ์์
์ ๊ด๋ฆฌํ ์ ์์ต๋๋ค
- ์ผํ์ฑ ์์
์์์ ์๋จธํ์ ์ ํ์ผ๋ก ๊ฑด๋๋ฐ๊ฒ ๋๋ ํ์ง ์๊ฐ์ ๊ฑฐ๋ถํฉ๋๋ค. ์์
์ ์์ฑํ๊ฑฐ๋ ์ ์ฅํ๊ธฐ ์ ์ ๋ค๋ฅธ ์๊ฐ์ ์ ํํ์ธ์.
- ๋ํ๋ API๊ฐ ์๋จธํ์์ผ๋ก ๊ฑด๋๋ฐ๊ฒ ๋๋ ํ์ง ์๊ฐ์ ์ ์ฅํ ๊ฒฝ์ฐ์๋, ๊ธฐ์กด ์ผํ์ฑ ์์
์ ์ค์ผ์ค๋ฌ์ ์คํ ์๊ฐ์ ํ์ํฉ๋๋ค. ๋ช
์์ ์ธ ์คํ์
์ด ์๋ ํ์ง ์๊ฐ์ ๋ฐ๋ณต๋๋ ํ ์๊ฐ ๊ตฌ๊ฐ ์ค ์ฒซ ๋ฒ์งธ ์์ ์ ์ฌ์ฉํฉ๋๋ค.
- ๊ฐ ์์ฝ ์์
์ด ์ค๋ ๋์ ๊ทธ ๋ํ ๊ธฐ๋ก์ ์ฌ์ฌ์ฉํ ์ง, ์คํ(run)๋ง๋ค ์ ์ค๋ ๋๋ฅผ ๋ง๋ค์ง ์ ํํ ์ ์์ต๋๋ค
- ๊ฐ ์์
์ `lead_agent`(๊ธฐ๋ณธ๊ฐ) ๋๋ ์์ ์๊ฐ ์ด๋ฏธ ๊ฐ์ง๊ณ ์๋ ์ปค์คํ
์์ด์ ํธ์ ๊ณ ์ ํ ์ ์์ผ๋ฉฐ, ์ ์ ์๋ ์ด๋ฆ์ ๊ฑฐ๋ถ๋ฉ๋๋ค
- ์์ฝ ์์
PATCH์์ `assistant_id: null`์ ๋ณด๋ด๋ฉด ์์
์ด `lead_agent`๋ก ์ฌ์ค์ ๋ฉ๋๋ค. `assistant_id`๋ฅผ ์๋ตํ๋ฉด ํ์ฌ ์์ด์ ํธ๊ฐ ์ ์ง๋๋ฉฐ, ํด๋น ์ปค์คํ
์์ด์ ํธ๊ฐ ๊ทธ์ฌ์ด ์ญ์ ๋ ๊ฒฝ์ฐ์๋ ๋ง์ฐฌ๊ฐ์ง์
๋๋ค
- ๊ธฐ์กด ์์
์ ์คํ ๊ธฐ๋ก์ ๋ณต์ฌํ์ง ์๊ณ ํธ์ง ๊ฐ๋ฅํ ์ด์์ผ๋ก ์์ฑ ์์์ ๋ณต์ ํ ์ ์์ต๋๋ค
- `once`, `cron`, `interval` ์ผ์ ์ ์ง์ํฉ๋๋ค
- ๊ฐ๊ฒฉ ์์
์ ํธ์งํ๊ฑฐ๋ ๋ณต์ ํด๋ ๊ฐ๊ฒฉ์ ๋ช
์์ ์ผ๋ก ๋ณ๊ฒฝํ๊ธฐ ์ ๊น์ง๋ ์ ์ฅ๋ ์ฃผ๊ธฐ๊ฐ ์ ์ง๋๋ฉฐ, ์ด์์์ ์ค์ผ์ค๋ฌ ์ค์ ์ด ํ์ฉํ๋ 1๋ถ ๋ฏธ๋ง ๊ฐ๊ฒฉ๋ ๋ง์ฐฌ๊ฐ์ง์
๋๋ค
- ๋ฐฑ๊ทธ๋ผ์ด๋ ์์ฝ ์คํ์ ๋น๋ํํ DeerFlow ์คํ์ผ๋ก ์ํํฉ๋๋ค(์ฌ๊ธฐ์๋ `ask_clarification`์ด ๋
ธ์ถ๋์ง ์์ต๋๋ค)
- ์ฌ์ฌ์ฉํ๋ ์ค๋ ๋๋ ์ ์ญ ์คํ ์์ฐ์ด ์ฌ์ฉ ์ค์ด๋ฉด ์คํ ์์ ์ด ๋ ์คํ์ `queued`๋ก ์์ ์ ์ฅํ ๋ค, ์ฌ์ ๊ฐ ์๊ธฐ๋ฉด ์์ํฉ๋๋ค. ๋๊ธฐ ์ค์ธ ํ์ฐจ๋ Gateway๊ฐ ์ฌ์์๋์ด๋ ์ ์ง๋๋ฉฐ `scheduler.queue_timeout_seconds`๊ฐ ์ง๋๋ฉด ์คํจํฉ๋๋ค
- ์์
์์ ์ ๊ฐ์ ์คํ ์ฌ๋กฏ์ ๊ณต์ ํ๊ฒ ๋๋๋๋ค. ํ ์์ ์๋ ๋์์ ์์ ์ค์ด๊ฑฐ๋ ์คํ ์ค์ธ ์์ฝ ์คํ์ ์ต๋ `scheduler.max_concurrent_runs_per_user`๊ฐ๊น์ง ๊ฐ์ง ์ ์์ผ๋ฉฐ(๊ธฐ๋ณธ๊ฐ 2, `max_concurrent_runs`๋ฅผ ๋์ ์ ์์, `0`์ด๋ฉด ์์ ์๋ณ ์ํ์ด ๊บผ์ง), ๋๊ธฐ ํ๋ ์์ ์๋ณ๋ก ๋ฒ๊ฐ์ ์ฒ๋ฆฌ๋๋ฏ๋ก ํ ์์ ์์ ์ ์ฒด๊ฐ ๋ค๋ฅธ ์์ ์์ ์คํ์ ๋ง์ง ์์ต๋๋ค. `scheduler.queue_timeout_seconds`๋ณด๋ค ์ค๋ ๊ธฐ๋ค๋ฆฐ ์คํ์ ๊ฑด๋๋ฐ๋ฉฐ, ๊ทธ ๊ธฐ๋ก์๋ "Skipped: it waited too long for a free slot"์ด ํ์๋ฉ๋๋ค
- ํ์ฐจ๊ฐ `queued`, `launching`, `running` ์ํ์ธ ๋์์๋ ์์
์ ์๋ฅผ ๊ณ ์ ํ๋ฏ๋ก, ์์ ํ์ฐจ๊ฐ ๋ค๋ฅธ ํ๋กฌํํธ, ์ค๋ ๋, ์ผ์ ์ ์กฐ์ฉํ ๋ฐ์ํ๋ ์ผ์ด ์์ต๋๋ค. ์์
์ ์ผ์ ์ค์ง ์ํ๋ก ์ ํํ๊ฑฐ๋ ์ญ์ ํ๋ฉด ๊ธฐ์กด์ ๋๊ธฐ ์ค์ธ ํ์ฐจ๊ฐ ์ทจ์๋์ง๋ง, `launching`/`running` ์์
์ ์ด๋ฌํ ๋ณ๊ฒฝ์ ์ฌ์๋ํ๊ธฐ ์ ์ ์๋ฃ๋์ด์ผ ํ๋ฉฐ, ๋ช
์์ ์ธ ์๋ ํธ๋ฆฌ๊ฑฐ๋ ์ผ์ ์ค์ง๋ ์ผ์ ์ ์ฌ๊ฐํ์ง ์๊ณ ๋ ์ฌ์ ํ ๋๊ธฐํ๋ค๊ฐ ์คํ๋ ์ ์์ต๋๋ค
- ์์
์ ์ผ์ ์ค์ง, ์ฌ๊ฐ, ํธ๋ฆฌ๊ฑฐ, ๊ธฐ๋ก ์กฐํ, ์ญ์ ํ ์ ์์ต๋๋ค
- ์ํ/์ ํ ํํฐ ๋ฐ ํ์ฌ ์ค๋ ๋ ๋ฒ์์ ํจ๊ป ์์
์ ๋ชฉ์ด๋ ํ๋กฌํํธ๋ฅผ ๊ฒ์ํ ์ ์์ต๋๋ค.
- ์์ฝ๋ ์์
์ ์ผ๋ฐ DeerFlow ์คํ ์๋ช
์ฃผ๊ธฐ๋ฅผ ํตํด ์คํํฉ๋๋ค
- `channel_connections.enabled: true`์ด๋ฉด, ๋ฅ๋ ํธ์(proactive push)๋ฅผ ์ง์ํ๋ ์ฑ(ํ์ฌ WeCom, Feishu/Lark, WeChat, QQ ๊ฐ์ธ ์ฑํ
)์์ ์์
์์ ์์ ์ฐ๊ฒฐ๋ IM ์๋ณ ์ ๋ณด๋ก ์์ฝ ์์
์
๋ฐ์ดํธ๋ฅผ ๋ณด๋
๋๋ค(์์๋ฐ์ค(outbox) + ์ ๋ฌ ์์ปค). Settings โ Notifications์์ ์ฐ๊ฒฐ๋ ์ฑ๋ณ๋ก ๋ฅ๋ ์
๋ฐ์ดํธ๋ฅผ ์ ์ดํ๋ฉฐ, ์ด๋ ๋ธ๋ผ์ฐ์ ์๋ฆผ ๋ฐ ์ผ๋ฐ ์ฑํ
์๋ต๊ณผ๋ ๋
๋ฆฝ์ ์
๋๋ค. ๊ฐ ํ์ฐจ๋ ๋์๋ง๋ค ์ต๋ ํ๋์ ๋ฉ์์ง๋ฅผ ํ์ ๋ฃ์ต๋๋ค. ํด๋นํ๋ ๊ฒฝ์ฐ๋ ์๋ฃ, ์คํจ ๋๋ ๋ชฉํ ๋ฏธ๋ฌ์ฑ ์คํ, ๋ชฉํ๋ฅผ ์ธ ๋ฒ ๋์น ๋ค์ ์๋ ์ผ์ ์ค์ง, ์์ด์ ํธ์ ์ํ ์ผ์ ์ค์ง(์ค์ง ์กฐ๊ฑด ์ถฉ์กฑ), ์์
์ข
๋ฃ(`max_runs`๋ฅผ ๋ชจ๋ ์์ง, `end_at` ๋๋ฌ)์
๋๋ค. ์ฌ๋ฌ ๊ฒฝ์ฐ๊ฐ ๊ฒน์น๋ฉด ์ผ์ ์ค์ง ๋๋ ์ข
๋ฃ๊ฐ ์ฐ์ ํ๋ฉฐ, ์ด๋๋ ๋ง์ง๋ง ์คํ ๊ฒฐ๊ณผ๋ฅผ ํจ๊ป ์๋ ค์ค๋๋ค. ์ผํ์ฑ ์์
์ ํด๋น ์คํ์ ๊ฒฐ๊ณผ๋ง ๋ณด๋
๋๋ค. ๋ฉ์์ง๋ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋กํ๋ ๊ฒ๊ณผ ๊ฐ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํธ๋์ญ์
์์ ํ์ ๋ค์ด๊ฐ๋ฏ๋ก, ํฌ๋์๋ ๋ฆฌ์ค ์์ค ํ์ ๋ง๋ฌด๋ฆฌ๋ ์คํ์ด ๊ฐ์ ๋์์ ์ค๋ณต ์๋ฆผ์ ๋ฃ์ง ์์ต๋๋ค. ๋ฉ์์ง๋ ๊ทธ ์์ฒด๋ง์ผ๋ก ์ดํดํ ์ ์๋๋ก ์น UI ์ธ์ด(์์ผ๋ฉด `channel_connections.notification_locale`)๋ก ์์ฑ๋๋ฉฐ, ์์
์ ๋ชฉ, ๋ฐ์ํ ์ผ, ์์ด์ ํธ๊ฐ ์๋ตํ ๊ฒฝ์ฐ ํ ์ค ๊ฒฐ๊ณผ, ๊ทธ๋ฆฌ๊ณ "Open DeerFlow โ Scheduled tasks for details."๋ฅผ ๋ด๊ณ , ID๋ ๋งํฌ๋ ํฌํจํ์ง ์์ต๋๋ค. ๋จ์ ์๋ "run now" ์ํ ์คํ๊ณผ ์ค๋จ๋ ์คํ์ ์๋ฆผ์ ๋ณด๋ด์ง ์์ผ๋ฉฐ, ์๋ฃ๋ ์คํ ์์ด ๋๋๋ ํ์ฐจ(์์ ์ค๋ฅ, ํ ํ์์์, ์ฌ์์์ผ๋ก ์ธํ ์ค๋จ)๋ ๋ง์ฐฌ๊ฐ์ง์
๋๋ค. ์ฑ๋/์ ์ก ๊ณ์ธต ์ฅ์ ์์๋ ์ฌ์๋ ํ์๋ฅผ ์์งํ์ง ์๊ณ ์ต๋ ์ฝ ํ๋ฃจ ๋์ ์ ๋ฌ์ ๋ณด๋ฅํฉ๋๋ค. ํ๋ซํผ์ด ๊ฑฐ๋ถํ๋ฉด ์ฝ 15๋ถ ๋์ ์ฌ์๋ํ ๋ค `failed`๋ก ํ์ ๋ฉ๋๋ค. ์ ๋ฌ ๋๊ธฐ ์ค์ ์ฐ๊ฒฐ์ ํด์ ํ ์๋ณ ์ ๋ณด์๋ ์ ๋ ํธ์ํ์ง ์์ผ๋ฉฐ, ํด๋น ํ์ `failed`๋ก ํ๊ธฐ๋ฉ๋๋ค.
- ์คํ ๊ธฐ๋ก์ 50๊ฐ ๋จ์ ํ์ด์ง๋ก ํ์ํ ์ ์์ต๋๋ค. ์ด์ ํ์ด์ง์์๋ ์๋ ์๋ก ๊ณ ์นจ์ด ์ผ์ ์ค์ง๋๋ฉฐ, ์ต์ ์คํ์ผ๋ก ๋ช
์์ ์ผ๋ก ๋์๊ฐ ์ ์์ต๋๋ค. ๊ฐ์๋ ์ฝ๊ธฐ์ ์ฑ๊ณตํ ๋ค์๋ง ํ์๋๋ฉฐ, ๋ก๋ฉ ์ค์ด๊ฑฐ๋ ์ฝ๊ธฐ์ ์คํจํ ๊ฒฝ์ฐ๋ฅผ ์คํ 0๊ฑด์ผ๋ก ๋ณด๊ณ ํ์ง ์์ต๋๋ค.
ํ์๋ ์คํ ์์ฝ์ ํ
์คํธ ๊ธธ์ด๋ฅผ ์ ํํ๊ธฐ ์ ์ ์๋ถ๋ถ์ ์ธ๋ผ์ธ `` ์ถ๋ก ์ ์๋ตํ๋ฏ๋ก, ๊ธด ์ฌ๊ณ ๊ณผ์ ์ด ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ์์ฝ ์๋ฆผ์์ ์ค์ ๋ต๋ณ์ ๋ฐ์ด๋ด์ง ์์ต๋๋ค. ์๋ณธ ์๋ต ๊ธฐ๋ก๊ณผ ๋ต๋ณ ์์ ๋ฆฌํฐ๋ด ํ๊ทธ๋ ๋ณ๊ฒฝ๋์ง ์์ผ๋ฉฐ, ์ด์ ์ ์ ์ฅ๋ ์คํ ์์ฝ์ ๋ค์ ์์ฑ๋์ง ์์ต๋๋ค.
**API๋ก ์คํ ๊ธฐ๋ก ํํฐ๋ง**
์ฑ๊ณตํ ํ์ฐจ๋ฅผ ๋ชจ๋ ๋ด๋ ค๋ฐ์ง ์๊ณ ์คํจ๋ง ์ดํด๋ณด๋ ค๋ฉด, `threads:read` ๊ถํ์ด ์๋ ์ธ์ฆ๋ ํด๋ผ์ด์ธํธ๊ฐ ์์ ํ ์์
์ ๋ํด `GET /api/scheduled-tasks/{task_id}/runs?status=failed&limit=50&offset=0`์ ์์ฒญํ ์ ์์ต๋๋ค. ์ ํ ์ฌํญ์ธ `status`๋ `queued`, `launching`, `running`, `success`, `failed`, `skipped`, `interrupted`, `unmet` ์ค ํ๋๋ฅผ ๋ฐ์ต๋๋ค. ์ด ๊ฐ๋ค์ ํ์ฐจ ์ํ์ด๋ฏ๋ก `completed` ๊ฐ์ ์์
์ํ๋ ์ ํจํ์ง ์์ต๋๋ค(422).
ํํฐ๋ง์ ํ์ด์ง๋ค์ด์
๋ณด๋ค ๋จผ์ ์ด๋ฃจ์ด์ง๋๋ค. `limit`(1โ200, ๊ธฐ๋ณธ๊ฐ 50)๊ณผ `offset`(์์ด ์๋ ์ ์, ๊ธฐ๋ณธ๊ฐ 0)์ ์ผ์นํ๋ ๋ ์ฝ๋์ ์ ์ฉ๋๋ฉฐ, ๋ ์ฝ๋๋ ์์ฑ ์๊ฐ, ๊ทธ๋ค์ ID ๊ธฐ์ค์ผ๋ก ๋ชจ๋ ๋ด๋ฆผ์ฐจ์ ์ ๋ ฌ๋ฉ๋๋ค. `status`๋ฅผ ์๋ตํ๋ฉด ๊ธฐ์กด์ ํผํฉ ๊ธฐ๋ก ๋ฐฐ์ด ์๋ต์ด ์ ์ง๋๋ฉฐ, ์ผ์นํ๋ ํญ๋ชฉ์ด ์์ผ๋ฉด `[]`๋ฅผ ๋ฐํํฉ๋๋ค. ์ด API๋ ์์
์คํ์ ๋ณ๊ฒฝํ์ง ์์ผ๋ฉฐ, ์ํฌ์คํ์ด์ค ๊ธฐ๋ก UI๋ ๊ณ์ ํํฐ๋ง ์์ด ํ์๋ฉ๋๋ค.
ํ์ฌ MVP ์ ํ:
- ํ
์คํธ ์ ์ฉ ์๋ฆผ ์์
์ ์ง์ํ์ง ์์ต๋๋ค
- ์ฑ๋ ๋๋ GitHub ๋์คํจ์น ๋์์ ์ง์ํ์ง ์์ต๋๋ค(์์ ๊ฒฐ๊ณผ ํธ์๋ ๋์คํจ์น ๋์์ด ์๋๋๋ค)
`config.yaml -> scheduler.enabled`๋ก ๋ฐฑ๊ทธ๋ผ์ด๋ ํด๋ง์ ํ์ฑํํ์ธ์. ์๋ ํธ๋ฆฌ๊ฑฐ๋ ๋์ผํ ์์ฝ ์์
๋ฆฌ์์ค์ ์คํ ๊ฒฝ๋ก๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์์
์์์์ ๋งค์๊ฐ, ๋งค์ผ, ๋งค์ฃผ ๋๋ ๋งค์ ์ผ์ ์ **Custom cron**์ผ๋ก ์ ํํ๋ฉด, ์ ํํ ์์ผ์ด๋ ๋ ์ง๋ฅผ ํฌํจํ ํ์ฌ ์๊ฐ ์ค์ ์์ ์์ํฉ๋๋ค. ํ๋ฆฌ์
์ ํธ์งํ ๋ค ๋ค์ Custom cron์ผ๋ก ์ ํํ๋ฉด ์ด์ ํํ์์ด ์๋๋ผ ๊ทธ ํธ์ง ๋ด์ฉ์ ์ฌ์ฉํฉ๋๋ค.
### ๋ฅ๋ IM ์๋ฆผ ์ ์ด
**Settings โ Notifications โ IM notifications**๋ฅผ ์ด์ด ์ฐ๊ฒฐ๋ ํธ์ ์ง์ ์ฑ๋ณ๋ก ์์ฝ ์์
์
๋ฐ์ดํธ๋ฅผ ์ผ๊ฑฐ๋ ๋ ์ ์์ต๋๋ค. ๊ธฐ์กด ์ฐ๊ฒฐ์ ์ตํธ์์ํ ๋๊น์ง ๊ณ์ ์
๋ฐ์ดํธ๋ฅผ ๋ฐ์ต๋๋ค. ์ฑ๋์ ๋๋ฉด ๋ช
์์ ์ผ๋ก ์ ํํ Feishu ๊ทธ๋ฃน์ ํฌํจํด ๋๊ธฐ ์ค์ด๊ฑฐ๋ ์ฌ์๋ ์ค์ธ ์๋ฆผ์ด ์ทจ์๋๋ฉฐ, ๋ค์ ์ผ๋ ์ด์ ์ ์์ธ ์๋ฆผ์ ์ฌ์ ์ก๋์ง ์์ต๋๋ค. ํ๋ซํผ ์ ๋ฌ์ด ์ด๋ฏธ ์์๋ ์๋ฆผ์ ์ฌ์ ํ ๋์ฐฉํ ์ ์์ต๋๋ค. ์ฑํ
์๋ต๊ณผ ์์ฝ ์คํ์๋ ์ํฅ์ด ์์ต๋๋ค. ์ด ์๋ฆผ ์ค์ ์ด ์ ์ฉ๋๋ ค๋ฉด ๋ชจ๋ Gateway ์์ปค๊ฐ ์
๊ทธ๋ ์ด๋๋ ๋ฒ์ ์ ์คํํด์ผ ํฉ๋๋ค.
WeChat์ ๋ฐ์ธ๋ฉ ํ ํ์ฌ ๋ํ ์ปจํ
์คํธ๋ฅผ ์์ ํ๊ฒ ์ ์ฅํ๊ธฐ ์ํด ๊ฐ์ธ ๋ฉ์์ง๊ฐ ํ์ํ๋ฉฐ, ์ค๋๋ ๋ฐ์ธ๋ฉ์ด๊ฑฐ๋ ๋ด ํ ํฐ์ด ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ์๋ ์ ๊ฐ์ธ ๋ฉ์์ง๊ฐ ํ์ํฉ๋๋ค. QQ๋ ๋ฅ๋ ์ ์ก์ ์ํด C2C/๊ฐ์ธ ๋ฐ์ธ๋ฉ๊ณผ ํ๋ซํผ ๊ถํ์ด ํ์ํฉ๋๋ค. ์ด ๋ฒ์ ์ WeChat์ด๋ QQ ๊ทธ๋ฃน ๋์์ ์ถ๊ฐํ์ง ์์ต๋๋ค. [์ค์ ๋ฐ ์ ๋ฌ ์ ํ](backend/docs/IM_CHANNEL_CONNECTIONS.md#proactive-notification-settings)์ ์ฐธ๊ณ ํ์ธ์.
### ์ ํ์ Feishu ๊ทธ๋ฃน ์๋ฆผ
์์
์ ์์ฑ ๋๋ ํธ์ง ์์์์ **Also notify a Feishu group (optional)** ์ต์
์ ๊ธฐ์กด ๊ฐ์ธ ์๋ฆผ์ ์ ํํ ๊ทธ๋ฃน ํ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค. ์ฑ ๋ด์ ๊ทธ๋ฃน์ ์ถ๊ฐํ๊ณ , **Bind a Feishu group**์ ์ฌ์ฉํด ๋ช
๋ น์ ๋ฐ์ ๋ค์, ํด๋น ๊ทธ๋ฃน์์ ๋ด์ ๋ฉ์
ํ๋ฉด์ ๊ทธ ๋ช
๋ น์ ๋ณด๋ด๊ณ , ๋ชฉ๋ก์ ์๋ก ๊ณ ์น ๋ค ์ด๋ฆ์ผ๋ก ๊ทธ๋ฃน์ ์ ํํ์ธ์. ์ฑ์๋ ๋ด ๋ฉ์์ง ์ ์ก ๊ถํ์ด ํ์ํ๊ณ , ๊ทธ๋ฃน ์ด๋ฆ์ ํ์ํ๋ ค๋ฉด `im:chat:read`๋ ํ์ํฉ๋๋ค.
์์์ด ๊ทธ๋ฃน ์๋ฆผ ์ง์ ์ฌ๋ถ๋ฅผ ํ์ธํ๋ ๋์์๋ ๋ก๋ฉ ์๋ด๋ฅผ ํ์ํ๊ณ ์ ์ฅ๋ ์ ํ์ ์ ์งํฉ๋๋ค.
๊ทธ๋ฃน์ ์๋์ผ๋ก ์ ํ๋์ง ์์ต๋๋ค. ์ ํ์ ํด์ ํ๋ฉด ์ ๊ทธ๋ฃน ์๋ฆผ์ด ์ค์ง๋๊ณ , ์ ํ์ ๋ณ๊ฒฝํ๋ฉด ์ดํ ์๋ฆผ์ ๋ฐ์๋๋ฉฐ, ์ด๋ฏธ ํ์ ๋ค์ด๊ฐ ์๋ฆผ์ ์๋ ๋์์ ์ ์งํฉ๋๋ค. ์ฐ๊ฒฐ์ด ํด์ ๋ ๋ฐ์ธ๋ฉ์ ๋๊ธฐ ์ค์ธ ์๋ฆผ์ ์ ๋ ๋ฐ์ง ์์ต๋๋ค. ์ฒซ ๋ฒ์ ์์๋ ์์
์์ ๋๋ REST API๋ก ์ค์ ํ๋ฉฐ, ๋ํ์ฉ ์ผ์ ๋๊ตฌ์ ์
๋ ฅ์ ๊ธฐ์กด๊ณผ ๊ฐ์ต๋๋ค. [๊ทธ๋ฃน ์ ๋ฌ ๊ฐ์ด๋](backend/docs/IM_CHANNEL_CONNECTIONS.md#feishu-group-notifications)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
### ์๋ช
์ฃผ๊ธฐ, ์์ ์ํ, ์ค์ง ์กฐ๊ฑด
- ์์
ํ์ด์ง์ REST API(`POST` / `PATCH /api/scheduled-tasks`)๋ ๋ํ์ ๋์ผํ๊ฒ ์คํ๋ณ ๋ชฉํ(`goal_objective`), ์์ ์ํ(`max_runs`, `end_at`), ์ค์ง ์กฐ๊ฑด(`stop_condition`)์ ๋ฐ์ต๋๋ค. PATCH์์ `null`์ ๋ณด๋ด๋ฉด ์ด ๋ค ๊ฐ์ง ์ค ์ด๋ ๊ฒ์ด๋ ์ง์ธ ์ ์์ผ๋ฉฐ, UTC ์คํ์
์ด ์๋ `end_at`์ ์์
์๊ฐ๋์ ๋ฒฝ์๊ณ ์๊ฐ์ผ๋ก ํด์๋ฉ๋๋ค.
- ์ค์ง ์กฐ๊ฑด์ ์ฌ์ฉ์์ "โฆ๋๋ฉด ์ค์ง" ๊ท์น์
๋๋ค. ์ด๋ ์์ฒด ํ๋(๋ง์ด๊ทธ๋ ์ด์
`0031`)์ ์ ์ฅ๋๋ฉฐ, ์์
์ง์ ์์๋ ์ ๋ ์ ์ฅ๋์ง ์์ต๋๋ค. ์คํ์ด ์์๋ ๋์๋ง DeerFlow๊ฐ ์ด๋ฅผ ํด๋น ์คํ์ ๋ฉ์์ง์ ๋ง๋ถ์ด๊ณ , ๊ท์น์ด ์ถฉ์กฑ๋๋ฉด `stop_scheduled_task`๋ฅผ ํธ์ถํ๋๋ก ์คํ์ ์์ฒญํฉ๋๋ค. `scheduler.tool_enabled`๊ฐ ์ผ์ ธ ์๋ ๋์์๋ ์ฑํ
์์ ๋ง๋ ์์
์ด๋ ์์
ํ์ด์ง์์ ๋ง๋ ์์
์ด๋ ๋ชจ๋ ์์ฝ ์คํ์ด ์์ ์ ์ผ์ ์ ์ค์งํ ์ ์์ต๋๋ค. ๊บผ์ ธ ์์ผ๋ฉด ์คํ์ ๊ฐ๊ณ ์์ง ์์ ๋๊ตฌ๋ฅผ ํธ์ถํ๋ ๋์ ๊ท์น์ด ์ถฉ์กฑ๋์์์ ๋ณด๊ณ ํ๋๋ก ์์ฒญ๋ฐ์ต๋๋ค.
- ์์
ํ์ด์ง์์ ๋ง๋ ๋ชฉํ ์์
๋ ์ด์ ์ฑํ
์์ ๋ง๋ ์์
๊ณผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ํ๊ฐ๋๋ฉฐ, ๊ทธ ์คํ๋ ์ ์ฅ๋ ๋ฉ๋ชจ์ ์ด์ ์คํ ์ฐธ์กฐ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ๊ฐ๋ ํ์ฌ ์์ ๋ถํฐ ๋ค์ ์คํ์ ๊ณ์ฐํ๋ฏ๋ก, ์ค๋ ์ผ์ ์ค์ง๋์๋๋ผ๋ ๋ฐ๋ผ์ก๊ธฐ ์คํ์ด ๋ฐ์ํ์ง ์์ต๋๋ค. ์๊ฐ์ด ์ด๋ฏธ ์ง๋ ์ผํ์ฑ ์์
์ `422 once_time_passed`๋ฅผ ๋ฐํํ๋ฉฐ ์ ์๊ฐ์ด ํ์ํฉ๋๋ค. ํ์ฑ ์์
์ ์ฌ๊ฐํด๋ ์๋ฌด๊ฒ๋ ๋ฐ๋์ง ์์ผ๋ฉฐ, ์๋ฃ๋ ์์
์ ์ผ์ ์ค์งํ๋ฉด `409 task_finished`๋ฅผ ๋ฐํํฉ๋๋ค.
- `max_runs`๋ ์์
์ ์ฒด ๊ธฐ๊ฐ์ ๊ฑธ์น ์๋ ์คํ์ ๋์ ์ดํ์์ด๋ฉฐ, ์ํ ์คํ์ ์ ๋ ํฌํจ๋์ง ์์ต๋๋ค. ์ํ์ ๋ชจ๋ ์์งํ ์์
์ ๋ค์ ํ์ฑํํ๋ฉด(์ฌ๊ฐ, ๋๋ ์๋ฃ๋ ์์
์ ์ผ์ ์ ๋ค์ ํ์ฑํํ๋ PATCH) ๊ฐ์ ์์ฒญ์์ ์์ง๋ ์ ํ์ ๊ฐฑ์ ํ์ง ์๋ ํ `409 limits_exhausted`๋ฅผ ๋ฐํํฉ๋๋ค. ์์ง๋ ์คํ ํ์ ์ ํ์๋ ๋ ํฐ `max_runs` ๋๋ `null`์ด, ์ง๋๊ฐ ์ข
๋ฃ ์๊ฐ์๋ ๋ ๋ฆ์ `end_at` ๋๋ `null`์ด ํ์ํฉ๋๋ค(๋ ๋ฆ์ `end_at`๋ง์ผ๋ก๋ ์์ง๋ `max_runs`๊ฐ ๊ฐฑ์ ๋์ง ์์ต๋๋ค). `POST /api/scheduled-tasks/{task_id}/resume`์ ์ด๋ฅผ ์ํด ์ ํ์ ์ธ `{"max_runs": โฆ, "end_at": โฆ}` ๋ณธ๋ฌธ์ ๋ฐ์ต๋๋ค(`null`์ ์ํ์ ์ง์ฐ๋ฉฐ, ์ฑํ
์์ ๋ง๋ 1์๊ฐ ๋ฏธ๋ง ์ฃผ๊ธฐ ์์
์ ์ํ์ ํ๋ ์ ์งํด์ผ ํฉ๋๋ค). ์๋ฃ๋ ์์
์ ์ํ๋ง ๋ณ๊ฒฝํ๋ PATCH๋ ๋ณ๊ฒฝ ๋ด์ฉ์ ์ ์ฅํ๊ณ ์์
์ ์๋ฃ ์ํ๋ก ๋ก๋๋ค.
- ๋ชฉํ ํ์ธ ์คํจ(ํ๊ฐ์๊ฐ ์คํจํ๊ฑฐ๋ ํ์ธ ์ค์ ๋ํ๊ฐ ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ)๋ ์ธ ๋ฒ ๋ฏธ๋ฌ์ฑ ์์ ์๋ ์ผ์ ์ค์ง ํ์์ ํฌํจ๋์ง๋ ์๊ณ , ์ด๋ฅผ ์ด๊ธฐํํ์ง๋ ์์ต๋๋ค. ๋ชฉํ, ์์
์ง์ ๋๋ ์ค์ง ์กฐ๊ฑด์ ๋ณ๊ฒฝํ๊ฑฐ๋ ๋ฉ๋ชจ๋ฅผ ์ถ๊ฐํ๋ฉด ํ์๋ฅผ ์๋ก ์
๋๋ค. ์ฌ๊ฐ๋ ๊ธฐ์กด ํ์๋ฅผ ์ ์งํฉ๋๋ค.
- ์ด Gateway ํ๋ก์ธ์ค์ ์ค์ผ์ค๋ฌ๊ฐ ์คํ ์ค์ด ์๋ ๋์ ์์
์ ์์ฑํ๋ฉด(Duplicate ํฌํจ) `409 scheduler_not_running`์ ๋ฐํํฉ๋๋ค. ์์
์ด ์ผ์ ๋๋ก ์คํ๋์ง ์์ ๊ฒ์ด๊ธฐ ๋๋ฌธ์
๋๋ค. `GET /api/features`๋ `scheduled_tasks.available`, `running`, `tool_enabled`, `min_interval_seconds`๋ฅผ ๋ณด๊ณ ํฉ๋๋ค.
- `/api/scheduled-tasks*`์ ์ค๋ฅ๋ `{"detail": {"code", "message", "params"}}` ํ์์
๋๋ค. [`backend/docs/API.md`](backend/docs/API.md#scheduled-tasks)์ `contracts/scheduled_task_errors_contract.json`์ ์ฐธ๊ณ ํ์ธ์.
### ๋ํ์์ ์ผ์ ๋ง๋ค๊ธฐ
`scheduler.enabled: true`์ `scheduler.tool_enabled: true`๋ฅผ ๋ชจ๋ ์ค์ ํ ๋ค Gateway๋ฅผ ์ฌ์์ํ์ธ์. ๊ถํ์ด ์๋ ๋ํํ ํด์ `schedule_task`๋ฅผ ์ฌ์ฉํด ์์
์ ์์ฑ, ์
๋ฐ์ดํธ, ์กฐํ, ์ผ์ ์ค์ง, ์ฌ๊ฐ, ์ญ์ ํ๊ฑฐ๋, ์ํ ์คํ์ ์์ํ๊ฑฐ๋, ๋ฉ๋ชจ๋ฅผ ์ ์ฅํ ์ ์์ต๋๋ค. ์: โํ์ผ๋ง๋ค 9:00์ release-checklist.md๋ฅผ ํ์ธํ๊ณ ์์ง ์ฒดํฌ๋์ง ์์ ํญ๋ชฉ์ ์๋ ค์ค. ๋ชจ๋ ์ฒดํฌ๋๋ฉด ์ค์งํด.โ ์น ์ฑ์์๋ ๊ฒฐ๊ณผ๊ฐ ์ผ์ , ์ค์ง ์กฐ๊ฑด, ๋ฒํผ์ ๋ด์ ์ค์๊ฐ ์นด๋๋ก ํ์๋๊ณ ์์ด์ ํธ๋ ํ๋ ๋ฌธ์ฅ์ผ๋ก ๋ตํฉ๋๋ค. IM ๋ฐ ๊ธฐํ ์น์ด ์๋ ํด์์๋ ์ผ์ , ๋ค์ ์คํ, ์ค์ง ์กฐ๊ฑด์ ์ผ๋ฐ ํ
์คํธ๋ก ์ค๋ช
ํฉ๋๋ค.
- **๋ํ๊ฐ ๊ด๋ฆฌํ๋ ์์
.** ํด๋น ๋ํ์์ ๋ง๋ ์์
, ๊ทธ๋ฆฌ๊ณ ์คํ ๋ํ(์์ฝ ์คํ์ด ๊ฒฐ๊ณผ๋ฅผ ๊ฒ์ํ ์ฑํ
)์์๋ ๊ทธ ์คํ์ด ์ํ ์์
์
๋๋ค. ๊ทธ๊ณณ์์๋ โ์ด๊ฑฐ ์ผ์ ์ค์งํดโ๋ โ10:00๋ก ์ฎ๊ฒจ์คโ๊ฐ ๋์ํฉ๋๋ค. ์ด๋ ์ฌ์ฉ์๊ฐ ๋ณด๋ธ ํด์๋ง ์ ์ฉ๋ฉ๋๋ค. ์์ฝ ์คํ ์์ฒด๋ `stop_scheduled_task`๋ก ์์ ์ ์ผ์ ์ ์ผ์ ์ค์งํ๋ ๊ฒ๋ง ํ ์ ์์ต๋๋ค.
- **ํธ์งํด๋ ์์
์ ๊ทธ๋๋ก์
๋๋ค.** ์๊ฐ, ์์
์ง์, ๋ชฉํ, ์ค์ง ์กฐ๊ฑด ๋๋ ์์ ์ํ์ ๋ณ๊ฒฝํ๋ ๊ฒ์ ๊ฐ์ ์์
์ ๋ํ `update`์ด๋ฏ๋ก ID์ ์คํ ๊ธฐ๋ก์ด ์ ์ง๋ฉ๋๋ค. `resume`์ ์ผ์ ์ค์ง๋์๊ฑฐ๋ ์๋ฃ๋ ์์
์ ๋ฐ๋ผ์ก๊ธฐ ์คํ ์์ด ๋ค์ ์์ํฉ๋๋ค. ์ํ์ด ์์ง๋ ๊ฒฝ์ฐ ์์ด์ ํธ๋ ์์ง๋ ์ ํ์ ์ด๋ป๊ฒ ๊ฐฑ์ ํ ์ง(๋ ํฐ `max_runs` ๋๋ ์์, ๋ ๋ฆ์ `end_at` ๋๋ ์์) ๋ฌป๊ณ , ๊ทธ ๊ฐ์ ์ฌ๊ฐ ์์ฒญ๊ณผ ํจ๊ป ๋ณด๋
๋๋ค.
- **์๊ฐ๋.** ์ฌ์ฉ์๊ฐ ์ง์ ํ ์๊ฐ๋๊ฐ ์ฐ์ ํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์ ์์
์ ์น ์ฑ์ด ๊ฐ ๋ฉ์์ง์ ํจ๊ป ๋ณด๋ด๋ ๋ธ๋ผ์ฐ์ ์๊ฐ๋(`context.client_timezone`, ์ด ์ฉ๋๋ก๋ง ์ฝ์)๋ฅผ ์ฌ์ฉํ๋ฉฐ, ๊ฒฐ๊ณผ์ ์ด๋ค ์๊ฐ๋๊ฐ ์ฌ์ฉ๋์๋์ง ํ์๋ฉ๋๋ค. ๊ฐ๊ฒฉ ์ผ์ ๊ณผ UTC ์คํ์
์ด ์๋ ์ผํ์ฑ ์๊ฐ์๋ ์๊ฐ๋๊ฐ ํ์ ์์ต๋๋ค. cron ์ผ์ ์ด๋ ์๊ฐ๋๋ฅผ ์ ์ ์๋ ํ์ง ์ผํ์ฑ ์๊ฐ(์: IM์์ ์จ ๊ฒฝ์ฐ)์ด๋ฉด ์์ด์ ํธ๊ฐ ์๊ฐ๋๋ฅผ ๋ฌป์ต๋๋ค. ํธ์ง ์์๋ ์ ์ฅ๋ ์๊ฐ๋๊ฐ ์ ์ง๋๋ฉฐ, ๋ธ๋ผ์ฐ์ ์๊ฐ๋๋ ๊ธฐ์กด ์์
์ ์ ๋ ๋ณ๊ฒฝํ์ง ์์ต๋๋ค.
- **๊ฒฐ๊ณผ๊ฐ ํ์๋๋ ๊ณณ.** ๊ฐ ์คํ์ โ{task} ยท {local time}โ์ด๋ผ๋ ์ ๋ชฉ์ ๋ณ๋ ์ ์ฑํ
์ ๊ฒฐ๊ณผ๋ฅผ ๊ฒ์ํ๋ฉฐ, ์์
์ด ์๋ ์ฑํ
์์ ์คํ๋๋ ๊ฒฝ์ฐ์๋ ๊ทธ ์ฑํ
์ ๊ฒ์ํฉ๋๋ค. ์ผ์ ์ด ์์ด์ ํธ์ ์ํด ์ผ์ ์ค์ง๋๊ฑฐ๋, ์๋์ผ๋ก ์ผ์ ์ค์ง๋๊ฑฐ๋, ์ข
๋ฃ๋๋ฉด ์๋ ์ฑํ
์์ ๋ํ๊ฐ ๋ฉ์ถฐ ์๋ ์ง์ ์ ํด๋น ์คํ ๋๋ ์์
์ผ๋ก ๊ฐ๋ ๋งํฌ์ ํจ๊ป ํ ์ค์ด ํ์๋๋ฉฐ, ๊ทธ ๋ฐ์๋ ์๋ฌด๊ฒ๋ ๋ค์ ๊ฒ์๋์ง ์์ต๋๋ค. ์ด ์ค์ ์์
์ด ์ญ์ ๋ ๋ค์๋ ๋จ์ต๋๋ค. ์คํ ์ฑํ
์ ๊ธด ์ฌ์ฉ์ ๋ฉ์์ง ๋์ ์คํ ํค๋ ์๋์ ์์
์ง์๋ฅผ ํ๋์ ์ ํ โTask instructionsโ ๋ธ๋ก์ผ๋ก ํ์ํฉ๋๋ค.
- **์ธ์ด.** ์์ด์ ํธ๋ ์ ๋ชฉ, ์์
์ง์, ์ค์ง ์กฐ๊ฑด์ ์ฌ์ฉ์์ ์ธ์ด๋ก ์์ฑํ๋ฉฐ, ์์ฝ ์คํ์ ์์
์ง์์ ์ธ์ด๋ก ๋ตํฉ๋๋ค.
์ ์์
์ ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ฐจ๋ง๋ค ์ ๋ํ๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ค์ ๋ `goal_objective`๋ ํด๋น ํ์ฐจ์๋ง ์ ์ฉ๋๋ฏ๋ก, ์ฑ๊ณตํด๋ ๋ฐ๋ณต ์ผ์ ์ด ์ค์ง๋์ง ์์ต๋๋ค. ์คํ ์ค์ธ ์์ด์ ํธ๋ ์ฌ์ฉ์์ ์ค์ง ์กฐ๊ฑด์ด ์ถฉ์กฑ๋๋ฉด ์์ ์ ์ผ์ ์ ๋ํด `stop_scheduled_task`๋ฅผ ์์ฒญํ ์ ์์ผ๋ฉฐ, ์ด ์์ฒญ์ ์ข
๋ฃ ๋ง๋ฌด๋ฆฌ(terminal finalization) ๋จ๊ณ์์ ์ ์ฉ๋ฉ๋๋ค. `max_runs`๋ ์๋ ์์๋ง ์ง๊ณํ๊ณ , `end_at`์ ๋ง๊ฐ ์๊ฐ์ ์ ๊ณตํฉ๋๋ค. ๋ ์ข
๋ฃ ์กฐ๊ฑด ๋ชจ๋ ์ผ์ ์ค์ง ์์ฒญ๋ณด๋ค ์ฐ์ ํฉ๋๋ค. ๋๊ตฌ๋ก ๋ง๋ 1์๊ฐ ๋ฏธ๋ง ์ฃผ๊ธฐ ์ผ์ ์๋ ์ข
๋ฃ ์กฐ๊ฑด์ด ํ์ํ๋ฉฐ, ๊ฐ ์์ ์๋ ์ผ์ ์ค์ง๋ ์์
์ ํฌํจํด ๋๊ตฌ๋ก ๋ง๋ ์ ํจํ(live) ์์
์ ์ต๋ 20๊ฐ๊น์ง ์ ์งํ ์ ์์ต๋๋ค.
๋ฏธ๋ฌ์ฑ ํ์ฐจ๋ ์คํ ์คํจ์ ๊ตฌ๋ถ๋๋ `unmet`์ผ๋ก ๊ธฐ๋ก๋ฉ๋๋ค. ์ง๊ณ ๋์์ธ ์๋ ๋ฏธ๋ฌ์ฑ ํ์ฐจ๊ฐ ์ธ ๋ฒ ๋ฐ์ํ๋ฉด ๋ฐ๋ณต ์์
์ด ์ผ์ ์ค์ง๋ฉ๋๋ค. ์๋ฝ๋ ์ฑ๊ณต์ ์ฐ์ ํ์๋ฅผ ์ด๊ธฐํํ๋ฉฐ, ๊ณต๊ฐ๋ ๊ฐ์ ์ ์์กดํ ์ฑ๊ณต๋ ๋ง์ฐฌ๊ฐ์ง์
๋๋ค. ์๋ ์ํ ์คํ, ์ค๋จ, ์คํ ์คํจ, ์ธ๋ถ ๋๊ธฐ, ๋ชฉํ ํ์ธ ์คํจ๋ ์ฐ์ ํ์๋ฅผ ๋๋ฆฌ์ง ์์ต๋๋ค. ์ฌ๊ฐ๋ ์ฐ์ ํ์๋ฅผ ์ ์งํ๋ฏ๋ก, ์ง๊ณ ๋์์ธ ๋ฏธ๋ฌ์ฑ ํ์ฐจ๊ฐ ํ ๋ฒ ๋ ๋ฐ์ํ๋ฉด ์์
์ด ๋ค์ ์ผ์ ์ค์ง๋ ์ ์์ต๋๋ค. ๋ฅ๋ ํธ์๋ฅผ ์ง์ํ๋ ์ฐ๊ฒฐ๋ IM ์ฑ์ ๊ฐ์ ์์ ์์๋ฐ์ค๋ฅผ ํตํด ํ์ฐจ๋น ํ๋์ ์๋ฆผ(๋ชฉํ ๋ฏธ๋ฌ์ฑ, ์๋ ์ผ์ ์ค์ง, ์์ด์ ํธ์ ์ํ ์ผ์ ์ค์ง, ์ข
๋ฃ)์ ๋ฐ์ผ๋ฉฐ, ๋จ์ ์๋ ์ํ ์คํ์ ์๋ฆผ์ ๋ณด๋ด์ง ์์ต๋๋ค.
์์
์ ๊ด๋ฆฌํ๋ ๋ํ์์ ์์ด์ ํธ์๊ฒ ์ดํ ์คํ์ ์ํ ๋ช
์์ ์ธ ๋ฉ๋ชจ๋ฅผ ์ ์ฅํ๋๋ก ์์ฒญํ ์ ์์ต๋๋ค(500์ ๋ฉ๋ชจ ์ต๋ 10๊ฐ). ์ ๋ํ๋ก ์์ํ๋ ๋ฐ๋ณต ์คํ์ ์ตํธ์ธ ๋ฐฉ์์ `read_conversation`์ ํตํด ์ง์ ์ ์คํ๋ ํ์ฐจ๋ฅผ ์ฝ์ ์ ์์ผ๋ฉฐ, ๋์ผํ ์์ ์ ๋ฐ ์ฝ๊ธฐ ๊ถํ ๊ฒ์ฌ๊ฐ ์ ์ฉ๋ฉ๋๋ค. ์ด๋ ์ถ์ฒ ์ฐธ์กฐ๋ฅผ ์ ๊ณตํ ๋ฟ, ์๋ ์์ฝ์ด๋ ์๋ ์ฑํ
์ผ๋ก์ ๊ฒฐ๊ณผ ๊ฒ์๊ฐ ์๋๋๋ค.
์ํ ์คํ์ ํ๋ ค๋ฉด โRun it nowโ, โOK, run it nowโ ๋๋ โๅ
่ทไธๆฌกๅงโ์ฒ๋ผ ์ง์ ์์ฒญํ์ธ์. ์น ์ฑ์์๋ ์นด๋์ **Run once now** ๋ฒํผ์ด ๊ฐ์ ์ญํ ์ ํฉ๋๋ค. ํธ์คํธ๋ ํ์ฌ ์ฌ์ฉ์ ํด์์ ์์ด/์ค๊ตญ์ด๋ก ๋ ์ ํ๋ ๋ฒ์์ ์ง์ ์คํ ์์ฒญ์ ๋ฐ์ผ๋ฉฐ, โSure,โ๋ โๅฅฝ็๏ผโ ๊ฐ์ ์งง์ ์๋ฝ ํํ ๋ค์ ์ค๋ ์์ฒญ๋ ํ์ฉํฉ๋๋ค. ๋จ์ํ โyesโ๋ โๅฅฝโ, ์์
์ธ๊ธ, ์ธ์ฉ๋๊ฑฐ๋ ์กฐ๊ฑด์ด ๋ถ์ ์์ฒญ์ ๋น์ฉ์ด ๋๋ ์คํ์ ์์ํ์ง ์์ต๋๋ค. ์ด๋ฏธ ์์์ ๊ธฐ๋ค๋ฆฌ๋ ์คํ์ด ์์ผ๋ฉด ์ํ ์คํ์ ์ถ๊ฐํ์ง ์์ผ๋ฉฐ ์์ด์ ํธ๊ฐ ๊ทธ๋ ๊ฒ ์๋ ค์ค๋๋ค. ์ํ ์คํ์ `max_runs`์ ํฌํจ๋์ง ์์ต๋๋ค.
๋ชฉํ ํ์ฐจ๋ ์ต๋ ์ํ ๋ฒ์ ์์ด์ ํธ ํด์ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ๊ฐ ํด ๋ค์ ํ๊ฐ์ ์์ฒญ์ด ์ด์ด์ง๋๋ค. ํ๊ฐ์ ์์ฒญ๊ณผ ํ๋ก๋ฐ์ด๋๊ฐ ๋ณด๊ณ ํ ํ ํฐ์ ์คํ ์ฌ์ฉ๋์ ํฌํจ๋๋ฉฐ, ์ฌ์ฉ๋์ด ๋๋ฝ๋๋ฉด ํด๋น ๋น์ฉ ์ถ์ ์น๋ ์ ์ ์์์ด ๋ฉ๋๋ค. `token_budget`์ ๋ฉ์ธ ๊ทธ๋ํ๋ฅผ ์ ํํ๋ฉฐ ๋ชจ๋ธ ํธ์ถ ํ์ ํ์ธ๋ฉ๋๋ค. ํ๊ฐ์ ์ฌ์ฉ๋์ ๋ณ๋๋ก ์ถ๊ฐ๋๋ฏ๋ก, ์ด๋ ์คํ ์ ์ฒด๋ ๊ธ์ก์ ๋ํ ์๊ฒฉํ ์ ํ์ด ์๋๋๋ค.
**๋ชฉํ ํ๊ฐ ์
๊ทธ๋ ์ด๋:** ๊ธฐ์กด์ ์์ฝ, ์นํ
, ์์จ ๋ชฉํ ์คํ์ ๊ณต๊ฐ๋ ์ ์ํยท๋๋๋ฆด ์ ์๋ ๊ฐ์ ์ ๋ฐ์๋ค์ด๊ณ ํ์ ์ `relied_on_assumption`์ ๊ธฐ๋กํ ์ ์์ต๋๋ค. ๋ํํ ๋ชฉํ ํ๊ฐ๋ ๊ณ์ ์๊ฒฉํ๊ฒ ์ ์ง๋ฉ๋๋ค. ์ด ์ ์ฑ
์ ๋ํ์ฉ ์ผ์ ๋๊ตฌ๊ฐ ๋นํ์ฑํ๋ ๊ฒฝ์ฐ์๋ ์ ์ฉ๋๋ฉฐ, ๋ฏผ๊ฐํ ๋์์ ํ๊ฐํ๊ฑฐ๋ ์ฌ์ฉ์์ ๊ถํ ๋ถ์ฌ๋ฅผ ๋์ ํ์ง ์์ต๋๋ค.
์์ฝ ์คํ์ `config.yaml`์ `scheduler.recursion_limit`์ ์ฌ์ฉํฉ๋๋ค(๊ธฐ๋ณธ๊ฐ `1000`, ์น UI์ ๋ํํ ์์ฐ๊ณผ ๋์ผ). `max_recursion_limit`๋ณด๋ค ํฐ ๊ฐ์ ๊ทธ ๊ฐ์ผ๋ก ์ ํ๋ฉ๋๋ค. ์ด ํ๋๋ ๋์คํจ์น ์์ ์ ์ฝํ๋ฏ๋ก, ๋ค์ ์์ฝ ์คํ์ Gateway๋ฅผ ์ฌ์์ํ์ง ์์๋ ๋ณ๊ฒฝ ์ฌํญ์ ๋ฐ์ํฉ๋๋ค.
๋ฐฑ๊ทธ๋ผ์ด๋ ์ค์ผ์ค๋ฌ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋จ์ผ ์ธ์คํด์ค์
๋๋ค. ๋ฉํฐ Pod ๋ฐฐํฌ์์๋ `scheduler.multi_instance: true`๋ฅผ ์ค์ ํ๊ณ ๊ณต์ Postgres, `run_ownership.heartbeat_enabled: true`, `run_events.backend: db`๋ฅผ ์ฌ์ฉํ์ธ์. ๊ทธ๋ฌ๋ฉด ์์ ์์ ์ฃผ๊ธฐ์ ๋ณต๊ตฌ ์์ ์ด์ ์๋ ํผ์ด ์คํ์ ๋ณด์กดํ๊ณ , ๋ง๋ฃ๋ ์์ ํด๋ ์์ ์์์ ์ผ๋ก ํ์ ๋๋๋ฆฌ๋ฉฐ, ๋ง๋ฃ๋ ์คํ ๋ฆฌ์ค๋ง ์ธ์ํ๊ณ , ์ค๋๋ ์์ ์ฐ๊ธฐ๋ฅผ ์ฐจ๋จ(fence)ํฉ๋๋ค. `max_concurrent_runs`๋ `launching`/`running` ํ์ฐจ์ ๋ํด ๋ชจ๋ Pod๊ฐ ๊ณต์ ํ๋ ์ ์ญ ์ํ์ด๋ฉฐ, ๋๊ธฐ ์ค์ธ `queued` ํ์ ์ด๋ฅผ ์๋นํ์ง ์์ต๋๋ค. ์ด๋ฌํ ์ค์ ์ด ์๋ค๋ฉด ์ ํํ ํ๋์ Gateway Pod์์๋ง ์ค์ผ์ค๋ฌ๋ฅผ ํ์ฑํํ์ธ์. ์ด ์ค์ผ์ค๋ฌ ํ๋๋ ์์ ์์๋ง ์ ์ฉ๋๋ฏ๋ก, ๋ณ๊ฒฝํ ๋๋ ๋ชจ๋ Gateway Pod๋ฅผ ํจ๊ป ์ฌ์์ํ์ธ์.
### API๋ก cron ํ์ฐจ ๋ฏธ๋ฆฌ๋ณด๊ธฐ
`threads:read` ๊ถํ์ด ์๋ ์ธ์ฆ๋ ํด๋ผ์ด์ธํธ๋ ์์
์ ์์ฑํ๊ธฐ ์ ์ `POST /api/scheduled-tasks/preview-cron`์ ํธ์ถํ ์ ์์ต๋๋ค:
```json
{"cron":"0 9 * * 1-5","timezone":"Asia/Shanghai","count":3,"start_at":"2026-09-12T00:00:00Z"}
```
์๋ต์๋ ์ ๊ทํ๋ `cron`, `timezone`, ์ค์ ์ ์ฉ๋ UTC `start_at`, ๊ทธ๋ฆฌ๊ณ UTC `run_at`๊ณผ ์คํ์
์ด ํฌํจ๋ `local_time`์ ๋ด์ `occurrences`๊ฐ ๋ค์ด ์์ต๋๋ค. ์ด ์์์์ ์ฒซ ๋ฒ์งธ ํ์ฐจ๋ `2026-09-14T01:00:00Z` / `2026-09-14T09:00:00+08:00`์
๋๋ค.
`count`๋ 1๋ถํฐ 10๊น์ง์ ์ ์์
๋๋ค(๊ธฐ๋ณธ๊ฐ 5). `start_at`์๋ ์๊ฐ๋๊ฐ ํฌํจ๋์ด์ผ ํ๋ฉฐ, ์๋ตํ๋ฉด ์๋ฒ ์๊ฐ์ ํ ๋ฒ ์บก์ฒํด ์ฌ์ฉํฉ๋๋ค. cron ํํ์์ ์ค์ผ์ค๋ฌ์ 5ํ๋ ๋ฌธ๋ฒ์ ์ฌ์ฉํ๋ฉฐ(์ต๋ 256์), ์๊ฐ๋ ์ด๋ฆ์ ์ต๋ 128์์
๋๋ค. ์๋ชป๋ ์
๋ ฅ์ด๋ ์์ฒญํ ์๋งํผ์ ๋ฏธ๋ ํ์ฐจ๊ฐ ์๋ ์ผ์ ์ 422๋ฅผ ๋ฐํํฉ๋๋ค. ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ ์ค์ผ์ค๋ฌ์ ๋์ผํ DST ๋์์ ๋ฐ๋ฅด๋ฉฐ, ์์
, ์ค๋ ๋, ์คํ์ ์์ฑํ์ง ์๊ณ ์คํ ์์์ ๋ฏธ๋ฆฌ ํ๋ณดํ์ง๋ ์์ต๋๋ค. ์ด๋ API ๊ธฐ๋ฅ์ด๋ฉฐ, ์ํฌ์คํ์ด์ค ์์์ ์์ง ์ด ํ์ฐจ๋ค์ ํ์ํ์ง ์์ต๋๋ค.
### ์
๊ทธ๋ ์ด๋ ์ฐธ๊ณ ์ฌํญ
- ํ์ฐจ ์์ ๋ณด์ฅ์ ์
๊ทธ๋ ์ด๋๋ Gateway ์ธ์คํด์ค๊ฐ ์น์ธ(admission)ํ ํ์ ์ ์ฉ๋ฉ๋๋ค. ์ด ์ธ์คํด์ค๋ค์ ์๋ฒ์ด ๋ถ์ฌ๋ ํ์ฐจ๋ง ์์ ์์
์ ํฌ์(projection)ํ๋ฉฐ, ์ด๋ ์ธ์คํด์ค๊ฐ ์น์ธํ๋ ์์ง ์งํ ์ค์ธ ํ์ฐจ๊ฐ ์์ผ๋ฉด ๋ณต๊ตฌ๋ฅผ ๋ฏธ๋ฃน๋๋ค. ๊ธฐ๋ก ์ ์ฒด๊ฐ ์๋ฒ ์๋ ํ์ฐจ๋ก ์ด๋ฃจ์ด์ง ์์
์ ์ฒซ ๋ฒ์งธ ์๋ฒ ์น์ธ ์ ๊น์ง ์ด์ ์ ํ์์คํฌํ ์์๋ฅผ ์ ์งํฉ๋๋ค. ๋กค๋ง ์
๊ทธ๋ ์ด๋ ์ค์๋ ์
๊ทธ๋ ์ด๋ ์ด์ ์ธ์คํด์ค๊ฐ ์น์ธํ ํ์ ์
๊ทธ๋ ์ด๋ ์ ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ํด๋น ์ธ์คํด์ค๊ฐ ์ง์ ํฌ์ํ๋ฉฐ, ์์ ๋ณด์ฅ์ ๋ชจ๋ Gateway ์ฐ๊ธฐ ์ฃผ์ฒด๊ฐ ์
๊ทธ๋ ์ด๋๋ ๋ฒ์ ์ ์คํํ ๋ค๋ถํฐ ์ฑ๋ฆฝํฉ๋๋ค. ๊ธฐ์กด ๊ธฐ๋ก์ ๋ฐฑํ๋์ง ์์ผ๋ฉฐ, ์
๊ทธ๋ ์ด๋๋ ๊ณผ๊ฑฐ ์์๋ฅผ ์ฌ๊ตฌ์ฑํ๊ฑฐ๋ ๊ณผ๊ฑฐ ์ง๊ณ๋ฅผ ๋ณต๊ตฌํ์ง ์์ต๋๋ค.
- `GATEWAY_WORKERS > 1`์ด๊ณ `scheduler.enabled: true`์ธ ๋ฐฐํฌ๋ฅผ ์
๊ทธ๋ ์ด๋ํ๊ธฐ ์ ์, ์ค์ผ์ค๋ฌ๋ฅผ ์ ํํ ํ๋์ Gateway ์์ปค์์๋ง ์ ์งํ๊ฑฐ๋, ๊ณต์ Postgres, `run_ownership.heartbeat_enabled: true`, `run_events.backend: db`์ ํจ๊ป `scheduler.multi_instance: true`๋ฅผ ์ค์ ํ์ธ์. ์
๊ทธ๋ ์ด๋๋ Gateway๋ ์ด ์์ ํ์ง ์์ ์กฐํฉ์ ์กฐ์ฉํ ์์ํ์ง ์๊ณ ์์ ์์ ์ ๊ฑฐ๋ถํฉ๋๋ค.
- ๋ฉํฐ ์ธ์คํด์ค ๋ชจ๋์์ `scheduler.max_concurrent_runs`๋ Pod๋ณ ์ํ์ด ์๋๋ผ ํด๋ฌ์คํฐ ์ ์ฒด์ ์คํ ์ํ์
๋๋ค. ์ฌ๊ธฐ์๋ `launching` ๋ฐ `running` ์ํ์ ์์ฝ ํ์ฐจ๊ฐ ํฌํจ๋๋ฏ๋ก ๋ ํ๋ฆฌ์นด ์์ ๋ฐ๋ผ ์ฉ๋์ด ๋์ด๋์ง ์์ผ๋ฉฐ, ์์ ๋๊ธฐ ํ์ ์ํ์ ํฌํจ๋์ง ์์ต๋๋ค.
- `scheduler.multi_instance`์ ๊ด๋ จ ์ค์ผ์ค๋ฌ, ์์ ๊ถ, ์คํ ์ด๋ฒคํธ ์ค์ ์ ์์ ์์๋ง ์ ์ฉ๋ฉ๋๋ค. ๋ชจ๋ Gateway Pod๋ฅผ ์กฐ์จํด ์ฌ์์ํ๋ ๋ฐฉ์์ผ๋ก ๋ณ๊ฒฝ ์ฌํญ์ ์ ์ฉํ์ธ์. ConfigMap๋ง ๋ณ๊ฒฝํด์๋ ๋ฉํฐ ์ธ์คํด์ค ๋ณต๊ตฌ๊ฐ ํ์ฑํ๋์ง ์์ต๋๋ค.
## ํฐ๋ฏธ๋ ์ํฌ๋ฒค์น (TUI)
`deerflow`๋ ์
ธ์์ ์ฃผ๋ก ์์
ํ๋ ์ฌ๋๋ค์ ์ํ ํฐ๋ฏธ๋ ๋ค์ดํฐ๋ธ ์ํฌ๋ฒค์น์
๋๋ค. `DeerFlowClient` ์์์ **์๋ฒ ๋๋** ๋ฐฉ์์ผ๋ก ์คํ๋๋ฏ๋ก Gateway, ํ๋ก ํธ์๋, nginx, Docker๊ฐ ํ์ ์์ผ๋ฉฐ, ๋๋จธ์ง DeerFlow์ ๋์ผํ `config.yaml`, ์ฒดํฌํฌ์ธํฐ, ์คํฌ, ๋ฉ๋ชจ๋ฆฌ, MCP, ์๋๋ฐ์ค ์ค์ ์ ๋ฐ๋ฆ
๋๋ค.
๋ณ๋ ฌ ๋๊ธฐ stdio MCP ํธ์ถ์ ๊ฐ์์ ์ด๋ฒคํธ ๋ฃจํ์์ ๋
๋ฆฝ๋ ์ธ์
์ ์ฌ์ฉํฉ๋๋ค. ์๋ก์ ์ฐ๊ฒฐ์ ์ทจ์ํ์ง๋ ์์ง๋ง ์๋ฒ ์ธก ์ํ๋ฅผ ๊ณต์ ํ์ง๋ ์์ผ๋ฉฐ, ์ธ์
์ ์ฌ์ฌ์ฉํ๋ ค๋ฉด ๊ฐ์ ๋ฃจํ๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ์์ธํ ๋ด์ฉ์ [MCP ์ธ์
์ฐธ๊ณ ์ฌํญ](backend/docs/MCP_SERVER.md)์ ํ์ธํ์ธ์. ์๋์ผ๋ก ๊ด๋ฆฌํ๋ ์ด๋ฒคํธ ๋ฃจํ๋ ๋ซ๊ธฐ ์ ์ ๋๊ธฐ ์ค์ธ ์ธ์
์์ ์๋ฅผ ๋ชจ๋ ์ ๋ฆฌ(drain)ํด์ผ ํ๋ฉฐ, ์ผ๋ฐ์ ์ธ `asyncio.run()` ๊ฒฝ๋ก๋ ์ด๋ฅผ ์๋์ผ๋ก ์ํํฉ๋๋ค.

```bash
uv pip install 'deerflow-harness[tui]' # optional 'textual' dependency
deerflow # launch the terminal UI (TTY required)
deerflow --tui-transparent # use the terminal's default background
deerflow --continue # resume the most recent thread
deerflow --resume THREAD # resume a thread by id
deerflow --print "summarize this repo" # headless one-shot answer to stdout
deerflow --json "hello" # headless newline-delimited StreamEvents; failure -> one {"type": "error"} record, exit 1
deerflow --recursion-limit 250 --print "task" # override the headless agent-loop limit
```
ํค๋๋ฆฌ์ค `--print`์ `--json`์ ์คํ์ด ์คํจํ๋ฉด ์ํ ์ฝ๋ `1`๋ก ์ข
๋ฃํ๋ฉฐ, ํ๋ก๋ฐ์ด๋ ์ค๋ฅ๊ฐ ํด๋ฐฑ ๋ฉ์์ง๋ก ๋ฐํ๋ ๊ฒฝ์ฐ๋ ํฌํจ๋ฉ๋๋ค. ์ด๋๋ `--print`๋ ํด๋ฐฑ ํ
์คํธ๋ฅผ stdout์ ์ฐ๊ณ , `--json`์ ๋ง์ง๋ง์ ์ค๋ฅ ๋ ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
์คํธ๋ฆฌ๋ฐ ๋ํ๋ก(Markdown์ผ๋ก ๋ ๋๋ง๋ ๋ต๋ณ), ๊ฐ๊ฒฐํ ๋๊ตฌ ํ๋ ์นด๋, `/` ์ฌ๋์ ๋ช
๋ น ํ๋ ํธ, ํ๋ฉด ์ ์ฉ `/clear`, `/goal` ๋ชฉํ ๊ด๋ฆฌ, `/model` ๋ฐ `/threads` ์ ํ๊ธฐ, ์
๋ ฅ ๊ธฐ๋ก, PageUp/PageDown ๋ํ๋ก ํ์, `Esc` / `Ctrl+C` ์ค๋จ์ ๊ฐ์ถ ํค๋ณด๋ ์ค์ฌ์ ์ฑํ
ํ๋ฉด์
๋๋ค. ์
๋ ฅ์ฐฝ(composer)์ ๋ถ์ฌ ๋ฃ์ ์ฝ๋, ์คํ ํธ๋ ์ด์ค, ์ฌ๋ฌ ๋ฌธ๋จ์ผ๋ก ๋ ํ๋กฌํํธ์ ์ค๋ฐ๊ฟ๊ณผ ๋ค์ฌ์ฐ๊ธฐ๋ฅผ ๋ณด์กดํ๋ฉฐ, `Enter`๋ฅผ ๋๋ฅด๋ฉด ์ ์ฒด ๋ฌธ์๋ฅผ ๋ณด๋
๋๋ค. ๋ํ๋ก์ด ๊ฐฑ์ ๋ ๋ ์๋ก ์คํฌ๋กคํ ์ํ๋ผ๋ฉด ์ฝ๋ ์์น๋ฅผ ์ ์งํ๊ณ , ๋งจ ์๋๋ก ๋์์ค๋ฉด ๋ค์ ์ ์ถ๋ ฅ์ ๋ฐ๋ผ๊ฐ๋๋ค. `/clear`๋ ์ค๋ ๋๋ ์ ์ฅ๋ ๋ํ๋ฅผ ์ญ์ ํ์ง ์๊ณ ํ์ฌ ํฐ๋ฏธ๋ ํ๋ฉด์์ ํ๋ง ์ ๊ฑฐํฉ๋๋ค. `/new`์ `/clear`๋ ์คํ ์ค์๋ ์งํ ์ค์ธ ํ๋ฉด ์ํ๋ฅผ ์ฌ์ค์ ํ๋ ๋์ ๊ธฐ๋ค๋ ค ๋ฌ๋ผ๊ณ ์๋ดํฉ๋๋ค. TUI์์ ์ฐ ์ธ์
์ ์น UI ์ฌ์ด๋๋ฐ์๋ ํ์๋ฉ๋๋ค. TUI๋ ๋ก์ปฌ ๊ธฐ๋ณธ ์ฌ์ฉ์๋ก ๊ณต์ ์ค๋ ๋ ์ ์ฅ์์ ๊ธฐ๋กํ๋ฏ๋ก, **Gateway๋ฅผ ์คํํ์ง ์๊ณ ๋** ํฐ๋ฏธ๋๊ณผ ์น์ด ๋๊ธฐํ๋ ์ํ๋ฅผ ์ ์งํฉ๋๋ค.
์คํ ์ค์๋ `/resume`, `/threads`, `/switch`๊ฐ ๋ํ๋ฅผ ์ ํํ๊ธฐ ์ ์ ๊ธฐ๋ค๋ ค ๋ฌ๋ผ๊ณ ์๋ดํฉ๋๋ค. ์๋ชป๋ `/resume` ์ฐธ์กฐ๋ TUI๋ฅผ ๋ซ๊ฑฐ๋ ํ์ฌ ๋ํ๋ฅผ ๋ฐ๊พธ์ง ์๊ณ ์ค๋ฅ๋ง ํ์ํฉ๋๋ค. ์ค๋จ ํ์๋ ๋ ํ๋กฌํํธ๊ฐ ๊ฐ์ ๋ํ๋ฅผ ์ฌ์ฉํ๋๋ผ๋ ์ด์ ์คํ์์ ๋ฆ๊ฒ ๋์ฐฉํ ์คํธ๋ฆผ ๋์์ด ๋ค์ ์คํ์ ํ๋ฉด์ด๋ ์ํ๋ฅผ ๋ฐ๊ฟ ์ ์์ต๋๋ค. ์ด๋ฏธ ์งํ ์ค์ธ ๋๊ตฌ ํธ์ถ์ ๋๊น์ง ์๋ฃ๋๋ฏ๋ก, ์๋ฃ๋ ๋๊น์ง ๊ทธ ๋ํ์ ์ ํ๋กฌํํธ๋ ๊ฒฝ์ ์ํ๋ฅผ ํผํ๋๋ก ์๋ฆผ๊ณผ ํจ๊ป ๋ณด๋ฅ๋๋ฉฐ, `/new`์ `/resume`์ ๊ณ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ข
๋ฃํ ๋๋ ๊ทธ ๋จ๊ณ๊ฐ ๋๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ ธ๋ค๊ฐ TUI๋ฅผ ๋ซ์ผ๋ฉฐ, `Ctrl+C`๋ฅผ ํ ๋ฒ ๋ ๋๋ฅด๋ฉด ๊ทธ ๋จ๊ณ๋ฅผ ์ ์ฅํ์ง ์๊ณ ๋ฐ๋ก ์ข
๋ฃํฉ๋๋ค. ์คํ์ ์์ํ ์ ์์ผ๋ฉด TUI๊ฐ ์ค๋ฅ๋ฅผ ๋ณด๊ณ ํ๊ณ ์ ํด ์ํ๋ก ๋์๊ฐ๋ฏ๋ก ์ฌ์๋ํ ์ ์์ต๋๋ค. ๋ณด๋ฅ๋์๊ฑฐ๋ ์์ํ ์ ์๋ ๋ฉ์์ง๋ ์
๋ ฅ์ฐฝ์ ๋จ์ ์์ผ๋ฏ๋ก `Enter`๋ก ๋ค์ ๋ณด๋ผ ์ ์์ต๋๋ค.
์
๋ ฅ์ฐฝ์ ๋ง์ง๋ง ํ์์ `Down`์ ์
๋ ฅ ๊ธฐ๋ก์ ํ์ํ๋ ์ค์ด ์๋๋ฉด ๋ณด๋ด์ง ์์ ์ด์์ ๊ฑด๋๋ฆฌ์ง ์์ต๋๋ค. ๊ธฐ๋ก์ ๋ถ๋ฌ์จ ๋ค์๋ ์์ผ๋ก ์ด๋ํด ์ ์ฅํด ๋ ์ด์์ ๋ณต์ํฉ๋๋ค.
์
๋ ฅ์ฐฝ์ ์ฒซ ๋ฒ์งธ ํ์์ `Up`๋ ์
๋ ฅ ๊ธฐ๋ก์ด ์์ผ๋ฉด ์ด์, ์ปค์, ์คํ ์ทจ์ ๊ธฐ๋ก์ ๊ฑด๋๋ฆฌ์ง ์์ต๋๋ค. ๋์ผํ ๊ธฐ๋ก ํ
์คํธ๋ ์ ์ฅ๋ ์ด์์ ๋ถ๋ฌ์ฌ ๋๋ ์ปค์์ ์คํ ์ทจ์ ๊ธฐ๋ก์ด ์ ์ง๋ฉ๋๋ค.
์ ์ฒด ๊ฐ์ด๋๋ [backend/docs/TUI.md](backend/docs/TUI.md)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
## ๋ฌธ์
- [๊ธฐ์ฌ ๊ฐ์ด๋](CONTRIBUTING.md) - ๊ฐ๋ฐ ํ๊ฒฝ ์ค์ ๋ฐ ์ํฌํ๋ก
- [์ค์ ๊ฐ์ด๋](backend/docs/CONFIGURATION.md) - ์ค์น ๋ฐ ์ค์ ์๋ด
- [์ํคํ
์ฒ ๊ฐ์](backend/CLAUDE.md) - ๊ธฐ์ ์ํคํ
์ฒ ์์ธ
- [๋ฐฑ์๋ ์ํคํ
์ฒ](backend/README.md) - ๋ฐฑ์๋ ์ํคํ
์ฒ ๋ฐ API ๋ ํผ๋ฐ์ค
## โ ๏ธ ๋ณด์ ๊ณ ์ง
### ๋ถ์ ์ ํ ๋ฐฐํฌ๋ ๋ณด์ ์ํ์ ์ด๋ํ ์ ์์ต๋๋ค
DeerFlow๋ **์์คํ
๋ช
๋ น ์คํ, ๋ฆฌ์์ค ์กฐ์, ๋น์ฆ๋์ค ๋ก์ง ํธ์ถ** ๋ฑ ํต์ฌ์ ์ธ ๊ณ ๊ถํ ๊ธฐ๋ฅ์ ๊ฐ์ถ๊ณ ์์ผ๋ฉฐ, ๊ธฐ๋ณธ์ ์ผ๋ก **๋ก์ปฌ ์ ๋ขฐ ํ๊ฒฝ(127.0.0.1 ๋ฃจํ๋ฐฑ ์ธํฐํ์ด์ค๋ก๋ง ์ ๊ทผ ๊ฐ๋ฅ)์ ๋ฐฐํฌ**๋๋๋ก ์ค๊ณ๋์์ต๋๋ค. ์๊ฒฉํ ๋ณด์ ์กฐ์น ์์ด LAN ๋คํธ์ํฌ, ํผ๋ธ๋ฆญ ํด๋ผ์ฐ๋ ์๋ฒ ๋๋ ์ฌ๋ฌ ์๋ํฌ์ธํธ์์ ์ ๊ทผํ ์ ์๋ ๊ธฐํ ํ๊ฒฝ์ฒ๋ผ ์ ๋ขฐํ ์ ์๋ ํ๊ฒฝ์ ์์ด์ ํธ๋ฅผ ๋ฐฐํฌํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋ณด์ ์ํ์ด ๋ฐ์ํ ์ ์์ต๋๋ค:
- **๋ฌด๋จ ๋ถ๋ฒ ํธ์ถ**: ๊ถํ์ด ์๋ ์ 3์๋ ์
์์ ์ธ ์ธํฐ๋ท ์ค์บ๋๊ฐ ์์ด์ ํธ ๊ธฐ๋ฅ์ ๋ฐ๊ฒฌํด ๋๋์ ๋ฌด๋จ ์์ฒญ์ ๋ณด๋ด๊ณ , ์์คํ
๋ช
๋ น ๋ฐ ํ์ผ ์ฝ๊ธฐ/์ฐ๊ธฐ ๊ฐ์ ๊ณ ์ํ ์์
์ ์คํํ์ฌ ์ฌ๊ฐํ ๋ณด์ ๋ฌธ์ ๋ฅผ ์ผ์ผํฌ ์ ์์ต๋๋ค.
- **๊ท์ ์ค์ ๋ฐ ๋ฒ์ ์ํ**: ์์ด์ ํธ๊ฐ ์ฌ์ด๋ฒ ๊ณต๊ฒฉ, ๋ฐ์ดํฐ ํ์ทจ ๋๋ ๊ธฐํ ๋ถ๋ฒ ํ๋์ ๋ถ๋ฒ์ ์ผ๋ก ์ด์ฉ๋ ๊ฒฝ์ฐ ๋ฒ์ ์ฑ
์๊ณผ ๊ท์ ์ค์ ์ํ์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
### Gateway ๊ด๋ฆฌ์ ๊ถํ์ ๊ณง ์ฝ๋ ์คํ ๊ถํ์
๋๋ค
๊ด๋ฆฌ์๋ Gateway ์ปจํ
์ด๋ ์์์ ๋ช
๋ น์ ์คํํ๋ stdio MCP ์๋ฒ๋ฅผ ๋ฑ๋กํ ์ ์์ต๋๋ค. API๋ ์ด๋ฅผ ํ์ฉ ๋ชฉ๋ก(๊ธฐ๋ณธ๊ฐ `npx`, `uvx`, `DEER_FLOW_MCP_STDIO_COMMAND_ALLOWLIST`๋ก ํ์ฅ ๊ฐ๋ฅ)์ผ๋ก ์ ํํ๊ณ , ์์ ์ฝ๋๋ฅผ ํ๊ฐํ ์ ์๋ ์ธ์์ ํ๊ฒฝ ๋ณ์๋ฅผ ๊ฑฐ๋ถํฉ๋๋ค. ์ด๋ ์ฌ์ธต ๋ฐฉ์ด์ผ ๋ฟ ๊ฒฝ๊ณ๊ฐ ์๋๋๋ค. ์ด๋ฌํ ๋ฐ์ฒ๋ ์๊ฒฉ ํจํค์ง๋ฅผ ๊ฐ์ ธ์ ์คํํ๊ธฐ ์ํด ์กด์ฌํ๋ฏ๋ก, **Gateway ๊ด๋ฆฌ์ ๊ถํ์ ํธ์คํธ์์์ ์ฝ๋ ์คํ๊ณผ ๋๋ฑํ๊ฒ ์ทจ๊ธ**ํ๊ณ ๊ทธ์ ๋ง๊ฒ ๋ถ์ฌํ์ธ์.
### ์ธ๋ถ ์ฑํ
๋ฉ์์ง ์ญํ
Gateway ์คํ ์์ฒญ๊ณผ ์๋ ์ค๋ ๋ ์ํ ์
๋ฐ์ดํธ๋ ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ธ `system` / `developer` ๋ฉ์์ง๋ฅผ HTTP 400์ผ๋ก ๊ฑฐ๋ถํ๋ฉฐ, ์ด์ ๋๋ฑํ ์ง๋ ฌํ๋ ๋ฉ์์ง ํํ๋ ๋ง์ฐฌ๊ฐ์ง์
๋๋ค. ์ผ๋ฐ ์ฑํ
, ์ฒจ๋ถ ํ์ผ, assistant/tool ๊ธฐ๋ก ์ฌ์(replay)์ ๊ณ์ ์ง์๋ฉ๋๋ค. ์ธ์
๋๋ PAT ์ธ์ฆ์ ์์คํ
ํ๋กฌํํธ ๊ถํ์ ๋ถ์ฌํ์ง ์์ผ๋ฉฐ, ์ ๋ขฐํ ์ ์๋ ๋ด๋ถ ์คํ ์์ฑ์๋ ์ด ๊ถํ์ ์ ์งํฉ๋๋ค.
์ด ๊ฒ์ฌ๋ ์๋ก์ด ์ญํ ์ฃผ์
์ ๋ง์ ๋ฟ, ๊ธฐ์กด ์ฒดํฌํฌ์ธํธ๋ฅผ ๋ค์ ์ฐ์ง๋ ์์ต๋๋ค. ์ด์ ๋ฒ์ ์ด ์ฃผ์
๋ ์์คํ
๋ฉ์์ง๋ฅผ ๋ฐ์๋ค์๋ค๋ฉด ์ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ๊ฑฐ๋, ์ด์์๊ฐ ์ํฅ์ ๋ฐ์ ์ํ๋ฅผ ๊ฒํ ํ๊ณ ์ ๋ฆฌํ๋๋ก ํ์ธ์. ์๋น์ค๋ฅผ ์ฌ์์ํด๋ ์ ์ฅ๋ ์ง์๋ ์ ๊ฑฐ๋์ง ์์ผ๋ฉฐ, ์ด์ ์ฒดํฌํฌ์ธํธ๋ฅผ ๋ณต์ํ๋ฉด ๊ทธ ์ง์๋ ํจ๊ป ๋ณต์๋ ์ ์์ต๋๋ค.
๋ก์ปฌ ๊ฒ์ฆ์๋ `python backend/tests/poc_external_system_message_injection.py --help`๋ฅผ ์คํํ์ธ์. ๊ฐ์ ์ตํธ์ธ PoC๋ ๊ฒฉ๋ฆฌ๋ ์ด์ ๋ฆฌ๋น์ ์์๋ `--expect vulnerable`์, ์์ ํ์๋ `--expect blocked`๋ฅผ ์ง์ํฉ๋๋ค. ๋์๋ง์๋ PAT ์์ฑ, ์ค๋ ๋ ID ์ ํ, ๋ธ๋ผ์ฐ์ ์์์ ํ์ ํ์ธ, ๊ทธ๋ฆฌ๊ณ ์์ ์ ์ฅ๊ณผ ๋ชจ๋ธ ์์์ ์ฐจ์ด๊ฐ ์ค๋ช
๋์ด ์์ต๋๋ค. ํ
์คํธ๊ฐ ๋ฉ์์ง๋ฅผ ์ถ๊ฐํ๋ฏ๋ก ์คํํ ๋๋ง๋ค ์๋ก์ด ์ผํ์ฉ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ์ธ์.
์์ ๋์ง ์์ ๊ฒฉ๋ฆฌ ์ฒดํฌ์์์์ `--expect vulnerable`์ ์์ฒญ์ด 200์ ๋ฐํํ๊ณ , ์ฃผ์
ํ ๋ฉ์์ง๊ฐ ์ ํํ ๊ทธ๋๋ก ์ผ๋ฐ ํ์ ์์ฒญ ์ดํ์๋ ์ฒดํฌํฌ์ธํธ์ `type=system`์ผ๋ก ๋จ์ ์์ ๋์๋ง ์๋ฝ๋์์์ ์
์ฆํฉ๋๋ค. ์น ๋ต๋ณ์ ๋ํ๋๋ ๋ง์ปค๋ ๋ชจ๋ธ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ฉฐ, ๋ง์ปค๋ง์ผ๋ก๋ ์ญํ ์ด ์น๊ฒฉ๋์๋ค๋ ์ฆ๊ฑฐ๊ฐ ๋์ง ์์ต๋๋ค. ์์ ์ ์ ์ฉํ ๋ค์๋ ๊ฐ์ ์คํฌ๋ฆฝํธ๋ฅผ `--expect blocked`๋ก ์คํํ์ธ์. ์ด ๋ชจ๋๋ ํด๋น ์ญํ ๊ฑฐ๋ถ์ ๋ํ 400, ๋ณ๊ฒฝ๋์ง ์์ ์ฒดํฌํฌ์ธํธ, ์ฑ๊ณตํ ์ผ๋ฐ ํ์ ์์ฒญ, ๊ฑฐ๋ถ๋ ๋ฉ์์ง ID์ ๋ถ์ฌ๋ฅผ ์๊ตฌํฉ๋๋ค. ๊ทธ ๋ฐ์ 400 ์๋ต๊ณผ ์ธ์ฆ, ์ถฉ๋, ์๋ฒ ์ค๋ฅ๋ ํต๊ณผ๊ฐ ์๋๋ผ ํ๋จ ๋ถ๊ฐ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค.
PoC๋ ์๋์ผ๋ก ์ ๋ฆฌํ์ง ์์ต๋๋ค. ๊ฒ์ฆ์ด ๋๋๋ฉด ์น ์ฌ์ด๋๋ฐ์ ์ญ์ ๋์์ผ๋ก ์ผํ์ฉ ์ฑํ
์ ์ญ์ ํ๊ณ , ๋จ๊ธฐ PAT๋ฅผ ๋ง๋ค์๋ค๋ฉด ์ด๋ฅผ ํ๊ธฐํ์ธ์. ์๋น์ค๋ฅผ ์ฌ์์ํด๋ ์ ์ฅ๋ ์ฃผ์
์ง์๋ ์ ๊ฑฐ๋์ง ์์ต๋๋ค.
### ๋ฐฐํฌ ๊ธฐ๋ณธ๊ฐ
Docker ์คํ์ ์ง์
ํฌํธ๋ฅผ `127.0.0.1`์๋ง ๊ณต๊ฐํ๋ฉฐ, ๋ก์ปฌ `make dev` / `make start`๋ nginx, Gateway, ํ๋ก ํธ์๋๋ฅผ ๋ฃจํ๋ฐฑ์ ๋ฐ์ธ๋ฉํ๋ฏ๋ก ์์์ ์ค๋ช
ํ ๋ก์ปฌ ์ ๋ขฐ ํ๊ฒฝ ๋ชจ๋ธ๊ณผ ์ผ์นํฉ๋๋ค. ๋ค๋ฅธ ๋จธ์ ์์ ์ ๊ทผํ๋ ค๋ฉด `.env`์ `BIND_HOST`๋ฅผ ์ค์ ํ์ธ์(์: `BIND_HOST=0.0.0.0`). ๋จ, ๋ฐ๋์ ์๋ ๋ณด์ ์กฐ์น๋ฅผ ๊ฐ์ถ ๋ค์๋ง ์ค์ ํด์ผ ํฉ๋๋ค. ๋ก์ปฌ ์คํ์์๋ `BIND_HOST`๊ฐ ํฌํธ `2026`์ nginx์๋ง ์ ์ฉ๋๋ฉฐ, Gateway์ ํ๋ก ํธ์๋๋ ๊ทธ ๋ค์์ ๊ณ์ ๋ฃจํ๋ฐฑ์ ๋จธ๋ญ
๋๋ค.
**ํธ์คํธ์ ์ ๊ทผ ๊ฐ๋ฅํด์ง๊ธฐ ์ ์ ์ต์ด ์คํ ์ค์ ์ ์๋ฃํ์ธ์.** ์ ์ธ์คํด์ค์๋ ์์ง ๊ณ์ ์ด ์์ผ๋ฏ๋ก, ๋ฃจํ๋ฐฑ ์ ์ฉ์ด ์๋ ๋ฐฐํฌ๋ ์์ํ ์งํ `/setup`์ ํตํด ๊ด๋ฆฌ์ ๊ณ์ ์ ๋ง๋์ธ์.
### ๋ณด์ ๊ถ์ฅ ์ฌํญ
**์ฐธ๊ณ : DeerFlow๋ฅผ ๋ก์ปฌ ์ ๋ขฐ ๋คํธ์ํฌ ํ๊ฒฝ์ ๋ฐฐํฌํ ๊ฒ์ ๊ฐ๋ ฅํ ๊ถ์ฅํฉ๋๋ค.** ๊ธฐ๊ธฐ ๊ฐ ๋๋ ๋คํธ์ํฌ ๊ฐ ๋ฐฐํฌ๊ฐ ํ์ํ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ ์๊ฒฉํ ๋ณด์ ์กฐ์น๋ฅผ ๋ฐ๋์ ๊ตฌํํด์ผ ํฉ๋๋ค:
- **IP ํ์ฉ ๋ชฉ๋ก**: `iptables`๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ ์ ๊ทผ ์ ์ด ๋ชฉ๋ก(ACL)์ ๊ฐ์ถ ํ๋์จ์ด ๋ฐฉํ๋ฒฝ/์ค์์น๋ฅผ ๋ฐฐํฌํ์ฌ **IP ํ์ฉ ๋ชฉ๋ก ๊ท์น์ ์ค์ **ํ๊ณ , ๊ทธ ๋ฐ์ ๋ชจ๋ IP ์ฃผ์์์์ ์ ๊ทผ์ ๊ฑฐ๋ถํ์ธ์.
- **์ธ์ฆ ๊ฒ์ดํธ์จ์ด**: ๋ฆฌ๋ฒ์ค ํ๋ก์(์: nginx)๋ฅผ ์ค์ ํ๊ณ **๊ฐ๋ ฅํ ์ฌ์ ์ธ์ฆ์ ํ์ฑํ**ํ์ฌ ์ธ์ฆ๋์ง ์์ ๋ชจ๋ ์ ๊ทผ์ ์ฐจ๋จํ์ธ์.
- **๋คํธ์ํฌ ๊ฒฉ๋ฆฌ**: ๊ฐ๋ฅํ๋ค๋ฉด ์์ด์ ํธ์ ์ ๋ขฐํ ์ ์๋ ๊ธฐ๊ธฐ๋ฅผ **๋์ผํ ์ ์ฉ VLAN**์ ๋์ด ๋ค๋ฅธ ๋คํธ์ํฌ ๊ธฐ๊ธฐ์ ๊ฒฉ๋ฆฌํ์ธ์.
- **์ต์ ์ํ ์ ์ง**: DeerFlow์ ๋ณด์ ๊ธฐ๋ฅ ์
๋ฐ์ดํธ๋ฅผ ๊ณ์ ํ์ธํ์ธ์.
## ๊ธฐ์ฌํ๊ธฐ
๊ธฐ์ฌ๋ฅผ ํ์ํฉ๋๋ค! ๊ฐ๋ฐ ํ๊ฒฝ ์ค์ , ์ํฌํ๋ก, ๊ฐ์ด๋๋ผ์ธ์ [CONTRIBUTING.md](CONTRIBUTING.md)๋ฅผ ์ฐธ๊ณ ํ์ธ์.
๋ฐฑ์๋ `make test`๋ ์คํ ์๊ฐ์ด ๊ท ํ ์๊ฒ ๋ถ๋ฐฐ๋ ๋ค ๊ฐ์ ์ค๋๋ฅผ ๋์์ ์คํํ๋ฉฐ, ํ๋๋ผ๋ ์คํจํ๋ฉด ์คํจ๋ก ๋ณด๊ณ ํฉ๋๋ค. ์ค๋๋ฅผ ์์ฐจ์ ์ผ๋ก ์คํํ๋ ค๋ฉด `make test TEST_JOBS=1`์ ์ฌ์ฉํ์ธ์. ์ด ๋ช
๋ น์ ์ค์ ์ธ๋ถ API ํ
์คํธ์ ๋ธ๋กํน I/O ํ
์คํธ๋ฅผ ์ ์ธํฉ๋๋ค. ์๊ฒฉํ ๋ธ๋กํน I/O ๊ฒ์ฌ๋ `cd backend && make test-blocking-io`๋ฅผ ์คํํ์ธ์. ๋ฉ์ธํ
์ด๋๋ `cd backend && make test-live`๋ก ์ค์ `DeerFlowClient` ํ
์คํธ ์ค์ํธ๋ฅผ ์คํํ ์ ์์ต๋๋ค. ์ด ๋ช
๋ น์๋ ์ ํจํ ๋ฃจํธ `config.yaml`๊ณผ API ์๊ฒฉ ์ฆ๋ช
์ด ํ์ํฉ๋๋ค. API ๋น์ฉ์ด ๋ฐ์ํ ์ ์์ผ๋ฉฐ ๋ก์ปฌ ์๋๋ฐ์ค, ์ํฐํฉํธ ๋๋ ํ์ผ์ด ์์ฑ๋ ์ ์์ต๋๋ค. pytest๋ฅผ ์ง์ ์คํํ ๋๋ ์ถ๊ฐ๋ก `DEER_FLOW_RUN_LIVE_TESTS=1`์ด ํ์ํฉ๋๋ค.
ํ๊ท ํ
์คํธ์๋ `backend/tests/`์ Docker ์๋๋ฐ์ค ๋ชจ๋ ๊ฐ์ง ๋ฐ Provisioner kubeconfig ๊ฒฝ๋ก ์ฒ๋ฆฌ ํ
์คํธ๊ฐ ํฌํจ๋ฉ๋๋ค. ๋ฐฑ์๋ ๋ธ๋กํน I/O ์ง๋จ์ ์ ์ฅ์ ๋ฃจํธ์์ `make detect-blocking-io`๋ก ์คํํ ์ ์์ต๋๋ค. ์ด ๋ช
๋ น์ ๋ฐฑ์๋ ์ด๋ฒคํธ ๋ฃจํ์์ ์คํ๋ ์ ์๋ ๋ธ๋กํน I/O๋ฅผ ์ฐพ๊ธฐ ์ํด ๋ฐฑ์๋ ๋น์ฆ๋์ค ์ฝ๋๋ฅผ ์ ์ ์ผ๋ก ์ค์บํ๊ณ , ๊ฐ๊ฒฐํ ์์ฝ์ ์ถ๋ ฅํ๋ฉฐ, ์ ์ฒด JSON ๊ฒฐ๊ณผ๋ฅผ `.deer-flow/blocking-io-findings.json`์ ๊ธฐ๋กํฉ๋๋ค. JSON์๋ `priority`, `location`, `blocking_call`, `event_loop_exposure`, `reason`, `code`๋ฅผ ๋ด์ ๊ฐ๊ฒฐํ ๊ฒํ ๋ ์ฝ๋๊ฐ ํฌํจ๋ฉ๋๋ค. Gateway ์ํฐํฉํธ ์๋น์ ์ด์ ํ์ฑ ์น ์ฝํ
์ธ ์ ํ(`text/html` ๋ฐ `.xml`, `.xhtml`, `.svg` ๊ฐ์ XML ๋ฌธ์)์ ์ธ๋ผ์ธ์ผ๋ก ๋ ๋๋งํ์ง ์๊ณ ์ฒจ๋ถ ํ์ผ๋ก ๋ค์ด๋ก๋ํ๋๋ก ๊ฐ์ ํ์ฌ, ์์ฑ๋ ์ํฐํฉํธ์ XSS ์ํ์ ์ค์
๋๋ค.
ํ๋ก ํธ์๋ ๋ผ์ฐํธ ์์
์์ฐ์ `cd frontend && pnpm
perf:check`๋ก ํ์ธํ ์ ์์ต๋๋ค. ์ด ๋ช
๋ น์ ์ผ๋ฐ ํ๋ก๋์
๋น๋์์ `/login`์ ์ธก์ ํ ๋ค์, ํฝ์ค์ฒ ๊ธฐ๋ฐ ์ํฌ์คํ์ด์ค ๋ผ์ฐํธ๋ฅผ ์ํ ํ๋ก๋์
์ ์ ๋ฐ๋ชจ ๋น๋๋ฅผ ์ํํฉ๋๋ค. ๋ํ ๋ผ์ฐํธ๊ฐ ์ฐธ์กฐํ๋ ๊ณ ์ JavaScript์ CSS๋ฅผ ์ธก์ ํ๊ณ ์์ธ ๊ฒฐ๊ณผ๋ฅผ `.next/performance-results.json`์ ๊ธฐ๋กํฉ๋๋ค.
### ์คํฌ๋ฆฝํธ ์ํฌํ๋ก (์ ํ์ ํ์ฅ)
[์คํฌ๋ฆฝํธ ์ํฌํ๋ก ํ์ฅ](examples/deerflow-extension-workflows/README.md)์ ์์ ํ AgentRun, ๋ฐฑ๊ทธ๋ผ์ด๋ ์์, ์ ํ๋ ๋ณ๋ ฌ ์คํ, ์งํ ์ํฉ, ๊ฒฐ๊ณผ ๋ณด์กด, ์ทจ์๋ฅผ ํตํด ๊ฒ์ฌ ๊ฐ๋ฅํ JavaScript ์ค์ผ์คํธ๋ ์ด์
์ ์ถ๊ฐํฉ๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ๋นํ์ฑํ๋์ด ์์ผ๋ฉฐ, POSIX Gateway์ ์ด์์๊ฐ ์น์ธํ Agent ์ฐธ์กฐ๊ฐ ํ์ํฉ๋๋ค. 1๋จ๊ณ์์๋ ์ฌ๊ฐ, ์ฌ๋์ ์ํ ์ถ๋ ฅ ์น์ธ, ์ฌ์์ ์ ์ฌ์(replay), ์๊ฒฉํ ๊ธ์ก ์์ฐ์ ์ง์ํ์ง ์์ต๋๋ค. ์ํฌํ๋ก ๋ง๊ฐ ์๊ฐ๊ณผ ์์ ๊ด์ฐฐ ํ์์์์ ๋ถํ์คํ ์น์ธ(admission)๊ณผ ๋ณ๋๋ก ๋ณด๊ณ ๋ฉ๋๋ค. ์๋ฝ๋ ์์์ ๊ฒ์ฌ ์๋ก ๊ณ ์นจ์ด ์คํจํด๋ ์์ฒญ ์๋ณ ์ ๋ณด๋ฅผ ์ ์งํ๋ฉฐ, ๋ณ๋์ ๊ฒ์ฌ ์ฌ์๋ ๋์์ ์ ๊ณตํฉ๋๋ค. ์คํ ๊ฐ๋ฅํ ์์ , ์ค์น ๋จ๊ณ, ๊ทธ๋ฆฌ๊ณ ๋ค๋ฅธ Python/CPU ์กฐํฉ์ ์ํ QuickJS ์์ค ๋น๋ ์ฌ์ ์๊ตฌ ์ฌํญ์ด ํฌํจ๋์ด ์์ต๋๋ค.
## ๋ผ์ด์ ์ค
์ด ํ๋ก์ ํธ๋ ์คํ ์์ค์ด๋ฉฐ [MIT ๋ผ์ด์ ์ค](./LICENSE)๋ก ์ ๊ณต๋ฉ๋๋ค.
## ๊ฐ์ฌ์ ๋ง
DeerFlow๋ ์คํ ์์ค ์ปค๋ฎค๋ํฐ์ ๋๋ผ์ด ์ฑ๊ณผ ์์ ๋ง๋ค์ด์ก์ต๋๋ค. DeerFlow๋ฅผ ๊ฐ๋ฅํ๊ฒ ํด ์ค ๋ชจ๋ ํ๋ก์ ํธ์ ๊ธฐ์ฌ์์ ๋
ธ๋ ฅ์ ๊น์ด ๊ฐ์ฌ๋๋ฆฝ๋๋ค. ์ฐ๋ฆฌ๋ ์ง์ ์ผ๋ก ๊ฑฐ์ธ์ ์ด๊นจ ์์ ์ ์์ต๋๋ค.
๋ค์ ํ๋ก์ ํธ๋ค์ ์์คํ ๊ธฐ์ฌ์ ์ง์ฌ์ผ๋ก ๊ฐ์ฌ๋๋ฆฝ๋๋ค:
- **[LangChain](https://github.com/langchain-ai/langchain)**: ๋ฐ์ด๋ ํ๋ ์์ํฌ๋ก LLM ์ํธ์์ฉ๊ณผ ์ฒด์ธ์ ๊ตฌ๋ํ์ฌ ๋งค๋๋ฌ์ด ํตํฉ๊ณผ ๊ธฐ๋ฅ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
- **[LangGraph](https://github.com/langchain-ai/langgraph)**: ๋ฉํฐ ์์ด์ ํธ ์ค์ผ์คํธ๋ ์ด์
์ ๋ํ ํ์ ์ ์ธ ์ ๊ทผ ๋ฐฉ์์ผ๋ก DeerFlow์ ์ ๊ตํ ์ํฌํ๋ก๋ฅผ ๊ตฌํํ๋ ๋ฐ ํต์ฌ์ ์ธ ์ญํ ์ ํ์ต๋๋ค.
์ด ํ๋ก์ ํธ๋ค์ ์คํ ์์ค ํ์
์ด ์ง๋ ๋ณํ์ ํ์ ์ ๋ณด์ฌ์ฃผ๋ฉฐ, ์ฐ๋ฆฌ๋ ๊ทธ ๊ธฐ๋ฐ ์์ DeerFlow๋ฅผ ๋ง๋ค ์ ์์์ ์๋์ค๋ฝ๊ฒ ์๊ฐํฉ๋๋ค.
### ์ฃผ์ ๊ธฐ์ฌ์
๋น์ ๊ณผ ์ด์ , ํ์ ์ผ๋ก ์ด ํ๋ก์ ํธ์ ์๋ช
์ ๋ถ์ด๋ฃ์ `DeerFlow`์ ํต์ฌ ์ ์๋ค์๊ฒ ์ง์ฌ์ผ๋ก ๊ฐ์ฌ๋๋ฆฝ๋๋ค:
- **[Daniel Walnut](https://github.com/hetaoBackend/)**
- **[Henry Li](https://github.com/magiccube/)**
์ฌ๋ฌ๋ถ์ ๋ณํจ์๋ ํ์ ๊ณผ ์ ๋ฌธ์ฑ์ DeerFlow ์ฑ๊ณต์ ์๋๋ ฅ์ด์์ต๋๋ค. ์ด ์ฌ์ ์ ์ ๋์ ์ฌ๋ฌ๋ถ์ด ์์ด ์๊ด์
๋๋ค.
## Star History
[](https://star-history.dera.page/#bytedance/deer-flow&Date)