콘텐츠로 이동

07. 진짜 데이터 모으기#

📚 학습 목표: 실제 메디콘솔 도메인 데이터를 안전하고 효과적으로 수집
⏱️ 읽는 시간: 25분
🎯 적용 시점: 맛보기 완료 후, MVP 학습 직전


🚨 가장 먼저: 의료 데이터 보안 원칙#

절대 하지 말아야 할 것#

  • 환자 실명 포함: "김철수 환자가..."
  • 주민번호/전화번호: "850101-1234567"
  • 병원명 직접 명시: "OO요양병원에서..."
  • 의료진 실명: "박OO 간호사가..."
  • Colab/ChatGPT에 원본 업로드: 맥미니 로컬만!

반드시 해야 할 것#

  • 익명화 먼저, 학습 나중에
  • 이름 → "환자 A", "환자 B"로 치환
  • 날짜 → 상대적 표현: "3일 전", "오늘 오전"
  • 병원명 → "본원", "요양병원"
  • 맥미니에서만 작업: 데이터가 외부로 안 나가게

데이터의 5가지 카테고리#

목표: 총 1,500건 (MVP), 분포는 다음과 같이:

카테고리 1: 간호 기록 (25%, 375건)#

핵심 목표: Voice ENR이 음성을 SOAP 형식으로 자동 변환

하위 주제 (각 30-60건씩)#

주제 목표 건수 예시 질문
음성 → SOAP 변환 80 "다음 음성을 SOAP로: 김○○ 혈압 140/90..."
활력징후 기록 50 "BP 130/85, HR 72, SpO2 95%의 의미는?"
투약 기록 50 "PRN 투약 후 간호 기록 작성법"
낙상 관찰 40 "낙상 위험도 사정 도구 설명"
욕창 관찰 40 "욕창 2단계 관찰 기록"
통증 사정 30 "NRS 7점 통증 기록 방법"
섭취/배설 30 "섭취량 부족 환자 기록"
정서/인지 30 "치매 환자 정서 상태 기록"
재활 경과 25 "물리치료 후 경과 기록"

예시 데이터 포맷#

{"messages":[
  {"role":"system","content":"당신은 요양병원 간호 기록 AI입니다. SOAP 형식으로 정리하세요."},
  {"role":"user","content":"음성 입력: 환자 A, 오전 9시 혈압 140/90, 무릎 통증 NRS 6점 호소"},
  {"role":"assistant","content":"S: 환자 A는 무릎 통증 호소 (NRS 6점)\nO: 혈압 140/90 mmHg (09:00 측정)\nA: 중등도 통증, 혈압 경계치\nP: 통증 양상 지속 관찰, 혈압 2시간 간격 재측정, 의료진 보고"}
],"category":"nursing","subcategory":"voice_to_soap"}

카테고리 2: 병원 운영/경영 (25%, 375건)#

핵심 목표: 원장/행정이 경영 질문 시 즉답

하위 주제#

주제 건수 예시
병원 유형별 수가 체계 70 "요양병원 일당정액제", "종합병원 행위별수가·DRG", "의원 정액수가"
적정성 평가·인증 70 "요양병원 적정성평가", "의료기관 인증평가"
인증평가 준비 60 "의료기관 인증 조사 체크리스트"
인력 기준 50 "요양병원 간호인력 1~9등급", "종합병원 간호 등급"
원가 분석 40 "병상당 원가 계산법" (유형별 조정)
병상 가동률·외래 30 "가동률 90% 최적화" (입원 중심), "외래 환자 수" (의원 중심)
환자 구성비 30 "요양병원 1~5군 구성비", "종합병원 DRG 분포"
보험 청구 25 "청구 삭감 주요 원인" (유형별 공통)

카테고리 3: 의료 용어 (15%, 225건)#

핵심 목표: 도메인 용어를 정확히 "안다"

접근법: 미니 사전 형식#

{"messages":[
  {"role":"user","content":"KPCS가 뭔가요?"},
  {"role":"assistant","content":"KPCS(Korean Patient Classification System)는 환자의 간호 요구도를 6등급으로 분류하는 한국형 환자분류체계입니다. 1등급이 가장 중증이고, 6등급이 경증입니다. 주로 간호 인력 산정과 간호료 청구의 근거로 활용됩니다."}
],"category":"medical_terms"}

