본문으로 건너뛰기

LangGraph.js 통합 아키텍처 설계 - SOL Chain of Debate 시스템

1. 설계 개요​

1.1 설계 목적​

본 문서는 SOL(Sleep Onset Latency) Chain of Debate 시스템에서 AI 워크플로우 오케스트레이션을 위한 LangGraph.js 통합 아키텍처를 정의합니다.

1.2 핵심 설계 목표​

  • 워크플로우 표준화: Chain of Debate 과정의 체계적 관리
  • 에이전트 확장성: 신규 전문가 에이전트 동적 추가 지원
  • 상태 투명성: 토론 진행 상황의 실시간 추적 가능
  • 결정적 실행: 동일 조건에서 일관된 결과 보장

1.3 비즈니스 가치​

  • 전문가 간 토론 과정 자동화로 의사결정 품질 향상
  • 복합적 수면 분석을 통한 개인맞춤형 SOL 예측 정확도 개선
  • 토론 품질 지표를 통한 AI 모델 성능 지속적 개선

2. 아키텍처 설계 결정사항​

2.1 LangGraph.js 선택 근거​

선택한 솔루션: LangGraph.js (StateGraph)​

선택 이유:

  • 상태 기반 워크플로우: Chain of Debate의 복잡한 상태 전환을 명확히 표현
  • 조건부 분기: 설문 데이터 유무에 따른 동적 워크플로우 구성
  • LangChain 생태계 통합: 프롬프트 관리, LLM 호출의 표준화

고려했던 대안들​

대안장점단점선택하지 않은 이유
직접 구현완전한 제어, 경량개발 복잡도 증가, 유지보수 부담표준화된 도구 사용이 더 효율적
Temporal강력한 워크플로우 엔진인프라 복잡도, 과도한 기능Chain of Debate에는 오버엔지니어링
Step FunctionsAWS 네이티브벤더 종속성, 복잡한 상태 관리멀티클라우드 전략과 충돌

2.2 CQRS 통합 패턴​

선택한 패턴: Command Handler 내 StateGraph 실행​

아키텍처 결정:

Command → Handler → StateGraph → Domain Events → Response

설계 근거:

  • 책임 분리: Command Handler는 오케스트레이션, StateGraph는 워크플로우 실행
  • 트랜잭션 경계: Command 단위로 성공/실패 처리
  • 이벤트 발행: 각 단계별 도메인 이벤트 자동 발행

고려했던 대안​

  • StateGraph를 별도 서비스로 분리: 복잡도 증가, 네트워크 레이턴시
  • Event Sourcing 기반: 과도한 복잡성, 요구사항 대비 오버헤드

2.3 상태 관리 전략​

상태 저장 방식: 하이브리드 (In-Memory + Database)​

  • In-Memory: 실행 중인 워크플로우의 임시 상태 (StateGraph channels)
  • Database: 영구 보관이 필요한 상태 (예측 결과, 토론 기록)

상태 동기화 전략​

  • 각 노드 완료 시: 중요 상태를 데이터베이스에 영속화
  • 실패 복구: 마지막 체크포인트부터 재시작 가능

3. 시스템 아키텍처​

3.1 전체 시스템 구성도​

3.2 Chain of Debate 워크플로우 아키텍처​

3.3 데이터 흐름 아키텍처​

4. Command 및 Query 인터페이스 설계​

4.1 핵심 Command 인터페이스 명세​

StartSOLPredictionCommand​

목적: SOL 예측 워크플로우 시작
요구사항: COD-FR-BE-004, COD-FR-BE-007

필드타입필수설명
userIdstringY대상 사용자 ID
userCycleIdstringY치료 주기 ID
predictionScheduleIdstring?N스케줄 ID (자동 실행 시)
triggerTypePredictionTriggerTypeY실행 트리거 유형
includeQuestionnairebooleanY설문 데이터 포함 여부

처리 흐름: 데이터 수집 → 검증 → 에이전트 결정 → Chain of Debate → 결과 저장

ExecuteDebateRoundCommand​

목적: 토론 라운드 실행
요구사항: COD-FR-BE-009, COD-FR-BE-010

필드타입필수설명
predictionIdstringY예측 세션 ID
debateSessionIdstringY토론 세션 ID
roundNumbernumberY라운드 번호 (1-3)
consensusThresholdnumberY합의 임계값 (0.67-0.75)

4.2 핵심 Query 인터페이스 명세​

GetSOLPredictionQuery​

목적: SOL 예측 결과 조회

필드타입설명
predictionIdstring예측 ID
includeDebateDetailsboolean토론 상세 포함 여부

GetDebateSessionQuery​

목적: 토론 세션 상세 조회

필드타입설명
debateSessionIdstring토론 세션 ID
includeOpinionsboolean전문가 의견 포함 여부

5. 전문가 에이전트 아키텍처​

5.1 에이전트 설계 철학​

설계 원칙​

  • 단일 책임 원칙: 각 에이전트는 특정 수면 분야 전문성에 집중
  • 일관된 인터페이스: 모든 에이전트는 동일한 분석/토론/검증 인터페이스 구현
  • 독립적 추론: 에이전트 간 결합도 최소화, 각자 독립적 분석 수행
  • 투명한 근거: 모든 분석 결과에 명확한 근거와 신뢰도 제공

5.2 BaseExpertAgent 인터페이스 설계​

핵심 메서드 명세​

interface BaseExpertAgent {
// 1차 분석: 개별 전문 영역 분석
analyze(context: SOLAnalysisContext): Promise<ExpertAnalysis>

// 토론 참여: 다른 전문가 의견에 대한 반응
debate(myOpinion: ExpertAnalysis, others: ExpertAnalysis[]): Promise<DebateResponse>

// 최종 검증: 합의 결과에 대한 전문가 검증
validate(consensus: SOLConsensus): Promise<ValidationResult>
}

