TrialProof를 만들며 정확도 추적을 멈추고, 잃지 않은 적격 환자를 세기 시작했다. 고정 13사례 골드셋에서 0명 대 3명.
Clinical TrialsMachine LearningHealthcare

유명한 AI 실수를 재현하려 데모를 만들었더니, 베이스라인이 그 실수를 거부했다

Ashutosh SinghalAshutosh Singhal2026년 6월 29일12 min

내가 재현할 수 없었던 실수

나는 이 빌드를 특정하고 잘 문서화된 실패를 재현하려는 마음으로 시작했다. 환자 매칭 AI는 임상 소견서를 텍스트로 읽기 때문에, 겉보기에 비슷하지만 의학에서는 다른 의미인 단어들을 혼동한다. 전형적 사례는 깔끔하다. 3상 항응고제 임상시험이 이전 심장 카테터 삽입술 병력이 있는 환자를 제외하는데, 환자 소견서에는 중심정맥 카테터 삽입이라고 적혀 있고, 유사도 매처는 두 심혈관 카테터 시술로 보고 점수를 가깝게 매긴 뒤, 실제로는 적격이었던 환자를 제외한다. 발표된 평가들은 실제 모델이 바로 이 오류를 낸다는 것을 확인한다(Fierce Biotech, 2025). 나는 내 데모가 그 일이 일어나는 모습을 보여 주고, 이어서 내 엔진이 그것을 잡아내는 모습을 보여 주길 원했다.