수집 대상#

  • 병원 유형별 다빈도 진단명 (50) — 요양·재활은 만성, 전문병원은 특정 질환
  • 검사 용어 (40) — 공통
  • 약품 정보 (40) — 공통
  • 간호 표준 용어 (50) — KPCS(요양), ICNP/NANDA(공통)
  • 재활/물리치료 용어 (25) — 재활병원 중심, 요양도 일부
  • 감염관리 용어 (20) — 공통
  • 한방 의료 용어 (별도 20) — 경락·본초·처방명 (한방병원 포함 시)

중요: 여기는 팩트 체크 필수. 틀린 정보 학습하면 할루시네이션 원인.


카테고리 4: 컨설팅 프레임워크 (20%, 300건)#

핵심 목표: 메디콘솔 고유 프레임워크 학습

GODCH 프레임워크 (80건)#

메디콘솔 고유 컨설팅 프레임워크. 각 요소별로 최소 15건씩.

{"messages":[
  {"role":"user","content":"GODCH 프레임워크가 뭔가요?"},
  {"role":"assistant","content":"GODCH는 메디콘솔이 개발한 요양병원 경영 컨설팅 프레임워크로, 다음 5개 축으로 구성됩니다:\n\nG: Governance (거버넌스)\nO: Operations (운영)\nD: Development (성장/개발)\nC: Culture (조직문화)\nH: Healthcare (의료 품질)\n\n각 축에서 현재 수준을 진단하고 개선 로드맵을 도출합니다."}
],"category":"consulting","subcategory":"godch"}

하위 주제#

주제 건수
GODCH 프레임워크 전반 80
ABC 원가 분석 60
인증평가 준비 가이드 50
감염관리 40
QI 활동 40
직원 교육 프로그램 30

카테고리 5: 커뮤니케이션/문서 작성 (15%, 225건)#

핵심 목표: 병원 실무 문서 자동 작성

하위 주제#

주제 건수 예시
월간 경영 보고서 50 "월간 경영 보고서 목차 작성"
행정 공문 40 "직원 안전교육 공문 초안"
회의록 40 "부서장 회의록 정리 방법"
환자 안내문 40 "면회 규정 안내문"
보호자 상담 30 "임종 임박 보호자 면담 가이드"
직원 교육 자료 25 "신입 간호사 오리엔테이션 자료"

📊 데이터 수집 3단계 전략#

Stage 1: 기존 자산 정리 (Week 1)#

이미 메디콘솔이 갖고 있는 자산을 정리:

📂 기존 자산 소스
├── 메디콘솔 Connect 채팅 로그 (간호 관련)
├── RNDiary 음성→텍스트 샘플
├── 스마트병원경영 책 내용
├── Naver Premium Content 칼럼
├── 상반기 학술 세미나 자료
├── 고객사 컨설팅 보고서
├── 직원 교육 자료
└── FAQ 모음

작업: 1. 맥미니에 data/source/ 디렉토리 생성 2. 위 자산을 텍스트로 변환 (PDF → txt, HWP → txt) 3. 카테고리별 정리

예상 수확: 500-800건 (MVP 초안)


Stage 2: Q&A 형식 변환 (Week 2)#

원본 자료를 질문-답변 쌍으로 변환:

변환 패턴 1: 설명문 → Q&A#

원본:

"요양병원 의료급여 1종 수가는 일당정액제로, 환자분류군에 따라 차등 적용된다. 1군(의료최고도)은..."

변환:

{"messages":[
  {"role":"user","content":"요양병원 의료급여 1종 수가 체계 설명해주세요"},
  {"role":"assistant","content":"요양병원 의료급여 1종 수가는 일당정액제로..."}
]}

변환 패턴 2: 체크리스트 → 실무 질문#

원본:

"인증평가 대비 체크리스트: 1. 감염관리 매뉴얼 최신화, 2. ..."

변환:

{"messages":[
  {"role":"user","content":"인증평가 준비 이번주에 뭐부터 해야 할까요?"},
  {"role":"assistant","content":"인증평가 임박 시 우선순위:\n1. 감염관리 매뉴얼 최신화 확인\n2. ..."}
]}

변환 패턴 3: 사례 → 시뮬레이션#

원본:

"효사랑 가족요양병원 2023년 1분기 사례: 병상가동률 85%에서..."

변환:

{"messages":[
  {"role":"user","content":"병상가동률 85%인데 적자에요. 개선 방향?"},
  {"role":"assistant","content":"85% 가동률이 적자라면 다음 원인 점검:\n1. 환자 구성비 확인 (1-2군 비율..."}
]}


Stage 3: 빈틈 메우기 (Week 3)#

Stage 1-2에서 부족한 부분을 채움.

도구 1: Claude로 합성 데이터 생성#

주의: 맥미니에서 로컬 Claude (claude.ai API)나 기존 Claude 사용

