멀티 에이전트 코스 빌더

한 줄 정의

멀티 에이전트 코스 빌더는 실라버스 설계, 본문 집필, 평가 문항 출제, 슬라이드 덱 생성 단계를 개별 에이전트와 휴먼 검토 루프(Revision Loop)로 구성하여, 비결정론적 모델의 맥락 분산 문제를 극복하는 프로덕션급 콘텐츠 생성 파이프라인 아키텍처다.

핵심 요지

  • 단일 프롬프트의 한계 극복: 긴 콘텐츠(예: 12개 강의가 포함된 전체 코스)를 단일 컨텍스트와 하나의 거대한 프롬프트로 처리할 때 나타나는 글의 산포(drift), 문체 일관성 상실, 학습 목표 모순 등의 실패 패턴을 차단한다.
  • 역할 분할 및 모델 최적화: ADDIE 교수 설계 프레임워크와 유사하게 기획(실라버스), 집필(본문), 설계(평가), 빌드(프로덕션) 단계를 나누고, 각 단계에 맞는 모델(기획 단계에는 고성능 Reasoning 모델, 본문 작성에는 저렴하고 빠른 모델 등)을 차등 매칭한다.
  • 공유 상태 기반 데이터 규약: 모든 에이전트가 LangGraph 내에서 하나의 Pydantic 상태 스키마(State Schema)를 함께 읽고 쓰며, API 계약 구조(Data Contract)를 명확히 유지한다.
  • 병렬 팬아웃(Parallel Fan-out) 실행: 실라버스 확정 이후 개별 강의 본문 및 퀴즈 출제 작업을 독립된 세션으로 병렬 처리함으로써, 실행 시간을 대폭 단축(예: 15분에서 90초로 단축)하고 에이전트 대화 맥락 간의 상호 오염을 원천 제거한다.
  • 적대적 검증(Anti-slop Reviewer): 작업 에이전트가 완성한 결과물을 받아 regex 프리체크와 평가 가이드를 기반으로 상투적 미사여구(AI Slop), 코드 결여 등을 교차 검증하고 반려(Verdict) 시 구체적 방향을 제공하는 특화 노드를 둔다.
  • 결정론적 최종 빌드 (Deterministic Production): 디자인이나 레이아웃이 붕괴하기 쉬운 영역(슬라이드 덱, PDF 등)은 LLM의 임의 생성에 맡기지 않고, 마크다운(Marp CLI 등) 컴파일러를 실행하는 규칙 기반 코드로 처리한다.

상세

1. 4단계 멀티 에이전트 역할 구조

  1. 커리큘럼 에이전트 (Curriculum Agent): 한 줄의 자연어 입력으로부터 대주제, 모듈 구분, 모듈별 학습 목표(Learning Objectives), 강의 아웃라인이 담긴 실라버스를 기획한다.
  2. 콘텐츠 에이전트 (Content Agent): 확정된 아웃라인을 바탕으로 실제 본문 텍스트를 채운다. 이 단계는 각 강의별로 독립적으로 병렬 구동된다.
  3. 평가 에이전트 (Evaluation Agent): 각 모듈의 본문과 학습 목표를 읽고 이에 부합하는 객관식 퀴즈(JSON 규격)와 실무 과제 가이드를 제작한다.
  4. 프로덕션 에이전트 (Production Agent): 최종 본문과 퀴즈, 과제를 취합하여 규칙 기반 컴파일러 코드를 구동하고 정적 슬라이드 PDF를 컴파일한다.

2. 제어 흐름과 개입 게이트

  • 휴먼 승인 게이트 (Human Approval Gate): 비결정론적 기획 단계인 커리큘럼 에이전트 작동 완료 직후, 파이프라인은 상태를 보존한 채 실행을 정지(interrupt)한다. 사용자는 실라버스를 확인하여 필요시 방향성 수정을 지시할 수 있으며, 이 Revision Loop를 거쳐 최종 승인한 경우에만 대규모 집필 작업(Content/Evaluation)으로 진입한다.
  • 안티 슬롭 검토기 (Anti-slop Reviewer): 콘텐츠 에이전트가 본문을 작성할 때마다 호출되어 “AI slop” 필터를 적용한다. 이 노드는 주 기획 노드 대비 저렴한 모델을 활용하며, 통과 실패 시 에이전트에게 반려 피드백을 전달하여 재생성을 유도한다.

예시

LangGraph 상태 스키마 정의 (Pydantic 규약)

from typing import Annotated, Literal
from pydantic import BaseModel, Field
 
BloomLevel = Literal[
    "remember", "understand", "apply", "analyze", "evaluate", "create"
]
 
class LearningObjective(BaseModel):
    id: str = Field(description="안정적인 식별자 (예: 'lo-1-2')")
    text: str = Field(description="측정 가능하며 학습자 중심적인 동사구 목표")
    bloom: BloomLevel
    module_id: str
 
class Lesson(BaseModel):
    id: str
    module_id: str
    title: str
    objectives: list[str] = Field(description="이 강의에서 다루는 LearningObjective ID 목록")
 
class CourseState(BaseModel):
    topic: str
    syllabus_approved: bool = False
    objectives: list[LearningObjective] = []
    lessons: list[Lesson] = []
    content: dict[str, str] = {} # lesson_id -> markdown content
    quizzes: list[dict] = []

아키텍처 제어 흐름

graph TD
    Start([입력: 한 줄 주제]) --> Curriculum[커리큘럼 에이전트]
    Curriculum --> Interrupt[Human Approval Gate]
    Interrupt -- 수정 요구 --> Curriculum
    Interrupt -- 승인 --> FanOut{병렬 팬아웃}
    FanOut --> Content1[콘텐츠 에이전트: 강의 1]
    FanOut --> Content2[콘텐츠 에이전트: 강의 2]
    FanOut --> Eval[평가 에이전트: 퀴즈/과제]
    
    Content1 --> Reviewer1[Anti-slop 검토기]
    Reviewer1 -- 반려 --> Content1
    Reviewer1 -- 승인 --> Join{Join}
    
    Content2 --> Reviewer2[Anti-slop 검토기]
    Reviewer2 -- 반려 --> Content2
    Reviewer2 -- 승인 --> Join
    
    Eval --> Join
    Join --> Production[프로덕션 에이전트: Marp CLI]
    Production --> Output([최종 PDF / 마크다운 묶음])

충돌

현재 확인된 충돌 없음.

관련 노트