尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
대회 규칙·환자 상호작용·공개 샘플과 공식 평가의 차이·SOAP 고정 필드·제출 전 체크리스트는 docs/NOVA_RULES_SOAP.md에 상세히 정리되어 있습니다. N.O.V.A. 2026 공개 샘플 C01·C03·C10을 fixtures/nova-samples-2026/에 추가했고, CPX 저장 형식으로 변환한 케이스 맵은 fixtures/nova-samples-cases.json입니다. 공개 샘플 원문·모범 기록은 연습과 검증용이며 공식 평가 증례나 만점 답안이 아닙니다. 스타터 ZIP의 대회 제출 계약을 먼저 검사합니다. 로컬 개발 키트로 세 공개 샘플을 차례로 실행하려면, OpenAI 호환 Doctor/시뮬레이터 모델을 준비한 뒤 실행합니다. 개발 키트는 채점하지 않고 transcript.json과 record.json을 만듭니다. 파일을 화면에서 제출하려면 별도 로컬 실행기를 켜고 http://127.0.0.1:8765/nova-evaluate.html을 여세요.檢視完整 README ↗
대회 규칙·환자 상호작용·공개 샘플과 공식 평가의 차이·SOAP 고정 필드·제출 전 체크리스트는 docs/NOVA_RULES_SOAP.md에 상세히 정리되어 있습니다.
N.O.V.A. 2026 공개 샘플 C01·C03·C10을 fixtures/nova-samples-2026/에 추가했고, CPX 저장 형식으로 변환한 케이스 맵은 fixtures/nova-samples-cases.json입니다. 공개 샘플 원문·모범 기록은 연습과 검증용이며 공식 평가 증례나 만점 답안이 아닙니다.
스타터 ZIP의 대회 제출 계약을 먼저 검사합니다.
python scripts/validate_submission.py /Users/haechan/Downloads/nova-starter.zip
로컬 개발 키트로 세 공개 샘플을 차례로 실행하려면, OpenAI 호환 Doctor/시뮬레이터 모델을 준비한 뒤 실행합니다. 개발 키트는 채점하지 않고 transcript.json과 record.json을 만듭니다.
python scripts/evaluate_submission.py \
--submission /Users/haechan/Downloads/nova-starter.zip \
--devkit /Users/haechan/Downloads/nova-devkit \
--out submission-runs/starter
파일을 화면에서 제출하려면 별도 로컬 실행기를 켜고 http://127.0.0.1:8765/nova-evaluate.html을 여세요.
python scripts/submission_server.py --devkit /Users/haechan/Downloads/nova-devkit
화면의 3건 실행은 C01·C03·C10을 대회와 같은 prepare()/consult() 계약으로 실행합니다. 공개 개발 키가 있고 서버 참고 점수까지 확인하려면 스타터의 sample.py로 NOVA_API_BASE와 NOVA_DEV_KEY를 설정해 NOVA 서버 샘플 검증을 별도로 실행하세요. 로컬 개발 키트는 의도적으로 채점하지 않습니다.
DB에 세 환자를 배포한 CPX 화면에 넣으려면 관리자 API에서 사용할 비밀번호로 다음을 실행합니다.
SP_WEB_PASSWORD='비밀번호' python scripts/import_nova_to_api.py \
https://<project>.supabase.co/functions/v1
로컬 API는 NOVA 공개 규정에 맞춰 증례당 30분, 최대 50턴, SAY·EXAM 30 NFC 코드 포인트, 예선 TEST 금지, 빈 내용·30자 초과·잘못된 EXAM의 1턴 사용, 제공하지 않는 TEST의 무턴 반려를 적용합니다. 점수 영역은 정보수집 25·진단추론 15·검사·추적 10·안전 15·의사소통 15·효율 20입니다.
N.O.V.A. 2026 진단 에이전트 대회 예선 규정(SAY·EXAM·TEST, 30자·한 번에 하나, 50턴)으로 표준화 환자를 진료하고, S·O·A·P 초진 기록을 제출하면 CPX 방식으로 채점하는 연습 도구입니다. 사람은 웹에서, AI 의사(Claude·GPT 등)는 아래 API로 진료합니다.
| 절 | 누가 |
|---|---|
| 1. 웹에서 진료하기 | 사람 |
| 2. API: 대화하고 SOAP 제출하기 | AI 의사·직접 만든 코드 |
| 3. 가설 세우고 시험하기 | Claude·GPT 로 실험하는 사람 |
| 4. 구성·배포 | 관리자 |
여럿이 함께 쓸 때
환자에 대해 알아 둘 것 (NOVA 개발 키트 nova_local.py와 같은 규칙)
AI 의사나 직접 만든 코드가 진료할 때 씁니다. 웹과 같은 서버·규칙·채점이고, 기록은 웹 사이드바에 남아 결과 탭에서 똑같이 볼 수 있습니다. 이 절을 그대로 Claude Code·Claude(Haiku 등)·GPT 같은 도구 사용 에이전트에게 주면 직접 진료할 수 있습니다.
주소 https://yobrfksujprspfziukoa.supabase.co/functions/v1 — 모두 JSON. 로그인 말고는 Authorization: Bearer <토큰> 헤더가 필요합니다.
로그인 → 환자 목록 → 진료 시작 → [대화·진찰·검사] × 최대 50턴 → SOAP 제출 → 점수·피드백
POST /api/login GET /api/cases POST /api/start POST /api/act POST /api/submit
① 로그인 POST /api/login
요청 {"password": "팀 비밀번호"}
응답 {"ok": true, "token": "1791…a3f", "days": 1}
② 환자 목록 GET /api/cases
응답 {"cases": [{"no": 1, "cid": "A", "age": 20, "sex": "여", "cc": "심한 복통"}, …], "max_turns": 50, "maxlen": 30}
③ 진료 시작 POST /api/start — 이후 모든 요청은 응답의 name 으로 이 진료를 가리킵니다.
label·title·memo 는 넣지 않아도 됩니다 (실험할 때 쓰는 법은 3절).
요청 {"cid": "A", "mode": "예선", // 본선이면 검사(TEST) 가능
"label": "H1 감별 먼저 묻기", "title": "haiku-4.5 · 1회", "memo": "가설: …"}
응답 {"name": "20261007_152919_A",
"patient": {"name": "김서연", "age": 20, "sex": "여", "cc": "심한 복통",
"opening": "저는 김서연이고 스무 살이에요. 배가 너무 아파서 왔어요.",
"vitals": "혈압: 고혈압(수치 미기재); 맥박: 빈맥(수치 미기재); …"},
"meta": {"label": "H1 감별 먼저 묻기", "title": "haiku-4.5 · 1회", "memo": "가설: …"},
"turn": 0, "max_turns": 50, …}
④ 한 턴 POST /api/act — 한 번에 하나씩.
요청 {"name": "20261007_152919_A", "act": "SAY", "text": "언제부터 아프셨어요?"}
요청 {"name": "20261007_152919_A", "act": "EXAM", "text": "배를 눌러 볼게요"}
요청 {"name": "20261007_152919_A", "act": "TEST", "text": "CBC 볼게요"} // 본선만
응답 {"ok": true, "out": "엿새 전부터 아팠어요.", "turn": 3, "rejected": 0}
응답 {"ok": true, "out": "복부 전체 압통(+), 반발통(-)", "turn": 4, …} // EXAM 은 진찰표 결과만 (대회와 같음)
응답 {"ok": false, "code": "EXAM_NOT_SPECIFIC", "out": "반려: 진찰 동작 하나를 구체적으로 요청해 주세요 (…) (1턴 사용)", "turn": 5, "rejected": 1}
| act | 뜻 | 규칙 |
|---|---|---|
SAY | 질문·설명·공감 | 30자 이하, 한 번에 하나만 묻기. 인사·공감 뒤에 질문 하나는 괜찮음 |
EXAM | 진찰 동작 하나 | 진찰 목록은 대회 규칙상 일부러 주지 않음. 전신·부위 전체·여러 동작 묶음은 EXAM_NOT_SPECIFIC, 진찰이 아닌 요청은 EXAM_NOT_RECOGNIZED (둘 다 1턴). 진찰표에 없는 실제 진찰은 나이·성별에 맞는 구체적 소견을 한 번 만들고 같은 진찰엔 같은 답 |
TEST | 검사 하나 | 본선만 |
ok: false 는 반려(규칙 위반)나 불가이며 code 에 대회와 같은 오류 코드가 옵니다. 빈 내용 EMPTY_CONTENT·30자 초과 CONTENT_TOO_LONG·EXAM_NOT_SPECIFIC·EXAM_NOT_RECOGNIZED 는 1턴을 쓰고, 예선의 TEST ACTION_NOT_AVAILABLE·턴 소진은 턴을 쓰지 않습니다. 환자·진찰 판정 모델이 답을 못 하면 503(턴 안 씀)이니 다시 보내면 됩니다.
⑤ SOAP 제출 POST /api/submit — 진료가 끝나고 채점합니다. 1~2분 걸리니 요청 시간 제한을 넉넉히 (예: curl --max-time 180).
요청 {"name": "20261007_152919_A",
"note": {"S": {"cc": "20세 여성, 6일 전부터 배 전체 통증", "hpi": "구토 반복", "pmh": "", "fh": "", "sh": "", "ros": "발열 부인"},
"O": {"exam": "고혈압·빈맥, 복부 전체 압통", "tests": ""},
"A": {"evidence": "복통과 구토, 활력징후 이상", "differential": "r/o 급성 위장염 : 구토 동반"},
"P": {"tests": "소변 PBG·전해질", "treatment": "수액·진통", "disposition": "관찰", "follow_up": "신경 증상 확인", "education": ""}},
"diagnosis": "급성 간헐성 포르피린증"}
응답 {"name": "…", "done": true,
"submit": {"total": 73, "scores": {"정보수집": 22, "진단추론": 12, "검사·추적": 8, "안전": 11, "의사소통": 6, "효율": 14},
"truth": "급성 간헐성 포르피린증 (E80.2)", "turns": 35, "rejected": 3,
"judge": {"accuracy": 100, "soap_sentences": […], "turn_notes": […], "checklist": […], "red_flags": […], "soap_top": […]},
"patient": {"good": […], "regret": […], "ppi": {…}}}}
note는 SDK empty_record()와 동일한 고정 중첩 구조여야 합니다. A에는 diagnosis가 없고, 주진단은 diagnosis로 별도 보냅니다. SOAP에는 대화·진찰로 실제로 얻은 것만 씁니다. 묻지 않은 것을 쓰면 '지어낸 기록'으로 깎입니다.
환자의 짐작·들은 말은 "환자는 ~라고 함"처럼 환자 말로 적습니다. dx 는 병명 하나 (코드는 붙이지 않아도 됨).
결과 화면은 https://bbi-bbo.github.io/cpx-sim/#c/<name>/result.
그 밖
| 요청 | 쓰임 |
|---|---|
GET /api/conv?name= | 진료 전체 (대화, 쓰다 만 SOAP, 제출 결과, meta) |
GET /api/history | 진료 목록 (label·title·점수 포함) |
POST /api/draft {"name", "soap", "dx"} | 제출 전 SOAP 저장 |
POST /api/record/update {"name", "label", "title", "memo"} | 실험 라벨·제목·메모. 보낸 칸만 고침 |
POST /api/record/rescore {"name", "soap", "dx"} | 대화는 그대로 두고 SOAP 만 고쳐 다시 채점 |
curl 로 해 보기
API=https://yobrfksujprspfziukoa.supabase.co/functions/v1
TOK=$(curl -s -X POST $API/api/login -H 'Content-Type: application/json' -d "{\"password\":\"$CPX_PASSWORD\"}" | python3 -c 'import sys,json;print(json.load(sys.stdin)["token"])')
H=(-H "Authorization: Bearer $TOK" -H 'Content-Type: application/json')
curl -s -X POST $API/api/start "${H[@]}" -d '{"cid":"A","mode":"예선","label":"H0 기본","title":"curl 시험"}'
curl -s -X POST $API/api/act "${H[@]}" -d '{"name":"<start 가 준 name>","act":"SAY","text":"어디가 불편하세요?"}'
curl -s --max-time 180 -X POST $API/api/submit "${H[@]}" -d '{"name":"<name>","soap":{"S":"…","O":"…","A":"…","P":"…"},"dx":"주진단"}'
scripts/agent_doctor.py 는 위 API로 AI 의사(Claude·GPT)를 붙이는 예제입니다. 파이썬 표준 라이브러리만 씁니다.
매 차례 규칙과 지금까지의 진료 기록을 주고 SAY / EXAM / TEST / SUBMIT 중 하나를 JSON 으로 받아 API에 보냅니다.
CPX_PASSWORD='팀 비밀번호' ANTHROPIC_API_KEY=sk-ant-... python3 scripts/agent_doctor.py --patient 1
CPX_PASSWORD='팀 비밀번호' OPENAI_API_KEY=sk-... python3 scripts/agent_doctor.py --patient all --model gpt-6-luna --quiet
| 옵션 | 뜻 |
|---|---|
--patient 1 · 1,3 · all | 환자 번호 |
--mode 본선 | 검사(TEST)까지 허용 |
--repeat N | 같은 환자를 N번 (제목에 회차가 붙음) |
--model | 기본 claude-haiku-4-5-20251001. claude… 면 Anthropic, 그 밖은 OpenAI 호환 (--base-url·--key-env) |
--label --title --memo | 실험 표시 (3절) |
--hint "지시" | 가설로 바꿔 보는 지시를 의사 지시문 끝에 덧붙임. 메모에 자동으로 남음 |
--quiet | 대화는 찍지 않고 점수표만 |
Claude·GPT 의사로 "이렇게 바꾸면 점수가 오를까?"를 시험할 때, 진료마다 세 가지를 붙여 두면 웹에서 모아 보고 비교할 수 있습니다. 실험 관리 도구(MLflow·W&B)의 group·run name·notes 와 같은 짜임입니다.
| 칸 | 뜻 | 정하는 법 | 예 |
|---|---|---|---|
라벨 label | 실험 묶음. 같은 가설·같은 조건으로 돌린 진료는 같은 라벨 | H번호 + 가설 요약, 대조군은 H0 기본 | H0 기본, H1 감별 먼저 묻기 |
제목 title | 이 진료 한 줄 | 모델 · 조건 · 회차 | haiku-4.5 · 예선 · 2회 |
메모 memo | 가설과 결과 | 아래 틀 |
메모 틀
가설: 주호소를 들은 뒤 감별 세 가지를 가르는 질문부터 하면 정보수집·진단추론 점수가 오른다
바꾼 것: 의사 지시문에 "주호소를 들은 뒤 감별 3개를 정하고 그걸 가르는 질문부터" 추가 (--hint)
기대: H0 대비 정보수집 +3, 진단추론 +2
결과·관찰: (돌린 뒤 웹에서 적기)
순서
H0 기본 라벨로 돌립니다. 환자 응답과 채점에 무작위성이 있어 한 번으로는 차이를 말하기 어려우니 같은 환자를 --repeat 3 이상.H1 … 라벨로 같은 환자·같은 모델·같은 횟수. 한 번에 한 가지만 바꿔야 무엇이 효과인지 압니다.# 대조군과 가설 하나 (환자 1, 각 3회)
python3 scripts/agent_doctor.py --patient 1 --repeat 3 --quiet --label "H0 기본" --memo "가설 없음 (대조군)"
python3 scripts/agent_doctor.py --patient 1 --repeat 3 --quiet --label "H1 감별 먼저 묻기" \
--memo $'가설: 감별을 가르는 질문부터 하면 정보수집·진단추론이 오른다\n기대: H0 대비 +5' \
--hint "주호소를 들은 뒤 감별진단 3개를 정하고, 그것들을 가르는 질문부터 하세요."
API로 직접 붙일 때는 /api/start 에 label·title·memo 를 같이 보내거나, 진료 뒤 /api/record/update 로 붙입니다 (2절).
web/index.html → GitHub Pagessupabase/functions/api (Deno) → Supabase Edge Functionsupabase/schema.sql). 증례 정답·모범 답안은 DB 에만 있고 이 저장소에는 없습니다.main 에 올리면 .github/workflows/deploy.yml 이 DB 표·함수·비밀값을 Supabase 에 배포하고 화면을 Pages 로 올립니다.
저장소 Settings → Secrets and variables → Actions 에 다음이 있어야 합니다.
| 이름 | 내용 |
|---|---|
SUPABASE_ACCESS_TOKEN | Supabase 계정 Access Token |
SUPABASE_PROJECT_REF | 프로젝트 주소 https://<ref>.supabase.co 의 <ref> |
SP_OPENAI_API_KEY | 서버가 쓰는 OpenAI API 키 |
SP_WEB_PASSWORD | 팀 공용 접속 비밀번호 |
프롬프트·규칙(supabase/functions/api/prompts.ts)과 화면(web/index.html, 공통 스타일 web/ui.css)은 이 저장소가 원본입니다. 예전 연구 폴더의 tools/export_cpx_sim.py 는 더 이상 쓰지 않습니다.
가상 환자·진찰 판정 문구(PATIENT_RULES·EXAMINER_RULES·EXAM_RESULT_RULES)는 NOVA 개발 키트 nova_local.py 와 같게 유지합니다.
증례는 공개 샘플 case.json 과 같은 대회 형식으로 저장합니다.
{"start_information": {"opening": "첫마디", "vital_signs": "활력징후"},
"patient_script": "환자가 아는 전부 (글 한 덩어리)",
"exam_results": [{"exam": "복부 촉진 (Abdominal palpation)", "result": "우하복부 압통(+)"}],
"model_record": {"S": {…}, "O": {…}, "A": {…}, "P": {…}, "diagnosis": "…"}, // 선택
"truth": "정답", "patient": {"name", "age", "sex", "chief_complaint"}, "reference": …, "checklist": …}
선택 칸 patient_profile(AgentClinic Patient_Actor 구조: demographics·primary_symptom·secondary_symptoms·past_medical_history·social_history·review_of_systems)이 있으면
가상 환자에게 줄 때만 대본 뒤에 "추가 정보"로 붙입니다 (환자 규칙 문구는 개발 키트 그대로).
AgentClinic-MedQA 를 영어 참고용 연습 증례로 바꾸려면 (서버에는 넣지 않음, reference_only: true 표시):
python3 scripts/import_agentclinic.py --input <AgentClinic-MedQA>/agentclinic_medqa_extended.jsonl --output /tmp/agentclinic-cases --limit 10
채점: 주진단은 5점 척도(5 정확·4 매우 근접·3 밀접 관련·2 관련·1 무관, Nori et al. 2025)로 매겨 진단추론의 주진단 6점으로 환산하고,
기록은 ACI-Bench 방식으로 사실마다 근거·지어냄·누락을 나눠 정보수집(기록)·안전(지어낸 기록 감점)에 씁니다. 자세한 기준은 docs/NOVA_RULES_SOAP.md 14.1.
예전 형식(A~G: script·qa·beliefs·exam·vitals)은 엔진이 그 글을 이어 붙여 읽습니다. 저장된 증례를 바꾸려면
scripts/convert_cases.py (파일 또는 --api 로 DB, 기본은 미리 보기·--apply 로 저장). 증례 관리 → 대회 형식 탭에서도 고칠 수 있습니다.
nova-evaluate.html 에서 ZIP 을 실행하면 각 진료 기록에 라벨 = ZIP 이름(확장자 뺀 것), 제목 = ZIP 이름 · 증례 주호소,
메모 = ZIP 이름·크기·sha256 앞 12자리·실행 ID·시각·방식이 붙어 사이드바에서 ZIP 별로 묶입니다.