이 글은 누구를 위한 것인가
- 복잡한 다단계 작업을 AI로 자동화하려는 팀
- 오케스트레이터-서브에이전트 패턴을 구현하려는 개발자
- 병렬 AI 작업으로 속도를 높이려는 팀
들어가며
단일 LLM 호출로 처리하기 너무 복잡한 작업이 있다. "경쟁사 10개를 조사하고, 각각의 가격을 비교하고, 보고서를 작성해라" — 오케스트레이터 에이전트가 작업을 분해하고, 서브에이전트들이 병렬로 실행한다.
이 글은 bluefoxdev.kr의 멀티 에이전트 오케스트레이션 가이드 를 참고하여 작성했습니다.
1. 멀티 에이전트 패턴
[오케스트레이터-서브에이전트 패턴]
오케스트레이터:
- 작업 분해 (task decomposition)
- 서브에이전트 할당
- 결과 집계
- 에러 처리
서브에이전트:
- 특화된 단일 작업
- 도구(tool) 사용 가능
- 독립적 실행
[실행 모드]
순차 실행: A → B → C (의존성 있을 때)
병렬 실행: A || B || C (독립 작업)
DAG 실행: 의존성 그래프 기반
[에이전트 통신]
공유 컨텍스트: 중앙 상태 저장소
메시지 패싱: 큐 기반 비동기
직접 호출: 오케스트레이터가 결과 전달
[에러 처리]
재시도: 지수 백오프 (최대 3회)
폴백: 간소화된 대안 작업
체크포인트: 중간 결과 저장
2. 멀티 에이전트 구현
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic();
interface Task {
id: string;
type: string;
input: any;
dependencies?: string[];
}
interface TaskResult {
taskId: string;
success: boolean;
output?: any;
error?: string;
}
// 서브에이전트: 특화 작업 실행
async function runSubAgent(task: Task): Promise<TaskResult> {
const agentPrompts: Record<string, string> = {
research: '웹 검색 결과를 분석하고 핵심 정보를 추출하는 리서치 전문가입니다.',
summarize: '복잡한 내용을 명확하게 요약하는 전문가입니다.',
analyze: '데이터를 분석하고 인사이트를 도출하는 분석가입니다.',
write: '명확하고 설득력 있는 콘텐츠를 작성하는 전문가입니다.',
};
try {
const response = await client.messages.create({
model: 'claude-sonnet-4-6',
max_tokens: 2048,
system: agentPrompts[task.type] ?? '전문 AI 어시스턴트입니다.',
messages: [{
role: 'user',
content: `작업 ID: ${task.id}\n\n${JSON.stringify(task.input, null, 2)}`,
}],
});
return {
taskId: task.id,
success: true,
output: response.content[0].type === 'text' ? response.content[0].text : '',
};
} catch (error) {
return { taskId: task.id, success: false, error: String(error) };
}
}
// 오케스트레이터: 작업 분해 + 실행 관리
async function orchestrate(goal: string): Promise<string> {
// 1단계: 작업 분해
const planResponse = await client.messages.create({
model: 'claude-sonnet-4-6',
max_tokens: 1024,
system: '작업을 분해하고 실행 계획을 JSON으로 반환하는 오케스트레이터입니다.',
messages: [{
role: 'user',
content: `다음 목표를 달성하기 위한 작업 계획을 JSON으로 작성하세요.
목표: ${goal}
형식:
{"tasks": [{"id": "t1", "type": "research|summarize|analyze|write", "input": {...}, "dependencies": []}]}`,
}],
});
const planText = planResponse.content[0].type === 'text' ? planResponse.content[0].text : '{"tasks":[]}';
const match = planText.match(/\{[\s\S]*\}/);
const plan: { tasks: Task[] } = match ? JSON.parse(match[0]) : { tasks: [] };
// 2단계: 의존성 기반 병렬 실행
const results = new Map<string, TaskResult>();
const executeTasks = async (tasks: Task[]) => {
const ready = tasks.filter(t =>
!t.dependencies?.length || t.dependencies.every(dep => results.get(dep)?.success)
);
if (!ready.length) return;
// 준비된 작업 병렬 실행
const batchResults = await Promise.all(ready.map(runSubAgent));
batchResults.forEach(r => results.set(r.taskId, r));
// 남은 작업 재귀 실행
const remaining = tasks.filter(t => !results.has(t.id));
if (remaining.length) await executeTasks(remaining);
};
await executeTasks(plan.tasks);
// 3단계: 결과 집계
const aggregateResponse = await client.messages.create({
model: 'claude-sonnet-4-6',
max_tokens: 2048,
system: '에이전트 작업 결과를 통합해 최종 답변을 작성합니다.',
messages: [{
role: 'user',
content: `목표: ${goal}\n\n작업 결과:\n${Array.from(results.values()).map(r => `[${r.taskId}]: ${r.output ?? r.error}`).join('\n\n')}\n\n위 결과를 바탕으로 최종 보고서를 작성하세요.`,
}],
});
return aggregateResponse.content[0].type === 'text' ? aggregateResponse.content[0].text : '';
}
마무리
멀티 에이전트의 핵심은 작업 분해와 병렬 실행이다. 오케스트레이터가 의존성 그래프를 분석해 독립 작업을 Promise.all로 병렬 처리하면 전체 실행 시간을 크게 줄인다. 각 서브에이전트는 특화된 역할을 가지며, 실패 시 체크포인트에서 재시작할 수 있도록 중간 결과를 저장한다.