# ๐ŸฆŒ 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) | ํ•œ๊ตญ์–ด [![Python](https://img.shields.io/badge/Python-3.12%2B-3776AB?logo=python&logoColor=white)](./backend/pyproject.toml) [![Node.js](https://img.shields.io/badge/Node.js-22%2B-339933?logo=node.js&logoColor=white)](./Makefile) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE) bytedance%2Fdeer-flow | Trendshift > 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)์—์„œ ๋” ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ณ  **์‹ค์ œ ๋ฐ๋ชจ**๋ฅผ ํ™•์ธํ•˜์„ธ์š”. ๋žœ๋”ฉ ํŽ˜์ด์ง€์˜ ์‚ฌ๋ก€ ์—ฐ๊ตฌ๋Š” ํ—ˆ์šฉ ๋ชฉ๋ก์— ๋“ฑ๋ก๋œ ์ฝ๊ธฐ ์ „์šฉ ์‡ผ์ผ€์ด์Šค๋กœ ์—ด๋ฆฌ๋ฉฐ, ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ## ์ž๋งค ํ”„๋กœ์ ํŠธ image - [**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) InfoQuest_banner --- ## ๋ชฉ์ฐจ - [๐ŸฆŒ 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 ์ฑ„๋„ ์‹คํ–‰์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. IM ์ฑ„๋„์˜ `session.config`์— ์ง€์ •ํ•œ `recursion_limit`์ด ์šฐ์„ ํ•˜๋ฉฐ, GitHub ์ฑ„๋„ ์‹คํ–‰์€ ์ž์ฒด ํ•˜ํ•œ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์ž„๋ฒ ๋””๋“œ `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 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()` ๊ฒฝ๋กœ๋Š” ์ด๋ฅผ ์ž๋™์œผ๋กœ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ![DeerFlow TUI](docs/tui/tui-preview.svg) ```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 [![Star History Chart](https://star-history.dera.page/svg?repos=bytedance/deer-flow&type=Date)](https://star-history.dera.page/#bytedance/deer-flow&Date)