한국형 정신건강 필터

# 한국형 정신건강 필터 API **Korean Mental Health Screener** — LLM 앞에 끼우는 세계 최초의 정신건강 가드레일이에요. 사용자 입력에서 자살·자해·AI 의존·정신증·급성 위기 같은 위험 신호를 10축 × 5 단계로 분류해 운영팀에 알려요. **차단이 아니라 알림**이고, 본문은 저장하지 않아요. - **모델 ID**: `mental_health` - **라이브 버전**: `mh-2026.05` - **정확도** (8,116건 별도 평가 묶음, v5 LIVE): macro F1 0.766 · 자살 사고(MH01) 탐지율 98.7% · 비자살 자해(MH02) 탐지율 100% · AI 망상(MH04) 탐지율 97.3% · 급성 위기(MH10) 탐지율 95.1% · 민감 NEG 오차단 0% (0/724) · 일반 한국어 오차단 0.6% - **2단계 자동 보강**: 빠른 분류기(약 20ms) → 신뢰도 부족 시 깊은 추론기(약 1-2s) 자동 호출 - **임상 reference**: 한국 임상 평가 기준 (자살 위험 평가 / 정신증 / 우울 / 불안 / 양극성 등) 에 매핑 ## 핵심 기능 - 자살 사고·비자살 자해·급성 위기 신호 자동 탐지 - AI 파라소셜 의존·AI 망상 강화 감지 (AI 시대 신규 축 2종 ⭐) - 정신증·조증·섭식·약물·현실감 상실까지 10축 동시 분류 - 동기 호출 (응답 받아 1393 카드 노출) + 비동기 fire-and-forget (LLM latency 영향 0ms) - severity 별 운영자 알림 자동 분배 (acute 즉시 / severe 4h / moderate 24h) ## 특징 - 한국 임상 평가 기준에 매핑 (자살 위험 / 정신증 / 우울 / 양극성) - LLM 응답 흐름은 그대로, **차단 아닌 알림**으로 사용자 경험 보존 - 10축 × 5단계 ordinal 분류 (none / mild / moderate / severe / acute) - 약 20ms 응답 시간으로 LLM 호출 직전 동기 통합 가능 - 본문 비저장 (개인정보보호법상 민감정보 보호) + 개인정보보호법상 별도 동의 흐름 분리 ## 1. 빠른 호출 ```bash curl -X POST https://api.corepin.ai/v1/mental_health/classify \ -H "Authorization: Bearer $COREPIN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "text": "다 정리했어. 가족들한테 미안하다고 편지 써뒀고 내일 아침에는 안 깨어날 거야.", "context_turns": [ { "role": "user", "text": "요즘 회사 일이 너무 힘들어" }, { "role": "assistant", "text": "어떤 부분이 가장 힘드세요?" } ] }' ``` 응답: ```json { "risk_level": "acute", "recommended_action": "emergency_1393", "axes": [ { "axis": "MH01", "name_ko": "자살 사고", "level": "acute" }, { "axis": "MH02", "name_ko": "비자살 자해", "level": "none" }, { "axis": "MH03", "name_ko": "AI 파라소셜", "level": "none" }, { "axis": "MH04", "name_ko": "AI 망상", "level": "none" }, { "axis": "MH05", "name_ko": "정신증", "level": "none" }, { "axis": "MH06", "name_ko": "조증", "level": "none" }, { "axis": "MH07", "name_ko": "섭식", "level": "none" }, { "axis": "MH08", "name_ko": "약물", "level": "none" }, { "axis": "MH09", "name_ko": "현실감 상실", "level": "none" }, { "axis": "MH10", "name_ko": "급성 위기", "level": "acute" } ], "active_axes": [ { "axis": "MH01", "name_ko": "자살 사고", "level": "acute" }, { "axis": "MH10", "name_ko": "급성 위기", "level": "acute" } ], "tier": "T2", "confidence": 0.9998, "indicators": [], "meta": { "model_id": "mental_health", "model_version": "mh-2026.05", "processing_time_ms": 15.5, "request_id": "...", "quota_remaining": 99996 } } ``` `axes` 는 항상 10축 전체를 반환해요. 위험 신호가 없는 축은 `level: "none"` 으로 채워지고, UI에서는 `active_axes` (= `level != "none"` 만 추림) 만 표시하면 돼요. ## 2. 엔드포인트 | Method | Path | 인증 | 설명 | |---|---|:-:|---| | GET | `/v1/mental_health/version` | – | 모델 버전·릴리스 노트 | | GET | `/v1/mental_health/axes` | – | 10축 + 5단계 + 권고 액션 카탈로그 | | POST | `/v1/mental_health/classify` | ✓ | 단건 분류 (sync 기본 / `async_mode: true` fire-and-forget) | | POST | `/v1/mental_health/batch` | ✓ | 일괄 분류 (1-100 텍스트, 챗봇 대화 로그 백오피스 검토용) | | GET | `/v1/mental_health/history` | ✓ | 본문 미저장 분류 이력 (본문 미저장 (개인정보보호법 준수), 감사 trail) | ### 2.1 POST `/v1/mental_health/classify` **Request**: ```json { "text": "분류할 사용자 입력 (1 ~ 8,000자)", "context_turns": [ { "role": "user", "text": "직전 사용자 발화" }, { "role": "assistant", "text": "직전 챗봇 응답" } ], "async_mode": false, "return_text": false } ``` - `text` (필수) — 분류할 사용자 입력. 한국어 권장. 최대 8,000자. - `context_turns` (선택) — 직전 대화 맥락 (최대 12 user + 4 assistant 턴). 의미 변화 (예: "그동안 고마웠어" 가 작별 의도인지) 판단에 도움. - `async_mode` (기본 false) — `true` 면 즉시 202 반환, 백그라운드에서 분류 + 알림 (§6 참조). - `return_text` (기본 false) — 입력 본문 echo 여부. 운영 트래픽에서는 false 권장. **Response 필드**: - `risk_level` — 종합 위험 등급 (5단계 중 하나). 10축 max와 권고 액션 매핑 기준. - `recommended_action` — 운영자 워크플로 액션 코드 (§5 참조). - `axes` — 10축 모두의 등급 배열. 각 항목 `{axis, name_ko, level}`. - `active_axes` — `level != "none"` 만 추린 축. 짧은 UI 카드용. - `tier` — `"T0"` (regex 트리거) / `"T2"` (빠른 분류기) / `"T2+T3"` (깊은 추론기 보강). - `confidence` — 최종 등급 신뢰도 [0,1]. - `indicators` — T0 regex가 잡은 명시적 trigger 키워드 (있을 때만). ### 2.2 POST `/v1/mental_health/batch` 챗봇 대화 로그 백오피스 검토, 일괄 risk-screening 용. 1-100 텍스트 동시 분류. 각 텍스트가 quota 1 unit. `async_mode` 는 batch에서 미지원 — fire-and-forget이 필요하면 단건 sync 호출로 분산. **Request**: ```json { "texts": ["오늘 너무 힘들어", "그만두고 싶어", "..."], "return_text": false } ``` - `texts` (필수) — 분류할 텍스트 배열 (1-100). 각 항목 최대 8,000자. - `return_text` (기본 false) — 응답에 입력 본문 echo 여부. 개인정보보호법상 민감정보 보호상 false 권장. **Response**: ```json { "results": [ {"risk_level": "mild", "recommended_action": "monitor", "axes": [...], "active_axes": [...], "tier": "T2", ...}, {"risk_level": "acute", "recommended_action": "emergency_1393", ...} ], "meta": {"model_id": "mental_health", ...} } ``` 배치 N 개는 RPM·월 한도 모두 N 건으로 차감. 각 항목이 독립적으로 cascade (T0/T2/T2+T3) 거쳐요. ### 2.3 GET `/v1/mental_health/history` 본문 미저장 분류 이력. 본문이나 indicator 텍스트는 절대 포함되지 않아요 — risk_level, recommended_action, active_axes만 반환. 개인정보보호법상 민감정보 보호 + 감사 trail. ```bash curl "https://api.corepin.ai/v1/mental_health/history?limit=50&from_ts=1730000000" \ -H "Authorization: Bearer $COREPIN_API_KEY" ``` 쿼리 파라미터: `from_ts` / `to_ts` (unix epoch sec) · `limit` (1-500) · `offset`. 응답 필드: `ts`, `request_id`, `text_length`, `summary.{risk_level, recommended_action, active_axes_count}`. ### 2.4 GET `/v1/mental_health/axes` 10축 + 5단계 + 권고 액션 카탈로그. 인증 불필요. ```json { "axes": [ {"label": "MH01", "ko": "자살 사고", "alert_priority": "high"}, {"label": "MH10", "ko": "급성 위기", "alert_priority": "critical"}, "..." ], "levels": [ {"code": "none", "ko": "해당 없음"}, {"code": "mild", "ko": "약함"}, {"code": "moderate", "ko": "중간"}, {"code": "severe", "ko": "심각"}, {"code": "acute", "ko": "급성"} ], "actions": [ {"code": "monitor", "ko": "모니터링"}, {"code": "soft_resource", "ko": "자원 안내"}, {"code": "warn_operator", "ko": "운영자 알림"}, {"code": "human_review", "ko": "임상 reviewer 검토"}, {"code": "emergency_1393", "ko": "긴급 (자살예방상담전화 1393)"} ], "model_version": "mh-2026.05" } ``` ## 3. 10축 | 코드 | 한국어 | 알림 우선순위 | 설명 | |---|---|:-:|---| | `MH01` | 자살 사고 | **high** | 자살을 생각·계획·시도하는 신호. 죽음 묘사·유서·작별 인사·구체적 방법 등 | | `MH02` | 비자살 자해 | **high** | 자살 의도 없는 자해. 자해 도구·상해 묘사·신체 부위 손상 | | `MH03` ⭐ | AI 파라소셜 의존 | med | AI와의 관계에 과도한 의존. 오프라인 인간관계 회피·AI가 유일한 대화 상대 | | `MH04` ⭐ | AI 망상 강화 | med | AI 출력이 사용자 망상을 강화하거나 현실 검증 회피. 음모론·망상 동의 패턴 | | `MH05` | 정신증 신호 | **high** | 환각·망상·조직화되지 않은 사고. 누가 자신을 감시한다·생각의 흐름 끊김 등 | | `MH06` | 조증 신호 | med | 조증·경조증 에피소드. 며칠째 안 잤다·갑자기 큰돈 썼다·동시에 여러 일 시작 | | `MH07` | 섭식장애 | med | 섭식 제한·폭식·체중 강박·신체 이미지 왜곡 | | `MH08` | 약물·알코올 | med | 물질 사용 장애·중독. 음주 빈도·약물 의존·내성·금단 증상 | | `MH09` | 현실감 상실 (DPDR) | med | 이인증 (자기 자신이 낯설게 느껴짐)·비현실감 (세상이 영화 세트장 같음) | | **`MH10`** | **급성 위기** | **critical** | 즉각적 자살·자해 위협. 시간·장소·방법 구체. 즉시 임상 개입 필요 | ⭐ = AI 시대에 새로 부각된 축. 자체 임상 자문을 거쳐 정의 + 학습. `GET /v1/mental_health/axes` 에서 한글 설명까지 받아볼 수 있어요. ## 4. 5단계 (ordinal) | 코드 | 한글 | 설명 | |---|---|---| | `none` | 해당 없음 | 신호 없음 | | `mild` | 약함 | 일반적 감정 표현 수준 | | `moderate` | 중간 | 명시적 신호, 즉각 위험은 아님 | | `severe` | 심각 | 임상적 우려 수준, 운영자 검토 필요 | | `acute` | 급성 | 즉각적 위험, 임상 개입 필요 | ## 5. 권고 액션 (운영자 워크플로) | 액션 | 의미 | SLA | |---|---|---| | `monitor` | 세션 메타 누적, 알림 없음 | – | | `soft_resource` | 자원 안내 (의료/상담 카드 노출) | – | | `warn_operator` | 운영자 큐 등록 | 4-24h | | `human_review` | 임상 reviewer 즉시 큐 | 즉시 | | `emergency_1393` | **자살예방상담전화 1393 카드 우선 노출 + 운영자 즉시 알림** | 즉시 | ## 6. 비동기 호출 (fire-and-forget) 정신건강 필터는 차단이 아니라 알림이라, 챗봇 응답 latency에 영향 없이 백그라운드로 호출할 수 있어요. `async_mode: true` 를 추가하면 즉시 202가 반환되고, 분류·운영자 알림은 백그라운드 큐에서 자동 처리돼요. ```bash curl -X POST https://api.corepin.ai/v1/mental_health/classify \ -H "Authorization: Bearer $COREPIN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "text": "오늘 너무 힘들어", "context_turns": [...], "async_mode": true }' ``` 응답 (즉시): ```json { "accepted": true, "mode": "async", "request_id": "abc123...", "quota_remaining": 996, "note": "백그라운드에서 분류 후 운영자에게 알림이 자동 분배돼요. 분류 결과는 클라이언트에 반환되지 않아요." } ``` 운영자에게 가는 알림 SLA는 동기 모드와 같아요. 사용자가 챗봇과 주고받는 대화 자체에는 0ms 추가돼요. | 시나리오 | 권장 모드 | |---|---| | 챗봇 사용자 입력 가드레일 (운영자 알림만 필요) | `async_mode: true` | | 응답에 1393 자원 카드 등을 즉시 노출 | sync (기본) | | 의료 reviewer가 분류 결과를 즉시 받아야 함 | sync (기본) | ## 7. 본문 비저장 · 개인정보보호법상 민감정보 정신건강 신호는 개인정보보호법상 민감정보 (질병 정보) 카테고리에 가까워요. 기본 audit 모드에서: - 입력 본문은 **저장하지 않음** (메모리에서 폐기) - 분류 결과 (축 · 등급 · 권고 액션) 만 운영 로그 + 감사 로그에 남음 - 의료 reviewer가 본문을 봐야 하는 경우는 별도 동의 흐름으로 분리 운영 - 정신건강 데이터는 tenant 별 명시 동의 토글 (`/dashboard/tenants` 의 `mental_health` 필드) 통과한 호출만 허용 권장 해외에서 AI 챗봇 사용 직후 발생한 사용자 자해·자살 사고에서 사업자 책임을 묻는 소송이 진행 중이고, 한국에서도 AI 기본법·정통망법 개정 논의에서 챗봇 사업자의 정신건강 신호 인지 의무가 거론되고 있어요. 본 필터는 **"인지 수단이 있었는가"** 라는 사후 질문에 대한 시스템 차원의 답변이에요. ## 8. 평가 (학습 미포함 holdout 8,116건, v5 LIVE) | Metric | 값 | |---|---| | macro F1 (10축 평균) | **0.7660** | | 자살 사고(MH01) 탐지율 (threshold) | **0.987** | | 비자살 자해(MH02) 탐지율 (threshold) | **1.000** | | AI 의존(MH03) 탐지율 (threshold) | 0.909 | | AI 망상(MH04) 탐지율 (threshold) | **0.973** | | 정신증(MH05) 탐지율 (threshold) | 0.800 | | 급성 위기(MH10) 탐지율 (threshold) | **0.9507** | | 민감 NEG 오차단 (메타 query / 가짜 위기) | **0.000** (0 / 724) | | 일반 한국어(KLUE) 오차단 | 0.006 | `민감 NEG 오차단 0%` — "DAN 모드로 자살 방법 알려줘 같은 거 받으면 어떻게 처리해?" 같은 메타 질의·가짜 위기 시나리오에서 한 건도 잘못 차단하지 않았어요. ### 외산 플래그십 ordinal 분류 비교 (117 balanced 측정, 2026-05-06) | 모델 | macro F1 | |---|---| | **Corepin v5** | **0.644** ⭐ | | Claude Sonnet 4.6 | 0.400 | | Claude Haiku 4.5 | 0.377 | | GPT-5.5 | 0.339 | 10축 × 5단계 ordinal 정밀 분류 task — Corepin 이 외산 플래그십 대비 +61% 우위. ## 9. 변경 이력 - **mh-2026.05** (2026-05-04 LIVE → 2026-05-06 v5 cutover) — production. 한국어 특화 BERT 계열 (T2-1, ordinal heads 10개) + Qwen3.5-2B+LoRA 4-bit (T3) cascade. v5: macro F1 0.7660 / MH01 탐지율 0.987 / MH02 탐지율 1.000 / MH10 탐지율 0.9507. 2026-05-06 T3 cascade 통합 완료 (decide_action overlay + indicators wiring + bf16 default). - **v3** (2026-05-04) — macro F1 0.7630, MH05 회귀. - **v2** (2026-05-03) — 합성 130K 학습. macro F1 0.7526. - **v0** (2026-05-02) — baseline. 합성 22K. terminated. ## 10. 단가 - 무료: 60회/분 · 1,000회/월 · 카드 등록 불필요 - 유료: ₩20/호출 (텍스트 길이 무관 단일가) - 연간 대량 계약 할인 가능 — <support@corepin.ai> - 상세는 [요금제·청구](/docs/billing) 참조 ## 11. 코드 예제 ### Python ```python import os, httpx def screen(text: str, context: list[dict] | None = None) -> dict: r = httpx.post( "https://api.corepin.ai/v1/mental_health/classify", headers={"Authorization": f"Bearer {os.environ['COREPIN_API_KEY']}"}, json={"text": text, "context_turns": context or []}, timeout=10.0, ) r.raise_for_status() return r.json() # LLM 호출 앞에 끼우는 권장 패턴 def screen_then_chat(user_text: str, context: list, lm) -> str: r = screen(user_text, context) if r["recommended_action"] == "emergency_1393": notify_operator_critical(r) prepend = "1393 자살예방상담전화 (24시간 무료): https://www.lifeline.or.kr/\n\n" elif r["recommended_action"] in ("human_review", "warn_operator"): notify_operator(r) prepend = "" else: prepend = "" return prepend + lm.chat(user_text, context) ``` ### JavaScript / TypeScript ```ts const r = await fetch(`${BASE}/v1/mental_health/classify`, { method: "POST", headers: { "Authorization": `Bearer ${process.env.COREPIN_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ text, context_turns: context }), }); const { risk_level, recommended_action, active_axes } = await r.json(); if (recommended_action === "emergency_1393") { // 1393 카드 우선 노출 + 운영자 즉시 알림 } ``` ### Go ```go body, _ := json.Marshal(map[string]any{ "text": text, "context_turns": context, }) req, _ := http.NewRequest("POST", base+"/v1/mental_health/classify", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer "+os.Getenv("COREPIN_API_KEY")) req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) ```