입출력 데이터 구조​

SOLAnalysisContext

{
userId: string
userCycleId: string
sleepData: SleepDataSummary // 수면 패턴, SOL 이력
questionnaireData?: QuestionnaireData // 설문 응답 (선택적)
userProfile: UserProfileData // 나이, 성별, 치료 단계
learningData: LearningDataSummary // 학습 진도, 세션 완료도
treatmentPhase: 'EARLY'|'MID'|'LATE'
}

LearningDataSummary (신규 추가)

{
overallProgress: number // 전체 학습 진도 (0-100%)
articleProgress: LearningProgress[] // 아티클 학습 진도
coreProgress: LearningProgress[] // 코어 학습 진도
recentSessions: LearningSession[] // 최근 학습 세션 기록
completedModules: string[] // 완료된 모듈 목록
engagementScore: number // 학습 참여도 점수 (0-1.0)
lastActivityDate: Date // 마지막 학습 활동 일자
averageSessionDuration: number // 평균 세션 시간 (분)
}

ExpertAnalysis

{
agentType: ExpertAgentType
solScore: number // 예측 SOL (분)
confidenceScore: number // 신뢰도 (0.0-1.0)
keyFactors: string[] // 주요 영향 요인
reasoning: string // 분석 근거
evidenceData: any // 분석 근거 데이터
}

5.3 전문가 에이전트 역할 정의​

Sleep Latency Analyst (수면잠복기 분석전문가)​

전문 영역: 수면 패턴 데이터 중심 SOL 분석

  • 주요 데이터: LOT, AST 시간, SOL 추세, 수면 효율
  • 분석 관점: 객관적 수면 지표 기반 예측
  • 강점: 데이터 기반 정확성, 추세 분석

Psychological State Analyst (심리상태 분석전문가)​

전문 영역: 설문 데이터 기반 심리적 요인 분석

  • 주요 데이터: ISI, PHQ-9, GAD-7, PSS 점수
  • 분석 관점: 불안, 우울, 스트레스가 SOL에 미치는 영향
  • 강점: 심리적 요인의 정량적 평가

CBT-I Sleep Behavior Specialist (CBT-I 수면행동전문가)​

전문 영역: 인지행동치료 관점의 수면 행동 분석

  • 주요 데이터: 수면 위생 패턴, 침실 환경, 취침 전 루틴, 학습 진도 및 모듈 완료도
  • 분석 관점: 행동 변화가 SOL 개선에 미치는 영향, 학습 이수도와 실제 행동 변화 상관관계
  • 강점: 실행 가능한 행동 개선 권장사항, 개인화된 학습 경로 추천

Digital Environment Analyst (디지털수면환경전문가)​

전문 영역: DTA Wide 앱 사용 패턴이 수면에 미치는 영향

  • 주요 데이터: 앱 내 활동 로그, 취침 전 앱 사용 빈도, 수면 기록 입력 패턴
  • 분석 관점: 앱 사용 습관과 수면 의식 형성의 상관관계 분석
  • 강점: 디지털 치료 도구 활용도와 SOL 개선 효과 연관성 분석

Melatonin System Analyst (멜라토닌시스템분석전문가)​

전문 영역: 생체시계 및 멜라토닌 분비 시스템 기반 수면 분석

  • 주요 데이터: 기상 시간 패턴, 빛 노출 이력, 카페인 섭취, 운동 시간대, 시간형(chronotype)
  • 분석 관점: DLMO(Dim Light Melatonin Onset) 예측 및 일주기 리듬 위상 변화 분석
  • 강점: 생리학적 근거 기반 SOL 예측, 개인 시간형에 따른 맞춤형 분석

5.4 DTA Wide 앱 내 수집 가능한 디지털 환경 데이터​

5.4.1 앱 활동 로그 기반 분석 데이터​

수집 가능한 앱 내 활동 데이터:

interface DigitalEnvironmentData {
// 앱 사용 패턴
dailyAppUsageDuration: number // 일일 앱 사용 시간 (분)
bedtimeAppUsage: boolean // 취침 전 1시간 내 앱 사용 여부
lateNightActivity: AppActivityLog[] // 22:00 이후 앱 활동 기록

// 수면 기록 입력 패턴
sleepLogConsistency: number // 수면 기록 입력 일관성 (0-1.0)
logEntryTiming: 'IMMEDIATE' | 'DELAYED' | 'NEXT_DAY'

// 치료 도구 활용도
relaxationToolUsage: number // 이완 도구 사용 빈도
sleepMeditationUsage: number // 수면 명상 콘텐츠 사용
bedtimeReminderResponse: number // 취침 시간 알림 응답률

// 학습 콘텐츠 접근 패턴
learningSessionTiming: Date[] // 학습 세션 접근 시간대
contentCompletionRate: number // 콘텐츠 완독률
}

5.4.2 디지털 환경 분석 제한사항 및 대안​

제한사항:

  • ❌ 다른 앱의 스크린 타임 데이터 접근 불가
  • ❌ 시스템 레벨 디바이스 사용 패턴 수집 불가
  • ❌ 타사 앱의 취침 전 사용량 분석 불가

대안적 접근 방식:

  • ✅ 간접 지표 활용: 앱 사용 패턴을 통한 디지털 웰빙 의식 수준 추정
  • ✅ 자가 보고 연계: 설문 데이터와 앱 사용 패턴 상관관계 분석
  • ✅ 치료 도구 효과성: 앱 내 이완 도구 사용과 SOL 개선 직접 연관성 분석

