--- id: agent-orchestrator-decomposition title: "Agent 오케스트레이터 분해" category: "AI_and_ML" status: "draft" verification_status: "applied" canonical_id: "" aliases: ["agent executor", "orchestrator", "god class 분해", "multi-agent", "ChunkedWriter", "sequential dispatch", "에이전트 파이프라인"] duplicate_of: "" source_trust_level: "A" confidence_score: 0.9 created_at: 2026-06-13 updated_at: 2026-06-13 review_reason: "" merge_history: [] tags: ["agent", "orchestrator", "multi-agent", "architecture", "ai", "connectai"] raw_sources: ["ConnectAI/src/agent.ts", "ConnectAI/src/agents/AgentWorkflowManager.ts", "ConnectAI/src/agent/multiAgent/workflow.ts", "ConnectAI/src/features/company/dispatcher.ts"] applied_in: ["ConnectAI"] github_commit: "" --- # [[Agent 오케스트레이터 분해]] ## 🎯 한 줄 통찰 (One-line insight) 한 턴의 복잡한 처리(컨텍스트 조립→라우팅→스트리밍→후처리→학습)는 거대 orchestrator 하나가 *흐름의 골격만 쥐고 세부는 추출된 모듈에 위임*하는 구조가 유지보수에 유리하며, 멀티에이전트는 "병렬 persona 줄세우기"보다 **자원 제약에 맞춘 순차 실행 + 단일 작성자 다중 역할**이 로컬 환경에서 더 견고하다 [S1][S2][S4]. ## 🧠 핵심 개념 (Core concepts) 1. **얇은 골격 + 추출 위임:** `agent.ts`(orchestrator)는 한 턴의 흐름을 읽을 수 있게 유지하고, 세부는 `handlePrompt/`, `llm/`, `actions/`, `sessions/`, `multiAgent/` 로 추출 [S1]. 2. **Action tag 실행:** 모델 출력의 ``, `` 등 태그를 액션 실행기로 라우팅해 도구를 수행 [S1][S4]. 3. **단일 작성자 다중 역할(ChunkedWriter):** outline → section[N] → polish 를 같은 모델이 번갈아 수행 — hop 마다 컨텍스트 폭증·본문 손실을 피함 [S2]. 4. **순차 디스패치(company):** CEO 플래너 → 전문가들 순차 실행(peer-context 전달) → CEO 리포터 합성 [S4]. 5. **mission 락:** 무거운 LLM 작업은 `missionId` 단위로 직렬화 [S2][참조: [[동시성 제어 Lock Queue Transaction]]]. ## 🧩 추출된 패턴 (Extracted patterns) - **God-class 분해:** orchestrator 의 import 가 100줄을 넘지만, 이는 "기능을 작은 모듈로 추출하고 흐름에서 다시 끌어모은" 결과 — 흐름은 한 곳, 구현은 분산 [S1]. - **메시지 프로토콜 UI:** webview 와 `streamStart`/`streamChunk`/`streamEnd`/`workflowStage` 메시지로 통신 — 진행 단계는 본문이 아니라 상단 인디케이터로 [S3]. - **모든 종료 경로에서 인디케이터 닫기:** 성공·취소·에러 어디서든 `workflowStage{done:true}` 를 보내 "영원히 도는 스피너" 방지 [S3]. - **peer-context 버퍼:** 앞 에이전트 출력을 잘라(`PEER_OUTPUT_BUDGET 1500`) 다음 에이전트 프롬프트에 전달 [S4]. - **raw 출력 → 공용 액션 실행기 재사용:** 전문가도 action tag 를 낼 수 있고, 채팅과 같은 실행기를 통과시켜 도구 동작 일관성 유지 [S4]. ## 📖 세부 내용 (Details) ### 멀티에이전트 설계의 진화 (post-mortem) 초기엔 planner/researcher/reflector/writer/synthesizer 5개 persona 를 줄세웠다. 문제: 각 hop 마다 컨텍스트가 누적되고 *원본 본문이 추상화로 손실* 돼, 사용자가 본문 분석을 요청해도 "분석 방법론" 만 만들어내는 사고가 났다. → 현재는 단일 `ChunkedWriter` 가 outline/section/polish 세 역할을 같은 모델에서 번갈아 수행 — 각 호출이 작고 본문은 매 호출에 직접 전달돼 손실이 없다 [S2]. ### 왜 순차 디스패치인가 (company 모드) 사용자는 단일 GPU/제한된 RAM 에서 Astra 를 돌린다. 병렬 에이전트는 여러 모델을 동시에 메모리에 상주시켜야 한다. 순차 실행은 "정확히 한 번에 하나의 모델만 상주" 를 보장하고, LM Studio lifecycle 매니저가 이전 모델을 unload 하고 다음을 load 한다 [S4]. → 이 위키의 sub-agent 제약(병렬 fanout 금지)과도 같은 원리. ### 왜 handlePrompt 를 재사용하지 않는가 `handlePrompt` 는 *대화형* 경로용이라 대화 이력·스트리밍 UI·에이전트 모드 주입 등 12가지를 떠안는다. company 턴은 "system 1개 + user 1개 → 문자열 1개" 의 깨끗한 primitive 가 필요하므로 `AIService.chat()` 을 쓴다 — 책임이 다른 경로는 다른 primitive [S4]. ## ⚖️ 비교 및 선택 기준 (Comparison & decision criteria) | 멀티에이전트 방식 | 장점 | 단점 | 언제 | |---|---|---|---| | 병렬 persona N개 | 빠름(자원 충분 시) | 모델 다중 상주, 컨텍스트 누적/본문 손실 | RAM/GPU 넉넉한 서버 | | 단일 작성자 다중 역할 | 컨텍스트 작고 본문 보존 | 한 모델 품질에 의존 | 로컬 단일 모델 | | 순차 디스패치 | 한 번에 한 모델, 자원 안전 | 총 시간 김 | 단일 GPU/제한 RAM | ## ⚖️ 모순 및 업데이트 (Contradictions & updates) - **orchestrator 크기:** 분해했어도 agent.ts 가 크다 — "흐름 가독성" 을 위해 의도적으로 골격을 남긴 트레이드오프(완전 분해 시 흐름 추적이 파일 사이를 떠돈다). - **순차의 비용:** 응답이 느리다. 사용자 경험을 위해 진행 단계를 webview 인디케이터로 보여 체감 지연을 완화한다. ## 🛠️ 적용 사례 (Applied in summary) - `ConnectAI/src/agent.ts` — orchestrator 골격 + 추출 모듈 import [S1]. - `ConnectAI/src/agents/AgentWorkflowManager.ts` — ChunkedWriter 단일 작성자 다중 역할 [S2]. - `ConnectAI/src/agent/multiAgent/workflow.ts` — webview 메시지 프로토콜, 모든 경로 인디케이터 닫기 [S3]. - `ConnectAI/src/features/company/dispatcher.ts` — 순차 디스패치, peer-context, 설계 근거 주석 [S4]. ## 💻 코드 패턴 (Code patterns) ```typescript // 1) 단일 작성자 다중 역할 — 스테이지를 UI 라벨로 (src/agents/AgentWorkflowManager.ts) const writer = new ChunkedWriter(modelName, overrides); // outline → section → polish const engine = new AgentEngine(writer); return await engine.runMission(missionId, prompt, brainContext, signal, (stage, msg) => onProgress(this.mapStageToUI(stage), msg)); // ① 구조 → ② 본문 → ③ 다듬기 // 2) 모든 종료 경로에서 인디케이터 닫기 (src/agent/multiAgent/workflow.ts) } catch (error: any) { deps.getWebview()?.postMessage({ type: 'workflowStage', value: { step: '완료', done: true } }); if (error.name === 'AbortError') { /* 취소 */ return; } // ... 에러 카드 } finally { deps.options.onStreamLifecycle?.end(); } // 3) 순차 디스패치 + peer-context 버퍼 (src/features/company/dispatcher.ts, 개념) let peerContext = ''; for (const task of plan.tasks) { const prompt = buildSpecialistPrompt(task, peerContext); // 앞 에이전트 맥락 포함 const out = await aiService.chat({ system, user: prompt }); // 한 번에 한 모델만 상주 writeAgentOutput(sessionDir, task, out.content); peerContext += '\n' + out.content.slice(0, PEER_OUTPUT_BUDGET); // 다음 에이전트에 전달 } ``` ## ✅ 검증 상태 및 신뢰도 - **상태:** draft - **검증 단계:** applied - **출처 신뢰도:** A - **신뢰 점수:** 0.90 - **중복 검사 결과:** 신규 생성 (New discovery) ## 🔗 지식 그래프 (Knowledge Graph) - **상위/루트:** [[ConnectAI 아키텍처 개요]] - **관련 개념:** [[Intelligence 검증 레이어]], [[LLM 프로바이더 추상화]], [[동시성 제어 Lock Queue Transaction]], [[Agent Orchestration Pattern]] - **참조 맥락:** 로컬 LLM 이 에이전트 실행 파이프라인·멀티에이전트 구조를 자원 제약 하에서 설계할 때 참조. ## 📚 출처 (Sources) - [S1] ConnectAI/src/agent.ts — orchestrator 골격, 추출 모듈 import 구조 - [S2] ConnectAI/src/agents/AgentWorkflowManager.ts — ChunkedWriter, 멀티에이전트 진화 post-mortem - [S3] ConnectAI/src/agent/multiAgent/workflow.ts — 메시지 프로토콜, 인디케이터 닫기 - [S4] ConnectAI/src/features/company/dispatcher.ts — 순차 디스패치 근거, peer-context, primitive 분리 ## 📝 변경 이력 (Change history) - 2026-06-13: ConnectAI 코드 분석 기반 초안 생성.