Blog로컬에서 AI 멀티 에이전트 만들기 (1) — 설계와 환경 구성

로컬에서 AI 멀티 에이전트 만들기 (1) — 설계와 환경 구성

시리즈 (3편 중 1편)

제목핵심
→ 1편설계와 환경 구성AgentEngine 추상화, CLI/API 팩토리
2편에이전트 구현EventBus, Orchestrator, 3개 에이전트
3편실전과 확장실행 결과, 피드백 루프, 비용 최적화

“AI한테 코드 짜달라고 하면 되는데, 에이전트를 왜 여러 개 돌려?”

나도 처음엔 그렇게 생각했다. Claude에게 “TODO 앱 만들어줘” 하면 한 번에 끝나니까. 그런데 codemon-make를 7에이전트로 운영하면서 생각이 바뀌었다.

3에이전트 파이프라인


단일 에이전트의 한계

하나의 에이전트에 모든 것을 맡기면:

  • 컨텍스트 오염: 기획, 코딩, 리뷰를 한 세션에서 하면 뒷부분으로 갈수록 품질이 떨어진다
  • 디버깅 불가: 어디서 잘못됐는지 알 수 없다. 계획이 나빴나, 코드가 나빴나?
  • 모델 낭비: 간단한 계획에도 비싼 모델을 쓰고, 코드 작성에도 같은 모델을 쓴다

프로덕션에서 7에이전트를 돌려보니 답이 보였다. 역할을 나누면 각 단계를 독립적으로 개선할 수 있다.


아키텍처: 3에이전트 파이프라인

codemon-make의 7에이전트에서 핵심 패턴만 뽑으면 3개로 충분하다.

사용자: "React로 TODO 앱 만들어줘"

  ▼ task.created

  ├─ PlannerAgent → 구현 계획 JSON

  ▼ plan.completed

  ├─ CoderAgent → 실제 코드 작성

  ▼ code.completed

  ├─ ReviewerAgent → 리뷰 + 점수

  ▼ review.completed → 결과 출력

이 파이프라인을 지탱하는 4가지 핵심 패턴:

패턴역할구현
AgentEngineLLM 호출 추상화CLI / API 교체 가능
EventBus에이전트 간 통신Redis pub/sub
Orchestrator이벤트 → 큐 라우팅BullMQ 큐 연결
Worker큐 소비 + 에이전트 실행BullMQ Worker

환경 설정

레포 클론

git clone https://github.com/codemon-ai/agent-basic.git
cd agent-basic
npm install

Redis 시작

docker compose up -d

compose.yml은 Redis 7 Alpine 이미지 하나:

services:
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data

환경변수

cp .env.example .env
ENGINE_TYPE=claude-cli        # 또는 anthropic-api
ANTHROPIC_API_KEY=sk-ant-...  # API 엔진 사용 시
REDIS_URL=redis://localhost:6379

AgentEngine: LLM 호출 추상화

멀티 에이전트의 첫 번째 설계 결정은 **“LLM을 어떻게 호출할 것인가”**다.

codemon-make에서는 Claude CLI와 Anthropic API를 모두 쓴다. CLI는 파일 시스템 접근이 가능하고, API는 가볍고 빠르다. 이 두 가지를 하나의 인터페이스로 묶었다.

// src/engines/types.ts
export interface AgentEngineResult {
  result: string;
  session_id: string;
  num_turns: number;
  duration_ms: number;
  cost_usd: number;
}
 
export interface AgentEngineRunOptions {
  cwd: string;
  timeoutMs?: number;
  disallowedTools?: string[];
  onProgress?: (message: string) => void;
}
 
export interface AgentEngine {
  name: string;
  run(prompt: string, options: AgentEngineRunOptions): Promise<AgentEngineResult>;
}

핵심은 run() 하나. 프롬프트를 넣으면 결과가 나온다. CLI든 API든 같은 인터페이스.

Claude CLI 엔진

// src/engines/claude-cli-engine.ts (핵심 부분)
const child = spawn("claude", [
  "-p",
  "--dangerously-skip-permissions",
  "--output-format", "json",
], { cwd, env });
 
// 프롬프트는 stdin으로 전달 (ARG_MAX 회피)
child.stdin.write(prompt);
child.stdin.end();

CLI 엔진의 장점: Claude Code의 도구(파일 생성, Bash 실행)를 그대로 쓸 수 있다. CoderAgent에 이상적.

Anthropic API 엔진

// src/engines/anthropic-api-engine.ts (핵심 부분)
const stream = this.client.messages.stream({
  model: this.model,
  max_tokens: 4096,
  messages: [{ role: "user", content: prompt }],
});
const response = await stream.finalMessage();

API 엔진의 장점: 빠르고, 비용 예측이 쉽다. PlannerAgent, ReviewerAgent에 적합.

팩토리 패턴

// src/engines/index.ts
export function createEngine(type: EngineType, options?): AgentEngine {
  switch (type) {
    case "claude-cli": return new ClaudeCliEngine();
    case "anthropic-api": return new AnthropicApiEngine(options?.apiKey);
  }
}

.env에서 ENGINE_TYPE만 바꾸면 전체 시스템의 엔진이 교체된다.

AgentEngine 추상화


다음 편에서

에이전트 엔진과 환경 구성을 마쳤다. 2편에서는 이 엔진 위에 EventBus, Orchestrator, 그리고 3개 에이전트를 구현한다.

→ 다음: 2편 — 에이전트 구현

전체 코드: github.com/codemon-ai/agent-basic