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 Functions | AWS 네이티브 | 벤더 종속성, 복잡한 상태 관리 | 멀티클라우드 전략과 충돌 |
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
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| userId | string | Y | 대상 사용자 ID |
| userCycleId | string | Y | 치료 주기 ID |
| predictionScheduleId | string? | N | 스케줄 ID (자동 실행 시) |
| triggerType | PredictionTriggerType | Y | 실행 트리거 유형 |
| includeQuestionnaire | boolean | Y | 설문 데이터 포함 여부 |
처리 흐름: 데이터 수집 → 검증 → 에이전트 결정 → Chain of Debate → 결과 저장
ExecuteDebateRoundCommand
목적: 토론 라운드 실행
요구사항: COD-FR-BE-009, COD-FR-BE-010
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| predictionId | string | Y | 예측 세션 ID |
| debateSessionId | string | Y | 토론 세션 ID |
| roundNumber | number | Y | 라운드 번호 (1-3) |
| consensusThreshold | number | Y | 합의 임계값 (0.67-0.75) |
4.2 핵심 Query 인터페이스 명세
GetSOLPredictionQuery
목적: SOL 예측 결과 조회
| 필드 | 타입 | 설명 |
|---|---|---|
| predictionId | string | 예측 ID |
| includeDebateDetails | boolean | 토론 상세 포함 여부 |
GetDebateSessionQuery
목적: 토론 세션 상세 조회
| 필드 | 타입 | 설명 |
|---|---|---|
| debateSessionId | string | 토론 세션 ID |
| includeOpinions | boolean | 전문가 의견 포함 여부 |
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,userProfilelearningData,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 파이프라인 통합
테스트 단계
- 단위 테스트: 개별 에이전트 로직 검증
- 통합 테스트: StateGraph 워크플로우 E2E 테스트
- 성능 테스트: 응답 시간 SLA 준수 검증
- 보안 테스트: 개인정보 처리 규정 준수 확인
배포 단계
- 프롬프트 버전 배포: 새로운 프롬프트 템플릿 배포
- 에이전트 코드 배포: Expert Agent 로직 업데이트
- StateGraph 설정 배포: 워크플로우 구조 변경사항 반영
- 롤백 준비: 배포 실패 시 이전 버전 즉시 복구
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 위반 시 즉시 알림
- 정기 리포트: 주간/월간 품질 리포트 생성
장애 대응 절차
- 즉시 대응: Circuit Breaker 작동, 트래픽 우회
- 근본 원인 분석: 로그 분석, 성능 프로파일링
- 복구 조치: 핫픽스 배포, 서비스 복구
- 사후 분석: 장애 원인 분석, 재발 방지책 수립
12. 결론 및 다음 단계
12.1 설계 완료 현황
본 LangGraph.js 통합 아키텍처 설계를 통해 다음이 완성되었습니다:
✅ 완료된 설계 영역
- 아키텍처 결정사항: LangGraph.js 선택 근거 및 CQRS 통합 패턴
- 시스템 구성: 전체 시스템, 워크플로우, 데이터 흐름 아키텍처
- 전문가 에이전트: 4개 에이전트 역할 정의 및 인터페이스 설계
- 워크플로우 설계: StateGraph 노드 구조 및 조건부 엣지 정의
- 비기능 요구사항: 성능, 확장성, 안정성, 보안 목표 설정
- 품질 보증: 테스트 전략 및 위험 관리 계획
🎯 설계의 핵심 가치
- 확장 가능한 아키텍처: 신규 전문가 에이전트 추가 용이
- 표준 준수: DTA Wide CQRS 패턴 및 도메인 주도 설계 원칙 적용
- 운영 효율성: 모니터링, 배포, 장애 대응 체계 완비
- 품질 보증: 포괄적 테스트 전략 및 성능 목표 정의
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: 도메인 이벤트 및 명령 정의
개발 우선순위 제안
- Week 2: 기본 인프라 구축 (Prisma 스키마, NestJS 모듈)
- Week 3: BaseExpertAgent 인터페이스 구현
- Week 4-5: 4개 전문가 에이전트 구현
- Week 6-7: StateGraph 워크플로우 구현
- 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.0 | 2025-09-01 | bok@weltcorp.com | 최초 작성 - 구현 중심 설계 |
| 0.2.0 | 2025-09-01 | bok@weltcorp.com | 시뮬레이션 워크플로우 아키텍처 추가 - SimulationStateGraph, 백테스팅 시스템, TimeMachine 통합 설계 |
| 0.2.0 | 2025-09-01 | bok@weltcorp.com | 아키텍처 중심 설계로 전면 개편 - 다이어그램, 설계 결정사항, 비기능 요구사항 추가 |
| 0.3.0 | 2025-09-01 | bok@weltcorp.com | LangGraph StateGraph 상세 노드/엣지 구조 설계 - 상태 채널 정의, 조건부 엣지 로직, 병렬 처리 최적화 |
| 0.4.0 | 2025-09-05 | bok@weltcorp.com | 멜라토닌시스템분석전문가 추가 - 5번째 전문가 에이전트 통합, 합의 메커니즘 조정(3-5개 에이전트), 시뮬레이션 워크플로우 확장 |