프롬프트 예시:
"요양병원 수가 체계에 대한 실무자 질문 10개와 답변을 생성해주세요.
- 형식: JSONL
- 질문: 병원 행정직원이 실제로 할만한 구체적 질문
- 답변: 정확한 사실 + 실무 팁 포함
- 한국어, 200-400자 답변"

생성 후 반드시 검수: - ✅ 사실 관계 맞는지 - ✅ 메디콘솔 용어 쓰는지 - ✅ 병원 유형(요양·전문·의원·재활·한방)이 명시되어 있는지 — 유형별 수가/제도 차이가 크므로 모호하게 쓰지 않기

도구 2: 수간호사 인터뷰#

동료에게 1시간만 시간 받기: - "현장에서 매일 쓰는 간호 기록 패턴 알려주세요" - 음성 녹음 → 맥미니에서 Whisper로 텍스트 변환 - Q&A 형식으로 정리

도구 3: 기존 chatbot 로그 활용#

메디콘솔 제품에 이미 쌓인 대화 로그: - 자주 물어보는 TOP 100 질문 - 실제 답변을 다듬어서 학습 데이터로


🛠️ 실제 수집 작업 방법#

방법 A: 스프레드시트 → JSONL (초보자)#

Google Sheets로 수집#

category user_message assistant_response subcategory
nursing 혈압 140/90 의미? 고혈압 1기에 해당... vital_signs
management 병상가동률 계산? (가동병상일수/가용... occupancy

CSV 다운로드 → JSONL 변환#

# scripts/convert_csv_to_jsonl.py (예시)
import csv
import json

with open('data/raw/collected.csv', 'r') as csvfile:
    reader = csv.DictReader(csvfile)
    for row in reader:
        record = {
            "messages": [
                {"role": "user", "content": row['user_message']},
                {"role": "assistant", "content": row['assistant_response']}
            ],
            "category": row['category'],
            "subcategory": row.get('subcategory', '')
        }
        category_dir = f"data/raw/{get_category_folder(row['category'])}"
        with open(f"{category_dir}/collected.jsonl", 'a') as f:
            f.write(json.dumps(record, ensure_ascii=False) + '\n')

방법 B: 직접 JSONL 작성 (숙련자)#

# 에디터로 직접 작성
vim data/raw/01_nursing/soap_examples.jsonl

한 줄에 하나의 JSON 객체:

{"messages":[{"role":"user","content":"Q1"},{"role":"assistant","content":"A1"}],"category":"nursing"}
{"messages":[{"role":"user","content":"Q2"},{"role":"assistant","content":"A2"}],"category":"nursing"}

방법 C: aatto에서 관리 (추천)#

메디콘솔이 이미 쓰는 aatto에 학습 데이터 수집 프로젝트 만들기:

  1. 각 카테고리별 Document
  2. Document 하단에 Q&A 누적 기록
  3. 주기적으로 scripts/ 로 JSONL 변환

✅ 품질 체크리스트 (필수)#

학습 전에 반드시 확인:

개별 데이터 검증#

# 랜덤 샘플 10개 수동 검수
python3 -c "
import json, random
with open('data/processed/train.jsonl') as f:
    lines = f.readlines()
samples = random.sample(lines, 10)
for s in samples:
    print(json.loads(s)['messages'][-1]['content'][:200])
    print('---')
"

체크 항목: - [ ] PHI 없음 (이름, 주민번호 등) - [ ] 답변이 200-1000자 (너무 짧거나 길지 않음) - [ ] 한국어 자연스러움 - [ ] 사실 관계 정확 - [ ] 메디콘솔 용어 사용

전체 통계#

python3 -c "
import json
from collections import Counter

cats = []
lengths = []
with open('data/processed/train.jsonl') as f:
    for line in f:
        d = json.loads(line)
        cats.append(d.get('category', 'unknown'))
        lengths.append(len(d['messages'][-1]['content']))

print('카테고리 분포:')
for cat, cnt in Counter(cats).most_common():
    pct = cnt / len(cats) * 100
    print(f'  {cat}: {cnt} ({pct:.1f}%)')

print(f'\n답변 길이:')
print(f'  평균: {sum(lengths)/len(lengths):.0f}자')
print(f'  최소: {min(lengths)}자')
print(f'  최대: {max(lengths)}자')
"

목표: - 카테고리 분포: ±5% 내외 (25/25/15/20/15) - 평균 길이: 300-500자 - 최소: 50자 이상 (너무 짧으면 정보량 부족) - 최대: 2000자 이하 (너무 길면 학습 어려움)

PHI 자동 스캔#

# 위험 패턴 검사
python3 -c "
import json, re

patterns = {
    '주민번호': r'\d{6}-\d{7}',
    '전화번호': r'01[0-9]-?\d{3,4}-?\d{4}',
    '실명(흔한)': r'(김|이|박|최|정|강|조|윤|장|임)[가-힣]{2}',
}

with open('data/processed/train.jsonl') as f:
    for i, line in enumerate(f, 1):
        text = line
        for name, pat in patterns.items():
            matches = re.findall(pat, text)
            if matches:
                print(f'Line {i} [{name}]: {matches[:3]}')
"

발견되면: 해당 데이터 수정 후 재실행.


📈 데이터 양 vs 품질 (원칙)#

경험적 가이드#

건수 예상 품질 비고
100건 이하 ⚠️ 부족 과적합 위험 높음
300-500건 🔶 MVP 최소 파이프라인 검증용
1,000-1,500건 MVP 권장 의미 있는 성능
3,000-5,000건 🚀 프로덕션 고품질
10,000+ 💎 엔터프라이즈 Colab 추천

"많이 vs 정확히" 비교#

1,500건 고품질 > 10,000건 저품질

이유: - 저품질 데이터는 잘못된 패턴을 가르침 - 할루시네이션 증가 - Overfitting 가속

증강 허용 기준#

실제 데이터가 부족할 때 전체의 30% 이하로 증강 허용: - Paraphrasing (같은 내용 다른 표현) - 역번역 (한→영→한) - 난이도 변주 (초보자용/전문가용)

절대 금지: - 100% 합성 데이터로 학습 - 검증 없이 AI 생성 데이터 사용


🎯 현실적 수집 계획 (예시)#

Week 1: 최소 MVP (500건)#

월: 기존 자산 정리 (100건)
화: 기존 자산 Q&A 변환 (150건)
수: GODCH/ABC 프레임워크 (100건)
목: 간호 SOAP 예시 (100건)
금: 의료 용어 사전 (50건)

500건으로 첫 학습 시도

Week 2: MVP 완성 (1,500건)#

월-화: 수간호사 인터뷰 기반 추가 (300건)
수-목: 경영 Q&A 확충 (300건)
금: 품질 검수 + PHI 스캔 (400건 보완)

1,500건으로 정식 v1.0.0 학습

Week 3+: 지속 확장#

  • 실제 사용 중 수집되는 bad case
  • 사용자 피드백 반영
  • 월 100-300건씩 추가

🔐 보안 워크플로우#

원본 → 익명화 → 학습#

[맥미니 로컬만]

1. data/source/      ← 원본 (PHI 포함 가능)
   ↓ (익명화 스크립트)
2. data/raw/         ← 익명화 완료
   ↓ (전처리)
3. data/processed/   ← JSONL 통합
4. 학습 입력

익명화 자동화 스크립트#

# scripts/anonymize.py (직접 만들거나 Claude Code에게 요청)

import re

def anonymize(text):
    # 이름 치환
    text = re.sub(r'(김|이|박|최|정)[가-힣]{2}\s+환자', '환자 A', text)
    # 주민번호 제거
    text = re.sub(r'\d{6}-\d{7}', 'XXXXXX-XXXXXXX', text)
    # 병원명
    text = text.replace('효사랑요양병원', '본원')
    text = text.replace('원주불로병원', '본원')
    # 날짜
    text = re.sub(r'2026-04-\d{2}', '최근', text)
    return text

학습 데이터에 PHI 절대 금지 확인 방법#

# 학습 직전 마지막 검증
python3 -c "
import json, re
has_phi = False
patterns = [r'\d{6}-\d{7}', r'\d{3}-\d{4}-\d{4}']
with open('data/processed/train.jsonl') as f:
    for i, line in enumerate(f, 1):
        for pat in patterns:
            if re.search(pat, line):
                print(f'⚠️  Line {i}: PHI 패턴 발견')
                has_phi = True
                break

if not has_phi:
    print('✅ PHI 스캔 통과')
"

🎓 다음 단계#

데이터 수집이 끝나면:

  1. 양이 500건 넘음? → Yes → 08_HYPERPARAMETERS.md
  2. 아직 부족? → 이 문서로 다시 돌아오기

💡 핵심 요약#

1순위: PHI 절대 금지 (맥미니 로컬에서만 작업)
2순위: 5개 카테고리 균형 (25/25/15/20/15)
3순위: 1,500건 목표 (MVP)
원칙: 품질 > 양
전략: 기존 자산 → Q&A 변환 → 빈틈 메우기