콘텐츠로 이동

분산 Agent 시스템

단일 에이전트 시스템은 단순하고 디버깅이 쉽습니다. 하지만 규모가 커지면 한계에 부딪힙니다.

단일 에이전트 한계:
- 컨텍스트 윈도우 한도 (대규모 코드베이스 처리 불가)
- 직렬 실행 (병렬 작업 불가)
- 단일 실패 지점 (에이전트 실패 시 전체 중단)
- 특화 불가 (모든 작업을 동일한 에이전트가 처리)

분산 에이전트 시스템은 이 문제를 마이크로서비스와 유사한 방식으로 해결합니다.

마이크로서비스 스타일 에이전트

섹션 제목: “마이크로서비스 스타일 에이전트”

각 에이전트가 명확한 책임 영역을 갖고 독립적으로 동작합니다.

코드 생성 팀
├── spec-agent: 요구사항 분석, 스펙 작성
├── architect-agent: 설계 결정, 아키텍처 다이어그램
├── coder-agent: 실제 코드 구현
├── test-agent: 테스트 코드 작성
└── reviewer-agent: 코드 리뷰, 피드백
agents/base-agent-service.ts
interface AgentServiceConfig {
name: string
version: string
capabilities: string[]
model: string
maxConcurrency: number
timeoutMs: number
}
interface AgentTask {
id: string
type: string
payload: Record<string, unknown>
priority: 'low' | 'normal' | 'high'
deadline?: Date
}
interface AgentResult {
taskId: string
success: boolean
output: unknown
tokensUsed: number
durationMs: number
error?: string
}
abstract class BaseAgentService {
constructor(protected config: AgentServiceConfig) {}
abstract canHandle(task: AgentTask): boolean
abstract execute(task: AgentTask): Promise<AgentResult>
async handleWithTimeout(task: AgentTask): Promise<AgentResult> {
const timer = new Promise<AgentResult>((_, reject) =>
setTimeout(
() => reject(new Error(`Task timeout after ${this.config.timeoutMs}ms`)),
this.config.timeoutMs
)
)
return Promise.race([this.execute(task), timer])
}
}

에이전트들이 직접 통신하는 대신 이벤트 버스를 통해 느슨하게 결합됩니다.

개발자 작업 요청
EventBus.publish('task.created', taskData)
┌───────────────────────────────────┐
│ Event Bus │
└───────────────────────────────────┘
↓ ↓ ↓
spec-agent coder-agent reviewer-agent
(구독 중) (구독 중) (구독 중)
각 에이전트가 관련 이벤트만 처리
harness/event-bus.ts
type EventHandler<T = unknown> = (event: AgentEvent<T>) => Promise<void>
interface AgentEvent<T = unknown> {
id: string
type: string
payload: T
timestamp: Date
source: string
correlationId?: string
}
class AgentEventBus {
private handlers: Map<string, EventHandler[]> = new Map()
private eventLog: AgentEvent[] = []
subscribe<T>(eventType: string, handler: EventHandler<T>): () => void {
const existing = this.handlers.get(eventType) ?? []
this.handlers.set(eventType, [...existing, handler as EventHandler])
// 구독 취소 함수 반환
return () => {
const current = this.handlers.get(eventType) ?? []
this.handlers.set(
eventType,
current.filter(h => h !== handler)
)
}
}
async publish<T>(eventType: string, payload: T, source: string): Promise<void> {
const event: AgentEvent<T> = {
id: crypto.randomUUID(),
type: eventType,
payload,
timestamp: new Date(),
source
}
this.eventLog.push(event as AgentEvent)
const handlers = this.handlers.get(eventType) ?? []
await Promise.all(handlers.map(h => h(event as AgentEvent)))
}
getEventLog(filter?: { type?: string; since?: Date }): AgentEvent[] {
return this.eventLog.filter(e => {
if (filter?.type && e.type !== filter.type) return false
if (filter?.since && e.timestamp < filter.since) return false
return true
})
}
}

복잡한 작업을 여러 에이전트에게 분배하고 결과를 집계하는 오케스트레이터가 필요합니다.

harness/orchestrator.ts
interface SubTask {
agentType: string
task: AgentTask
dependsOn?: string[] // 다른 서브태스크 ID
}
class AgentOrchestrator {
constructor(
private agents: Map<string, BaseAgentService>,
private eventBus: AgentEventBus
) {}
async executeWorkflow(subtasks: SubTask[]): Promise<Map<string, AgentResult>> {
const results = new Map<string, AgentResult>()
const pending = new Map(subtasks.map(st => [st.task.id, st]))
while (pending.size > 0) {
// 의존성이 모두 완료된 태스크 찾기
const ready = [...pending.values()].filter(st =>
(st.dependsOn ?? []).every(dep => results.has(dep))
)
if (ready.length === 0) {
throw new Error('순환 의존성 감지: 실행 불가능한 워크플로우')
}
// 준비된 태스크 병렬 실행
await Promise.all(
ready.map(async st => {
const agent = this.agents.get(st.agentType)
if (!agent) throw new Error(`에이전트 미발견: ${st.agentType}`)
const result = await agent.handleWithTimeout(st.task)
results.set(st.task.id, result)
pending.delete(st.task.id)
await this.eventBus.publish('subtask.completed', result, 'orchestrator')
})
)
}
return results
}
}
기준중앙화 선택분산화 선택
팀 규모1~5명10명 이상
작업 복잡도단순, 순차적복잡, 병렬 가능
컨텍스트 크기단일 컨텍스트로 충분다수의 대용량 컨텍스트 필요
실패 허용도단순 재시도로 충분부분 실패 허용 필요
운영 복잡도낮게 유지 선호복잡도 수용 가능

동일한 에이전트를 여러 인스턴스로 실행합니다.

harness/agent-pool.ts
class AgentPool {
private instances: BaseAgentService[] = []
private queue: AgentTask[] = []
private activeCount = 0
constructor(
private factory: () => BaseAgentService,
private maxInstances: number
) {
// 초기 인스턴스 생성
for (let i = 0; i < Math.min(2, maxInstances); i++) {
this.instances.push(factory())
}
}
async submit(task: AgentTask): Promise<AgentResult> {
if (this.activeCount < this.maxInstances) {
return this.executeImmediate(task)
}
return this.enqueue(task)
}
private async executeImmediate(task: AgentTask): Promise<AgentResult> {
this.activeCount++
const agent = this.instances[this.activeCount - 1] ?? this.factory()
try {
return await agent.handleWithTimeout(task)
} finally {
this.activeCount--
this.processQueue()
}
}
private enqueue(task: AgentTask): Promise<AgentResult> {
return new Promise((resolve, reject) => {
this.queue.push({ ...task, _resolve: resolve, _reject: reject } as AgentTask & {
_resolve: (r: AgentResult) => void
_reject: (e: Error) => void
})
})
}
private processQueue(): void {
const next = this.queue.shift() as (AgentTask & {
_resolve?: (r: AgentResult) => void
}) | undefined
if (next && next._resolve) {
this.executeImmediate(next).then(next._resolve)
}
}
}

분산 에이전트 시스템은 단일 에이전트의 컨텍스트 한계와 직렬 실행 제약을 극복합니다. 이벤트 드리븐 아키텍처로 에이전트 간 느슨한 결합을 유지하고, 오케스트레이터 패턴으로 복잡한 워크플로우를 관리하세요. 하지만 분산 시스템의 복잡성은 실제로 필요한 팀에게만 정당화됩니다. 단순함을 기본값으로 유지하세요.