5.5 학습 데이터 활용 전략​

5.5.1 학습 진도 기반 SOL 예측 보정​

학습 참여도별 예측 신뢰도 조정:

  • 높은 참여도 (80% 이상 완료): 예측 신뢰도 +15%, 행동 변화 가능성 높음
  • 중간 참여도 (40-80% 완료): 기본 신뢰도 유지, 점진적 개선 예상
  • 낮은 참여도 (40% 미만): 예측 신뢰도 -10%, 행동 변화 제한적

5.5.2 에이전트별 학습 데이터 활용법​

CBT-I Sleep Behavior Specialist:

  • 완료된 수면 위생 모듈 → 실제 행동 적용 가능성 평가
  • 이완 기법 학습 진도 → SOL 단축 효과 예측 강화
  • 학습 세션 빈도 → 지속적 개선 동기 평가

Psychological State Analyst:

  • 인지 재구성 모듈 완료도 → 수면 관련 불안 감소 효과 예측
  • 스트레스 관리 학습 → PSS 점수와 연계한 SOL 영향 분석

Digital Environment Analyst:

  • 수면 루틴 설정 학습 모듈 → 앱을 통한 수면 의식 형성도 평가
  • 디지털 웰빙 학습 → 취침 전 앱 사용 자제 실천 가능성 분석
  • 앱 사용 패턴 분석 → 치료 도구 활용도와 SOL 개선 상관관계

5.5.3 학습 데이터 기반 권장사항 필터링​

학습 진도 기반 권장사항 조정:

  • 완료된 모듈과 중복되는 권장사항 제외
  • 학습 참여도가 낮은 사용자에게는 기본적이고 실행 가능한 권장사항 우선
  • 높은 참여도 사용자에게는 고급 기법 및 세부 조정 권장사항 제공

5.6 합의 메커니즘 설계​

합의 계산 방식​

  • 표준편차 기반: 에이전트들의 SOL 예측 값 간 표준편차 계산
  • 임계값 적용:
    • 3개 에이전트: 67% 합의 (σ ≤ 7분)
    • 4개 에이전트: 75% 합의 (σ ≤ 5분)
    • 5개 에이전트: 80% 합의 (σ ≤ 4분)

토론 진행 규칙​

  • 최대 라운드: 참여 에이전트 수에 따라 2-3라운드 (5개 에이전트 시 3라운드)
  • 라운드별 시간 제한: 8초 (전체 25초 내 완료)
  • 합의 실패 시: 가중 평균 + 다수결 결정

6. StateGraph 워크플로우 설계​

6.1 LangGraph StateGraph 상세 구조​

6.1.1 StateGraph 채널(State) 정의​

interface SOLPredictionState {
// 기본 식별자
userId: string
userCycleId: string
predictionId: string

// 수집된 데이터
sleepData: SleepDataSummary | null
questionnaireData: QuestionnaireDataSummary | null
userProfile: UserProfileSummary | null
learningData: LearningDataSummary | null
treatmentPhase: 'EARLY' | 'MID' | 'LATE' | null
learningEngagement: 'HIGH' | 'MEDIUM' | 'LOW' | null

// 토론 설정
participatingAgents: ExpertAgentType[]
maxRounds: number
consensusThreshold: number
currentRound: number

// 토론 진행 상태
expertOpinions: ExpertAnalysis[]
roundHistory: DebateRound[]
consensusReached: boolean
consensusScore: number

// 최종 결과
finalSOLScore: number | null
confidenceScore: number | null
recommendations: RecommendationItem[]

// 실행 메타데이터
startTime: Date
dataCompleteness: number
processingTimeMs: number
status: 'IN_PROGRESS' | 'COMPLETED' | 'FAILED'
}

6.1.2 노드별 입출력 스키마​

collectData 노드​

입력 상태:

  • userId, userCycleId, predictionId (필수)

출력 상태:

  • sleepData: SleepDataSummary - 수면 패턴 통계 및 기록
  • questionnaireData: QuestionnaireDataSummary - 설문 응답 (옵션)
  • userProfile: UserProfileSummary - 사용자 프로필 및 치료 단계
  • learningData: LearningDataSummary - 학습 진도 및 참여도 데이터
validateData 노드​

입력 상태:

  • sleepData (필수)
  • questionnaireData (옵션)
  • learningData (필수)

출력 상태:

  • dataCompleteness: number - 데이터 완성도 점수 (0.0-1.0)
  • treatmentPhase: 'EARLY'|'MID'|'LATE' - 치료 단계 결정
  • learningEngagement: 'HIGH'|'MEDIUM'|'LOW' - 학습 참여도 평가
determineAgents 노드​

입력 상태:

  • questionnaireData (심리상태분석전문가 참여 결정용)
  • sleepData (멜라토닌시스템분석전문가 참여 결정용 - 기상시간 데이터 충분성)
  • learningData (에이전트 선택 기준)
  • learningEngagement (참여도 기반 임계값 조정)

출력 상태:

  • participatingAgents: ExpertAgentType[] - 참여 에이전트 목록 (3-5개)
  • maxRounds: number - 최대 토론 라운드 (2-3)
  • consensusThreshold: number - 합의 임계값 (0.67-0.80, 에이전트 수 및 학습 참여도에 따라 조정)
conductRound 노드​

입력 상태:

  • 모든 수집된 데이터 (sleepData, questionnaireData, userProfile, learningData)
  • participatingAgents, currentRound, roundHistory

