Spaces:
Sleeping
Sleeping
| # CLAUDE.md โ Interactive Novel Engine Backend | |
| ## ํ๋ก์ ํธ ๊ฐ์ | |
| ์์ ๊ณ ์ ์์ค(์นด๋ฅด๋ฐ๋ผ)์ ์จํจ๋ก์ง ๊ธฐ๋ฐ์ผ๋ก ํ์ํํ์ฌ "์ฑ ์ ์ฝ๋ ๋๋ + ํต์ฌ ์ฌ์์์ ์ํธ์์ฉ"์ ์ ๊ณตํ๋ ์ธํฐ๋ํฐ๋ธ ๋ ธ๋ฒจ ์์ง. Google ADK ๊ธฐ๋ฐ ํ์ดํ๋ผ์ธ์ด ์ ์ ์ ๋ ฅ์ ๋ฐ์ ๊ฐ๋ โ ์บ๋ฆญํฐ ์๋ต โ ๋๋ ํฐ(์๋ ด ํ๋จ) ์์ผ๋ก ์ฒ๋ฆฌํ๊ณ , ์์ยท์จํจ๋ก์ง ๊ฒ์์ GraphRAG ๊ณ์ธต์ด ๋ด๋น. | |
| **์ต์์ ๊ฐ์น: ์์ ์ถฉ์ค.** ์์์ ํค๊ณผ ์ธ๊ณ๊ด์ด ๊นจ์ง๋ ์๊ฐ ์คํจ๋ค. LLM์ ์์ ๋๋ ๊ธฐ๋ฅ์ด ์๋๋ผ ๋ฆฌ์คํฌ๋ก ์ทจ๊ธํ๋ค. | |
| ## ์ํคํ ์ฒ 3์ธต ๊ตฌ์กฐ | |
| ``` | |
| [๋ฐ๋จ] ์จํจ๋ก์ง/์ํ ์ค๊ณ ๋ฌธ์ โ YAML v1.0 (๋ํ๋ ์ฐ์ถ๋ฌผ) โ ์์ง์ด ํ์ฑ | |
| [์ค๊ฐ] GraphRAG: ์จํจ๋ก์ง YAML์ Neo4j์ ์ ์ฌ + ์๋ฌธ ๋ฐ์ท ๋ฒกํฐ ๊ฒ์ | |
| [์๋จ] ADK ์์ด์ ํธ ํ์ดํ๋ผ์ธ (guard โ character โ director) | |
| ``` | |
| - ์จํจ๋ก์ง์ **๋ด์ฉ**์ ๋ํ๋ ์์ , YAML **์คํค๋ง(ํ์)**๋ ๊ฐ๋ฐํ ์์ . ์คํค๋ง ๋ณ๊ฒฝ์ ์์ชฝ ํฉ์๋ก๋ง. | |
| - ๊ทธ๋ํ๋ ์๋ฌธ์์ LLM์ด ์๋ ์ถ์ถํ์ง ์๋๋ค. ํ๋ ์ด์ ๋ YAML์ ์ ์ฌํ๋ ๊ฒ์ด ์ ์ผํ ๊ฒฝ๋ก. | |
| ## ์์ ์์น | |
| ### 1. ๋ ผ์ โ ์ค๊ณ โ ๊ณํ โ ๊ตฌํ โ ๋ฆฌ๋ทฐ | |
| ์ฝ๋๋ฅผ ๋จผ์ ์์ฑํ์ง ์๋๋ค. ๋ฐ๋์ ์ด ์์๋ฅผ ๋ฐ๋ฅธ๋ค: | |
| 1. **๋ ผ์**: ์๊ตฌ์ฌํญ์ ์ ํํ ์ดํดํ๊ณ ์ง๋ฌธํ๋ค | |
| 2. **์ค๊ณ**: 2-3๊ฐ ์ ๊ทผ๋ฒ์ ๋น๊ตํ๊ณ ์ถ์ฒํ๋ค | |
| 3. **๊ณํ**: ๊ตฌ์ฒด์ ์ธ ํ์ผ ๋ชฉ๋ก๊ณผ ๋ณ๊ฒฝ ์ฌํญ์ ๋ฌธ์ํํ๋ค | |
| 4. **๊ตฌํ**: ๊ณํ๋๋ก๋ง ๊ตฌํํ๋ค. ๋ฒ์๋ฅผ ๋ฒ์ด๋์ง ์๋๋ค | |
| 5. **๋ฆฌ๋ทฐ**: ๊ตฌํ ๊ฒฐ๊ณผ๋ฅผ spec๊ณผ ๋์กฐํ์ฌ ๊ฒ์ฆํ๋ค | |
| 6. **๊ฐฑ์ **: ์ปค๋ฐ ๋ฐ ์ฝ๋ ๊ตฌํ์ด ์๋ฃ๋๋ฉด ํด๋น ๋ถ๋ถ์ ๊ผผ๊ผผํ๊ฒ ๋จ๊ณ๋ณ๋ก ๋ฉ๋ชจ๋ฆฌ์ ๋ฐ์ ๋ฐ ๊ฐฑ์ ํ์ธ์ | |
| ์ด ์ฌ์ดํด์ ์ถฉ๋ถํ ๋ฐ๋ณตํ๋ค. ๊ธํ๋ค๊ณ ๊ฑด๋๋ฐ์ง ์๋๋ค. | |
| ### 2. ๊ธฐ์กด ์ฝ๋์ ์ผ๊ด์ฑ์ ์งํจ๋ค | |
| - ์ ์ฝ๋๋ ๊ธฐ์กด ํจํด์ ๋ฐ๋ฅธ๋ค. ๋ ๋์ ํจํด์ด ์์ด๋ ํผ์ ๋ฐ๊พธ์ง ์๋๋ค | |
| - ํด๋ ๊ตฌ์กฐ, ๋ค์ด๋ฐ, import ์คํ์ผ์ ๊ธฐ์กด ์ฝ๋์์ ๋จผ์ ํ์ธํ๋ค | |
| - "๊ฐ์ "์ด๋ผ๋ ์ด๋ฆ์ผ๋ก ๊ธฐ์กด ์ปจ๋ฒค์ ์ ๋ฌด์ํ์ง ์๋๋ค | |
| ### 3. Google ADK ๊ณต์ ํจํด์ ๋ฐ๋ฅธ๋ค | |
| - ADK๊ฐ ์ ๊ณตํ๋ ๊ธฐ๋ฅ(LlmAgent, ParallelAgent, SequentialAgent, LoopAgent, AgentTool, FunctionTool)์ผ๋ก ํด๊ฒฐํ๋ค | |
| - Python์ผ๋ก ADK๋ฅผ ์ฐํํ๊ฑฐ๋ ๋์ฒดํ๋ ์ฝ๋๋ฅผ ์์ฑํ์ง ์๋๋ค | |
| - ํ๋กฌํํธ๋ก ํด๊ฒฐํ๋ ค ํ๊ธฐ ์ ์, ์์ด์ ํธ ๊ตฌ์กฐ(๊ณ์ธต, ํ์ , ์กฐํฉ)๋ก ํด๊ฒฐํ ์ ์๋์ง ๋จผ์ ๊ฒํ ํ๋ค | |
| - **์กฐ๊ธ์ด๋ผ๋ ์์ฌ๋๋ฉด ๋ฐ๋ก ADK ๊ณต์๋ฌธ์๋ฅผ ํ์ธํ๋ค**: https://google.github.io/adk-docs/ | |
| ### 4. ํ์ธ ์์ด ์ถ์ธกํ์ง ์๋๋ค | |
| - ํ์ผ์ ์์ ํ๊ธฐ ์ ์ ๋ฐ๋์ ์ฝ๋๋ค | |
| - ADK API๋ฅผ ์ฌ์ฉํ ๋ ๊ธฐ์ต์ ์์กดํ์ง ์๊ณ ๋ฌธ์๋ ์์ค๋ฅผ ํ์ธํ๋ค | |
| - Docker ๋ก๊ทธ, grep ๊ฒฐ๊ณผ ๋ฑ ์ค์ ์ฆ๊ฑฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋จํ๋ค | |
| - ์์ ์๋ฌธยท์จํจ๋ก์ง ๋ด์ฉ์ ๊ธฐ์ต์ผ๋ก ์ธ์ฉํ์ง ์๋๋ค. ๋ฐ๋์ content/ ๋๋ ๊ทธ๋ํ์์ ์กฐํํ๋ค | |
| ### 5. ์์ฌ ์งํ์ ์ฝ๋๊ฐ, ๋์ฌ๋ LLM์ด | |
| - ์ฑํฐ/์ฌ ์ ํ, ๋ถ๊ธฐ ์กฐ๊ฑด, ์๋ ด ํ์ ์ **์ต์ข ๊ฒฐ์ ์ ๊ฒฐ์ ์ ์ฝ๋**(์ํ๋จธ์ + director ์ถ๋ ฅ์ ๊ตฌ์กฐํ๋ ๊ฒ์ฆ)๊ฐ ๋ด๋ฆฐ๋ค | |
| - LLM์ "์ง๊ธ ์ด ์ฌ ์์์ ์ด ์บ๋ฆญํฐ๋ก ์๋ต"ํ๋ ์ข์ ์ญํ ๋ง ๋งก๋๋ค | |
| - LLM ์ถ๋ ฅ๋ง ๋ฏฟ๊ณ state๋ฅผ ์ ์ด์ํค์ง ์๋๋ค. ์ ์ด ์กฐ๊ฑด์ ๋ฐ๋์ ์ฝ๋์์ ์ฌ๊ฒ์ฆํ๋ค | |
| --- | |
| ## ํต์ฌ ๋๋ฉ์ธ ๊ท์น | |
| ### ์์ ์ถฉ์ค (Canon Fidelity) | |
| - ์บ๋ฆญํฐ๊ฐ ์์์ ์๋ ์ฌ์ค์ ๋จ์ ํ๋ ์๋ต์ ๊ฒฐํจ์ด๋ค. ํ๋กฌํํธ์ ์ฃผ์ ๋ ์จํจ๋ก์งยท์๋ฌธ ๋ฐ์ท ๋ฒ์ ์์์๋ง ๋งํ๊ฒ ํ๋ค | |
| - ์ ์ ๊ฐ ์ธ๊ณ๊ด์ ๋ฒ์ด๋ ํ๋์ ํ๋ฉด director๊ฐ ์ธ๊ณ๊ด ๋ด ํ๋ฒ์ผ๋ก ๋๋๋ฆฐ๋ค. ๋ฉํ ๋ฐํ("์ ๋ AI๋ผ์...")๋ ์ ๋ ๊ธ์ง | |
| - ๋ฌธ์ฒด๋ `content/style/` ๋ฌธ์ฒด์ฐ์ถ ๊ฐ์ด๋๊ฐ ๊ธฐ์ค. style_critic ๋ฃจํ๊ฐ ๊ฒ์ํ๋ค | |
| ### ์คํฌ์ผ๋ฌ ์ค์ฝํ (๋งค์ฐ ์ค์) | |
| - ๋ชจ๋ ์๋ฌธ ์ฒญํฌ, ๊ทธ๋ํ ๋ ธ๋/์ฃ์ง, ์จํจ๋ก์ง ํญ๋ชฉ์๋ `state_id`(์์ฌ ์งํ ๋จ์)๊ฐ ๋ถ๋๋ค | |
| - **๋ชจ๋ ๊ฒ์์ `state_id <= ํ์ฌ state` ํํฐ๋ฅผ ๊ฐ์ ํ๋ค.** ํํฐ ์๋ ๊ฒ์ ์ฝ๋๋ ๋ฆฌ๋ทฐ์์ ๋ฐ๋ ค | |
| - ์ง์ ์ํ: "state N ์์ ์ ์ด ์บ๋ฆญํฐ๊ฐ ์๋ ๊ฒ"์ ์จํจ๋ก์ง์ ์ง์ ์ํ ํญ๋ชฉ์ด ๊ถ์. ์บ๋ฆญํฐ ํ๋กฌํํธ์๋ ํด๋น ์์ ์ง์๋ง ์ฃผ์ ํ๋ค | |
| ### ์๋ ด (Convergence) | |
| - ์ฌ๋ง๋ค YAML์ ์ ์๋ ๋ชฉํ ๋นํธ(goal beats)์ ์๋ ด ์กฐ๊ฑด(exit condition)์ด ์๋ค | |
| - director๋ ๋งค ํด "๋ชฉํ ๋นํธ ๋ฌ์ฑ ์ฌ๋ถ / ์ดํ ์ ๋ / ์๋ ด ์์ ๋๋ฌ ์ฌ๋ถ"๋ฅผ ๊ตฌ์กฐํ ์ถ๋ ฅ์ผ๋ก ํ๋จํ๋ค | |
| - ์ต๋ ํด ์๋ฅผ ์ด๊ณผํ๋ฉด director๊ฐ ๊ฐ์ ์๋ ด ๋ด๋ ์ด์ ์ผ๋ก ์ฌ์ ๋ซ๋๋ค (๋ฌดํ ์ฒด๋ฅ ๋ฐฉ์ง) | |
| --- | |
| ## ์์ด์ ํธ ํด๋ ๊ท์น | |
| ``` | |
| ์์ด์ ํธ = ํด๋ + agent.py โ ํ์ ์์ด์ ํธ๊ฐ ์๋ ๊ณ์ธตํ | |
| ํ์ ์์ด์ ํธ = sub_agents/ ํด๋ โ ๋ถ๋ชจ-์์ ๊ณ์ธต | |
| ๊ฐ์ ๋์ค ๋ณ๋ ฌ ์์ด์ ํธ = agents/ ํ์ผ โ ์์ฒด ํ์ ์๋ ๋จ์ ์์ด์ ํธ (๊ฐ๋ ๋ฑ) | |
| ๋๊ตฌ = tools/ ์์ 1ํ์ผ = 1ํจ์ | |
| instruction 10์ค ์ด๊ณผ = instructions/ ํด๋๋ก ๋ถ๋ฆฌ | |
| ํฉํ ๋ฆฌ ํจ์ = ์กฐ๋ฆฝ๋ง ๋ด๋น (ํด๋์ค ์ ์/DB ํฌํผ ํฌํจ ๊ธ์ง) | |
| ``` | |
| ### sub_agents/ vs agents/ ๊ตฌ๋ถ | |
| - `sub_agents/X/agent.py` ํจํด์ **X๊ฐ ์ถ๊ฐ๋ก ํ์ ๊ณ์ธต์ ๊ฐ์ง ๋** ์ฌ์ฉ. | |
| ์: `sub_agents/director/sub_agents/style_critic/...` | |
| - `agents/X.py` ํจํด์ **X๊ฐ ์์ฒด ํ์ ์์ด ๋จ์ผ BaseAgent/LlmAgent๋ก ๋๋ ๋** ์ฌ์ฉ. | |
| ํฉํ ๋ฆฌ ํจ์(`create_X()`)์ ํด๋์ค๋ฅผ ๊ฐ์ ํ์ผ์ ๋ชจ์๋ . | |
| ์: `engine/agents/input_guard.py`, `spoiler_guard.py`, `scene_context_loader.py` | |
| ### ํฉํ ๋ฆฌ ํ์ผ ์ฑ ์ ๋ถ๋ฆฌ | |
| `factory.py`๋ **์กฐ๋ฆฝ๋ง** ๋ด๋น. ์์ด์ ํธ ํด๋์ค ์ ์ยทDB ํฌํผ ํจ์๋ | |
| `agents/*.py`๋ `sub_agents/*/agent.py`์ ์์น. ํฉํ ๋ฆฌ๋ ๊ทธ๊ฒ๋ค์ importํด์ | |
| `SequentialAgent(sub_agents=[create_guard(scene_id), create_character(scene_id), ...])` | |
| ํํ๋ก ์ฎ๋ ์ญํ ๋ง. | |
| ### ์์ง ๊ตฌ์กฐ | |
| ``` | |
| engine/ | |
| โโโ agent.py โ ๋ฃจํธ ์์ด์ ํธ (ํด ํ์ดํ๋ผ์ธ) | |
| โโโ app.py โ ADK App + Runner + Plugin ๋ฑ๋ก | |
| โโโ model.py โ LLM ๋ชจ๋ธ ์ค์ (env์์ ์ฝ์) | |
| โโโ router.py โ FastAPI ์๋ํฌ์ธํธ (HTTP๋ง ๋ด๋น) | |
| โโโ instructions/ โ instruction ํ ์คํธ (์บ๋ฆญํฐ/๋๋ ํฐ/๊ฐ๋) | |
| โโโ callbacks/ โ ์์ด์ ํธ๋ณ ์ฝ๋ฐฑ | |
| โโโ plugins/ โ ADK Plugin (ํก์ข ๋จ ๊ด์ฌ์ฌ) | |
| โ โโโ logging.py โ ํด ๋ก๊น (์ ๋ ฅ/์ปจํ ์คํธ/์๋ต/๊ฐ๋๋ฐ๋/์๋ ด) โ ์ฐ๊ตฌ ๋ฐ์ดํฐ ๊ฒธ์ฉ | |
| โโโ services/ โ ๋น์ฆ๋์ค ๋ก์ง | |
| โ โโโ story.py โ ์นด๋ ์งํ ์ํ๋จธ์ (canon ์ฝ๊ธฐ/next ์ ์ด/์๋ฉ ํ์ ) | |
| โ โโโ pocket.py โ ๊ฐ์ ํฌ์ผ: ADK ์ธ์ ๊ด๋ฆฌ + run_turn() + ์๋ ด ์ฝ๋ ์ฌ๊ฒ์ฆ | |
| โ โโโ state.py โ ์จ์ ์ํ (์ ๋ขฐ์ถ/์ ์ฝ๋/์) ์ปค๋ฐ | |
| โ โโโ retrieval.py โ ๊ฒ์ ์ค์ผ์คํธ๋ ์ด์ (์คํฌ์ผ๋ฌ ํํฐ ๊ฐ์ ์ง์ , GraphRAG๋ 2๋จ๊ณ) | |
| โโโ repositories/ โ ๋ฐ์ดํฐ ์ ๊ทผ | |
| โ โโโ ontology.py โ ์จํจ๋ก์ง ์กฐํ ์ธํฐํ์ด์ค (๊ตฌํ: yaml_direct / neo4j) | |
| โ โโโ manuscript.py โ ์๋ฌธ ์ฒญํฌ + ๋ฒกํฐ ๊ฒ์ | |
| โ โโโ playlog.py โ ํด ๋ก๊ทธ ์ ์ฅ | |
| โโโ tools/ โ 1ํ์ผ = 1๋๊ตฌํจ์ | |
| โ โโโ retrieval/ โ query_ontology, search_excerpt | |
| โ โโโ state/ โ set_flag, update_affinity, mark_beat | |
| โโโ sub_agents/ โ ์์ด์ ํธ ํธ๋ฆฌ | |
| โ โโโ character/ โ ์บ๋ฆญํฐ ์๋ต (์ธ๋ฌผ ์ํธ + ์ฌ ๋ธ๋ฆฌํ + ๋ฐ์ท ์ฃผ์ ) | |
| โ โโโ director/ โ ๋นํธ ๋ฌ์ฑ/์ดํ/์๋ ด ํ๋จ (๊ตฌ์กฐํ ์ถ๋ ฅ) | |
| โ โโโ style_critic/ โ LoopAgent (generator + critic) ๋ฌธ์ฒด ๊ฒ์ | |
| โโโ schemas/ โ Pydantic: ์ฝํ ์ธ 3๋ ์ด์ด ์คํค๋ง + validate CLI | |
| โโโ content/ โ (์ฝ๊ธฐ ์ ์ฉ) ์์ง์ ์ ์ผํ ์์ฌ ์ ๋ ฅ โ ์์ฒ์ ๋นํธ์นด๋ MD(๋ํ๋ ์์ ) | |
| โโโ beatcards/ โ ๋นํธ์นด๋ YAML (scripts/beatcard_convert.py ์ฐ์ถ๋ฌผ, E01~) | |
| โโโ chapters/ โ ์ฑํฐ ๋ฉํ (entry/exit beats, ending_rules, R์นด๋ ๋ฑ๋ก) | |
| โโโ characters.yaml โ ์ธ๋ฌผ ์ ์ฒด์ฑ ์ํธ (ENOS, ์ง์๊ฒฝ๊ณ, kb_query ํ ) | |
| โโโ style/ โ ๋ฌธ์ฒด์ฐ์ถ ๊ฐ์ด๋ | |
| โโโ narrative/ โ ์์ฌ/ํธ๋์คํ ๋ฌธ์ | |
| ``` | |
| ### ADK App + Plugin ๊ท์น | |
| - `app.py`์์ `App` ๊ฐ์ฒด + `Runner`๋ฅผ ์ ์ํ๋ค | |
| - ํก์ข ๋จ ๊ด์ฌ์ฌ(๋ก๊น , ๋ชจ๋ํฐ๋ง ๋ฑ)๋ Plugin์ผ๋ก ๋ถ๋ฆฌํ๋ค (`plugins/`) | |
| - Runner๋ `App` ๊ธฐ๋ฐ์ผ๋ก ์ด๊ธฐํํ๋ค (`Runner(app=app, ...)`) | |
| - agent๋ฅผ Runner์ ์ง์ ์ ๋ฌํ์ง ์๋๋ค (๋ ๊ฑฐ์ ํจํด) | |
| - ์ค์บํด๋ ํ์ผ(๋ฏธ๊ตฌํ ๋๊ตฌ, ๋น ์ฝ๋ฐฑ, ๋น instruction)์ ์ญ์ ํ์ง ์๋๋ค | |
| - Claude Code๊ฐ ADK ํจํด์ ๋ฒ์ด๋์ง ์๋๋ก ํ๋ ๊ฐ๋๋ ์ผ ์ญํ | |
| - ํธ์ถ ํ๋ฆ: Agent โ Tool(FunctionTool) โ Service โ Repository โ ๋ฐ์ดํฐ(YAML/Neo4j/DB) | |
| --- | |
| ## ์ฝํ ์ธ ํ์ดํ๋ผ์ธ (A์ ์ํคํ ์ฒ โ 2026-07-03 ํ์ ) | |
| ### ์ฝํ ์ธ 3๋ ์ด์ด | |
| | ๋ ์ด์ด | ํ์ผ | ๋ด์ฉ | ๋์ ์คํค๋ง | | |
| |------|------|------|------| | |
| | ์ ์ฒด์ฑ (๋ถ๋ณ) | `content/characters.yaml` | ์ธ๋ฌผ ์ํธ(ENOS), player=laura, ์ง์๊ฒฝ๊ณ, kb_query ํ | `schemas/character.py` | | |
| | ์ฑํฐ ๋ฉํ | `content/chapters/*.yaml` | entry/exit beats, beat_range, ์๋ฉ ๊ท์น, R์นด๋ ๋ฑ๋ก | `schemas/chapter.py` | | |
| | ๋ด๋ฌํฐ๋ธ | `content/beatcards/E##/*.yaml` | ์นด๋: narration ๋ธ๋ก/choices/next/canon/๋ณต์ ํ๊ทธ/์ฐ์ถ | `schemas/beatcard.py` | | |
| - **์ฝํ ์ธ ์์ฒ(๊ถ์)์ ๋นํธ์นด๋ MD**(`์นด๋ฅด๋ฐ๋ผ/.../๋นํธ์นด๋/`, ๋ํ๋ ์์ ). ๋ณํ YAML์ ํ์๋ฌผ์ด๋ฉฐ `scripts/beatcard_convert.py`(๊ฐ๋ฐํ ์์ )๋ก๋ง ์์ฑ | |
| - ์ฝํ ์ธ ๋ด์ฉ ์์ ์ ๊ฐ๋ฐํ์ด ํ์ง ์๋๋ค. ์คํค๋ง ์๋ฐ ๋ฐ๊ฒฌ ์ ๊ฒ์ฆ ๋ฆฌํฌํธ๋ก ๋ํ๋๊ป ์ ๋ฌ | |
| - `python -m engine.schemas.validate content/` ๊ฐ ํต๊ณผํ์ง ์๋ YAML์ ์ ์ฌํ์ง ์๋๋ค | |
| - MVP์ ์์ฌ ์งํ ๋จ์๋ ๋นํธ์นด๋ ์์: ์คํฌ์ผ๋ฌ ํํฐ์ `state_id`๋ `beat_id โค ํ์ฌ`๋ก ํด์ํ๋ค | |
| ### ์จ์ ์ํ ๋ชจ๋ธ (P0 4์ข ์์ง ๋ช ์ธ ์ค๊ฑฐ) | |
| - **์ ๋ขฐ์ถ**(์์ฌโ์ ๋ขฐ ์์) ยท **์ ์ฝ๋**(๋จ์กฐ ์ฆ๊ฐ, ์ ๋ขฐ์ ๋ ๋ฆฝ โ ํต์ฌ ์์ด๋ฌ๋) ยท **์**(์ ์ , ๋์ 1ํ ํ๋ฆฝ ํ ๋ถ๋ณ) | |
| - ์ซ์ยท๊ฒ์ด์งยท์์คํ ๋ฉ์์ง๋ฅผ ์ ์ ์๊ฒ ์ ๋ ๋ ธ์ถํ์ง ์๋๋ค. ์ํ๋ ๋ด๋ ์ด์ ํคยท์นด๋ฅด๋ฐ๋ผ์ ๊ฒฐยทํด๊ธ์ผ๋ก๋ง ๋๋ฌ๋ธ๋ค | |
| - ์๋ฉ ํ์ ์ ์ฑํฐ ๋ฉํ์ `ending_rules` ์กฐ๊ฑด์์ ์ฝ๋๋ก ํ๊ฐํ๋ค (LLM ํ์ ๊ธ์ง) | |
| ### GraphRAG ๊ณ์ธต (2๋จ๊ณ โ MVP ์ ์ธ) | |
| - MVP๋ pre_kb ์ํ: `content/`์ `kb_query` ํ (`source: kb_query, status: pending`)์ ์ฑ์ฐ์ง ์๊ณ ๊ทธ๋๋ก ๋๋ค | |
| - MVP ์ฝํ ์ธ ๋ก๋๋ `repositories/content.py`(YAML ๋ฉ๋ชจ๋ฆฌ ๋ก๋). ์ดํ GraphRAG ๋์ ์ `kb_query` ํ ์ ์ฑ์ฐ๋ ๊ตฌํ์ผ๋ก ๊ต์ฒด. ์์ ๊ณ์ธต์ ๊ตฌํ์ ๋ชฐ๋ผ์ผ ํ๋ค (ablation ์คํ ์๊ฑด) | |
| - Neo4j ์ ์ฌ ์ LLM ์๋ ์ถ์ถ KG ๋น๋(SimpleKGPipeline ๋ฅ)๋ ์ฌ์ฉ ๊ธ์ง โ ํ๋ ์ด์ ์ฝํ ์ธ ์ ์ถฉ๋ | |
| - ๋ ์ ์ํธ์์ฉ ๋ฐ์ดํฐ์ ๊ทธ๋ํํ๋ 2๋จ๊ณ. MVP์์๋ `playlog` ์คํค๋ง ์ค๊ณ๊น์ง๋ง | |
| --- | |
| ## ADK ํต์ฌ ๊ท์น | |
| ### Instruction | |
| | ์ข ๋ฅ | ์ฉ๋ | ์ฃผ์ | | |
| |------|------|------| | |
| | `instruction` | ๋์ . `{var}`๋ก state ๋ณ์ ์นํ | `{}`๋ state ๋ณ์๋ก ํ์ฑ๋จ. ์์ ํ ์คํธ์ `{}` ์ฐ์ง ๋ง ๊ฒ | | |
| | `global_instruction` | ์ ์ฒด sub_agent์ ์ ํ | ์๋์ ์ผ๋ก ์ฌ์ฉํ ๋๋ง ์ฑ์ธ ๊ฒ | | |
| | `static_instruction` | ๊ณ ์ . ๋ฉํฐ๋ชจ๋ฌ ์ง์ | ์บ๋ฆญํฐ ์ํธ์ฒ๋ผ ์ฌ ๋ด ๋ถ๋ณ ์ปจํ ์คํธ์ ๊ฒํ | | |
| - ์์ ๋ฐ์ทยท์จํจ๋ก์ง ์ปจํ ์คํธ๋ฅผ instruction์ ๋ฃ์ ๋ ์๋ฌธ์ `{`, `}`๊ฐ ํฌํจ๋ ์ ์์ผ๋ฏ๋ก ์ฃผ์ ์ ์ด์ค์ผ์ดํ ์ฒ๋ฆฌ๋ฅผ ๊ฑฐ์น๋ค (์ ์ฒ๋ฆฌ ์ ํธ ํ์) | |
| ### Callback (8์ข ) | |
| `before_agent`, `after_agent`, `before_model`, `after_model`, `before_tool`, `after_tool`, `on_model_error`, `on_tool_error` | |
| - `before_model`: ์คํฌ์ผ๋ฌ ํํฐ ์ต์ข ๋ฐฉ์ด์ (์ฃผ์ ์ปจํ ์คํธ์ state_id ๊ฒ์ฌ) | |
| - `after_model`: ํด ๋ก๊น ํ | |
| ### ์์ด์ ํธ ํ์ | |
| | ํ์ | ์ฉ๋ | ์์ | | |
| |------|------|------| | |
| | `LlmAgent` | LLM์ด ํ๋จ/๋๊ตฌ ํธ์ถ | character, director | | |
| | `ParallelAgent` | ํ์ ์์ด์ ํธ ๋ณ๋ ฌ ์คํ | (ํ์ ์) ๋ค์ค ๊ฒ์ | | |
| | `SequentialAgent` | ํ์ ์์ด์ ํธ ์์ฐจ ์คํ | turn_pipeline (guard โ character โ director) | | |
| | `LoopAgent` | ํ์ ์์ด์ ํธ ๋ฐ๋ณต (escalate๋ก ํ์ถ) | style_critic (generator + critic), ์ฌ ๋ด ํด ๋ฃจํ | | |
| | `BaseAgent` | LLM ์์ด ์ฝ๋๋ก ์ง์ ์ฒ๋ฆฌ | input_guard(๊ท์น ๊ธฐ๋ฐ 1์ฐจ), scene_context_loader, ์ํ ์ ์ด ๊ฒ์ฆ | | |
| | `CustomAgent` | BaseAgent ํ์ฅ. ์กฐ๊ฑด ๋ถ๊ธฐ, ๋์ ์์ด์ ํธ ์ ํ | ์ฌ ํ์ ๋ณ ํ์ดํ๋ผ์ธ ์ ํ | | |
| ### ์ ๋ ํ์ง ๋ง ๊ฒ | |
| - `output_schema`์ `tools` ๋์ ์ฌ์ฉ โ **Gemini 3.0๋ง ์ง์**, ๋ค๋ฅธ ๋ชจ๋ธ์์๋ ์ ๋จ. ํ์ํ๋ฉด sub-agent๋ก ์ถ๋ ฅ ํฌ๋งทํ ์ ๋ถ๋ฆฌํ ๊ฒ | |
| - `mode="ANY"` ์ฌ์ฉ (๋ฌดํ ๋ฃจํ ๋ฐ์) | |
| - instruction ์์ ์์ ํ ์คํธ๋ก `{ํ๊ตญ์ด}` ์ฌ์ฉ (state ๋ณ์๋ก ํ์ฑ๋จ โ ์๋ฌ) | |
| - Python ์ฝ๋๋ก ADK ์ํฌํ๋ก์ฐ๋ฅผ ๋์ฒด (keyword matching, hardcoded fallback ๋ฑ) | |
| - `LlmAgent`์ `output_key`๋ก **๊ตฌ์กฐํ๋ ๊ฐ์ ๊ธฐ๋** โ LLM ํ ์คํธ๋ง ์ ์ฅ๋จ. director์ ์๋ ด ํ์ ์ฒ๋ผ ๊ตฌ์กฐํ ๊ฐ์ด ํ์ํ๋ฉด `FunctionTool`์ด `tool_context.state`์ ์ง์ ์ฐ๊ฑฐ๋ BaseAgent๋ก ๊ตฌํ | |
| - ๊ฒ์/์ปจํ ์คํธ ์ฃผ์ ๊ฒฝ๋ก์์ `state_id` ํํฐ๋ฅผ ์๋ต (์คํฌ์ผ๋ฌ ์ฌ๊ณ ) | |
| - LLM ํ๋จ๋ง์ผ๋ก ์ฌ/์ฑํฐ ์ ์ด (๋ฐ๋์ `services/scene.py`์ ์ฝ๋ ๊ฒ์ฆ์ ๊ฑฐ์น ๊ฒ) | |
| - ์์ ์๋ฌธ์ ํ๋กฌํํธ์ ๊ธฐ์ต์ผ๋ก ์ฌํ (๋ฐ๋์ repository ์กฐํ) | |
| ### Escalate scope ๊ฒฉ๋ฆฌ (๋งค์ฐ ์ค์) | |
| ADK `LoopAgent`๋ sub_agent์ `escalate=True` ์ด๋ฒคํธ๋ฅผ **์์๋ก yield**ํ๋ค. ์ฆ | |
| ์ค์ฒฉ LoopAgent๊ฐ ์์ผ๋ฉด ๋ฐ๊นฅ ๋ฃจํ๊น์ง ํจ๊ป ํ์ถํ๋ค(์ ํ๋ก์ ํธ ์ค์ธก ํ์ธ). ์ด๋ก ์ธํด: | |
| - **SequentialAgent๋ escalate๋ฅผ ์ธ์ํ์ง ์์**. escalate๊ฐ ํ์ํ ์๋ฆฌ์ ๋์ผ๋ ค๋ฉด | |
| ํด๋น ๋ฒ์๋ง `LoopAgent(max_iterations=1)`๋ก ๊ฐ์ ๊ฒ | |
| - **๋ด๋ถ LoopAgent์ ์ฑ๊ณต-escalate๊ฐ ๋ฐ๊นฅ์ ์ค์ผ์ํค๋ฉด ์ ๋๋ ๊ฒฝ์ฐ**์ ๋ฐ๋์ | |
| ๋ฐ๊นฅ์ SequentialAgent๋ก ๋๊ณ , escalate๋ฅผ ์ํํ scope๋ง LoopAgent๋ก | |
| - ์ฌ ํด ํ์ดํ๋ผ์ธ ์ค๊ณ ์ ์ด ๊ท์น์ ์ ์ฉํ ๊ธฐ์ค ๊ตฌ์กฐ: | |
| ``` | |
| scene_session (SequentialAgent) | |
| โโโ scene_context_loader โ BaseAgent, YAML/๊ทธ๋ํ์์ ์ฌ ๋ธ๋ฆฌํ ๋ก๋ | |
| โโโ turn_loop (LoopAgent max=์ฌ๋ณ max_turns) โ director์ ์๋ ด-escalate๊ฐ ์ฌ๊ธฐ์ ๊ทธ์นจ | |
| โ โโโ input_guard | |
| โ โโโ character | |
| โ โโโ director โ ์๋ ด ํ์ ์ escalate | |
| โโโ scene_closer (LoopAgent max=1) โ ๊ฐ์ ์๋ ด ๋ด๋ ์ด์ + ์ํ ์ ์ด ์ปค๋ฐ | |
| ``` | |
| ### ๊ถ์ ์์ค ์์น | |
| **"ํ ์ ๋ณด์ ์ง์ค์ ํ ๊ณณ์๋ง ์์ด์ผ ํ๋ค."** | |
| - ์์ฌ ๋ด์ฉ(์ธ๋ฌผ/๊ด๊ณ/์ฌ๊ฑด/์ง์์ํ) ๊ถ์: `content/yaml/` (์ ์ฌ๋ Neo4j๋ ๊ทธ ์ฌ๋ณธ). ์ฝ๋์ ์์ฌ ๋ด์ฉ ํ๋์ฝ๋ฉ ๊ธ์ง | |
| - ์ฌ ์งํ ์ํ ๊ถ์: `session.state` (์ฌ ๋ด) โ ์ฌ ์ข ๋ฃ ์ `scene.py`๊ฐ DB์ ์ปค๋ฐ (์์). ๋ ๊ณณ์ ๋์์ ๊ฐฑ์ ํ๋ ์ฝ๋ ๊ธ์ง | |
| - ํ์ฌ ์ ์ ์ ์์ฌ ์์น ๊ถ์: DB `play_session.current_state_id`. ๊ฒ์ ํํฐ๋ ์ด ๊ฐ์ผ๋ก๋ง | |
| - ๋ฌธ์ฒด ๊ธฐ์ค ๊ถ์: `content/style/`. ํ๋กฌํํธ๋ง๋ค ๋ฌธ์ฒด ์ง์๋ฅผ ์ฆํฅ ์์ฑํ์ง ์๋๋ค | |
| - ์๋ ด ํ์ ๊ถ์: director์ ๊ตฌ์กฐํ ์ถ๋ ฅ + `scene.py`์ ์ฝ๋ ๊ฒ์ฆ. LLM ํ ์คํธ ํ์ฑ์ผ๋ก ํ์ ๊ธ์ง | |
| --- | |
| ## LLM ๋ชจ๋ธ | |
| ```python | |
| # engine/model.py | |
| from google.adk.models.lite_llm import LiteLlm | |
| _MODEL_ID = os.environ.get("LLM_MODEL", "openai/gpt-5.4-nano") | |
| LLM_MODEL = LiteLlm(model=_MODEL_ID) | |
| ``` | |
| - ๋ก์ปฌ ํ ์คํธ: ์ ๋น์ฉ ๋ชจ๋ธ๋ก ํ์ดํ๋ผ์ธ ๊ฒ์ฆ | |
| - ์บ๋ฆญํฐ/๋ฌธ์ฒด ํ์ง์ด ์ค์ํ character, style_critic์ ์์ ๋ชจ๋ธ์ ๋ณ๋ env๋ก ๋ถ๋ฆฌ ๊ฐ๋ฅํ๊ฒ (`CHARACTER_MODEL`) | |
| - ๋ชจ๋ธ ๊ต์ฒด๊ฐ ์ฆ์ผ๋ฏ๋ก ํ๋กฌํํธ์ ํน์ ๋ชจ๋ธ ์์กด ๋ฌธ๋ฒ์ ๋ฃ์ง ์๋๋ค | |
| --- | |
| ## ํ ์คํธ & ๊ฒ์ฆ | |
| ```bash | |
| # ๋จ์ ํ ์คํธ | |
| python3 -m pytest tests/ -v | |
| # ์ฝํ ์ธ ์คํค๋ง ๊ฒ์ฆ | |
| python3 -m engine.schemas.validate content/ | |
| # ์คํฌ์ผ๋ฌ ํํฐ ํ๊ท ํ ์คํธ (state N์์ N+1 ์ ๋ณด ๋์ถ ์ฌ๋ถ) | |
| python3 -m pytest tests/test_spoiler_scope.py -v | |
| # ํ๊ฐ ํ๋ค์ค (LLM judge: ์์ ์ถฉ์ค๋ / ๋ฌธ์ฒด / ์๋ ด ์ฑ๊ณต๋ฅ ) | |
| python3 -m eval.run --scene <scene_id> --n 10 | |
| # Docker ๋น๋ ํ์ธ | |
| docker compose up -d --build backend | |
| docker compose logs --tail=20 backend | |
| ``` | |
| - ํ๋กฌํํธ ๋ณ๊ฒฝ์ ํ๊ฐ ํ๋ค์ค ์ ์์ ํจ๊ป PR์ ์ฒจ๋ถํ๋ค (๊ฐ์ด ์๋๋ผ ์ซ์๋ก) | |
| - ํด ๋ก๊ทธ๋ ์ญ์ ํ์ง ์๋๋ค (์ฐ๊ตฌ ๋ฐ์ดํฐ) | |
| --- | |
| ## ์ปค๋ฐ ๊ท์น | |
| - **main์ ์ง์ ํธ์ ๊ธ์ง.** ์์ ์ ๋ฌด์กฐ๊ฑด feature ๋ธ๋์น์์ ํ๊ณ PR๋ก ์ฌ๋ฆฐ๋ค | |
| - ํ์ผ ์์ ์ ๋ฐ๋์ Read๋ก ํ์ฌ ๋ด์ฉ ํ์ธ | |
| - ๊ตฌ์กฐ ๋ณ๊ฒฝ ์ "๋ณต์ฌ โ ์ ํ โ ์ญ์ " ์์ (๊ธฐ์กด ๊ธฐ๋ฅ ์ ์ง) | |
| - Docker ๋น๋๋ก ๊ฒ์ฆ ํ ์ปค๋ฐ | |
| - ๋นํธ์นด๋ MD ์๋ณธ๊ณผ `content/` ํ์ ์ฝํ ์ธ ๋ด์ฉ์ ๊ฐ๋ฐ ์ปค๋ฐ์์ ์์ ํ์ง ์๋๋ค (์ฝํ ์ธ ๋ณ๊ฒฝ์ ๋ณ๋ PR + ๋ํ๋ ์น์ธ. ๋ณํ ์คํฌ๋ฆฝํธ ์ฌ์คํ ์ฐ์ถ๋ฌผ ๊ฐฑ์ ์ ์์ธ) | |
| --- | |
| ## ์ฐธ๊ณ ๋งํฌ | |
| - ADK ๊ณต์๋ฌธ์: https://google.github.io/adk-docs/ | |
| - ADK GitHub: https://github.com/google/adk-python | |
| - Neo4j GraphRAG Python: https://github.com/neo4j/neo4j-graphrag-python | |
| - LiteLLM ๋ฌธ์: https://docs.litellm.ai/docs/providers |