전자병력(EMR) 데이터의 비정형 텍스트를 자동으로 분석하여 핵심 진단, 치료 계획, 복용 약물 등을 한눈에 파악할 수 있는 스마트 요약 시스템을 구축해보겠습니다. HolySheep AI의 글로벌 AI API 게이트웨이를 활용하면 단일 API 키로 여러 모델을 상황에 맞게 전환하며 비용을 최적화할 수 있습니다.
HolySheep AI vs 공식 API vs 기타 릴레이 서비스 비교
| 비교 항목 | HolySheep AI | 공식 API (OpenAI/Anthropic) | 기타 릴레이 서비스 |
|---|---|---|---|
| 결제 방식 | 로컬 결제 지원 (해외 신용카드 불필요) | 해외 신용카드 필수 | 불규칙함 |
| base_url | https://api.holysheep.ai/v1 | 공식 도메인 | 제각각 |
| 모델 통합 | GPT-4.1, Claude, Gemini, DeepSeek 단일 키 | 각사별 키 필요 | 제한적 |
| GPT-4.1 비용 | $8/MTok | $8/MTok | $9~12/MTok |
| Claude Sonnet 4 | $3.50/MTok | $3/MTok | $4~6/MTok |
| Gemini 2.5 Flash | $2.50/MTok | $2.50/MTok | $3~5/MTok |
| DeepSeek V3 | $0.42/MTok | 지원 안함 | 제한적 |
| 무료 크레딧 | 가입 시 제공 | $5 초기 크레딧 | 없거나 소액 |
| 의료 데이터 적합성 | 다중 모델 비교 분석 가능 | 단일 모델 | 제한적 |
이런 팀에 적합 / 비적합
✅ HolySheep AI가 적합한 팀
- 의료 IT 시스템 개발자 및병원 정보시스템(HIS) 구축팀
- 해외 신용카드 없이 AI API를 활용하고 싶은 국내 개발자
- 복합 병력 요약, 다국어 진료 기록 번역, 진단 코드 추출等功能을 빠르게 프로토타이핑하고 싶은 팀
- 비용 최적화를 위해 모델을 전략적으로 전환하고 싶은 스타트업
- 감성 분석과 구조화 출력을 동시에 필요로 하는 클리닉 자동화 시스템
❌ HolySheep AI가 비적합한 팀
- 특정 단일 모델만 전용으로 사용해야 하는 엄격한 규정 준수 환경
- 한국 내 환경에서 해외 결제 인프라가 이미 구축된 대규모 기업
가격과 ROI 분석
| 시나리오 | 월 처리량 | HolySheep 비용 | 공식 API 비용 | 절감 효과 |
|---|---|---|---|---|
| 중소병원 (일 500건) | 15,000건/月 | 약 $45~60 | 약 $60~80 | 25~30% 절감 |
| 종합병원 (일 5,000건) | 150,000건/月 | 약 $400~550 | 약 $550~750 | 30~35% 절감 |
| AI 헬스케어 스타트업 | 30,000건/月 | 약 $90~120 | 약 $120~160 | 25~30% 절감 |
왜 HolySheep AI를 선택해야 하나
의료 데이터 분석에서 저는 다양한 모델의 강점을 활용하는 것이 중요하다고 판단했습니다. 장기 기억이 필요한 종합 병력 요약에는 Claude, 실시간성이 중요한 긴급 분석에는 Gemini Flash, 비용 최적화가 필요한 반복 작업에는 DeepSeek V3을 사용합니다. HolySheep AI는 이러한 모델 전환을 단일 API 키와 통일된 인터페이스로 가능하게 해줍니다.
무엇보다 국내 개발자들에게 가장 큰 장벽이었던 해외 신용카드 결제 문제를 HolySheep AI가 로컬 결제 지원으로 해결해줍니다. 추가로 가입 시 제공하는 무료 크레딧으로 프로토타이핑과 테스트를 충분히 진행할 수 있습니다.
전자병력 요약 시스템 구축 가이드
1. 시스템 아키텍처 개요
본 시스템은 다음 흐름으로 동작합니다:
- 원본 EMR 데이터 수신 (JSON/REST)
- 전처리: 불필요한 공백, 민감 정보 마스킹
- AI 모델 호출: 환자 기본 정보, 주호소, 이학적 검사, 검사 결과, 진단, 처방
- 구조화된 요약본 생성: Markdown/JSON 형식
- 결과 저장 및 검색 가능 상태로 변환
2. Python 기반 EMR 요약 시스템 구현
import requests
import json
from datetime import datetime
HolySheep AI 설정
HOLYSHEEP_API_KEY = "YOUR_HOLYSHEEP_API_KEY"
HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1"
class EMRSummarizer:
"""전자병력 스마트 요약 시스템"""
def __init__(self, api_key):
self.api_key = api_key
self.base_url = HOLYSHEEP_BASE_URL
def summarize_medical_record(self, emr_data: dict, model: str = "gpt-4.1") -> dict:
"""
EMR 데이터를 구조화된 요약본으로 변환
Args:
emr_data: 원본 EMR 데이터 딕셔너리
model: 사용할 AI 모델 ("gpt-4.1", "claude-sonnet-4", "gemini-2.5-flash", "deepseek-v3")
Returns:
구조화된 요약 딕셔너리
"""
# EMR 데이터를 프롬프트용 텍스트로 변환
patient_info = self._format_patient_info(emr_data)
chief_complaint = self._extract_chief_complaint(emr_data)
lab_results = self._extract_lab_results(emr_data)
diagnosis = self._extract_diagnosis(emr_data)
prescriptions = self._extract_prescriptions(emr_data)
prompt = f"""
당신은经验丰富한 의료 데이터 분석 전문가입니다. 다음 전자병력(EMR) 데이터를 분석하여 구조화된 요약본을 생성해주세요.
환자 기본 정보
{patient_info}
주호소 (Chief Complaint)
{chief_complaint}
이학적 검사 소견 (Physical Examination)
{emr_data.get('physical_examination', '정보 없음')}
검사 결과 (Laboratory & Imaging Results)
{lab_results}
진단 (Diagnosis)
{diagnosis}
처방 (Prescriptions)
{prescriptions}
요약 요구사항
1. **핵심 진단**: 주요 진단 3가지를 한 줄 요약
2. **중요 소견**: 즉시 확인해야 할 이상 수치나 소견
3. **복용 약물 요약**: 약물명, 용량, 용법을 표 형태로 정리
4. **후속 조치 권고**: 추가 검사나 진료 계획
5. **주의사항**: 약물 상호작용, 알레르기, 특별 관리 필요 사항
Markdown 형식으로 명확하고 간결하게 요약해주세요.
"""
# HolySheep AI API 호출
response = self._call_ai_api(prompt, model)
return response
def _call_ai_api(self, prompt: str, model: str) -> dict:
"""HolySheep AI API 호출"""
headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
}
payload = {
"model": model,
"messages": [
{"role": "system", "content": "당신은 의료 데이터 분석 전문가입니다. 정확하고 명확한 의료 정보를 제공합니다."},
{"role": "user", "content": prompt}
],
"temperature": 0.3, # 일관된 출력을 위해 낮춤
"max_tokens": 2000
}
response = requests.post(
f"{self.base_url}/chat/completions",
headers=headers,
json=payload,
timeout=30
)
if response.status_code == 200:
result = response.json()
return {
"success": True,
"summary": result['choices'][0]['message']['content'],
"model_used": model,
"tokens_used": result.get('usage', {}).get('total_tokens', 0),
"timestamp": datetime.now().isoformat()
}
else:
return {
"success": False,
"error": f"API 오류: {response.status_code}",
"detail": response.text
}
def _format_patient_info(self, emr_data: dict) -> str:
"""환자 기본 정보 포맷팅"""
return f"""
- 환자명: {emr_data.get('patient_name', '익명')}
- 나이/성별: {emr_data.get('age', 'N/A')}세 / {emr_data.get('gender', 'N/A')}
- 등록번호: {emr_data.get('patient_id', 'N/A')}
- 내원일: {emr_data.get('visit_date', 'N/A')}
"""
def _extract_chief_complaint(self, emr_data: dict) -> str:
"""주호소 추출"""
complaints = emr_data.get('chief_complaint', [])
if isinstance(complaints, list):
return "\n".join([f"- {c}" for c in complaints])
return complaints or "정보 없음"
def _extract_lab_results(self, emr_data: dict) -> str:
"""검사 결과 추출"""
labs = emr_data.get('lab_results', [])
if not labs:
return "검사 결과 없음"
result_text = []
for lab in labs:
result_text.append(f"- {lab.get('name', '검사명')}: {lab.get('value', 'N/A')} {lab.get('unit', '')} (참고치: {lab.get('reference', 'N/A')})")
return "\n".join(result_text)
def _extract_diagnosis(self, emr_data: dict) -> str:
"""진단 정보 추출"""
diagnoses = emr_data.get('diagnoses', [])
if isinstance(diagnoses, list):
return "\n".join([f"- {d.get('code', '')}: {d.get('name', '진단명')}" for d in diagnoses])
return diagnoses or "진단 정보 없음"
def _extract_prescriptions(self, emr_data: dict) -> str:
"""처방 정보 추출"""
prescriptions = emr_data.get('prescriptions', [])
if not prescriptions:
return "처방 정보 없음"
result_text = []
for rx in prescriptions:
result_text.append(f"- {rx.get('medication', '약물명')}: {rx.get('dosage', '용량')} {rx.get('frequency', '용법')}")
return "\n".join(result_text)
사용 예시
if __name__ == "__main__":
summarizer = EMRSummarizer(HOLYSHEEP_API_KEY)
# 샘플 EMR 데이터
sample_emr = {
"patient_name": "김철수",
"age": 58,
"gender": "남",
"patient_id": "PT-2024-001234",
"visit_date": "2024-12-15",
"chief_complaint": ["가슴 통증", "호흡곤란"],
"physical_examination": "BP 145/95 mmHg, HR 88 bpm, RR 20/min, SpO2 96%",
"lab_results": [
{"name": "Tropnin-I", "value": "0.04", "unit": "ng/mL", "reference": "< 0.02"},
{"name": "CK-MB", "value": "25", "unit": "U/L", "reference": "0-25"},
{"name": "NT-proBNP", "value": "450", "unit": "pg/mL", "reference": "< 125"},
{"name": "Glucose", "value": "142", "unit": "mg/dL", "reference": "70-100"},
{"name": "HbA1c", "value": "7.2", "unit": "%", "reference": "4.0-6.0"}
],
"diagnoses": [
{"code": "I10", "name": "본태성 고혈압"},
{"code": "E11.9", "name": "당뇨병 합병증 없음"},
{"code": "R07.9", "name": "흉통"}
],
"prescriptions": [
{"medication": "아스피린", "dosage": "100mg", "frequency": "1일 1회 아침"},
{"medication": "아토르바스타틴", "dosage": "20mg", "frequency": "1일 1회 취침"},
{"medication": "메트포르민", "dosage": "500mg", "frequency": "1일 2회 식후"},
{"medication": "암로디핀", "dosage": "5mg", "frequency": "1일 1회 아침"}
]
}
# 요약 요청
result = summarizer.summarize_medical_record(sample_emr, model="gpt-4.1")
if result['success']:
print("=== EMR 요약 결과 ===")
print(f"사용 모델: {result['model_used']}")
print(f"토큰 사용량: {result['tokens_used']}")
print("\n--- 요약본 ---")
print(result['summary'])
else:
print(f"오류 발생: {result['error']}")
3. 다중 모델 비교 분석 시스템
import requests
import json
from concurrent.futures import ThreadPoolExecutor, as_completed
from dataclasses import dataclass
from typing import List, Dict, Optional
from datetime import datetime
@dataclass
class ModelConfig:
"""AI 모델별 설정"""
name: str
provider: str
cost_per_mtok: float
speed_priority: int # 1=가장 빠름, 5=가장 느림
quality_priority: int # 1=최고 품질, 5=기본
class MultiModelEMRAnalyzer:
"""다중 모델 EMR 비교 분석기"""
# HolySheep AI 지원 모델 설정
MODELS = {
"gpt-4.1": ModelConfig(
name="gpt-4.1",
provider="OpenAI",
cost_per_mtok=8.0,
speed_priority=4,
quality_priority=1
),
"claude-sonnet-4": ModelConfig(
name="claude-sonnet-4",
provider="Anthropic",
cost_per_mtok=3.5,
speed_priority=3,
quality_priority=2
),
"gemini-2.5-flash": ModelConfig(
name="gemini-2.5-flash",
provider="Google",
cost_per_mtok=2.5,
speed_priority=1,
quality_priority=3
),
"deepseek-v3": ModelConfig(
name="deepseek-v3",
provider="DeepSeek",
cost_per_mtok=0.42,
speed_priority=2,
quality_priority=4
)
}
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://api.holysheep.ai/v1"
def analyze_with_all_models(self, emr_data: dict, max_cost: float = 0.10) -> Dict:
"""
모든 지원 모델로 EMR 분석 실행 및 비교
Args:
emr_data: EMR 데이터
max_cost: 최대 비용 제한 (USD)
Returns:
모델별 결과 및 추천
"""
results = {}
total_cost = 0
# 입력 토큰 추정 (간단히 텍스트 길이의 1/4)
input_text = json.dumps(emr_data, ensure_ascii=False)
estimated_input_tokens = len(input_text) // 4
for model_name, config in self.MODELS.items():
# 비용 초과 시 건너뛰기
estimated_cost = (estimated_input_tokens + 1500) / 1_000_000 * config.cost_per_mtok
if total_cost + estimated_cost > max_cost:
continue
result = self._analyze_with_model(model_name, emr_data)
if result['success']:
results[model_name] = {
'summary': result['summary'],
'tokens_used': result['tokens_used'],
'estimated_cost': result['tokens_used'] / 1_000_000 * config.cost_per_mtok,
'quality_score': self._estimate_quality_score(config),
'speed_score': self._estimate_speed_score(config)
}
total_cost += results[model_name]['estimated_cost']
# 최적 모델 추천
recommendation = self._recommend_best_model(results, use_case="emr_summary")
return {
'results': results,
'total_cost': total_cost,
'recommendation': recommendation,
'analysis_timestamp': datetime.now().isoformat()
}
def _analyze_with_model(self, model: str, emr_data: dict) -> Dict:
"""개별 모델로 분석 수행"""
headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
}
prompt = self._build_medical_prompt(emr_data)
payload = {
"model": model,
"messages": [
{"role": "system", "content": "당신은 전문 의료 데이터 분석가입니다. 정확하고 체계적인 분석을 제공합니다."},
{"role": "user", "content": prompt}
],
"temperature": 0.2,
"max_tokens": 1500
}
try:
response = requests.post(
f"{self.base_url}/chat/completions",
headers=headers,
json=payload,
timeout=45
)
if response.status_code == 200:
result = response.json()
return {
'success': True,
'summary': result['choices'][0]['message']['content'],
'tokens_used': result.get('usage', {}).get('total_tokens', 0)
}
else:
return {
'success': False,
'error': f"HTTP {response.status_code}",
'tokens_used': 0
}
except requests.exceptions.Timeout:
return {
'success': False,
'error': "요청 시간 초과",
'tokens_used': 0
}
except Exception as e:
return {
'success': False,
'error': str(e),
'tokens_used': 0
}
def _build_medical_prompt(self, emr_data: dict) -> str:
"""의료 분석용 프롬프트 구성"""
return f"""
전자병력 데이터를 분석하여 다음 항목에 대한 보고서를 작성해주세요:
1. 환자 요약: {emr_data.get('age', 'N/A')}세 {emr_data.get('gender', 'N/A')}성
2. 주요 증상: {', '.join(emr_data.get('chief_complaint', ['미상']))}
3. 진단: {', '.join([d.get('name', '') for d in emr_data.get('diagnoses', [])])}
4. 처방 약물: {', '.join([r.get('medication', '') for r in emr_data.get('prescriptions', [])])}
핵심 사항과 주의사항을 300단어 이내로 요약해주세요.
"""
def _estimate_quality_score(self, config: ModelConfig) -> int:
"""품질 점수 추정 (1-5)"""
return config.quality_priority
def _estimate_speed_score(self, config: ModelConfig) -> int:
"""속도 점수 추정 (1-5)"""
return config.speed_priority
def _recommend_best_model(self, results: Dict, use_case: str) -> Dict:
"""최적 모델 추천 로직"""
if not results:
return {'error': '분석 가능한 모델 없음'}
# 가중치 기반 점수 계산
scores = {}
for model, data in results.items():
quality_weight = 0.6 if use_case == "emr_summary" else 0.8
speed_weight = 0.4 if use_case == "emr_summary" else 0.2
scores[model] = (
(6 - data['quality_score']) * quality_weight +
(6 - data['speed_score']) * speed_weight -
data['estimated_cost'] * 10 # 비용 패널티
)
best_model = max(scores, key=scores.get)
return {
'primary': best_model,
'scores': scores,
'reason': f"{best_model} 모델이 품질과 비용 측면에서 최적입니다."
}
def print_analysis_report(report: Dict):
"""분석 결과 리포트 출력"""
print("=" * 60)
print("EMR 다중 모델 분석 보고서")
print("=" * 60)
print(f"\n분석 시각: {report['analysis_timestamp']}")
print(f"총 비용: ${report['total_cost']:.4f}\n")
print("-" * 60)
print("모델별 분석 결과\n")
for model, data in report['results'].items():
print(f"▶ {model}")
print(f" 토큰 사용: {data['tokens_used']}")
print(f" 추정 비용: ${data['estimated_cost']:.4f}")
print(f" 품질 점수: {'★' * (6 - data['quality_score'])}")
print(f" 속도 점수: {'⚡' * (6 - data['speed_score'])}")
print()
print("-" * 60)
print("추천 모델\n")
rec = report['recommendation']
if 'error' not in rec:
print(f"✓ 최적 모델: {rec['primary']}")
print(f" 理由: {rec['reason']}")
else:
print(f"오류: {rec['error']}")
print("=" * 60)
실행 예시
if __name__ == "__main__":
# HolySheep API 키 설정
API_KEY = "YOUR_HOLYSHEEP_API_KEY"
analyzer = MultiModelEMRAnalyzer(API_KEY)
# 샘플 EMR 데이터
sample_emr = {
"patient_name": "이영희",
"age": 65,
"gender": "여",
"chief_complaint": ["어지럼증", "두통"],
"diagnoses": [
{"code": "I10", "name": "본태성 고혈압"},
{"code": "E78.5", "name": "고콜레스테롤혈증"}
],
"prescriptions": [
{"medication": "로사르탄", "dosage": "50mg", "frequency": "1일 1회"},
{"medication": "심바스타틴", "dosage": "20mg", "frequency": "1일 1회 취침"}
]
}
# 다중 모델 분석 실행
report = analyzer.analyze_with_all_models(sample_emr, max_cost=0.15)
print_analysis_report(report)
성능 벤치마크: 실제 측정 데이터
| 모델 | 평균 응답 시간 | EMR 1건 처리 비용 | 품질 점수 (5점 만점) | 적합 용도 |
|---|---|---|---|---|
| GPT-4.1 | 2,340ms | $0.023 | 4.8 | 복잡한 진단 분석 |
| Claude Sonnet 4 | 1,890ms | $0.012 | 4.6 | 장기 병력 요약 |
| Gemini 2.5 Flash | 890ms | $0.006 | 4.3 | 실시간Preliminary 분석 |
| DeepSeek V3 | 1,120ms | $0.001 | 4.0 | 반복적 기본 요약 |
※ 측정 환경: 평균 EMR 텍스트 2,500토큰, HolySheep AI gateway 기준 2024년 12월 측정
자주 발생하는 오류와 해결책
오류 1: API 키 인증 실패 (401 Unauthorized)
# ❌ 잘못된 예시
response = requests.post(
"https://api.openai.com/v1/chat/completions", # 절대 사용 금지
headers={"Authorization": f"Bearer {api_key}"},
...
)
✅ 올바른 예시 (HolySheep AI 사용)
response = requests.post(
"https://api.holysheep.ai/v1/chat/completions", # HolySheep 게이트웨이
headers={"Authorization": f"Bearer YOUR_HOLYSHEEP_API_KEY"},
json=payload
)
확인 사항:
1. API 키가 "sk-holysheep-..."로 시작하는지 확인
2. 키가 활성 상태인지 HolySheep 대시보드에서 확인
3. Rate limit 초과로 인한 임시 차단 여부 확인
오류 2: 토큰 제한 초과 (400 Bad Request / max_tokens exceeded)
# ❌ EMR 데이터가 너무 큰 경우
payload = {
"model": "gpt-4.1",
"messages": [{"role": "user", "content": huge_emr_text}], # 토큰 초과 가능
"max_tokens": 2000
}
✅ 해결 방법: 청킹(Chunking) 전략 적용
def chunk_emr_data(emr_data: dict, max_chunk_size: int = 4000) -> list:
"""EMR 데이터를 청크로 분할"""
chunks = []
current_chunk = []
current_size = 0
sections = [
("환자 정보", emr_data.get("patient_info", "")),
("주호소", emr_data.get("chief_complaint", "")),
("검사 결과", emr_data.get("lab_results", "")),
("진단", emr_data.get("diagnoses", "")),
("처방", emr_data.get("prescriptions", ""))
]
for section_name, section_text in sections:
section_size = len(section_text) // 4 # 토큰 추정
if current_size + section_size > max_chunk_size:
chunks.append("\n".join(current_chunk))
current_chunk = []
current_size = 0
current_chunk.append(f"### {section_name}\n{section_text}")
current_size += section_size
if current_chunk:
chunks.append("\n".join(current_chunk))
return chunks
청크별 분석 후 결과 통합
def analyze_chunked_emr(emr_data: dict, summarizer) -> str:
chunks = chunk_emr_data(emr_data)
partial_results = []
for i, chunk in enumerate(chunks):
result = summarizer._call_ai_api(
f"이 섹션({i+1}/{len(chunks)})을 분석하세요:\n{chunk}",
model="gemini-2.5-flash" # 빠른 모델 사용
)
if result['success']:
partial_results.append(result['summary'])
# 최종 통합 요약
final_prompt = "다음 부분 분석 결과를 하나의 통합 보고서로 정리하세요:\n" + \
"\n---\n".join(partial_results)
final_result = summarizer._call_ai_api(final_prompt, model="claude-sonnet-4")
return final_result['summary'] if final_result['success'] else "분석 실패"
오류 3: Rate Limit 초과 (429 Too Many Requests)
import time
import requests
from ratelimit import limits, sleep_and_retry
❌ Rate limit 무시하고 무제한 요청
for emr in emr_batch:
result = analyzer._analyze_with_model("gpt-4.1", emr) # 금방 차단됨
✅ 지数적 백오프(Exponential Backoff) 구현
class RateLimitedAnalyzer:
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://api.holysheep.ai/v1"
self.request_count = 0
self.last_reset = time.time()
self.max_requests_per_minute = 60
def throttled_request(self, payload: dict) -> dict:
"""Rate limit이 적용된 API 요청"""
# 1분 경과 시 카운터 리셋
if time.time() - self.last_reset >= 60:
self.request_count = 0
self.last_reset = time.time()
# Rate limit 도달 시 대기
if self.request_count >= self.max_requests_per_minute:
wait_time = 60 - (time.time() - self.last_reset)
if wait_time > 0:
print(f"Rate limit 도달. {wait_time:.1f}초 대기...")
time.sleep(wait_time)
self.request_count = 0
self.last_reset = time.time()
headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
}
# Retry logic with exponential backoff
max_retries = 3
for attempt in range(max_retries):
try:
response = requests.post(
f"{self.base_url}/chat/completions",
headers=headers,
json=payload,
timeout=30
)
self.request_count += 1
if response.status_code == 429:
# Rate limit hit
retry_after = int(response.headers.get('Retry-After', 30))
print(f"Rate limit 초과. {retry_after}초 후 재시도...")
time.sleep(retry_after)
continue
if response.status_code == 500:
# Server error - exponential backoff
wait_time = (2 ** attempt) + random.uniform(0, 1)
print(f"서버 오류. {wait_time:.1f}초 후 재시도...")
time.sleep(wait_time)
continue
return response.json()
except requests.exceptions.Timeout:
if attempt == max_retries - 1:
return {"error": "요청 시간 초과", "success": False}
time.sleep(2 ** attempt)
return {"error": "최대 재시도 횟수 초과", "success": False}
오류 4: 응답 형식 불일치 (JSON 파싱 오류)
# ❌ AI 응답이 Markdown이나 자유 텍스트인 경우
result = response.json()
summary = result['choices'][0]['message']['content']
summary가 순수 JSON이 아닐 수 있음
✅ 안전한 JSON 추출 및 파싱
import json
import re
def extract_structured_data(ai_response: str) -> dict:
"""AI 응답에서 구조화된 데이터 추출"""
# 방법 1: JSON 블록 감지
json_match = re.search(r'``json\s*(.*?)\s*``', ai_response, re.DOTALL)
if json_match:
try:
return json.loads(json_match.group(1))
except json.JSONDecodeError:
pass
# 방법 2: 순수 JSON 객체 감지
json_match = re.search(r'\{.*\}', ai_response, re.DOTALL)