출력 상태:

  • currentRound: number - 증가된 라운드 번호
  • expertOpinions: ExpertAnalysis[] - 누적된 전문가 의견
  • consensusScore: number - 현재 라운드 합의도
  • consensusReached: boolean - 합의 달성 여부
generateRecommendations 노드​

입력 상태:

  • expertOpinions (최종 전문가 의견)
  • treatmentPhase, userProfile
  • learningData, learningEngagement (권장사항 개인화에 활용)

출력 상태:

  • finalSOLScore: number - 최종 SOL 예측값
  • confidenceScore: number - 예측 신뢰도
  • recommendations: RecommendationItem[] - 개인맞춤 권장사항 (학습 진도 기반 필터링)

6.2 상세 워크플로우 다이어그램​

6.3 조건부 엣지 로직 설계​

6.3.1 shouldContinueDebate 분기 함수​

function shouldContinueDebate(state: SOLPredictionState): string {
// 1. 합의 달성 확인
if (state.consensusReached && state.consensusScore >= state.consensusThreshold) {
return 'generateRecommendations'
}

// 2. 최대 라운드 도달 확인
if (state.currentRound >= state.maxRounds) {
return 'generateRecommendations' // 강제 종료 후 다수결 적용
}

// 3. 토론 계속 진행
return 'conductRound'
}

6.3.2 데이터 품질 기반 분기​

function shouldProceedWithPrediction(state: SOLPredictionState): string {
const { dataCompleteness } = state

// 데이터 품질이 매우 낮음 (3일 미만)
if (dataCompleteness < 0.3) {
return 'failPrediction'
}

// 충분한 데이터 (정상 진행)
if (dataCompleteness >= 0.6) {
return 'determineAgents'
}

// 제한된 데이터 (경고와 함께 진행)
return 'determineAgentsWithWarning'
}

6.4 노드별 상태 변환 규칙​

6.4.1 상태 업데이트 패턴​

각 노드는 부분적 상태 업데이트를 수행하며, 기존 상태와 병합됩니다:

// collectData 노드의 상태 업데이트 예시
async function collectDataNode(state: SOLPredictionState): Promise<Partial<SOLPredictionState>> {
const sleepData = await sleepDataService.getCompleteCycleData(state.userId, state.userCycleId)
const questionnaireData = await questionnaireDataService.getLatestResponses(state.userId)
const userProfile = await userProfileService.getUserProfile(state.userId)

// 부분적 상태 반환 - LangGraph가 기존 상태와 자동 병합
return {
sleepData,
questionnaireData,
userProfile,
status: 'IN_PROGRESS'
}
}

6.4.2 상태 불변성 보장​

  • 모든 노드는 기존 상태를 변경하지 않고 새로운 상태 객체를 반환
  • LangGraph가 상태 병합 및 불변성 관리 자동 처리
  • 각 노드 실행 후 상태 스냅샷을 체크포인트로 저장

6.5 병렬 처리 및 성능 최적화​

6.5.1 conductRound 노드의 병렬 에이전트 실행​

6.5.2 타임아웃 및 오류 처리​

  • 노드별 타임아웃: 각 노드 8초 제한
  • 전체 워크플로우 타임아웃: 25초 제한
  • 부분 실패 처리: 일부 에이전트 실패 시에도 나머지로 예측 진행
  • Circuit Breaker: LLM API 연속 실패 시 자동 차단

6.6 StateGraph 인스턴스화 및 실행​

6.6.1 StateGraph 구성 코드​

class SOLPredictionStateGraph {
private stateGraph: StateGraph<SOLPredictionState>

constructor(private readonly workflow: SOLPredictionWorkflow) {
this.initializeGraph()
}

private initializeGraph() {
// StateGraph 인스턴스 생성
this.stateGraph = new StateGraph<SOLPredictionState>({
channels: {
userId: null,
userCycleId: null,
predictionId: null,
sleepData: null,
questionnaireData: null,
userProfile: null,
treatmentPhase: null,
participatingAgents: [],
maxRounds: 0,
consensusThreshold: 0,
currentRound: 0,
expertOpinions: [],
roundHistory: [],
consensusReached: false,
consensusScore: 0,
finalSOLScore: null,
confidenceScore: null,
recommendations: [],
startTime: null,
dataCompleteness: 0,
processingTimeMs: 0,
status: 'IN_PROGRESS'
}
})

// 노드 추가
this.stateGraph
.addNode('collectData', this.workflow.collectDataNode.bind(this.workflow))
.addNode('validateData', this.workflow.validateDataNode.bind(this.workflow))
.addNode('determineAgents', this.workflow.determineAgentsNode.bind(this.workflow))
.addNode('initializeDebate', this.workflow.initializeDebateNode.bind(this.workflow))
.addNode('conductRound', this.workflow.conductRoundNode.bind(this.workflow))
.addNode('generateRecommendations', this.workflow.generateRecommendationsNode.bind(this.workflow))
.addNode('saveResults', this.workflow.saveResultsNode.bind(this.workflow))

// 엣지 정의 (선형 흐름)
this.stateGraph
.addEdge('collectData', 'validateData')
.addEdge('validateData', 'determineAgents')
.addEdge('determineAgents', 'initializeDebate')
.addEdge('initializeDebate', 'conductRound')

// 조건부 엣지 (토론 루프)
this.stateGraph
.addConditionalEdge(
'conductRound',
this.workflow.shouldContinueDebate.bind(this.workflow),
{
'conductRound': 'conductRound', // 토론 계속
'generateRecommendations': 'generateRecommendations' // 합의 달성 또는 최대 라운드
}
)

// 최종 엣지
this.stateGraph
.addEdge('generateRecommendations', 'saveResults')
.addEdge('saveResults', END)

// 시작점 설정
this.stateGraph.setEntryPoint('collectData')
}

async invoke(initialState: Partial<SOLPredictionState>): Promise<SOLPredictionState> {
return await this.stateGraph.invoke({
...this.getDefaultState(),
...initialState,
startTime: new Date()
})
}

private getDefaultState(): SOLPredictionState {
return {
userId: '',
userCycleId: '',
predictionId: '',
sleepData: null,
questionnaireData: null,
userProfile: null,
treatmentPhase: null,
participatingAgents: [],
maxRounds: 0,
consensusThreshold: 0,
currentRound: 0,
expertOpinions: [],
roundHistory: [],
consensusReached: false,
consensusScore: 0,
finalSOLScore: null,
confidenceScore: null,
recommendations: [],
startTime: new Date(),
dataCompleteness: 0,
processingTimeMs: 0,
status: 'IN_PROGRESS'
}
}
}