그래서 나는 악역을 맡을 공정한 베이스라인을 작성했다. 엔티티 수준 TF-IDF 코사인 유사도, 단어와 문자 3~5그램, 실제 벡터 유사도 방법이다. 허수아비는 아무것도 증명하지 않으므로, 관대한 설정까지 주고 결정 임계값을 스스로 교차검증하게 했다(층화 3-fold ROC, Youden's J, seed 13, t = 0.6932에서 고정). 그런 다음 심장 카테터 사례를 돌리고 잘못된 제외가 나오기를 기다렸다.

나오지 않았다. 베이스라인은 두 카테터 구절을 자체 교차검증 임계값보다 넉넉히 아래로 점수 매기고 적격으로 반환했다. 데모 전체를 그 위에 쌓아 둔 그 실수는 도무지 재현되지 않았다.

나는 유명한 실패를 연출하려다, 정직한 악역이 그 죄를 저지를 만큼 강하지 않다는 사실을 발견했다.

그 이유는 교훈적이었고, 과장하기 쉬워서 정확히 말하고 싶다. 희소한 어휘 베이스라인은 그 특정한 거짓 제외를 만들지 않는다. 두 구절을 임계값을 넘길 만큼 가깝게 끌어당기려면 밀집 의미 임베딩이 필요하다. 무거운 임베딩 모델을 넣으면 데모가 오프라인에서 한 명령으로 돌릴 수 없는 것으로 부풀어 오므로, 나는 결정을 내렸다. 베이스라인은 정직하고 희소하게 유지하고, 저지를 수 없는 범죄를 저지르는 척을 그만둔다. 그 결정이 내가 만들고 있는 글 전체를 재편했다. 직접 돌려 보고 싶다면 veriprajna.com/ko/demos/clinical-trial-recruitment-ai에 있다.

중심정맥관란 대체 무엇인가?

나는 그래도 심장 카테터 사례를 남겼다. 잡힌 실수보다 더 나은 것을 증명해 주었기 때문이다. 그것은 내 엔진의 답이 애초에 신뢰할 수 있는지를 증명한다. 여기 두 개념 모두 실제이고 확인 가능한 SNOMED-CT 식별자를 갖는다. 중심정맥 카테터 삽입술392230005이다. 심장 카테터 삽입술41976001이다. 어느 쪽이든 공개 SNOMED 브라우저에 붙여 넣으면 계층의 서로 다른 가지에 앉아 있음을 확인할 수 있다. 한쪽에서 다른 쪽으로 가는 is-a 경로는 없다. 중심정맥관은 심장 카테터가 아니며, 그것을 아는 것은 계층 구조뿐이다.

그것이 그래프의 한 간선에 담긴 논문 전체의 논지다. 유사도 점수는 "is-a"를 표현할 수 없다. 표현할 수 있는 것은 "이 문자열들이 비슷해 보인다"뿐이며, 비슷해 보이는 것과 의미가 같은 것은 다르다. 내 엔진이 "이전 심장 카테터 삽입술 없음"이라는 제외 기준을 평가할 때, 아무것도 점수 매기지 않는다. 구조적 질문을 던진다. 환자의 검증된 사실이 금지된 개념에 포함되는가? 온톨로지를 걷고, 포함 경로가 없음을 찾고, 두 개념 ID와 확인한 그래프 간선을 명명하는 세 단계 추적과 함께 적격으로 반환한다.

중심정맥 카테터 삽입술 392230005 is-a 심장 카테터 삽입술 41976001이 False로 평가되고, 계층의 다른 가지이며, 판정은 ELIGIBLE임을 보여 주는 TrialProof 추론 추적
합성 환자 P-074의 EXCL-CARDCATH 추적. 2단계는 중심정맥 카테터 삽입술(392230005)이 심장 카테터 삽입술(41976001)의 is-a인지 묻고, False(계층의 다른 가지)로 답한 뒤 ELIGIBLE을 반환한다. 아래 베이스라인 패널은 출처도 없고 재현할 것도 없는 임계값 미만 유사도 점수를 보고한다.

그 추적이 처음 렌더링되는 것을 보았을 때, 나를 친 것은 판정이 아니었다. 그 아래의 영수증이었다. 같은 화면의 베이스라인 상자는 출처도 없고 재현할 것도 없는 유사도 숫자를 보여 준다. 내 엔진의 상자는 두 SCTID와 정확히 물은 is-a 질문을 이름 붙인다. 이 둘 중 하나는 규제 당국이 파일로 넣을 수 있다. 다른 하나는 어깨를 으쓱하는 숫자다. 잡힌 오류가 아니라, 바로 그 대비가 심장 카테터 사례가 실제로 벌어 오는 것이다.

매처가 실제로 버린 환자

그래도 실제로 놓친 환자가 필요해서, 정직한 베이스라인이 진짜로 실패하는 곳을 찾아다녔고, 한 단어에서 찾았다: not. 합성 주인공 차트 P-074에는 "No evidence of diabetes."라는 소견 줄이 있다. 종양학 프로토콜의 제외 기준 중 하나는 "당뇨병 진단 없음"이다. 벡터 베이스라인은 토큰 "diabetes"가 기준의 "diabetes" 바로 옆에 있는 것을 보고 유사도 1.0으로 매칭한다. 완벽한 점수다. 부정에 대한 모델이 없으므로, 당뇨병을 배제하는 문장을 당뇨병을 포함하는 것처럼 읽고, 적격이었던 환자를 제외한다.

이것이 매처가 버리는 환자이며, 원래 심장 카테터 사례가 맡아주길 기대했던 박자다. 부정은 희소 베이스라인이 자체 최적 임계값에서, 조작 없이, 정직하게 깨지는 지점이다.

TrialProof EXCL-DM 추적: 베이스라인은 diabetes를 diabetes에 유사도 1.0으로 매칭해 EXCLUDED를 반환하고, 검증기는 부정된 언급을 제거해 엔진이 ELIGIBLE을 반환한다
P-074에 대한 EXCL-DM 결정. 베이스라인의 최고 언급은 "Diabetes mellitus"를 "Diabetes mellitus"에 유사도 1.0으로 매칭하고 EXCLUDED를 반환한다. TrialProof 검증기는 부정된 언급을 제거하므로, 금지된 개념에 포함되는 검증된 사실이 없고, 판정은 ELIGIBLE이다.

이 실패가 얼마나 조용한지 계속 생각한다. 오류 메시지도, 낮은 신뢰도 플래그도, 뭔가 잘못됐다는 신호도 없다. 점수는 1.0, 가능한 최고, 시스템이 가질 수 있는 가장 큰 확신이다. 베이스라인은 가장 틀리는 바로 그 순간에 가장 확신한다. 이런 것들의 대기열을 검토하는 코디네이터는, 이 완벽한 매칭이 등록되었어야 할 환자라는 것을 알 방법이 없다. 프로토콜 전체에 걸쳐 곱해 보면, 임상시험의 80%가 등록 일정을 놓치는 이유(업계 합의, 2025)와 스크린 실패 한 건이 평균 약 $1,200의 비용이 드는 이유(Antidote.me, 2025)를 이해하게 된다.

베이스라인은 가장 틀리는 바로 그 순간에 가장 확신했다. 그것은 튜닝으로 없앨 수 있는 버그가 아니다. 범주 오류다.

판정은 왜 모델 바깥에 있는가?

일찍이 내린 아키텍처 결정 하나가, 지금 와서는 유일하게 중요했던 결정이라고 생각하는데, 바로 언어 모델을 판정에서 완전히 멀리 두는 것이었다. 전체 파이프라인에서 확률론적 단계는 정확히 하나다. 제공자를 바꿀 수 있는 모델이, 자문만 하며, 지저분한 산문을 읽고 후보 사실들을 제안한다. 각 후보는 사실을 읽은 원문 스팬과 작은 폐쇄 어휘에서 가져온 후보 개념 ID를 함께 가진다. 모델이 진정으로 잘하는 단 한 가지가 바로 이것이다: 읽기. 누가 적격인지에 대한 투표권은 없다.

그 이후는 모두 내가 감사할 수 있는 결정론적 코드다. 제안된 사실이 결정에 도달하기 전에, 적대적 검증기가 원문 소견서에 대해 세 가지 검사로 도전한다. 스팬이 실제로 존재하는가, 부정되어 있는가, 주어가 가족이 아니라 환자인가. "No evidence of diabetes" 사실은 부정 검사에서 실패하고 엔진에 도달하지 않는다. 같은 차트에서 "Family history of breast cancer"는 주어 검사에서 실패한다. 그 병력은 환자가 아니라 가족 구성원의 것이므로, 실패한 검사 이름을 달고 거부로 표시된다.

결정에 들어가기 전에 제안된 모든 사실이 스팬 존재, 부정, 주어에 대해 도전받는 모습을 보여 주는 TrialProof Verify Facts 패널
P-074의 Verify Facts 단계. 모델이 제안한 모든 사실은 결정에 들어가기 전에 도전받는다: 스팬 존재, 부정되지 않음, 환자 본인의 주어. 여기서 중심정맥 카테터 삽입술 사실은 ACCEPTED이며, 이유: 스팬 존재, 부정되지 않음, 환자 주어. 검사에 실패한 사실은 이유를 명명하며 REJECTED로 표시된다.

전체 골드셋에서 이 검증기는 사실 인스턴스 7건, 서로 다른 나쁜 사실 3건을 거부했다(부정된 당뇨병 언급, 가족력 유방암 귀속, 지지 스팬이 없는 심어 둔 환각 약물). 채점된 13개 사례 실행 중 4개에 걸쳐 퍼져 있으며, 모두 판정에 닿기 전이었다. 사람들이 "에이전트가 내 소견서에서 뽑은 것을 어떻게 신뢰하느냐"고 물으면, 이 패널이 전부다. 신뢰하라고 하지 않는다. 무엇을 제안했고 무엇이 왜 버려졌는지를 보여 준다.

그다음 판정 자체는 에이전트 프레임워크 바깥에 앉은 평범한 Python이다 온톨로지와 약간의 날짜 연산 위에서 금지, 시간 예외, 요구 사항을 평가하는 의무 논리 엔진이다. 모델은 이 게이트를 덮어쓸 수 없다. 게이트가 돌아갈 때 모델은 그 방에 없기 때문이다. 그것이 엔진을 재현 가능하게 만드는 이유이기도 하다. 로직이 고정된 온톨로지 위의 결정론적 코드일 때, 같은 차트를 다시 돌리면 매번, 바이트 단위로 같은 답이 나온다.

모델은 읽는다. 투표하지 않는다. 그 단 하나의 경계가 재실행을 바이트 동일하게 만든다.

임상 운영 독자가 신경 쓴 유일한 숫자

나는 결국 스스로도 인정했듯이, 구매자가 잠 못 이루며 신경 쓰지 않는 지표를 몇 주 동안 최적화했다. 결정 정확도는 리더보드 숫자다. 스폰서나 CRO에서 실현 가능성을 책임지는 사람은 리더보드 점수를 비교하지 않는다. 등록 일정이 미끄러지는 것을 지켜보고, 미끄러지는 하루하루가 비싸다. Tufts CSDD Impact Report(2024)는 등록 지연 비용을 처방 매출 손실로 하루 약 $800K로 잡고, 이 데모가 다루는 치료 영역에서는 더 높다. 종양학에서 하루 약 $840K, 심혈관에서 하루 $1.4M. 프로토콜 복잡도는 2005년 이후 임상시험 시술에서 139% 올랐고(IQVIA, 2026), 이는 더 많은 기준, 더 많은 조항, 텍스트 매처가 하나를 틀릴 수 있는 더 많은 지점을 뜻한다.

그래서 나는 정확도를 앞세우기를 그만두고, 그 고통에 실제로 대응하는 숫자를 앞세우기 시작했다. 잃지 않은 적격 환자. 고정된 라벨 골드셋(합성 환자 7명과 합성 프로토콜 2개에서 뽑은 13개 사례)에서 내 엔진은 적격 환자 0명을 잃는다. 공정한 베이스라인은 3명을 잃는다. 같은 집합, 베이스라인 스스로에게 유리하게 교차검증된 같은 임계값.

라벨 골드셋에서 결정 정확도 100% 대 베이스라인 53.8%, 잃은 적격 환자 0명 대 3명, 감사 가능 추적 커버리지 100% 대 0%를 보여 주는 TrialProof 벤치마크 타일
골드셋 벤치마크. 라벨이 붙은 13개 사례에서 TrialProof는 결정 정확도 100% 대 베이스라인 53.8%, 잃은 적격 환자 0명 대 베이스라인 3명, 추론 추적 100% 대 베이스라인 0%를 기록한다. 13개 사례 전체를 다시 돌리면 판정과 추적이 바이트 동일하다.

그 숫자들이 무엇이고 무엇이 아닌지를 정확히 말하고 싶다. 그것들은 그 하나의 고정된 13개 사례 집합에 대한 하네스 자체의 출력이지, 열린 세계에 대한 약속이 아니다. 100%는 "이 골드셋에서 100%"이지, "항상 옳다"가 아니다. TrialProof가 절대 틀리지 않는다고 말하지 않겠다. 그렇게 말할 데이터가 없고, 그렇게 말하는 사람도 믿지 않을 것이다. 내가 말할 수 있는 것은 더 좁고, 내 생각에는 더 유용하다. 이 집합에서 엔진은 적격 환자를 0명 잃고, 모든 결정이 재현 가능한 추적을 가지며, 필요한 검사나 바이탈이 없을 때 추측 대신 NEEDS-REVIEW로 안전하게 기권한 결정이 두 건 있었고, 전체 집합을 다시 돌린 결과는 13건 모두 바이트 동일했다. 환자, 소견서, 프로토콜은 모두 합성 픽스처이며, 실제 기록은 어디에도 없다. 그 실행들을 전부 veriprajna.com/ko/demos/clinical-trial-recruitment-ai에서 볼 수 있다.

내가 신경 쓰는 숫자는 정확도가 아니다. 버리지 않은 적격 환자다. 이 집합에서 그것은 베이스라인의 3명에 대해 0명 손실이다.

여기에도 규제적 형태가 있고, 조심스럽게 이름 붙이겠다. FDA의 2026년 1월 Clinical Decision Support 가이던스가 이런 인간 개입(human-in-the-loop) 매칭 보조에 해당하는 프레임워크다. 엔진이 내는 모든 결정은 환자×기준당 한 행의 CDISC SDTM IE 레코드로 내보낼 수 있으며, 판정, 추론 추적, 개념 ID, 의무 연산을 담는다. 그것은 허가가 아니며, 허가를 주장하는 것도 아니다. 정합과 방향이다. 그러나 추적이 디버깅 편의가 아니라는 뜻이다. 제출 가능한 산출물이며, 사후 생각이 아니라 모든 결정에 설계상 존재한다.

내가 계속 돌아오는 것

악역이 배역을 거부한 순간으로 계속 돌아간다. 내가 묻던 질문이 바뀌었기 때문이다. 삼 년 동안 이 분야는 누가 적격인지 판정하는 일에서 모델을 더 낫게 만들 것인가를 물어 왔다. 더 나은 프롬프트, 더 큰 컨텍스트, 더 많은 검색 — 모두 확률론적 시스템을 환자 등록을 판정할 만큼 신뢰할 수 있게 만드는 데 겨냥했다. 이 빌드의 첫 구간도 그 프레임 안에 있었다. 모델을 고치려고 모델의 실수를 잡으려 했다.

결국 깨달은 것은, 그것이 잘못된 층이었다는 점이다. 유사도 점수는 "is-a"를 표현할 수 없고, "not"을 표현할 수 없으며, "치료가 무작위 배정 12개월 이전에 완료된 경우는 예외"를 표현할 수 없다. 프롬프트를 아무리 해도 그것들은 더해지지 않는다. 언어 문제가 아니기 때문이다. 논리 문제다. 그러니 시니어의 수는 모델을 신뢰할 수 있게 만드는 것이 아니다. 신뢰를 불필요하게 만드는 것이다. 모델에게는 잘하는 단 한 가지, 산문을 읽고 읽은 스팬과 함께 사실을 제안하는 일을 맡긴다. 그런 다음 검증기가 소견서가 지지하지 않는 것을 버리고, 의료 온톨로지 위의 평범하고 감사 가능한 코드가 판정을 계산하게 한다.

적격성은 예측이 아니라 계산되어야 한다. 들어가기 전에는 기대하지 못했던 것은, 그 보상이 벤치마크처럼 느껴지지 않는다는 점이다. 영수증처럼 느껴진다. 같은 차트가 매번 같은 답을 주고, 답은 그것을 결정한 개념 ID와 그래프 간선을 이름 붙이며, 실현 가능성 담당자가 실제로 잠 못 이루는 숫자 — 버려진 적격 환자 — 가 0으로 간다.

읽는 것보다 보는 편이 낫다면, 여기 처음부터 끝까지 돌아가는 전체가 있다.

그래서 내가 놓지 않고 뒤집고 있는 질문이 이것이고, 당신이 어떻게 답하는지 진심으로 알고 싶다. 실제 사람의 임상시험 기회가 걸려 있을 때, 신뢰를 어디에 두고 싶은가. 믿어야 하는 모델인가, 읽을 수 있는 코드인가?

관련 연구

다른 채널에도 게시됨

확신을 가지고 AI를 구축하세요.

차세대 엔터프라이즈 AI 구축에 깊은 경험을 갖춘 팀과 협업하세요. 신뢰할 수 있는 AI 전략을 설계하고 구축하며 배포할 수 있도록 지원해 드리겠습니다.

Veriprajna 딥테크 컨설팅 은(는) 헬스케어, 금융, 규제 분야를 위한 안전 필수 AI 시스템 구축을 전문으로 합니다. 당사의 아키텍처는 확립된 프로토콜에 따라 검증되며 포괄적인 규정 준수 문서를 갖추고 있습니다.