Skip to content

8ocket/MindLog_AI

Repository files navigation

MindLog AI — 심리상담 AI 백엔드

감정 기반 AI 심리상담 서비스의 Python 백엔드. 사용자-AI 상담사 대화, 세션 종료 시 감정 분석 리포트·감정 카드 생성. Java Spring Boot BE와 내부 API 연동, AI 추론·임베딩·RAG 검색 전담 서버.


목차


프로젝트 개요

일상적인 감정 기록 + AI 심리상담 서비스. 이 레포지토리는 AI 추론 전담 서버로 다음 역할을 담당한다.

역할 설명
실시간 AI 상담 LangGraph 기반 멀티 노드 그래프로 LLM 스트리밍 응답 제공
과거 기억 검색 pgvector + Proposition-based RAG로 유사 과거 상담 컨텍스트 주입
감정 분석 상담 종료 시 Plutchik Wheel 24개 감정 분류 → 세션 대표 감정 TOP 3 집계
감정 카드 생성 감정 데이터 기반 라인아트 이미지 생성 (DALL-E 3 / Amazon Titan Image)
AI 리포트 주간/월간 심리 경향 분석 리포트 병렬 생성
데이터 보안 Bedrock Guardrails PII 탐지·익명화, AES-256-GCM 민감 데이터 암호화

시스템 아키텍처

flowchart TD
    User["사용자 (Mobile App)"]
    Java["Java Spring Boot BE"]
    AI["MindLog AI (FastAPI)"]
    Redis["Redis\n대화 이력 공유"]
    PG["PostgreSQL + pgvector\n벡터 저장·검색"]

    User -- SSE --> Java
    Java -- HTTP --> AI
    Java <--> Redis
    AI <--> Redis
    AI <--> PG
    Java <--> PG

    subgraph Bedrock["AWS Bedrock"]
        B1["Claude 3.x (LLM)"]
        B2["Titan Embed v2"]
        B3["Titan Image v2"]
        B4["Guardrails"]
    end

    AI --> Bedrock
Loading