## 7. 프롬프트 관리 아키텍처

### 7.1 프롬프트 버전 관리 전략

#### 저장소 설계
- **Firestore Collection**: `sol_cod_prompts`
- **시맨틱 버저닝**: MAJOR.MINOR.PATCH 형식
- **활성 상태 관리**: 에이전트별 단일 활성 프롬프트 보장

#### 프롬프트 구조
```typescript
{
id: string
agentType: ExpertAgentType
version: string
template: string // 프롬프트 템플릿
variables: string[] // 템플릿 변수 목록
description: string // 용도 설명
isActive: boolean // 활성 상태
performanceMetrics?: { // 성능 지표
averageResponseTime: number
accuracyScore: number
}
}

7.2 프롬프트 최적화 전략​

A/B 테스트 지원​

  • 버전 분기: 동일 에이전트의 여러 프롬프트 버전 동시 운영
  • 성능 비교: 응답 시간, 예측 정확도, 사용자 만족도 비교
  • 자동 전환: 성능 우수 버전으로 자동 활성화

동적 프롬프트 개선​

  • 사용 패턴 분석: 자주 사용되는 변수 조합 최적화
  • 오류 패턴 학습: 실패 케이스 기반 프롬프트 개선
  • 도메인 전문가 피드백: 의료진 검토 기반 프롬프트 정제

8. 비기능 요구사항​

8.1 성능 요구사항​

응답 시간 목표​

구분목표 시간최대 허용
전체 SOL 예측20초25초
개별 에이전트 분석3초5초
토론 라운드6초8초
데이터 수집1초2초

처리량 목표​

  • 동시 예측: 최대 10개 예측 동시 처리
  • 일일 처리량: 1,000건 예측 처리 가능
  • 에이전트 부하: 에이전트당 초당 2회 분석 요청

8.2 확장성 요구사항​

수직적 확장 (Scale Up)​

  • CPU 집약적: LLM 추론 작업에 최적화된 CPU 리소스
  • 메모리 요구사항: StateGraph 상태 관리를 위한 충분한 RAM
  • 네트워크 대역폭: LLM 서비스 API 호출 최적화

수평적 확장 (Scale Out)​

  • 상태 비저장: StateGraph 실행을 위한 stateless 아키텍처
  • 로드 밸런싱: Command Handler 인스턴스 간 부하 분산
  • 에이전트 격리: 각 전문가 에이전트 독립적 확장 가능

8.3 안정성 요구사항​

오류 복구​

  • Circuit Breaker: LLM API 호출 실패 시 자동 차단
  • Retry Mechanism: 일시적 오류에 대한 지수 백오프 재시도
  • Graceful Degradation: 일부 에이전트 실패 시에도 예측 결과 제공

모니터링 및 알림​

  • SLA 모니터링: 응답 시간 SLA 위반 시 자동 알림
  • 품질 지표: 예측 정확도, 합의 도달률 추적
  • 시스템 건강도: StateGraph 실행 성공률 모니터링

8.4 보안 요구사항​

데이터 보호​

  • 개인정보 처리: 수면 데이터, 설문 응답 암호화 처리
  • 로깅 제한: 민감 데이터 로깅 금지
  • 접근 제어: 전문가 에이전트별 데이터 접근 권한 제한

API 보안​

  • 인증: JWT 토큰 기반 API 접근 제어
  • rate Limiting: 과도한 예측 요청 방지
  • 감사 로깅: 모든 예측 요청 감사 추적

9. 통합 및 배포 전략​

9.1 NestJS 모듈 통합 전략​

모듈 구조​

libs/feature/sleep-onset-latency-cod/
├── src/lib/
│ ├── application/ # CQRS Handlers
│ ├── domain/ # Business Logic
│ │ ├── workflows/ # StateGraph Workflows
│ │ ├── agents/ # Expert Agents
│ │ └── prompts/ # Prompt Management
│ ├── infrastructure/ # Data Access
│ └── feature-sol-cod.module.ts

의존성 주입 설계​

  • StateGraph 인스턴스: 싱글톤으로 관리, Command Handler에 주입
  • Expert Agents: 개별 인스턴스, 독립적 생명주기
  • Prompt Manager: 캐싱 지원, 동적 프롬프트 로딩

9.2 환경별 배포 전략​

개발 환경 (Development)​

  • 목 에이전트: 실제 LLM 대신 모의 응답 제공
  • 빠른 피드백: 개발자 테스트를 위한 축소된 처리 시간
  • 로깅 강화: 모든 StateGraph 상태 변화 상세 로깅

스테이징 환경 (Staging)​

  • 실제 LLM 연동: 프로덕션과 동일한 LLM 서비스 사용
  • 성능 테스트: 부하 테스트 및 응답 시간 검증
  • A/B 테스트: 신규 프롬프트 버전 검증

프로덕션 환경 (Production)​

  • 고가용성: 다중 인스턴스 배포, 무정지 배포 지원
  • 모니터링 강화: 실시간 성능 지표 추적
  • 백업 전략: 프롬프트 버전 및 모델 가중치 백업

9.3 CI/CD 파이프라인 통합​

테스트 단계​

  1. 단위 테스트: 개별 에이전트 로직 검증
  2. 통합 테스트: StateGraph 워크플로우 E2E 테스트
  3. 성능 테스트: 응답 시간 SLA 준수 검증
  4. 보안 테스트: 개인정보 처리 규정 준수 확인

배포 단계​

  1. 프롬프트 버전 배포: 새로운 프롬프트 템플릿 배포
  2. 에이전트 코드 배포: Expert Agent 로직 업데이트
  3. StateGraph 설정 배포: 워크플로우 구조 변경사항 반영
  4. 롤백 준비: 배포 실패 시 이전 버전 즉시 복구

10. 품질 보증 및 테스트 전략​

10.1 테스트 피라미드​

단위 테스트 (Unit Tests) - 70%​

  • Expert Agents: 각 에이전트의 분석 로직 검증
  • Consensus Algorithm: 합의 계산 알고리즘 정확성
  • Prompt Manager: 프롬프트 버전 관리 로직

통합 테스트 (Integration Tests) - 20%​

  • StateGraph Workflow: 전체 워크플로우 흐름 검증
  • CQRS Integration: Command Handler와 StateGraph 통합
  • Domain Event Publishing: 이벤트 발행 및 처리 검증

E2E 테스트 (End-to-End Tests) - 10%​

  • Complete Prediction Flow: API → 예측 → 결과 반환
  • Error Scenarios: 다양한 실패 상황 처리 검증
  • Performance Validation: SLA 준수 확인

10.2 품질 지표​

기능적 품질​

  • 예측 정확도: 실제 SOL 대비 예측값 정확도 (목표: 80%)
  • 합의 도달률: 전문가 간 합의 성공률 (목표: 85%)
  • 권장사항 만족도: 사용자 권장사항 만족도 (목표: 4.0/5.0)

비기능적 품질​

  • 가용성: 시스템 가동률 (목표: 99.9%)
  • 응답 시간: SLA 준수율 (목표: 95%)
  • 처리량: 목표 처리량 달성률 (목표: 100%)

11. 위험 관리​

11.1 기술적 위험​

높은 위험도​

위험영향도완화 방안
LLM API 장애높음Circuit Breaker, 대체 LLM 서비스
StateGraph 성능 저하높음프로파일링 기반 최적화, 캐싱
합의 실패 빈발중간에이전트 로직 개선, 임계값 조정

중간 위험도​

위험영향도완화 방안
프롬프트 품질 저하중간A/B 테스트, 도메인 전문가 검토
데이터 품질 이슈중간데이터 검증 강화, 품질 지표 모니터링
확장성 한계낮음부하 테스트, 수평 확장 준비

11.2 운영적 위험​

모니터링 전략​

  • 실시간 대시보드: 핵심 지표 실시간 추적
  • 자동 알림: SLA 위반 시 즉시 알림
  • 정기 리포트: 주간/월간 품질 리포트 생성

장애 대응 절차​

  1. 즉시 대응: Circuit Breaker 작동, 트래픽 우회
  2. 근본 원인 분석: 로그 분석, 성능 프로파일링
  3. 복구 조치: 핫픽스 배포, 서비스 복구
  4. 사후 분석: 장애 원인 분석, 재발 방지책 수립

12. 결론 및 다음 단계​

12.1 설계 완료 현황​

본 LangGraph.js 통합 아키텍처 설계를 통해 다음이 완성되었습니다:

✅ 완료된 설계 영역​

  • 아키텍처 결정사항: LangGraph.js 선택 근거 및 CQRS 통합 패턴
  • 시스템 구성: 전체 시스템, 워크플로우, 데이터 흐름 아키텍처
  • 전문가 에이전트: 4개 에이전트 역할 정의 및 인터페이스 설계
  • 워크플로우 설계: StateGraph 노드 구조 및 조건부 엣지 정의
  • 비기능 요구사항: 성능, 확장성, 안정성, 보안 목표 설정
  • 품질 보증: 테스트 전략 및 위험 관리 계획

🎯 설계의 핵심 가치​

  1. 확장 가능한 아키텍처: 신규 전문가 에이전트 추가 용이
  2. 표준 준수: DTA Wide CQRS 패턴 및 도메인 주도 설계 원칙 적용
  3. 운영 효율성: 모니터링, 배포, 장애 대응 체계 완비
  4. 품질 보증: 포괄적 테스트 전략 및 성능 목표 정의

12.2 개발팀 인계사항​

sol_cod_developer 착수 준비​

다음 문서들을 기반으로 즉시 개발 시작 가능:

  • ✅ domain-model.md: 완전한 Prisma 스키마 및 ERD
  • ✅ langgraph-integration-design.md: 상세 아키텍처 및 인터페이스 설계
  • ✅ requirements.md: 19개 기능 요구사항 (COD-FR-BE-001~019)
  • ✅ business-rules.md: 비즈니스 규칙 및 제약사항
  • ✅ event-storming.md: 도메인 이벤트 및 명령 정의

개발 우선순위 제안​

  1. Week 2: 기본 인프라 구축 (Prisma 스키마, NestJS 모듈)
  2. Week 3: BaseExpertAgent 인터페이스 구현
  3. Week 4-5: 4개 전문가 에이전트 구현
  4. Week 6-7: StateGraph 워크플로우 구현
  5. Week 8: CQRS Command Handler 통합

12.3 성공 지표​

Phase 2 완료 목표 (Week 8)​

  • 기능 완성도: 19개 기능 요구사항 100% 구현
  • 성능 목표: 25초 내 SOL 예측 완료 달성
  • 품질 지표: 80% 예측 정확도, 85% 합의 도달률 달성
  • 통합 테스트: E2E 테스트 통과율 95% 이상

13. 시뮬레이션 워크플로우 아키텍처​

13.1 시뮬레이션 시스템 개요​

실제 사용자 데이터를 활용한 백테스팅 시뮬레이션을 위해 기존 StateGraph를 확장하여 시뮬레이션 전용 워크플로우를 구성합니다.

13.1.1 시뮬레이션의 핵심 가치​

  • 모델 검증: 실제 치료 완료 데이터로 예측 정확도 객관적 측정
  • 성능 개선: 예측 오차 패턴 분석을 통한 알고리즘 튜닝
  • 품질 보증: 배포 전 시스템 신뢰도 사전 검증

13.1.2 설계 원칙​

  • 독립성: 실제 예측 시스템에 영향을 주지 않는 격리된 환경
  • 일관성: 기존 Chain of Debate 워크플로우와 동일한 로직 사용
  • 시점 제한: TimeMachine 통합으로 미래 데이터 누출 방지

13.2 SimulationStateGraph 아키텍처​

13.2.1 시뮬레이션 전용 StateGraph​

interface SimulationStateGraph {
// 기존 StateGraph를 상속하되 시뮬레이션 컨텍스트 추가
nodes: {
// 시뮬레이션 전용 노드
simulation_data_prep: SimulationDataPrepNode;

// 기존 전문가 에이전트 재사용 (동일한 로직)
sleep_latency_analysis: SleepLatencyAnalyst;
psychological_analysis: PsychologicalExpert;
cbti_behavior_analysis: CBTIBehaviorExpert;
digital_env_analysis: DigitalEnvironmentExpert;
melatonin_system_analysis: MelatoninSystemAnalyst;

// 토론 진행 (기존과 동일)
debate_orchestrator: DebateOrchestrator;

// 시뮬레이션 전용 결과 처리
accuracy_calculation: AccuracyCalculationNode;
simulation_result_saver: SimulationResultSaver;
progress_updater: ProgressUpdaterNode;
};

state: SimulationWorkflowState;
}

13.2.2 시뮬레이션 워크플로우 상태​

interface SimulationWorkflowState extends BaseWorkflowState {
// 기존 상태 + 시뮬레이션 전용 필드
simulationSession: SimulationSession;
currentDayIndex: number; // 현재 예측 대상 일자
availableDataRange: DateRange; // 사용 가능한 데이터 범위
actualSOL?: number; // 실제 SOL 값 (정확도 계산용)
accumulatedMetrics: SimulationMetrics; // 누적 정확도 지표
}

13.3 핵심 시뮬레이션 노드​

13.3.1 SimulationDataPrepNode​

class SimulationDataPrepNode {
async execute(state: SimulationWorkflowState): Promise<SimulationWorkflowState> {
// 1. TimeMachine을 특정 시점으로 설정
await this.timeMachine.setVirtualTime(
state.simulationSession.userId,
state.currentDayIndex
);

// 2. 해당 시점까지의 데이터만 로딩
const availableData = await this.loadDataUpToDate(
state.simulationSession.userId,
state.currentDayIndex
);

// 3. 데이터 충분성 검증
this.validateDataSufficiency(availableData);

return {
...state,
availableDataRange: availableData.dateRange,
patientData: availableData
};
}
}

13.3.2 AccuracyCalculationNode​

class AccuracyCalculationNode {
async execute(state: SimulationWorkflowState): Promise<SimulationWorkflowState> {
const prediction = state.debateResult.finalPrediction;
const actual = await this.getActualSOL(
state.simulationSession.userId,
state.currentDayIndex
);

// 정확도 지표 계산
const accuracyMetrics = {
absoluteError: Math.abs(prediction - actual),
percentageError: Math.abs(prediction - actual) / actual * 100,
isWithinThreshold: Math.abs(prediction - actual) <= 15,
squaredError: Math.pow(prediction - actual, 2)
};

return {
...state,
actualSOL: actual,
currentAccuracy: accuracyMetrics
};
}
}

13.3.3 SimulationResultSaver​

class SimulationResultSaver {
async execute(state: SimulationWorkflowState): Promise<SimulationWorkflowState> {
// 시뮬레이션 예측 결과 저장
const simulationPrediction = new SimulationPrediction({
sessionId: state.simulationSession.id,
dayIndex: state.currentDayIndex,
predictedSOL: state.debateResult.finalPrediction,
actualSOL: state.actualSOL,
accuracyMetrics: state.currentAccuracy,
debateInfo: state.debateResult.metadata,
agentPredictions: state.debateResult.agentPredictions
});

await this.simulationRepository.savePrediction(simulationPrediction);

return state;
}
}

13.4 순차적 예측 실행 흐름​

13.4.1 시뮬레이션 실행 프로세스​

SimulationSession 생성
↓
For dayIndex = startDay to endDay:
┌─ TimeMachine 시점 설정 (dayIndex)
├─ SimulationStateGraph 실행:
│ ├─ 데이터 준비 (해당 시점까지만)
│ ├─ 참여 가능한 전문가 에이전트 결정 (3-5개)
│ ├─ 전문가 에이전트 분석 (수면잠복기, 심리상태, CBT-I, 디지털환경, 멜라토닌시스템)
│ ├─ Chain of Debate 토론
│ ├─ 최종 예측 결과 도출
│ ├─ 실제값과 비교하여 정확도 계산
│ └─ 시뮬레이션 결과 저장
├─ 진행 상황 업데이트
└─ 다음 dayIndex로 이동
↓
전체 시뮬레이션 지표 계산
↓
TimeMachine 상태 원복

13.4.2 CQRS 통합 패턴​

// 시뮬레이션 Command Handler
@CommandHandler(RunSequentialSimulationCommand)
class RunSequentialSimulationHandler {
async execute(command: RunSequentialSimulationCommand): Promise<void> {
const session = await this.createSimulationSession(command);

try {
for (let dayIndex = command.startDayIndex; dayIndex <= command.endDayIndex; dayIndex++) {
// 각 날짜별로 시뮬레이션 실행
const result = await this.simulationStateGraph.invoke({
simulationSession: session,
currentDayIndex: dayIndex,
// ... 기타 상태
});

// 진행 상황 업데이트
await this.updateProgress(session.id, dayIndex);
}

// 전체 지표 계산 및 세션 완료 처리
await this.finalizeSimulationSession(session.id);

} catch (error) {
await this.handleSimulationFailure(session.id, error);
}
}
}

13.5 시뮬레이션 전용 기능​

13.5.1 배치 시뮬레이션 지원​

// 여러 사용자에 대한 동시 시뮬레이션
@CommandHandler(RunBatchSimulationCommand)
class RunBatchSimulationHandler {
async execute(command: RunBatchSimulationCommand): Promise<void> {
const simulationPromises = command.userIds.map(userId =>
this.runUserSimulation(userId, command.config)
);

// 최대 5개까지 동시 실행
await this.executeWithConcurrencyLimit(simulationPromises, 5);
}
}

13.5.2 실시간 진행률 추적​

class ProgressUpdaterNode {
async execute(state: SimulationWorkflowState): Promise<SimulationWorkflowState> {
const progress = {
sessionId: state.simulationSession.id,
currentDayIndex: state.currentDayIndex,
completed: state.currentDayIndex - state.simulationSession.startDayIndex + 1,
total: state.simulationSession.endDayIndex - state.simulationSession.startDayIndex + 1,
percentage: Math.round((completed / total) * 100)
};

// WebSocket 또는 Server-Sent Events로 실시간 업데이트
await this.progressNotifier.updateProgress(progress);

return state;
}
}

13.6 성능 및 확장성 고려사항​

13.6.1 시뮬레이션 최적화​

  • 데이터 캐싱: 동일 사용자의 반복 시뮬레이션 시 데이터 재사용
  • 병렬 처리: 독립적인 예측 단계의 병렬 실행
  • 리소스 관리: 동시 실행 제한 및 메모리 사용량 모니터링

13.6.2 TimeMachine 통합 최적화​

class SimulationTimeMachineService {
// 시뮬레이션 전용 가상 시간 컨텍스트
async createSimulationTimeContext(
userId: string,
dayIndex: number
): Promise<SimulationTimeContext> {
// 기존 사용자의 TimeMachine 상태를 백업
const originalState = await this.timeMachine.backupUserState(userId);

// 시뮬레이션용 임시 시간 설정
await this.timeMachine.setVirtualTime(userId, dayIndex);

return new SimulationTimeContext(userId, originalState);
}

async restoreOriginalTimeState(context: SimulationTimeContext): Promise<void> {
await this.timeMachine.restoreUserState(
context.userId,
context.originalState
);
}
}

13.7 시뮬레이션 품질 보증​

13.7.1 시뮬레이션 전용 테스트​

describe('SimulationStateGraph', () => {
it('should prevent future data leakage', async () => {
// Day 10 예측 시 Day 11 이후 데이터 접근 불가 확인
});

it('should calculate accurate metrics', async () => {
// 정확도 지표 계산 로직 검증
});

it('should handle simulation failures gracefully', async () => {
// 시뮬레이션 중단 시 부분 결과 보존 확인
});
});

13.7.2 시뮬레이션 결과 검증​

  • 데이터 일관성: 실제값과 예측값의 데이터 타입 및 범위 검증
  • 시점 정확성: 각 예측이 올바른 시점의 데이터만 사용했는지 확인
  • 지표 계산: MAE, RMSE 등 정확도 지표의 수학적 정확성 검증

SOL Chain of Debate 시스템의 Phase 1 설계가 완료되었으며, 시뮬레이션 기능이 추가되어 개발팀의 본격적인 구현 작업을 위한 모든 기술적 기반이 준비되었습니다.

14. 변경 이력​

버전날짜작성자변경 내용
0.1.02025-09-01bok@weltcorp.com최초 작성 - 구현 중심 설계
0.2.02025-09-01bok@weltcorp.com시뮬레이션 워크플로우 아키텍처 추가 - SimulationStateGraph, 백테스팅 시스템, TimeMachine 통합 설계
0.2.02025-09-01bok@weltcorp.com아키텍처 중심 설계로 전면 개편 - 다이어그램, 설계 결정사항, 비기능 요구사항 추가
0.3.02025-09-01bok@weltcorp.comLangGraph StateGraph 상세 노드/엣지 구조 설계 - 상태 채널 정의, 조건부 엣지 로직, 병렬 처리 최적화
0.4.02025-09-05bok@weltcorp.com멜라토닌시스템분석전문가 추가 - 5번째 전문가 에이전트 통합, 합의 메커니즘 조정(3-5개 에이전트), 시뮬레이션 워크플로우 확장