의학 백과사전 2.0: 추측을 멈추고 멀티모달 RAG로 스캔 시작
Source: Dev.to
위에 제공된 소스 링크 외에 번역할 텍스트가 보이지 않습니다. 번역을 원하는 본문을 알려주시면 한국어로 번역해 드리겠습니다.
아키텍처 개요
The logic flow:
- 사용자가 약 라벨 사진을 업로드합니다.
- PaddleOCR이 텍스트를 추출합니다.
- Entity extraction이 약물 이름을 복용량 정보와 구분합니다.
- RxNav API가 약물 간 상호작용을 확인합니다.
- ChromaDB가 지역 가이드라인 및 개인 건강 컨텍스트를 검색합니다.
- LLM reasoning engine이 인간이 읽을 수 있는 안전 보고서를 종합합니다.
- RAGas가 답변의 충실도와 관련성을 평가합니다.
graph TD
A[User Uploads Photo] --> B[PaddleOCR: Text Extraction]
B --> C{Entity Extraction}
C -->|Drug Names| D[RxNav API: Interaction Check]
C -->|Dosage Info| E[ChromaDB: Manuals/Guidelines]
D --> F[LLM Reasoning Engine]
E --> F
F --> G[Final Response: Safety Advice]
G --> H[Evaluation: RAGas]
사전 요구 사항
| 구성 요소 | 필요 이유 |
|---|---|
| PaddleOCR | 의약품 포장에 기울어진 텍스트와 다양한 글꼴을 처리하는 초고속, 정확한 OCR. |
| ChromaDB | 로컬 약물 매뉴얼, 병원 지침 또는 개인 건강 기록을 위한 경량 벡터 스토어. |
| RxNav API | 약물 상호작용 데이터에 대한 표준 소스 (국립 의학 도서관). |
| RAGas | RAG 파이프라인이 환각을 일으키는지 평가하는 툴킷. |
Python 3.9+와 다음 패키지가 설치되어 있는지 확인하세요:
pip install paddleocr chromadb ragas datasets requests
Step 1 – PaddleOCR을 사용한 성분 추출
from paddleocr import PaddleOCR
# Initialise the OCR engine (angle classification enabled for rotated text)
ocr = PaddleOCR(use_angle_cls=True, lang='en')
def get_drug_names(img_path: str) -> str:
"""
Perform OCR on the image and return a single string with all detected text.
"""
result = ocr.ocr(img_path, cls=True)
# Flatten the nested list and keep only the recognized text fragments
raw_text = [line[1][0] for page in result for line in page]
print(f"Detected Text: {raw_text}")
return " ".join(raw_text)
# Example usage
# extracted_text = get_drug_names("advil_box.jpg")
출력 예시:
Detected Text: ['Advil', 'Ibuprofen', '200', 'mg', 'Take', '1', 'tablet', 'every', '4-6', 'hours']
Step 2 – RxNav API를 사용한 상호작용 조회
먼저 추출된 약물 이름을 RxNorm Concept Unique Identifiers (RXCUIs) 로 매핑합니다(이를 위해 RxNav “approximateTerm” 엔드포인트를 사용할 수 있습니다). 그런 다음 상호작용 데이터를 요청합니다:
import requests
from typing import List
def check_interactions(rxcuis: List[str]) -> List[str]:
"""
Query RxNav for interactions among the supplied RxCUIs.
Returns a list of interaction descriptions.
"""
ids = "+".join(rxcuis)
url = f"https://rxnav.nlm.nih.gov/REST/interaction/list.json?rxcuis={ids}"
response = requests.get(url).json()
interactions = []
if "fullInteractionTypeGroup" in response:
for group in response["fullInteractionTypeGroup"]:
for item in group["fullInteractionType"]:
# Each interactionPair may contain multiple descriptions; we take the first.
interactions.append(item["interactionPair"][0]["description"])
return interactions
# Example:
# rxcuis = ["5640"] # RxCUI for Ibuprofen
# interactions = check_interactions(rxcuis)
Step 3 – Augmenting with Local Context (ChromaDB)
공개 API는 기관별 지침이나 개인 건강 이력과 같은 세부 사항을 놓칠 수 있습니다. 이러한 뉘앙스를 벡터 스토어에 저장하고 쿼리 시 가장 관련성이 높은 스니펫을 검색하세요.
import chromadb
from chromadb.utils import embedding_functions
from typing import List
# Initialise Chroma client (in‑memory for the demo)
client = chromadb.Client()
collection = client.create_collection(name="medical_guidelines")
# Add a few example documents
collection.add(
documents=[
"Patient A has a history of stomach ulcers. Avoid NSAIDs like Ibuprofen.",
"Guideline: Do not combine antihistamines with MAO inhibitors."
],
metadatas=[
{"source": "electronic_health_record"},
{"source": "hospital_policy"}
],
ids=["rec1", "rec2"]
)
def get_local_context(query: str, n_results: int = 1) -> List[str]:
"""
Retrieve the most relevant local documents for the given query.
"""
results = collection.query(query_texts=[query], n_results=n_results)
return results['documents'][0] # Returns a list of strings
# Example:
# context = get_local_context("Ibuprofen ulcer")
AI 에이전트를 구축하는 “공식적인” 방법
이 튜토리얼은 Learning‑in‑Public 프로젝트를 시작하기에 좋은 출발점이지만, 실제 수준의 AI 헬스케어 도구를 만들려면 다음이 필요합니다:
- 정교한 프롬프트 엔지니어링 및 체인‑오브‑쓰레드(Chain‑of‑Thought) 추론.
- 엄격한 데이터 프라이버시 보호( HIPAA, GDPR).
- 모니터링, 로깅 및 모델‑버전 관리.
Agentic RAG, Production‑ready Multimodal Pipelines, 그리고 컴플라이언스 모범 사례에 대한 심층적인 내용은 **WellAlly Tech Blog**의 기사들을 참고하세요.
Step 4 – LLM을 사용한 안전 보고서 생성
OCR 출력, 상호작용 데이터 및 로컬 컨텍스트를 결합하여 간결하고 사용자 친화적인 메시지를 만듭니다.
def generate_safety_report(ocr_text: str,
interactions: List[str],
context: List[str]) -> str:
"""
Build a prompt for the LLM and return the generated safety report.
"""
prompt = f"""
User scanned a medicine label: "{ocr_text}"
Known clinical interactions: {interactions}
Personal health context: {context}
Provide a short, plain‑language report that tells the user whether the medication is safe
to take, or if a warning is needed. Use the format:
"SAFE: ..." or "WARNING: ..."
"""
# Replace the following line with your LLM call (e.g., OpenAI, Anthropic, etc.)
# response = llm.complete(prompt)
# For demo purposes we return a hard‑coded warning:
return "WARNING: You are taking Advil (Ibuprofen) while having a history of stomach ulcers. Consult a doctor before use."
# Example:
# report = generate_safety_report(extracted_text, interactions, context)
# print(report)
Source: …
Step 5 – Evaluating with RAGas
RAGas는 faithfulness(답변이 원본을 정확히 따르고 있는가?)와 answer relevance(답변이 사용자의 질문에 부합하는가?)를 측정하는 데 도움을 줍니다.
from ragas import evaluate
from datasets import Dataset
# Assume `generated_report` is the string returned by `generate_safety_report`
generated_report = generate_safety_report(extracted_text, interactions, context)
# Build a tiny evaluation dataset
data_samples = {
"question": ["Can I take Advil with my current meds?"],
"answer": [generated_report],
"contexts": [[f"{interactions} {context}"]],
"ground_truth": ["WARNING: Ibuprofen conflicts with ulcer history. Consult a physician."]
}
eval_dataset = Dataset.from_dict(data_samples)
# Run RAGas evaluation (you may need to configure the LLM and embedding models)
metrics = evaluate(eval_dataset, metrics=["faithfulness", "answer_relevance"])
print(metrics)
결과 점수는 파이프라인이 환각을 일으키고 있는지, 아니면 검색된 증거에 기반하고 있는지를 알려줍니다.
🎉 당신은 다음과 같은 멀티모달 RAG 시스템을 구축했습니다:
- 사진에서 약물 라벨을 읽음.
- OCR을 통해 약물 이름을 추출.
- RxNav를 사용해 상호작용을 조회.
- ChromaDB에 저장된 개인 맞춤형 로컬 컨텍스트로 답변을 보강.
- LLM으로 간결한 안전 보고서를 생성.
- RAGas를 이용해 출력물을 검증.
다음과 같이 시스템을 확장해 보세요:
- 배치 처리 – 한 번에 여러 알약을 처리.
- 음성 비서 통합 (예: Alexa, Google Assistant).
- 개인 건강 기록의 안전한 저장 (암호화, 디바이스 내 저장).
행복한 해킹 되시고, 안전을 지키세요! 🚀
taset = Dataset.from_dict(data_samples)
# score = evaluate(dataset, metrics=[faithfulness, answer_relevance])
# print(score)
결론: 헬스‑테크의 미래
PaddleOCR을 비전으로, RxNav를 의료 진실로, ChromaDB를 개인화된 컨텍스트로 결합하여, 우리는 실제로 생명을 구하는 강력한 도구를 만들었습니다. 멀티모달 RAG는 빠르게 발전하고 있으며, 이것은 빙산의 일각에 불과합니다!
다음은?
- CNN을 사용하여 pill identification 기능을 추가해 보세요.
- 사용자가 손을 사용하지 않고 질문할 수 있도록 voice‑to‑text를 통합하세요.
이 빌드가 마음에 들었다면 아래에 댓글을 남기거나 🦄 heart 이 게시물을 눌러 주세요! 그리고 더 높은 수준의 AI 튜토리얼을 보려면 WellAlly Tech 를 방문하는 것을 잊지 마세요.
코딩 즐겁게!