본문으로 건너뛰기

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개 에이전트), 시뮬레이션 워크플로우 확장