설계 원칙:

  • AI 서버는 추론 전담 — DB 쓰기는 Java BE가 담당 (Redis 대화 이력 포함)
  • 두 서버 간 통신은 내부 API (/internal/v1/*) — 외부 노출 없음
  • 대화 이력은 Redis, 벡터·지식 데이터는 PostgreSQL로 역할 분리

핵심 기술 및 구현 상세

1. LangGraph 기반 멀티 노드 대화 파이프라인

파일: app/graph/builder.py, app/services/chat_service.py

persona_node / history_node 병렬 실행 → chat_node 합류.

flowchart LR
    START(["START"]) --> persona["persona_node\nDB 조회 + RAG 검색\n→ system_prompt 구성"]
    START --> history["history_node\nRedis 대화 이력 로드"]
    persona --> chat["chat_node\nLLM 호출 streaming=True"]
    history --> chat
    chat --> END(["END"])
Loading

persona_node 구현 포인트:

  • 최근 5개 세션 컨텍스트 조회 (DB)
  • 현재 발화로 유사 과거 상담 벡터 검색 (RAG) — proposition_enabled 플래그로 검색 방식 분기
  • 사용자 닉네임 조회 → system_prompt에 참고용으로 주입 (매 발화 사용 강제 없음)
  • 대화 흐름은 LLM이 대화 내용 기반으로 자율 판단 (턴 수 기반 단계 강제 없음)

2. Proposition-based RAG + CRAG 필터링

파일: app/services/embedding_service.py, app/services/knowledge_service.py

세션 컨텍스트를 원자적 명제(Proposition) 단위로 분해해 검색 정밀도 향상.

저장 파이프라인:

flowchart TD
    A["context_summary (1~3문장)"] --> B["LLM: 5~10개 원자적 명제 추출\nPROPOSITION_EXTRACTION_PROMPT"]
    B --> C["AES-256-GCM 암호화\n→ session_propositions 저장"]
    C --> D["Contextual Retrieval 적용\n상담 요약 + 명제 텍스트 결합"]
    D --> E["Amazon Titan Embeddings v2\n1024차원 벡터 생성"]
    E --> F["embeddings 테이블 저장\nsource_type='proposition'"]
Loading

검색 파이프라인:

flowchart TD
    A["user_input"] --> B{"proposition_enabled?"}
    B -- True --> C["search_by_propositions\ntop_k × 5 후보 조회"]
    B -- False --> D["search_similar_contexts\ntop_k × 3 후보 조회\nlegacy session-level"]
    C --> E["pgvector cosine 검색\nsession_id별 MAX score 집계"]
    D --> E
    E --> F["CRAG 3단계 필터링"]
    F --> G["context_summary 복호화\n→ LLM 컨텍스트 주입"]
    F --> H["Redis 캐시\nTTL 180초"]
Loading

CRAG (Corrective RAG) 3단계 필터링:

구간 처리
score ≥ crag_high Correct — 즉시 채택
crag_low ≤ score < crag_high Ambiguous — top_k 미충족 시 보완 채택
score < crag_low Incorrect — 폐기

Dense-only 선택 이유: 상담 내용(session_context_summaries.content)은 AES-256-GCM으로 암호화 저장되므로 역인덱스 기반 Full-Text Search 적용 불가 → pgvector cosine 검색만 사용.


3. 감정 분석 파이프라인 (Plutchik Wheel)

파일: app/utils/emotion_analyzer.py, app/services/emotion_service.py

Robert Plutchik 감정의 수레바퀴 모델 기반 — 8개 카테고리 × 3개 강도 = 24개 감정, LLM으로 추출.

flowchart TD
    A["상담 전체 사용자 발화"] --> B["extract_message_emotions\n→ LLM: MESSAGE_EMOTIONS_PROMPT"]
    B --> C["per_message\n각 메시지별 감정 목록\n{emotion, intensity, source_keyword,\ntrigger_context, emotion_trajectory}"]
    C --> D["validate_per_message\n24개 코드 외 제거\nintensity 1~10 클램프\ntrajectory 검증\n메시지당 최대 5개 감정"]
    D --> E["aggregate_per_message_emotions\nΣ(intensity × trajectory_weight)\nTOP 3 집계"]
    E --> F1["aggregated_emotions\n{emotion_type 한글, category,\nlevel, intensity, is_primary}\n→ 이미지 생성 사용"]
    E --> F2["flat_emotions\n영문 코드\n→ Java BE 전달 → DB 저장"]
Loading

trajectory 가중치: peak: 1.2 / rising: 1.1 / stable: 1.0 / falling: 0.9 반환 intensity는 원본 평균 사용 (가중치 미적용 — DB 왜곡 방지)

감정 점수 산출 (compute_session_emotion_score):

감정 점수 = Σ(valence × intensity) / (count × 10) × 100   → -100 ~ +100

카테고리별 valence: joy(+1.0), trust(+0.8), anticipation(+0.5), surprise(0), fear(-0.8), disgust(-0.9), anger(-0.9), sadness(-1.0)


4. 감정 카드 이미지 생성

파일: app/services/image_service.py, app/services/summary_service.py

라인아트 스타일 감정 카드 이미지 생성. 색상은 프론트엔드 담당, 세션 종료 시 refine_session_title()과 병렬 실행.

flowchart TD
    A["context_summary 한국어\n+ aggregated TOP3 감정"] --> B["generate_image_scene\n→ LLM: IMAGE_SCENE_PROMPT\n추상적·상징적 자연/사물/공간\n인물·얼굴 제외"]
    B --> C["image_scene\n영어 추상 장면 묘사 1~2문장"]
    C --> D["build_card_image_prompt\ncoloring book style, thin line art\nwhite background, no fill..."]
    D --> E{"use_bedrock?"}
    E -- True --> F["BedrockImageProvider\nAmazon Titan Image v2\nbase64 → S3 업로드"]
    E -- False --> G["DallEProvider\nOpenAI DALL-E 3\nsize=1024×1792"]
    F --> H["image_url 반환"]
    G --> H
Loading

5. AWS Bedrock Guardrails — PII 보호 및 콘텐츠 안전

파일: app/services/guardrail_service.py

Bedrock Guardrails apply_guardrail API에 사전 검사 위임. 개입 결과는 3가지로 분류 → SSE guardrail_intervention 이벤트에 반영:

flowchart TD
    A["사용자 입력"] --> B["apply_guardrail INPUT"]
    B --> C{"결과 분류"}
    C -- "주제 차단 / 콘텐츠 필터" --> D["input_blocked\n→ LLM 호출 없이 종료\nguardrail_intervention 이벤트"]
    C -- "PII 감지" --> E["input_pii_masked\n→ 익명화된 텍스트로 LLM 호출\nguardrail_intervention 이벤트"]
    C -- "이상 없음" --> F["원본 텍스트로 LLM 호출"]
    F --> G["ChatBedrock guardrails 자동 검사"]
    G -- "출력 차단" --> H["output_blocked\nguardrail_intervention 이벤트"]
    G -- "통과" --> I["chunk 스트리밍"]
Loading

AWS 오류 발생 시 Fail-open 방식 적용 — 과도한 차단보다 서비스 가용성 우선.


6. 위기 감지 시스템 (Crisis Detection)

파일: app/services/crisis_service.py

자해·자살·극단적 선택 의도 감지, 4단계 레벨 시스템. 대화 처리와 비동기 병렬 실행.

레벨 기준 처리
0 위험 없음
1 극심한 소진·무기력 모니터링
2 소멸·종결 암시 crisis_check 이벤트 → Java BE
3 자해·자살 직접 언급 즉각 개입 응답
flowchart LR
    A["사용자 발화"] --> B["crisis_service.detect\n비동기 병렬 실행"]
    B --> C{"레벨 판정"}
    C -- "Level 0" --> D["통과"]
    C -- "Level 1" --> E["모니터링\n이벤트 없음"]
    C -- "Level 2+" --> F["crisis_check 이벤트\n→ SSE → Java BE"]
    C -- "Level 3" --> G["즉각 개입 응답\n+ crisis_check 이벤트"]
Loading

7. 사용자 지식 그래프 (Knowledge Graph)

파일: app/services/knowledge_service.py, app/models/knowledge.py

세션 종료 시 컨텍스트 요약에서 익명화된 심리적 패턴·관계 추출 → 사용자 프로파일 축적. PII 미저장, LLM 추상화 개념만 저장.

flowchart TD
    A["context_summary"] --> B["LLM: ENTITY_EXTRACTION_PROMPT"]
    B --> C["entities\n{entity_type, name, properties}\n예) 감정패턴: 분노 억압 후 자책"]
    B --> D["relations\n{source, target, relation_type}\n예) CAUSED_BY, AMPLIFIED_BY, COOCCURS_WITH"]
    C --> E["knowledge_entities upsert\nmention_count 증가"]
    D --> F["knowledge_relations 저장"]
Loading

8. AES-256-GCM 콘텐츠 암호화

파일: app/utils/crypto.py

session_context_summaries, session_propositions DB 저장 시 AES-256-GCM 암호화 적용.

  • 암호화 포맷: base64(IV[12bytes] + ciphertext + tag[16bytes])
  • RAG 검색은 평문 벡터로 수행 — 암호화된 content는 검색 불가
  • 검색 결과 복호화 후 LLM 주입
  • CONTENT_ENCRYPTION_KEY 미설정 시 암호화 비활성 (Fail-open)

9. SSE 스트리밍 응답 설계

파일: app/api/sessions.py, app/services/chat_service.py

Java BE ↔ AI BE 간 LLM 응답 실시간 스트리밍.

stream_message 이벤트 타입:

이벤트 용도
status 처리 단계 진행 상황
ai_chunk LLM 응답 토큰 스트리밍
ai_complete 전체 응답 완료
session_title 첫 메시지 시 세션 제목 (비동기 생성)
crisis_check L2+ 위기 감지 시 별도 이벤트
guardrail_intervention PII 익명화 또는 콘텐츠 차단 (input_blocked / input_pii_masked / output_blocked)

finalize_session_stream 이벤트 타입:

이벤트 용도
status 분석/요약/카드 생성 진행 상황
complete {summary, context_summary, emotions, card, title} 전체 결과

10. AI 심화 리포트 생성 (병렬 LLM 오케스트레이션)

파일: app/services/report_service.py, app/prompts/analysis_prompts.py

독립 섹션 병렬 처리, Phase 간 의존성은 순차 실행. Phase 1의 변곡점 감지(_detect_inflection) — 연속 2세션 간 점수 차이 ±25 이상인 지점을 emotion_graphs에 표시.

flowchart TD
    subgraph Phase1["Phase 1 (병렬)"]
        P1A["graph_evaluation\n감정 점수 흐름 해석\n변곡점 감지 ±25 기준"]
        P1B["topics 추출\nfacts ≥ 2 → LLM\nfacts < 2 → keyword 빈도 fallback"]
    end
    subgraph Phase2["Phase 2 (병렬)"]
        P2A["topics_evaluation\n주제 패턴 분석"]
        P2B["current_status\n현재 상태 요약"]
        P2C["tendency\n전반적 심리 경향"]
    end
    subgraph Phase3["Phase 3 (순차)"]
        P3A["suggestions\n행동 제언\nPhase 2 결과 기반"]
    end

    Phase1 --> Phase2
    Phase2 --> Phase3
Loading

11. Prometheus 모니터링

파일: app/metrics.py

/metrics 엔드포인트로 Prometheus 메트릭 노출.

메트릭 타입 측정 대상
bedrock_api_calls_total Counter LLM 호출 횟수
bedrock_api_failures_total Counter LLM 호출 실패 횟수
bedrock_api_retries_total Counter LLM 재시도 횟수
bedrock_api_response_seconds Histogram LLM 응답 레이턴시
embedding_api_calls_total Counter 임베딩 API 호출 횟수
embedding_api_failures_total Counter 임베딩 API 실패 횟수
embedding_api_response_seconds Histogram 임베딩 생성 레이턴시
rag_search_seconds Histogram RAG 검색 전체 레이턴시 (mode: session/proposition)
rag_candidate_score Histogram CRAG 필터링 전 후보 코사인 유사도 분포
rag_crag_category_total Counter CRAG correct/ambiguous/drop 분류 횟수
rag_miss_total Counter RAG 검색 결과 없음 횟수
guardrail_calls_total Counter Guardrail 결과별 호출 횟수
proposition_encrypt_seconds Histogram AES-256-GCM 암호화 레이턴시

기술 스택

Core

분류 기술
Web Framework FastAPI, Uvicorn, Pydantic v2
AI Orchestration LangGraph, LangChain
LLM Amazon Bedrock (Claude 3.x), OpenAI (DALL-E 3, fallback)
Embedding Amazon Titan Embeddings v2 (1024차원)
Image Generation Amazon Titan Image Generator v2, OpenAI DALL-E 3
Vector DB PostgreSQL + pgvector (cosine similarity)
Cache Redis (대화 이력, RAG 캐시)
ORM / Migration SQLAlchemy, Alembic

Infrastructure & Security

분류 기술
Cloud AWS (Bedrock, S3, IAM)
Content Safety AWS Bedrock Guardrails
Encryption AES-256-GCM (콘텐츠 암호화)
Monitoring Prometheus, Structlog
Rate Limiting SlowAPI
Containerization Docker, Docker Compose

프로젝트 구조

app/
├── api/
│   ├── sessions.py          # SSE 스트리밍 엔드포인트 (messages, finalize)
│   └── reports.py           # AI 리포트 생성 엔드포인트
├── graph/
│   ├── builder.py           # LangGraph StateGraph 정의 (persona/history/chat 노드)
│   ├── prompts.py           # 프롬프트 re-export
│   └── state.py             # SessionState TypedDict
├── models/                  # SQLAlchemy ORM 모델
│   ├── emotion_card.py      # 감정 카드 (front/back image_url)
│   ├── knowledge.py         # KnowledgeEntity, KnowledgeRelation, SessionProposition, Embedding
│   ├── session.py           # CounselingSession
│   ├── summary.py           # SessionSummary, SessionContextSummary
│   ├── user.py              # User, AiPersona, JwtToken, Attendance
│   ├── report.py            # AiReport, ReportEmotionGraph, ReportAnalysis, ReportActionSuggestion, ReportTopic
│   └── safety.py            # CrisisLog, Notification
├── prompts/
│   ├── analysis_prompts.py      # 모든 LLM 프롬프트 상수 (감정/요약/이미지/리포트/위기)
│   └── system_prompt_builder.py # 시스템 프롬프트 구성 (페르소나·닉네임·RAG 컨텍스트 조합)
├── schemas/
│   ├── session.py           # MessageCreateRequest
│   └── report.py            # ReportGenerateRequest
├── services/
│   ├── chat_service.py      # SSE Facade (stream_message, finalize_session_stream)
│   ├── session_service.py   # 세션 삭제 시 AI 소유 데이터 정리
│   ├── emotion_service.py   # 감정 추출·검증
│   ├── embedding_service.py # 임베딩 저장·검색·CRAG 필터링
│   ├── image_service.py     # 감정 카드 이미지 생성 (DALL-E / Bedrock)
│   ├── knowledge_service.py # 엔티티 추출·저장, 명제 생성
│   ├── guardrail_service.py # Bedrock Guardrails PII·콘텐츠 검사
│   ├── crisis_service.py    # 위기 감지 (4단계)
│   ├── summary_service.py   # 세션 요약·제목·이미지 장면 생성
│   ├── report_service.py    # AI 심화 리포트 병렬 생성
│   ├── redis_service.py     # 대화 이력 읽기
│   └── background_tasks.py  # 임베딩·엔티티·명제 백그라운드 저장
├── utils/
│   ├── emotion_analyzer.py  # Plutchik 24개 감정 맵, 집계 로직, 감정 점수 산출
│   ├── crypto.py            # AES-256-GCM 암호화/복호화
│   ├── llm.py               # LLM 팩토리 (Bedrock/OpenAI 분기)
│   ├── sse.py               # SSE 포맷팅 공통 함수
│   └── safety.py            # 위기 대응 메시지 및 가드레일 응답
├── metrics.py               # Prometheus 메트릭 싱글톤
├── config.py                # 환경 변수 설정 (Pydantic Settings)
├── database.py              # SQLAlchemy 세션 설정
├── exceptions.py            # 커스텀 예외 (MindLogError)
├── limiter.py               # SlowAPI 레이트 리미터
└── main.py                  # FastAPI 앱 진입점
migrations/                  # Alembic 마이그레이션

API 엔드포인트

모든 엔드포인트는 내부 API (/internal/v1/*) — Java BE에서만 호출.

Method Path 설명
POST /internal/v1/sessions/{session_id}/messages 메시지 처리 + LLM 스트리밍 (SSE)
POST /internal/v1/sessions/{session_id}/finalize 상담 종료 처리 — 감정 분석, 요약, 카드 생성 (SSE)
DELETE /internal/v1/sessions/{session_id} 세션 삭제 시 AI 소유 데이터 정리 (embeddings)
POST /internal/v1/reports/generate AI 심화 리포트 생성 (user_id는 body로 전달)
GET /health 헬스 체크
GET /metrics Prometheus 메트릭

로컬 개발 환경 설정

사전 요구사항

  • Python 3.11+
  • Docker & Docker Compose
  • AWS 계정 (Bedrock 활성화, us-east-1)

설치

# 가상환경 생성
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate

# 의존성 설치
pip install -r requirements.txt
pip install -r requirements-dev.txt

환경 변수 설정

cp .env.example .env
# .env 파일에서 필수 값 설정:
# - AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION
# - OPENAI_API_KEY (로컬 개발 시 DALL-E / GPT 사용)
# - DATABASE_URL, REDIS_URL
# - CONTENT_ENCRYPTION_KEY (선택, 미설정 시 암호화 비활성)

실행

# Docker Compose로 DB + Redis 실행
docker-compose -f docker-compose.local.yml up -d

# DB 마이그레이션
alembic upgrade head

# 개발 서버 실행
make dev

About

마인드 로그 프로젝트 AI 리포

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages