<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.4">Jekyll</generator><link href="https://kakyungkim.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://kakyungkim.github.io/" rel="alternate" type="text/html" /><updated>2026-09-22T22:28:03+00:00</updated><id>https://kakyungkim.github.io/feed.xml</id><title type="html">Ka-Kyung Kim</title><subtitle>Research notes on drug discovery and precision medicine: genomic analysis, AI model validation, and the LLM agent harnesses I build and check.</subtitle><author><name>Ka-Kyung Kim</name></author><entry xml:lang="en"><title type="html">How Far Generative AI Has Come in Drug Discovery, and How Far You Can Trust It</title><link href="https://kakyungkim.github.io/en/2026/09/11/gen-ai-drug-discovery-evidence/" rel="alternate" type="text/html" title="How Far Generative AI Has Come in Drug Discovery, and How Far You Can Trust It" /><published>2026-09-11T00:00:00+00:00</published><updated>2026-09-11T00:00:00+00:00</updated><id>https://kakyungkim.github.io/en/2026/09/11/gen-ai-drug-discovery-evidence</id><content type="html" xml:base="https://kakyungkim.github.io/en/2026/09/11/gen-ai-drug-discovery-evidence/"><![CDATA[<p class="lang-switch" style="margin-bottom:1.5em">
  
  <a href="/kr/2026/09/11/gen-ai-drug-discovery-evidence/" class="btn btn--primary btn--small">🇰🇷 이 글 한국어로 보기</a>
  
</p>

<p>I published a report with BRIC View on generative AI in biotech and drug discovery. This post is
the plain-language version, written so you can follow it without a background in the field. One
question runs through the whole report: generative AI is said to be changing biology, but how far
can you trust what comes out of it?</p>

<p>The answer depends on where you look. Protein design has reached the point where results are
confirmed in the lab. Small molecules are standing at the threshold of the clinic. Genome-scale
design is still inside the computer. The rest of this post walks through that gap.</p>

<h2 id="what-it-takes-to-produce-one-drug">What it takes to produce one drug</h2>

<p>Bringing a new drug to market means screening tens of thousands of candidate compounds down to
one, then testing it in animals and then in people. That takes well over a decade and costs on
the order of a billion dollars. Even among candidates that reach first-in-human dosing, roughly
one in ten becomes an approved drug.</p>

<p>Hence an old question: can we pick the candidates faster, and pick them better?</p>

<h2 id="where-generative-ai-fits">Where generative AI fits</h2>

<p>The same class of model that writes sentences in ChatGPT also generates proteins and compounds.
Earlier AI was mostly asked to predict: will this molecule be toxic? Generative AI answers a
different request: draw me something new with these properties. The work moved from searching to
designing.</p>

<p>That takes material to learn from. UniProt holds over 227 million protein sequences. The
AlphaFold structure database holds over 214 million predicted structures. ChEMBL holds over 20.3
million bioactivity measurements. Public resources like these are the training material.</p>

<h2 id="protein-design-has-reached-experimental-confirmation">Protein design has reached experimental confirmation</h2>

<p>The clearest results have come from protein design. RFdiffusion designs, from scratch, proteins
that bind to a chosen target. These designs were not left on paper. They were expressed,
purified, and imaged, and the designed shape matched the measured structure to within 0.63 Å of
backbone RMSD. A single atom is roughly 1 Å across, so the error was smaller than one atom.</p>

<p>The success rate, though, was about 19%. Design five and one works. That is a large improvement
over earlier methods, and the 2024 Nobel Prize in Chemistry went to protein structure prediction
and computational protein design.</p>

<h2 id="the-funnel-narrows-toward-the-back">The funnel narrows toward the back</h2>

<p>Generating candidates inside a computer is cheap and plentiful. Passing through the lab and then
through clinical trials, the number that survives drops sharply while the evidence demanded of
each one gets stronger.</p>

<p>The numbers trace that shape. Among AI-discovered drugs, 21 of 24 advanced out of Phase I, which
mainly tests safety. That is about 88%, well above the industry average of 40 to 65%. In Phase
II, where the question becomes whether the drug actually works, only 4 of 10 advanced. At 40%,
that does not beat the industry average.</p>

<p>The most advanced case sits in the same place. Rentosertib, a TNIK inhibitor aimed at idiopathic
pulmonary fibrosis, met its primary safety endpoint in a Phase 2a trial of 71 patients and
entered Phase 3 in July 2026. Efficacy showed a favorable trend, but only as a secondary
endpoint, in arms of roughly 18 patients each. Confirmation is still ahead.</p>

<h2 id="how-a-scorecard-gets-inflated">How a scorecard gets inflated</h2>

<p>Sometimes the scorecard itself deserves suspicion. If the practice problems show up on the exam,
the score looks good, and the same thing happens in data. Material used for training leaks into
the evaluation set.</p>

<p>This has been documented in at least 294 papers across 17 fields and sorted into eight distinct
types. With leakage, benchmark scores come out high and then fail to reproduce when someone
measures again elsewhere. I ran into the same problem a few days ago when I measured it myself on ADMET models, written
up <a href="/kr/2026/09/08/admet-split-audit/">here in Korean</a>.</p>

<h2 id="risk-grows-with-capability">Risk grows with capability</h2>

<p>As generative capability grows, so does the room for misuse. When researchers inverted the
objective of a drug discovery model, telling it to seek toxicity instead of avoiding it, roughly
40,000 toxic molecules were designed in under six hours. Nothing was synthesized or verified;
these are computational results.</p>

<p>There are moves in the other direction. Evo 2, a genome generative model, deliberately excluded
viral genomes that infect eukaryotes from its training data, blocking dangerous sequences at the
design stage rather than after the fact.</p>

<h2 id="where-the-rules-stand">Where the rules stand</h2>

<p>Regulation is catching up. The US FDA issued a draft framework for judging whether AI-generated
data is credible enough to support regulatory decisions. The EU set obligations for high-risk AI
under the AI Act and pushed the main compliance dates to December 2027 and August 2028. The USPTO
concluded that AI cannot be named an inventor and that a significant human contribution is
required. In Korea, the MFDS issued a guideline for LLM-based digital medical devices in June
2026, listing seven hazard categories along with validation metrics.</p>

<p>What is still missing is a separate standard for how evidence produced by generative models
should be weighed in drug review.</p>

<h2 id="where-this-started">Where this started</h2>

<p>Last spring I wrote a BRIC View report on how bio big data is being pooled and expanded. Once
that was done, the next question was sitting right there: what is actually being built on top of
that data?</p>

<p>Starting the survey, I found no shortage of material listing technologies and cases. What was
missing was a separation of how strong the evidence is at each stage. So instead of widening
coverage, I followed one question through.</p>

<h2 id="read-it">Read it</h2>

<p>The full report is available at BRIC View, in Korean.</p>

<ul>
  <li><a href="https://www.ibric.org/s.do?JpKhtZtuZJ">BRIC View 2026-T24, “Generative AI in Biotech and Drug Discovery: Technology, Cases, and Ecosystem Outlook”</a></li>
</ul>

<p>Every number in this post comes from the report, and the primary sources are in its reference
list.</p>

<h2 id="next">Next</h2>

<p>The part of the report that took longest was separating which claims rest on what grade of
evidence. Wanting to do that with my own hands, I measured how the choice of data split changes
reported performance in ADMET models, and wrote that up separately. Next I want to widen the task
and model set and work out why some of my results diverged from prior work.</p>

<p>The sentence the report closes on is this. In the era of generative AI, competitiveness in
biotech will rest less on how fast you can generate something, and more on how credibly you can
demonstrate that what you generated holds up.</p>]]></content><author><name>Ka-Kyung Kim</name></author><category term="Life Science" /><category term="Data Science" /><category term="Generative AI" /><category term="Drug Discovery" /><category term="Protein Design" /><category term="BRIC View" /><category term="Data Leakage" /><category term="Reproducibility" /><category term="Regulation" /><summary type="html"><![CDATA[I published a trend report on generative AI in biotech and drug discovery. One question runs through all of it: how far can you actually trust the output?]]></summary></entry><entry xml:lang="kr"><title type="html">생성형 AI 신약개발의 도달점과 신뢰 범위</title><link href="https://kakyungkim.github.io/kr/2026/09/11/gen-ai-drug-discovery-evidence/" rel="alternate" type="text/html" title="생성형 AI 신약개발의 도달점과 신뢰 범위" /><published>2026-09-11T00:00:00+00:00</published><updated>2026-09-11T00:00:00+00:00</updated><id>https://kakyungkim.github.io/kr/2026/09/11/gen-ai-drug-discovery-evidence</id><content type="html" xml:base="https://kakyungkim.github.io/kr/2026/09/11/gen-ai-drug-discovery-evidence/"><![CDATA[<p class="lang-switch" style="margin-bottom:1.5em">
  
  <a href="/en/2026/09/11/gen-ai-drug-discovery-evidence/" class="btn btn--primary btn--small">🇺🇸 Read this post in English</a>
  
</p>

<p>BRIC View에 「생성형 AI의 바이오·신약개발 혁신 동향」 리포트를 공개했습니다. 이 글에서는
그 리포트를 배경지식 없이도 읽을 수 있게 옮겼습니다. 리포트를 관통한 질문은 하나였습니다.
생성형 AI가 바이오를 바꾸고 있다는데, 그래서 그 결과를 어디까지 믿을 수 있나.</p>

<p>답은 단계마다 다릅니다. 단백질 설계는 실험으로 확인된 자리까지 왔고, 화합물은 임상 문턱에
서 있으며, 유전체 수준의 설계는 아직 계산 안에 머물러 있습니다. 아래에서 그 차이를 하나씩
짚어 보겠습니다.</p>

<h2 id="신약-하나가-나오는-과정">신약 하나가 나오는 과정</h2>

<p>새 약을 하나 만들려면 후보 물질을 수만 개 단위로 훑어 그중 하나를 골라내고, 동물과 사람에게
차례로 시험합니다. 여기에 십수 년과 조 단위의 비용이 듭니다. 그런데도 사람에게 처음 투여하는
단계까지 온 후보 중 실제로 약이 되는 것은 열에 하나 남짓입니다.</p>

<p>그래서 오래된 질문이 하나 있습니다. 후보를 더 빨리, 더 잘 고를 수는 없을까.</p>

<h2 id="생성형-ai가-맡은-자리">생성형 AI가 맡은 자리</h2>

<p>챗GPT가 문장을 만들어 내듯, 같은 원리의 모델이 단백질과 화합물을 만들어 냅니다. 기존 AI가
“이 물질이 독성이 있을까”를 맞히는 쪽이었다면, 생성형 AI는 “이런 성질을 가진 물질을 새로
그려 줘”에 답합니다. 찾는 일에서 설계하는 일로 옮겨 갔습니다.</p>

<p>여기에는 재료가 필요합니다. 단백질 서열을 모은 UniProt에는 2억 2,700만 개가 넘는 서열이,
AlphaFold 구조 데이터베이스에는 2억 1,400만 개가 넘는 예측 구조가 쌓여 있습니다. 생체활성
데이터를 모은 ChEMBL에는 측정값이 2,030만 건 넘게 있습니다. 이렇게 공개된 자료가 학습에
쓰입니다.</p>

<h2 id="실험으로-확인된-단백질-설계">실험으로 확인된 단백질 설계</h2>

<p>가장 뚜렷한 성과는 단백질 설계에서 나왔습니다. RFdiffusion이라는 모델은 원하는 표적에
달라붙는 단백질을 처음부터 설계합니다. 설계에 그치지 않고 실제로 만들어 현미경으로 구조를
확인했고, 설계한 모양과 실측한 모양이 주쇄 원자 기준 0.63 Å 차이로 맞았습니다. 원자 하나의
크기가 대략 1 Å이니, 오차가 그보다 작았습니다.</p>

<p>다만 성공률은 약 19%였습니다. 다섯 개를 설계하면 하나가 되는 정도이지만, 기존 방법보다는
크게 올랐습니다. 2024년 노벨 화학상도 단백질 구조 예측과 계산 설계에 돌아갔습니다.</p>

<h2 id="뒤로-갈수록-좁아지는-깔때기">뒤로 갈수록 좁아지는 깔때기</h2>

<p>컴퓨터 안에서는 후보를 싸게, 많이 만들어 낼 수 있습니다. 그런데 실험실과 임상시험을 지날수록
통과하는 수는 급격히 줄어들고, 요구되는 근거는 강해집니다.</p>

<p>숫자가 이 모양을 그대로 보여 줍니다. AI가 발굴한 신약은 안전성을 주로 보는 임상 1상에서
24건 중 21건, 약 88%가 다음 단계로 갔습니다. 업계 평균 40~65%를 크게 웃돕니다. 그런데 약이
실제로 듣는지를 가리는 2상에서는 10건 중 4건, 40%에 그쳐 업계 평균을 넘지 못했습니다.</p>

<p>가장 앞선 사례도 같은 자리에 있습니다. 폐가 굳는 병인 특발성 폐섬유증을 겨냥한 TNIK 저해제
렌토서팁은 환자 71명을 대상으로 한 2a상에서 1차 목표인 안전성을 확인했고, 2026년 7월 3상에
들어갔습니다. 효능은 2차 지표에서 개선 경향을 보이는 데 그쳤고, 군당 인원도 18명 정도로
적었습니다. 확증은 아직 남아 있습니다.</p>

<h2 id="성적표가-부풀려지는-경로">성적표가 부풀려지는 경로</h2>

<p>모델의 성적표 자체를 의심해야 할 때도 있습니다. 연습문제가 시험에 그대로 출제되면 점수가 잘
나오는데, 같은 일이 데이터에서도 일어납니다. 학습에 쓴 자료가 평가에도 섞여 들어가는 데이터
누수입니다.</p>

<p>이 문제는 17개 분야 최소 294편의 논문에서 확인되었고 8가지 유형으로 정리되어 있습니다.
누수가 끼면 벤치마크 점수는 높게 나오지만 다른 곳에서 다시 재면 재현되지 않습니다. 며칠 전
<a href="/kr/2026/09/08/admet-split-audit/">ADMET 예측 모델로 직접 재본 글</a>에서 다룬 문제이기도
합니다.</p>

<h2 id="능력과-함께-커지는-위험">능력과 함께 커지는 위험</h2>

<p>생성 능력이 늘어나면 오용 가능성도 함께 커집니다. 신약개발에 쓰던 생성 모델의 목표를 독성을
피하는 쪽에서 찾는 쪽으로 뒤집자, 6시간이 안 되어 약 4만 개의 독성 분자가 설계되었다고
보고되었습니다. 실제로 합성하거나 확인하지는 않은 계산 결과입니다.</p>

<p>반대 방향의 사례도 있습니다. 유전체 생성 모델 Evo 2는 사람 같은 진핵생물을 감염시키는
바이러스 유전체를 학습에서 일부러 빼 두어, 위험한 서열을 만들지 못하도록 설계 단계에서
미리 막았습니다.</p>

<h2 id="제도의-정비-현황">제도의 정비 현황</h2>

<p>규제도 따라오고 있습니다. 미국 FDA는 AI가 만든 데이터를 규제 판단에 쓸 때 신뢰할 만한지
가늠하는 평가 틀을 초안으로 냈습니다. EU는 AI Act로 고위험 AI가 지킬 의무를 정했고, 주요
조항의 적용 시점은 2027년 12월과 2028년 8월로 미뤘습니다. 미국 특허청은 AI가 발명자가 될 수 없고
사람의 상당한 기여가 있어야 특허 대상이라고 정리했습니다. 국내에서는 식약처가 2026년 6월
거대언어모델 기반 디지털의료기기 가이드라인을 내면서 위해요인 일곱 가지와 검증 지표를
붙였습니다.</p>

<p>다만 생성형 모델이 만들어 낸 근거를 신약 심사에서 어떻게 평가할지는 아직 별도 기준이
없습니다.</p>

<h2 id="출발점">출발점</h2>

<p>지난봄 BRIC View에 바이오 빅데이터가 어떻게 모이고 확장되는지를 다룬 리포트를 썼습니다.
데이터를 쌓는 이야기를 정리하고 나니 다음 질문이 자연스럽게 남았습니다. 그래서 그 데이터로
무엇을 만들어 내고 있나.</p>

<p>찾아보니 기술과 사례를 훑는 자료는 이미 충분히 많았습니다. 반면 각 단계에서 확보된 근거가
어느 수준인지 갈라 본 자료는 비어 있었습니다. 그래서 다루는 범위를 넓히는 대신 질문 하나를
두고 따라갔습니다.</p>

<h2 id="리포트-전문">리포트 전문</h2>

<p>리포트 전문은 BRIC View에서 읽으실 수 있습니다.</p>

<ul>
  <li><a href="https://www.ibric.org/s.do?JpKhtZtuZJ">BRIC View 2026-T24 「생성형 AI의 바이오·신약개발 혁신 동향: 기술, 사례, 생태계 전망」</a></li>
</ul>

<p>이 글에 적은 수치는 모두 리포트 본문에서 가져왔고, 원출처는 참고문헌에 정리해 두었습니다.</p>

<h2 id="다음">다음</h2>

<p>리포트를 쓰며 어느 주장에 어느 수준의 근거가 붙어 있는지 가르는 데 시간이 가장 많이
들었습니다. 같은 작업을 저도 해 보고 싶어 ADMET 예측 모델의 분할 방식을 직접 재봤고,
그 결과는 따로 정리해 두었습니다. 다음에는 과제와 모델을 늘려 선행 연구와 어긋난
부분의 원인을 가려 보려고 합니다.</p>

<p>리포트를 관통한 문장은 이렇게 남겼습니다. 생성형 AI 시대 바이오의 경쟁력은 무엇을 얼마나
빨리 만들어 내는가보다, 만들어 낸 것을 얼마나 신뢰할 수 있게 입증하는가에 달려 있습니다.</p>]]></content><author><name>Ka-Kyung Kim</name></author><category term="Life Science" /><category term="Data Science" /><category term="생성형AI" /><category term="신약개발" /><category term="단백질설계" /><category term="BRICView" /><category term="데이터누수" /><category term="재현성" /><category term="규제" /><summary type="html"><![CDATA[BRIC View에 생성형 AI의 바이오·신약개발 동향 리포트를 공개했습니다. 관통하는 질문은 하나였습니다. 그래서 그 결과를 어디까지 믿을 수 있나.]]></summary></entry><entry xml:lang="kr"><title type="html">ADMET 분할 방식이 성능 추정을 얼마나 바꾸는지 재봤습니다</title><link href="https://kakyungkim.github.io/kr/2026/09/08/admet-split-audit/" rel="alternate" type="text/html" title="ADMET 분할 방식이 성능 추정을 얼마나 바꾸는지 재봤습니다" /><published>2026-09-08T00:00:00+00:00</published><updated>2026-09-08T00:00:00+00:00</updated><id>https://kakyungkim.github.io/kr/2026/09/08/admet-split-audit</id><content type="html" xml:base="https://kakyungkim.github.io/kr/2026/09/08/admet-split-audit/"><![CDATA[<p>약물이 몸에 어떻게 흡수되고 대사되고 빠져나가는지를 미리 예측하는 모델을 ADMET 모델이라
부릅니다. 후보 물질을 임상으로 보낼지 판단하는 자리에서 씁니다.</p>

<p>이 모델을 학습용과 평가용으로 어떻게 나누느냐에 따라 성능 숫자가 달라집니다. 얼마나
달라지는지 공개 데이터로 재봤습니다. 결론부터 적으면, 업계 표준인 scaffold split에서는
12개 과제 중 8개만 성능이 떨어지는데 화학적 거리로 나누면 12개 전부 떨어집니다. 하락 폭도
중앙값 +0.020에서 +0.098로 커집니다.</p>

<h2 id="분할-방식이-문제가-되는-이유">분할 방식이 문제가 되는 이유</h2>

<p>머신러닝에서 데이터를 학습용과 평가용으로 나눌 때, 두 쪽에 비슷한 것이 섞이면 성능이
부풀려집니다. 시험에 나올 문제를 연습 문제로 미리 준 것과 같습니다. 이걸
데이터 누수(data leakage)라고 합니다.</p>

<p>화합물에서는 이 문제가 특히 심합니다. 신약개발에서는 <strong>뼈대 하나를 잡고 곁가지만 바꿔 가며
수십에서 수백 개 유도체를 만들기</strong> 때문입니다. 아스피린을 붙들고 아세틸기 자리를 이리저리
바꿔 보는 식입니다. 이렇게 나온 한 묶음을 시리즈(analog series)라고 부르는데, 안에 있는
화합물들은 서로 매우 닮았습니다.</p>

<p>무작위로 나누면 그 유도체 100개 중 80개가 학습에, 20개가 평가에 들어갑니다. 모델은 구조가
성질을 어떻게 좌우하는지(structure-property relationship)를 배우지 않고도 <strong>“이 뼈대는 대충
이런 값”</strong>을 외워서 좋은 점수를 받습니다.</p>

<h2 id="표준-관행-scaffold-split">표준 관행: scaffold split</h2>

<p>여기서 말하는 뼈대가 <strong>scaffold</strong>입니다. 정확히는 <strong>Bemis-Murcko scaffold</strong>라고 하는데,
분자에서 말단 곁사슬(side chain)을 전부 떼고 고리(ring)와 고리를 잇는 링커(linker)만
남긴 것입니다. 아스피린이라면 아세틸기와 카복실기를 떼고 남는 벤젠 고리가 scaffold입니다.</p>

<p><strong>scaffold split은 같은 scaffold를 가진 화합물을 통째로 한쪽에만 넣는 방식</strong>입니다.
아스피린 유도체 100개는 전부 학습에 들어가거나 전부 평가에 들어갑니다. 나눠 담지 않습니다.</p>

<p>ADMET 벤치마크의 표준 관행이고, Therapeutics Data Commons 리더보드도 이 기준으로 순위를
매깁니다. 그런데 최근 논문 몇 편이 <strong>scaffold split으로는 누수가 다 잡히지 않는다</strong>고
보고했습니다. Fooladi 등[1]은 TDC 8개 데이터셋에 분할 10종과 모델 14종을 교차해 scaffold
분할이 열 가지 중 가장 쉬운 시험임을 보였고, Zheng 등[3]은 라벨을 쓰지 않는 분할을 제안해
BBB 과제에서 AUROC가 0.879에서 0.409로 내려가는 것을 보고했습니다.</p>

<p>이유는 이렇습니다. <strong>scaffold가 다르다는 것과 화학적으로 멀다는 것이 같은 말이 아닙니다.</strong>
벤젠 고리와 피리딘 고리는 고리에 질소가 하나 들어갔는지 차이뿐이라 scaffold로는 다른
분자인데 성질은 비슷합니다. scaffold만 갈라 놓으면 이런 닮은꼴이 학습과 평가 양쪽에 남습니다.</p>

<h2 id="대안-화학적-거리로-나누기">대안: 화학적 거리로 나누기</h2>

<p>닮았는지를 재려면 분자를 숫자로 바꿔야 하는데, 그때 쓰는 것이 <strong>fingerprint</strong>입니다.</p>

<p>분자는 원자와 결합으로 이뤄진 그래프이고 대부분의 머신러닝 모델은 그 형태를 그대로
입력받지 못합니다. 그래서 <strong>2048칸짜리 스위치판</strong>을 하나 두고, 분자 안에 특정 부분구조가
있으면 해당 칸을 켜는 식으로 바꿉니다. Morgan fingerprint 2048이라고 부르고 ECFP라는
이름으로도 씁니다.</p>

<p>두 분자가 얼마나 닮았는지는 <strong>두 스위치판에서 켜진 칸이 얼마나 겹치는지</strong>로 잽니다. 겹친
칸을 전체 켜진 칸으로 나눈 값이 <strong>Tanimoto 유사도</strong>이고 0에서 1 사이입니다. 0.4를 넘으면
화학적으로 가깝다고 보는 것이 관행입니다.</p>

<p><strong>구조 분리 분할은 Tanimoto 0.4 이상인 화합물을 하나로 묶어 통째로 배정합니다.</strong>
scaffold가 서로 달라도 분자끼리 닮았으면 같은 쪽으로 보냅니다.</p>

<p>세 분할을 나란히 놓으면 이렇습니다.</p>

<table>
  <thead>
    <tr>
      <th>분할</th>
      <th>무엇을 같은 쪽에 묶나</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>무작위</td>
      <td>아무것도 묶지 않음</td>
    </tr>
    <tr>
      <td>scaffold split</td>
      <td>scaffold가 같은 것</td>
    </tr>
    <tr>
      <td>구조 분리</td>
      <td>화학적으로 가까운 것 전부</td>
    </tr>
  </tbody>
</table>

<figure style="margin:2em 0;text-align:center">
  <img src="/assets/images/posts/admet-split-comparison.png" alt="세 가지 분할 방식 비교. 무작위 분할은 같은 시리즈가 학습과 평가에 섞이고, scaffold split은 시리즈는 안 섞이지만 같은 무리 안에 학습이 남으며, 구조 분리는 가까운 무리를 통째로 한쪽에 배정한다." style="width:100%;max-width:900px;border-radius:10px;border:1px solid #e2e8f0" />
  <figcaption style="font-size:0.9em;color:#64748b;margin-top:0.7em">
    scaffold split에서도 같은 회색 원 안에 학습(파랑)과 평가(주황)가 함께 남습니다. 여기가 이 실험이 겨냥한 자리입니다.
  </figcaption>
</figure>

<h2 id="실험-설계">실험 설계</h2>

<p>데이터는 Therapeutics Data Commons의 ADMET 12개 과제에 사람 약동학(PK) 3개 과제를 더했습니다.
TDC는 하버드 Zitnik 랩이 운영하는 공개 플랫폼으로, 신약개발 머신러닝 데이터셋을 같은 규격으로
정리해 리더보드까지 제공합니다. ADMET 부문은 22개 데이터셋으로 이뤄져 있습니다.</p>

<p>같은 데이터와 같은 분할 로직을 두고 모델 계열 셋으로 돌렸습니다.</p>

<table>
  <thead>
    <tr>
      <th>모델</th>
      <th>분자를 어떻게 다루나</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Morgan fingerprint 2048 + LightGBM</td>
      <td>손으로 만든 스위치판</td>
    </tr>
    <tr>
      <td>메시지 전달 신경망</td>
      <td>그래프 구조에서 직접 학습</td>
    </tr>
    <tr>
      <td>ChemBERTa-77M 미세조정</td>
      <td>사전학습 언어모델</td>
    </tr>
  </tbody>
</table>

<p>분할별로 하이퍼파라미터를 따로 튜닝하지 않았습니다. 튜닝하면 분할 효과와 튜닝 효과가 섞입니다.</p>

<h2 id="scaffold-split과-구조-분리의-차이">scaffold split과 구조 분리의 차이</h2>

<p>fingerprint + LightGBM, 12개 과제, 시드 5개. 무작위 분할 대비 하락입니다.</p>

<table>
  <thead>
    <tr>
      <th>분할</th>
      <th>하락 중앙값</th>
      <th>떨어진 과제</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>scaffold split</td>
      <td>+0.020</td>
      <td>8 / 12</td>
    </tr>
    <tr>
      <td>구조 분리</td>
      <td>+0.098</td>
      <td>12 / 12</td>
    </tr>
  </tbody>
</table>

<p>하락 폭보다 개수가 눈에 띕니다. scaffold split에서는 네 과제가 오히려 올라갑니다. 부호가
뒤집힙니다. 구조 분리에서는 그 네 과제까지 모두 떨어져 12개가 같은 방향이 됩니다.</p>

<p>세 모델 계열에서 결과가 같았습니다.</p>

<table>
  <thead>
    <tr>
      <th>모델 계열</th>
      <th>scaffold 하락 중앙값</th>
      <th>구조 분리 하락 중앙값</th>
      <th>떨어진 과제</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>fingerprint + LightGBM</td>
      <td>+0.020</td>
      <td>+0.098</td>
      <td>12 / 12</td>
    </tr>
    <tr>
      <td>그래프 신경망</td>
      <td>+0.022</td>
      <td>+0.132</td>
      <td>11 / 12</td>
    </tr>
    <tr>
      <td>ChemBERTa</td>
      <td>+0.016</td>
      <td>+0.088</td>
      <td>12 / 12</td>
    </tr>
  </tbody>
</table>

<p>36개 과제-모델 쌍 가운데 35개가 구조 분리에서 떨어집니다. scaffold split에서는 23개입니다.
분자를 다루는 방식을 스위치판에서 그래프로, 다시 언어모델로 바꿔도 결론이 같습니다.</p>

<h2 id="후보-선별에서-더-큰-차이">후보 선별에서 더 큰 차이</h2>

<p>상관계수는 후보를 고르는 자리에서 직접 쓰이지 않습니다. 실제로 쓰는 것은 예측값 상위 몇 개를
가져가는지라, 상위 10% 적중률을 따로 쟀습니다. 시드 15개, 8개 과제이고 검정은
윌콕슨 부호순위 검정(Wilcoxon signed-rank test)입니다.</p>

<table>
  <thead>
    <tr>
      <th>분할</th>
      <th>하락 중앙값</th>
      <th>떨어진 과제</th>
      <th>부호순위 검정</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>scaffold split</td>
      <td>+0.066</td>
      <td>8 / 8</td>
      <td>p = 0.0078</td>
    </tr>
    <tr>
      <td>구조 분리</td>
      <td>+0.107</td>
      <td>8 / 8</td>
      <td>p = 0.0078</td>
    </tr>
  </tbody>
</table>

<p>과제별로는 사람 분포용적(VDss)의 낙차가 가장 큽니다. 0.358에서 0.176으로 내려가고 p &lt; 0.001입니다.
분포용적은 약물이 몸에서 얼마나 넓게 퍼지는지를 나타내는 값으로, 사람에서의 투여량을 정할 때
씁니다. 학습 데이터와 화학적으로 먼 화합물이 들어오면 그 예측의 상위 후보 적중률이 절반
수준이 된다는 뜻입니다.</p>

<h2 id="구현-편향-여부-확인">구현 편향 여부 확인</h2>

<p>성능이 떨어진 원인이 두 가지로 갈릴 수 있었습니다. 화학적으로 가까운 것을 묶어 나눴기
때문일 수도 있고, 큰 묶음이 학습 쪽으로 몰리는 바람에 평가 집합이 외톨이 분자로만 채워졌기
때문일 수도 있습니다. 후자라면 제 구현이 만든 결과입니다.</p>

<p>대조군을 두 개 두었습니다. 하나는 같은 Tanimoto 묶음을 쓰되 배정만 완전히 무작위로 합니다.
다른 하나는 묶는 방법 자체를 선행 연구의 k-means 방식으로 바꿉니다.</p>

<table>
  <thead>
    <tr>
      <th>성분</th>
      <th>하락 중앙값</th>
      <th>떨어진 과제</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>묶어서 나눈 효과</td>
      <td>+0.069</td>
      <td>12 / 12</td>
    </tr>
    <tr>
      <td>외톨이 분자가 평가 집합에 몰린 효과</td>
      <td>+0.026</td>
      <td>7 / 12</td>
    </tr>
  </tbody>
</table>

<p>하락의 약 73%가 묶어서 나눈 데서 왔습니다. 배정을 완전히 무작위로 돌려도 scaffold split의
두 배 넘게 떨어지고 12개 과제 전부에서 떨어집니다. 묶는 방법을 k-means로 바꿔도 하락
중앙값이 0.111과 0.087로 통계적으로 구분되지 않습니다(p = 0.301).</p>

<h2 id="임계값을-올린-재현">임계값을 올린 재현</h2>

<p>Tanimoto 0.4에서는 큰 데이터셋 셋에 거대한 묶음이 생깁니다. 임계값을 0.5로 올려 12개 과제를
다시 돌렸습니다.</p>

<p>세 어려운 분할 모두 12개 과제 전부에서 떨어지고 p = 0.0005입니다. 성분 분해는 오히려
깨끗해집니다. 묶음 효과가 +0.082(12/12)로 커지고 외톨이 효과는 +0.004(6/12)로 사실상
사라집니다. 0.4에서 관측된 외톨이 효과는 거대한 묶음이 배정 순서를 왜곡해 생긴 것으로 보입니다.</p>

<h2 id="정정한-것">정정한 것</h2>

<p>처음 정리한 결론 가운데 셋을 철회했습니다.</p>

<p><strong>선별 지표가 성능 지표보다 3.8배 빨리 무너진다</strong>고 적었는데, 시드를 5개에서 15개로 늘리자
1.7배였습니다. 방향은 남지만 크기가 훨씬 작습니다.</p>

<p><strong>사람 PK 선별이 scaffold split에서 크게 무너진다</strong>고 적었는데, ChemBERTa로 다시 하니 사람
분포용적이 0.418에서 0.418로 변하지 않았습니다. fingerprint 기반 모델에서만 나타나는
현상입니다. 모델 계열을 가로질러 남는 것은 구조 분리 쪽입니다.</p>

<p><strong>무작위 분할 성능으로 모델을 고르는 문제</strong>는 이 설계로 답할 수 없다고 판단해 비워 두었습니다.
모델이 세 계열뿐이라 “잘하는 모델이 어디서나 잘한다”가 상관을 지배합니다. 선행 연구는 성능이
비슷한 모델 14종의 순위가 뒤바뀌는지를 봤습니다. 세 점으로 순위 안정성을 재기는 어렵습니다.</p>

<h2 id="선행-연구와-맞지-않은-두-지점">선행 연구와 맞지 않은 두 지점</h2>

<p>Guo와 Ding[2]은 26개 종점 165,541건에 네 모델 계열을 적용해 무작위에서 구조 분리로 갈 때
고전 머신러닝이 가장 많이 잃는다고 보고했습니다. 이 실험은 순서가 반대로 그래프 신경망이
가장 많이 잃었습니다. 시드를 2개에서 5개로, epoch을 60에서
100으로 늘려도 유지됩니다. 원인은 아직 가리지 못했고 종점 구성과 모델 규격을 후보로 봅니다.</p>

<p>Fooladi 등[1]은 scaffold split에서 상위 K 선별이 1.8 퍼센트포인트 떨어진다고 보고했는데
이 실험은 6.6이었습니다. 정의를 맞춘 뒤에도 3.7배 차이가 납니다. 분류 적중률과 회귀 상위 K% 선별이
다른 문제라는 점, 데이터셋 크기 차이를 후보로 봅니다. 이것도 확인하지 못했습니다.</p>

<h2 id="범위">범위</h2>

<p>scaffold split이 낙관적이라는 것과 어려운 분할에서 성능이 떨어진다는 것은 이미 문헌에
있습니다. 이 실험은 그 결과를 재현하고, 하락이 묶어서 나눈 데서 오는지 구현에서 오는지를
대조군으로 갈라 본 것입니다. 12개 과제와 세 모델이라는 규모의 한계도 그대로 있습니다.</p>

<h2 id="참고문헌">참고문헌</h2>

<p>[1] Fooladi H, Vu TNL, Mathea M, Kirchmair J. Evaluating Machine Learning Models for
Molecular Property Prediction: Performance and Robustness on Out-of-Distribution Data.
<em>J Chem Inf Model</em> 2025;65(19):9871-9891.
<a href="https://doi.org/10.1021/acs.jcim.5c00475">doi:10.1021/acs.jcim.5c00475</a></p>

<p>[2] Guo J, Ding S. arXiv:2604.26498 (2026).
<a href="https://arxiv.org/abs/2604.26498">arxiv.org/abs/2604.26498</a></p>

<p>[3] Zheng J, Guo C, Wang Z, Liu X. arXiv:2607.10729 (2026).
<a href="https://arxiv.org/abs/2607.10729">arxiv.org/abs/2607.10729</a></p>

<p>데이터는 <a href="https://tdcommons.ai/benchmark/admet_group/overview/">Therapeutics Data Commons</a>
ADMET Benchmark Group을 썼습니다.</p>]]></content><author><name>Ka-Kyung Kim</name></author><category term="AI &amp; Tooling" /><category term="ADMET" /><category term="신약개발AI" /><category term="모델검증" /><category term="데이터누수" /><category term="벤치마크" /><category term="TDC" /><summary type="html"><![CDATA[Therapeutics Data Commons 12개 과제를 모델 세 계열로 돌렸습니다. 표준 관행인 scaffold split에서는 12개 중 8개만 성능이 떨어지는데, 화학적 거리로 나누면 12개 전부 떨어집니다.]]></summary></entry><entry xml:lang="en"><title type="html">I Read Someone Else’s Code Before Writing My Own</title><link href="https://kakyungkim.github.io/en/2026/08/08/reading-before-building/" rel="alternate" type="text/html" title="I Read Someone Else’s Code Before Writing My Own" /><published>2026-08-08T00:00:00+00:00</published><updated>2026-08-08T00:00:00+00:00</updated><id>https://kakyungkim.github.io/en/2026/08/08/reading-before-building</id><content type="html" xml:base="https://kakyungkim.github.io/en/2026/08/08/reading-before-building/"><![CDATA[<p class="lang-switch" style="margin-bottom:1.5em">
  
  <a href="/kr/2026/08/08/reading-before-building/" class="btn btn--primary btn--small">🇰🇷 이 글 한국어로 보기</a>
  
</p>

<p>I set out to build something like Google Forms. You make a form, share a link, collect answers and file attachments. That’s the whole scope. The target was to finish it inside a six-hour workshop, so the feature list had to shrink hard.</p>

<p>The usual move here is to scaffold a project and start drawing screens. I didn’t do that. I read two open-source products that have been solving this exact problem for years.</p>

<h2 id="the-problem">The problem</h2>

<p>Building anything means a steady stream of decisions. Do I split the question list into its own table or store it as one JSON blob? Do I persist whether a form is closed, or compute it at read time? When do I validate an uploaded file?</p>

<p>Decide each of these by instinct and you can’t explain them later. And a decision you can’t explain is a decision you can’t revise with confidence.</p>

<p>Products that already have users have made every one of those calls. The hard-to-reverse ones leave marks in the code. Reading those marks lets you borrow tuition someone else already paid.</p>

<h2 id="what-i-read">What I read</h2>

<p>I picked two. Both are form builders, both are open source, both still get commits.</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>OpnForm</th>
      <th>HeyForm</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Backend</td>
      <td>PHP, Laravel, REST</td>
      <td>Node.js, NestJS, GraphQL</td>
    </tr>
    <tr>
      <td>Frontend</td>
      <td>One Nuxt app</td>
      <td>React admin app + separate renderer package</td>
    </tr>
    <tr>
      <td>Database</td>
      <td>Relational, 112 migrations</td>
      <td>MongoDB, 26 Mongoose schemas</td>
    </tr>
    <tr>
      <td>Repo layout</td>
      <td>Split into api and client</td>
      <td>pnpm workspace, 7 packages</td>
    </tr>
  </tbody>
</table>

<p>Different languages, different databases, different API styles. That’s what made the comparison worth doing. <strong>Where the two diverge, it’s usually taste or context. Where the two converge, you’re probably looking at the answer to the problem.</strong></p>

<h2 id="how-i-read-them">How I read them</h2>

<p>I wrote down twelve angles first, then went through one angle across both repos before moving to the next. Author flow, respondent flow, editor structure, renderer structure, question type definitions, data model, state handling, submission validation, file upload, auth and permissions, testing.</p>

<p>I deliberately avoided sweeping one repo end to end and reconciling later. Do that and your comparison criteria drift while you read.</p>

<h2 id="where-they-went-opposite-ways">Where they went opposite ways</h2>

<p>The sharpest difference was the relationship between the editor and the respondent-facing screen.</p>

<p>OpnForm reuses a single renderer and switches behavior by mode. There are eight modes, and each one returns an object saying whether to validate, whether to show admin controls, whether to actually submit. The editor preview mounts <strong>the same component</strong> as the public form, in preview mode.</p>

<p>HeyForm goes the other way. The builder canvas has 25 per-type components, and the respondent renderer has 28 more. The switch that maps a question type to a component exists twice, once on each side. Files like <code class="language-plaintext highlighter-rouge">FakeRadio</code> and <code class="language-plaintext highlighter-rouge">FakeSelect</code>, which only mimic an input, make the split obvious.</p>

<p>It looked like duplication until I found the reason. The renderer ships as its own npm package. To embed a form on someone else’s site you have to break its coupling with the admin app. They bought deployment independence and paid for it in maintenance.</p>

<p>A six-hour MVP has no embed requirement, so I took OpnForm’s side.</p>

<p>Six of these forks came up: whether form state lives in one column or scattered across a settings object, whether drafts and published content are stored separately, when files get validated, whether a file belongs to a response or to a form.</p>

<h2 id="where-they-agreed">Where they agreed</h2>

<p>This was the real payoff.</p>

<p><strong>Neither normalizes the question list.</strong> OpnForm puts it in a JSON column, HeyForm in an array of objects. Two opposite database families, same call. Reordering questions, changing types, and adding choices are frequent operations, and normalizing means touching many rows every time.</p>

<p><strong>Neither trusts the question definition that arrives with the request.</strong> A client can submit answers alongside a definition claiming “this question is optional and its max length is 100,000.” Both products discard that and re-fetch the form by id to get their validation basis.</p>

<p><strong>The stored definition decides what a value means.</strong> I saw this in HeyForm’s payment path. It ignores the amount and currency the respondent sent and recomputes them from the published form settings. There’s even a comment explaining why.</p>

<p><strong>Closed-ness is computed, not stored.</strong> Whether the state is closed, whether the deadline has passed, whether the submission cap has been reached: all evaluated at read time.</p>

<p><strong>File type is verified by content, not by extension.</strong> HeyForm pairs each MIME type with an allowed extension list and a magic-byte check. OpnForm reads the leading bytes to detect the real type, and rather than blocking SVG outright it strips the scripts out.</p>

<h2 id="the-one-line-that-paid-off-most">The one line that paid off most</h2>

<p>OpnForm’s authorization policy class has a method that reads roughly like this:</p>

<blockquote>
  <p>Can this form be answered? Only if it isn’t closed, hasn’t hit its submission cap, and is publicly visible.</p>
</blockquote>

<p>It accepts a nullable user. The entire treatment of anonymous respondents sits in that one line. And it translates almost directly into a Supabase row-level security policy: a single SQL condition saying inserts are allowed only when the form is published.</p>

<p>Scatter permission checks through application code and you will forget one while adding a new route. Put it in the database and every route hits the same wall.</p>

<h2 id="then-i-had-the-spec-reviewed">Then I had the spec reviewed</h2>

<p>I turned the reading into documents: two per-angle analyses, a comparison table, and an adoption-decisions file. The last one ends with <strong>a table linking each decision to the source file it came from.</strong> Six months from now, “why did we do it this way” needs somewhere to land.</p>

<p>Then I wrote the product requirements from those decisions, and <strong>separated the author from the reviewer.</strong> The reviewer only gets the original brief and the decisions file, and reads the requirements against them.</p>

<p>Four blocking defects came back. Two of them stung.</p>

<p><strong>Four technical constraints were missing entirely.</strong> Next.js App Router and Turborepo were in the brief and appeared nowhere in the document. Neither did mobile responsiveness. The persona section said the respondent “often opens this on a phone,” but that isn’t a requirement.</p>

<p><strong>A security guarantee undercut itself.</strong> One section stated flatly that response inserts are enforced by row-level security in the database. Another section, the API summary, assumed that same path uses a service role key. A service role key bypasses row-level security completely. Implemented as written, the policy would have been decorative.</p>

<p>The acceptance criterion said this: “verify that a direct insert bypassing row-level security is blocked for the same reason.” Bypassing it, and being blocked by it. The sentence contradicts itself, and I couldn’t see it while writing.</p>

<h2 id="what-the-second-round-turned-up">What the second round turned up</h2>

<p>I applied the fixes and sent it back to the same reviewer. This time <strong>the reviewer caught something it had missed in round one.</strong></p>

<p>Files are uploaded before the response is submitted, and the submit request carries the storage path along with the answers. That path is also a client-controlled value. If the server takes it at face value, a respondent can attach a file that was uploaded to somebody else’s form.</p>

<p>I had written “don’t trust values that come with the request” all over the document, and then left one place where the principle wasn’t applied. Knowing a principle and applying it exhaustively turned out to be two different things.</p>

<h2 id="what-i-took-away">What I took away</h2>

<p><strong>Three things.</strong></p>

<p>First, when two products built on different stacks make the same call, that call is worth trusting. Reading only one, I couldn’t have told its taste apart from the problem’s answer.</p>

<p>Second, the author shouldn’t be the reviewer. Authors read what they meant. If it’s in your head, it reads as if it’s on the page. I did not find those four missing constraints myself.</p>

<p>Third, writing down what you haven’t decided beats deciding by default. The document currently carries twelve open items, each with a note on why it’s still open. Decide them silently and you lose the ability to tell a decision from a guess.</p>

<p>One of them was a repo tooling choice where the brief and my own prior analysis pointed in opposite directions. Nothing in the documents justified picking a side, so I didn’t. I asked instead.</p>

<h2 id="next">Next</h2>

<p>On to the architecture. The first things to settle are four security boundaries: what privilege reads a public form, which key handles response submission, how the file path gets verified, and how long a signed link stays alive.</p>

<p>The reading time paid for itself. A fair number of these I would have missed on instinct alone.</p>

<hr />

<p><em>This analysis and the documents around it were done with AI agents in the loop. They helped most with reading and organizing the repositories, and with reviewing the resulting documents from a perspective other than the author’s. Both reference repositories were read only and left unmodified.</em></p>]]></content><author><name>Ka-Kyung Kim</name></author><category term="AI &amp; Tooling" /><category term="Claude Code" /><category term="AI Agents" /><category term="Open Source" /><category term="Design Decisions" /><category term="PRD" /><category term="Building in Public" /><summary type="html"><![CDATA[I read two open-source form builders to ground the design of a small MVP. Then I had the spec reviewed by someone other than its author, and four blocking defects came back.]]></summary></entry><entry xml:lang="kr"><title type="html">코드를 쓰기 전에 남의 코드를 먼저 읽었습니다</title><link href="https://kakyungkim.github.io/kr/2026/08/08/reading-before-building/" rel="alternate" type="text/html" title="코드를 쓰기 전에 남의 코드를 먼저 읽었습니다" /><published>2026-08-08T00:00:00+00:00</published><updated>2026-08-08T00:00:00+00:00</updated><id>https://kakyungkim.github.io/kr/2026/08/08/reading-before-building</id><content type="html" xml:base="https://kakyungkim.github.io/kr/2026/08/08/reading-before-building/"><![CDATA[<p class="lang-switch" style="margin-bottom:1.5em">
  
  <a href="/en/2026/08/08/reading-before-building/" class="btn btn--primary btn--small">🇺🇸 Read this post in English</a>
  
</p>

<p>구글폼 비슷한 서비스를 만들어 보기로 했습니다. 폼을 만들어 링크로 뿌리고 응답과 파일을 받는, 딱 그만큼입니다. 여섯 시간짜리 실습 과정에서 완성하는 것이 목표라 기능을 크게 줄여야 했습니다.</p>

<p>보통 이런 걸 만들 때는 바로 프로젝트를 만들고 화면부터 그립니다. 이번에는 그러지 않았습니다. 같은 문제를 이미 오래 풀어 온 오픈소스 두 개를 먼저 읽었습니다.</p>

<h2 id="문제">문제</h2>

<p>만들다 보면 결정할 것이 계속 나옵니다. 질문 목록을 테이블로 나눌까 JSON 한 덩어리로 담을까. 폼이 마감됐는지를 컬럼에 저장할까 조회할 때 계산할까. 파일을 언제 검사할까.</p>

<p>이런 걸 하나씩 감으로 정하면 나중에 왜 그렇게 했는지 설명하지 못합니다. 그리고 설명하지 못하는 결정은 고칠 때도 근거가 없습니다.</p>

<p>이미 사용자를 받고 있는 제품은 그 결정을 다 내려 봤습니다. 되돌리기 어려운 결정은 코드에 흔적을 남깁니다. 그걸 읽으면 남이 지불한 수업료를 빌릴 수 있습니다.</p>

<h2 id="무엇을-읽었나">무엇을 읽었나</h2>

<p>두 개를 골랐습니다. 둘 다 폼 빌더이고 소스가 공개되어 있으며 지금도 커밋이 올라옵니다.</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>OpnForm</th>
      <th>HeyForm</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>백엔드</td>
      <td>PHP, Laravel, REST</td>
      <td>Node.js, NestJS, GraphQL</td>
    </tr>
    <tr>
      <td>프론트엔드</td>
      <td>Nuxt 한 앱</td>
      <td>React 관리자 앱 + 별도 렌더러 패키지</td>
    </tr>
    <tr>
      <td>데이터베이스</td>
      <td>관계형, 마이그레이션 112개</td>
      <td>MongoDB, Mongoose 스키마 26개</td>
    </tr>
    <tr>
      <td>저장소 구성</td>
      <td>api와 client 2분할</td>
      <td>pnpm 워크스페이스 7패키지</td>
    </tr>
  </tbody>
</table>

<p>언어도 다르고 데이터베이스도 다르고 API 방식도 다릅니다. 그래서 비교할 가치가 있었습니다. <strong>둘이 서로 다른 선택을 한 지점은 취향이나 상황의 문제이고, 둘이 같은 선택을 한 지점은 그 문제의 답에 가깝습니다.</strong></p>

<h2 id="어떻게-읽었나">어떻게 읽었나</h2>

<p>열두 개 관점을 먼저 적어 두고, 한 관점을 두 저장소에서 연달아 봤습니다. 작성자 흐름, 응답자 흐름, 편집기 구조, 렌더러 구조, 질문 타입 정의, 데이터 모델, 상태 관리, 제출 검증, 파일 업로드, 인증과 권한, 테스트 순입니다.</p>

<p>저장소별로 통째 훑고 나중에 맞추는 방식은 쓰지 않았습니다. 그렇게 하면 비교 기준이 읽는 동안 흔들립니다.</p>

<h2 id="정반대로-간-지점">정반대로 간 지점</h2>

<p>가장 인상 깊었던 차이는 편집기와 응답 화면의 관계였습니다.</p>

<p>OpnForm은 렌더러 하나를 모드만 바꿔 재사용합니다. 모드가 여덟 개 있고, 모드마다 검증할지, 관리자 컨트롤을 보일지, 실제로 제출할지를 객체로 돌려줍니다. 편집기 미리보기는 공개 폼과 <strong>똑같은 컴포넌트</strong>를 미리보기 모드로 띄웁니다.</p>

<p>HeyForm은 반대입니다. 빌더 캔버스에 질문 타입별 컴포넌트가 25개 있고, 응답자용 렌더러에 28개가 따로 있습니다. 타입을 컴포넌트에 연결하는 분기문도 두 곳에 각각 존재합니다. 입력을 흉내만 내는 <code class="language-plaintext highlighter-rouge">FakeRadio</code>, <code class="language-plaintext highlighter-rouge">FakeSelect</code> 같은 파일이 그 증거입니다.</p>

<p>처음에는 중복으로 보였는데 이유가 있었습니다. 렌더러를 npm 패키지로 따로 배포합니다. 다른 사이트에 폼을 임베드하려면 관리자 앱과 결합을 끊어야 합니다. 배포 독립성을 얻고 유지 비용을 냈습니다.</p>

<p>여섯 시간짜리 MVP에는 임베드가 필요 없습니다. 그래서 OpnForm 쪽을 택했습니다.</p>

<p>이런 갈림길이 여섯 개 나왔습니다. 폼 상태를 컬럼 하나에 둘지 설정 객체에 흩을지, 초안과 발행본을 나눌지, 파일을 언제 검증할지, 파일을 응답에 묶을지 폼에 묶을지 같은 것들입니다.</p>

<h2 id="둘이-같은-답을-낸-지점">둘이 같은 답을 낸 지점</h2>

<p>여기가 진짜 수확이었습니다.</p>

<p><strong>질문 목록을 정규화하지 않습니다.</strong> OpnForm은 JSON 컬럼에, HeyForm은 객체 배열에 담습니다. 관계형과 문서형이라는 정반대 데이터베이스를 쓰면서 같은 선택을 했습니다. 질문 순서를 바꾸고 타입을 바꾸는 일이 잦은데, 정규화하면 그때마다 여러 행을 손대야 합니다.</p>

<p><strong>서버는 요청이 보낸 질문 정의를 믿지 않습니다.</strong> 응답을 받을 때 클라이언트가 “이 질문은 필수가 아니고 최대 길이는 10만 자”라고 주장하는 정의를 함께 보낼 수 있습니다. 두 저장소 모두 그걸 무시하고 폼 id로 데이터베이스를 다시 조회해 검증 기준으로 삼습니다.</p>

<p><strong>값의 의미는 저장된 정의가 정합니다.</strong> HeyForm의 결제 처리에서 봤습니다. 응답자가 보낸 금액과 통화를 쓰지 않고 발행된 폼 설정에서 다시 계산합니다. 코드에 주석까지 달아 뒀습니다.</p>

<p><strong>마감 여부는 저장하지 않고 요청할 때 판정합니다.</strong> 상태가 닫힘인지, 마감 시각이 지났는지, 응답 수가 상한에 닿았는지를 조회 시점에 계산합니다.</p>

<p><strong>파일은 확장자가 아니라 내용으로 확인합니다.</strong> HeyForm은 MIME 타입마다 허용 확장자와 매직 바이트 검사를 짝지어 둡니다. OpnForm은 파일 앞부분을 읽어 실제 형식을 판독하고, SVG는 막는 대신 스크립트를 걷어 냅니다.</p>

<h2 id="쓸모-있었던-한-줄">쓸모 있었던 한 줄</h2>

<p>OpnForm의 권한 정책 클래스에 이런 메서드가 있었습니다.</p>

<blockquote>
  <p>응답을 받을 수 있는가: 마감되지 않았고, 제출 상한에 닿지 않았고, 공개 상태일 때.</p>
</blockquote>

<p>사용자를 널 허용으로 받습니다. 익명 응답자를 다루는 방식이 이 한 줄에 들어 있습니다. 그리고 이건 Supabase의 행 수준 보안 정책으로 거의 그대로 옮겨집니다. “폼이 발행 상태일 때만 응답 삽입을 허용한다”는 SQL 조건 하나가 됩니다.</p>

<p>애플리케이션 코드에 권한 검사를 흩어 두면 새 경로를 추가하면서 빠뜨립니다. 데이터베이스에 걸어 두면 어느 경로로 들어와도 막힙니다.</p>

<h2 id="만든-문서를-검증했더니">만든 문서를 검증했더니</h2>

<p>읽은 것을 문서로 만들었습니다. 관점별 분석 두 편, 대조표, 채택 결정 문서입니다. 결정 문서 마지막에는 <strong>어떤 원본 파일을 읽고 어떤 결정을 내렸는지 잇는 표</strong>를 붙였습니다. 나중에 “왜 이렇게 했지”를 물었을 때 되짚을 자리가 있어야 합니다.</p>

<p>그다음 이 결정들을 근거로 제품 요구사항 문서를 썼습니다. 그리고 <strong>쓴 쪽과 검증하는 쪽을 나눴습니다.</strong> 검증하는 쪽은 원본 브리프와 결정 문서만 보고 요구사항 문서를 훑습니다.</p>

<p>차단 결함 네 개가 나왔습니다. 그중 둘이 특히 뼈아팠습니다.</p>

<p><strong>기술 제약 네 개가 통째로 빠져 있었습니다.</strong> 브리프에 적어 둔 Next.js App Router와 Turborepo가 문서 본문에 한 번도 나오지 않았습니다. 모바일 반응형도 마찬가지였습니다. 페르소나 설명에 “스마트폰으로 접속하는 경우가 많다”는 문장은 있었지만 그건 요구사항이 아닙니다.</p>

<p><strong>보안 보증이 스스로 무너지는 구조였습니다.</strong> 한 절에서는 “응답 삽입은 데이터베이스의 행 수준 보안으로 강제한다”고 못박아 놓고, 다른 절의 API 요약에서는 그 경로가 서비스 롤 키를 쓴다고 전제했습니다. 서비스 롤 키는 행 수준 보안을 통째로 건너뜁니다. 그대로 구현했으면 정책은 있으나 마나가 됩니다.</p>

<p>수용 기준에는 이렇게 적혀 있었습니다. “행 수준 보안을 우회한 직접 삽입 시도도 같은 이유로 차단되는지 확인한다.” 우회했는데 그걸로 막힌다는 문장입니다. 문장 자체가 모순인데 쓸 때는 보이지 않았습니다.</p>

<h2 id="두-번째-라운드에서-나온-것">두 번째 라운드에서 나온 것</h2>

<p>지적을 반영하고 같은 검증자에게 다시 보냈습니다. 이번에는 <strong>검증자가 자기가 라운드 1에서 놓쳤던 것</strong>을 찾았습니다.</p>

<p>파일은 응답 제출보다 먼저 올라가고, 제출 요청이 그 저장 경로를 함께 보냅니다. 그런데 이 경로도 클라이언트가 조작할 수 있는 값입니다. 서버가 그대로 받으면 다른 폼에 올라간 파일을 자기 응답에 붙일 수 있습니다.</p>

<p>“요청이 보낸 값을 믿지 않는다”는 원칙을 문서 여기저기에 적어 두고도, 정작 그 원칙을 적용할 자리를 하나 빠뜨린 셈입니다. 원칙을 아는 것과 빠짐없이 적용하는 것은 다른 일이었습니다.</p>

<h2 id="배운-것">배운 것</h2>

<p><strong>세 가지가 남았습니다.</strong></p>

<p>첫째, 서로 다른 기술로 만든 두 제품이 같은 선택을 한 지점은 신뢰할 만합니다. 하나만 읽었으면 그게 그 제품의 취향인지 그 문제의 답인지 구분하지 못했을 겁니다.</p>

<p>둘째, 문서는 쓴 사람이 읽으면 안 됩니다. 쓴 사람은 자기가 이해한 대로 읽습니다. 문서에 안 적혀 있어도 머릿속에 있으면 있는 것처럼 읽힙니다. 기술 제약 네 개가 빠진 것을 저 스스로는 못 찾았습니다.</p>

<p>셋째, 모르는 것을 모른다고 적어 두는 편이 낫습니다. 이번 문서에는 아직 정하지 않은 항목이 열두 개 있고 각각 왜 아직 정하지 않았는지가 붙어 있습니다. 임의로 정해 버리면 그게 결정이었는지 추측이었는지 나중에 구분되지 않습니다.</p>

<p>특히 저장소 구성 도구 하나는 브리프와 선행 분석이 서로 다른 답을 주고 있었습니다. 어느 쪽을 따를 근거가 문서 안에 없어서 임의로 고르지 않고 사람에게 물었습니다.</p>

<h2 id="다음">다음</h2>

<p>이제 구조 설계로 넘어갑니다. 먼저 풀어야 할 건 보안 경계 네 가지입니다. 공개 폼을 어떤 권한으로 읽을지, 응답 제출에 어떤 키를 쓸지, 파일 경로를 어떻게 검증할지, 서명 링크를 얼마나 살려 둘지.</p>

<p>읽는 데 쓴 시간이 아깝지 않았습니다. 감으로 정했으면 몰랐을 것들이 꽤 있었습니다.</p>

<hr />

<p><em>이번 분석과 문서 작업은 AI 에이전트를 붙여 진행했습니다. 저장소를 읽고 정리하는 일, 그리고 만든 문서를 다른 관점으로 검증하는 일에 특히 도움이 됐습니다. 참고한 두 저장소는 읽기만 했고 수정하지 않았습니다.</em></p>]]></content><author><name>Ka-Kyung Kim</name></author><category term="AI &amp; Tooling" /><category term="Claude Code" /><category term="AI Agents" /><category term="오픈소스분석" /><category term="설계결정" /><category term="PRD" /><category term="Building in Public" /><summary type="html"><![CDATA[폼 빌더 오픈소스 두 개를 읽고 MVP 설계 근거를 만들었습니다. 그리고 만든 기획 문서를 다른 관점으로 검증했더니 차단 결함 네 개가 나왔습니다.]]></summary></entry><entry xml:lang="en"><title type="html">I Checked My Own Manuscript With Its Own Rule</title><link href="https://kakyungkim.github.io/en/2026/08/06/checking-my-own-manuscript/" rel="alternate" type="text/html" title="I Checked My Own Manuscript With Its Own Rule" /><published>2026-08-06T00:00:00+00:00</published><updated>2026-08-06T00:00:00+00:00</updated><id>https://kakyungkim.github.io/en/2026/08/06/checking-my-own-manuscript</id><content type="html" xml:base="https://kakyungkim.github.io/en/2026/08/06/checking-my-own-manuscript/"><![CDATA[<p class="lang-switch" style="margin-bottom:1.5em">
  
  <a href="/kr/2026/08/06/checking-my-own-manuscript/" class="btn btn--primary btn--small">🇰🇷 이 글 한국어로 보기</a>
  
</p>

<p><a href="/en/2026/08/05/remeasuring-a-papers-claim/">In the previous post</a> I re-measured a number from someone else’s paper. That left me with a question: if I’ve learned how to re-measure someone else’s number, shouldn’t I run the same check on my own?</p>

<p>This is that story.</p>

<h2 id="what-the-paper-is-about">What the paper is about</h2>

<p>I’m writing a manuscript on using LLMs for somatic variant interpretation. You find a change in a gene in tumor tissue and decide whether it drives the cancer. The answer determines which drug a patient gets, so this runs in hospitals.</p>

<p>Here’s the failure mode. Ask an LLM to draft a clinical report and the prose comes out fine. But a citation supporting a claim may point to a paper that doesn’t exist. From the manuscript:</p>

<blockquote>
  <p>In a clinical report, a fabricated reference is a patient-safety and medico-legal hazard, because the assertion it appears to support cannot be checked.</p>
</blockquote>

<p>So the system’s headline property isn’t accuracy. It’s <strong>faithfulness</strong>.</p>

<blockquote>
  <p>A usable decision-support draft must instead be auditable line by line and <strong>must abstain rather than fabricate.</strong></p>
</blockquote>

<p>Abstention means declining to answer when the evidence is thin. Like leaving a question blank instead of guessing. Your score doesn’t go up, but you don’t submit a wrong answer either.</p>

<p>The system does this. Given 10 variants with no supporting evidence at all, it <strong>abstained on all 10</strong>.</p>

<h2 id="the-manuscript-follows-the-same-rule">The manuscript follows the same rule</h2>

<p>The prose does it too. There are sentences throughout that decline to overclaim.</p>

<table>
  <thead>
    <tr>
      <th>Sentence in the manuscript</th>
      <th>What it concedes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">not claimed as a novel classifier</code></td>
      <td>The rule engine isn’t new work</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">remains uncontrolled</code></td>
      <td>An uncontrolled factor, stated as uncontrolled</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">not powered for an accuracy claim</code></td>
      <td>Sample too small to claim accuracy</td>
    </tr>
  </tbody>
</table>

<p>These sentences cost you. Writing “this isn’t novel” invites reviewers to score you down. They’re there because a system built on refusing to overclaim is worthless if its author overclaims.</p>

<h2 id="where-it-started-one-line-from-a-reviewer">Where it started: one line from a reviewer</h2>

<p>The manuscript has review-harness runs on record. The harness reads the draft like a journal referee and returns points and scores.</p>

<p>The second run gave reproducibility a <strong>perfect 5</strong>. The justification:</p>

<blockquote>
  <p>Offline-from-snapshots, 90 tests, scripts named per result; <strong>spot-checked</strong> headline numbers reconcile with committed JSONs.</p>
</blockquote>

<p>The first half is good news. It runs offline from stored snapshots, there are 90 tests, and every result names the script that produced it.</p>

<p>The last clause is what caught me. <strong>Spot-checked</strong> — a few headline numbers were sampled and found to match.</p>

<p>And there was the picture. <strong>Telling students to leave the blank blank, and never checking whether you did it on your own answer sheet.</strong></p>

<h2 id="what-i-built">What I built</h2>

<p>A checker that reconciles every number in the manuscript against committed result files. Not a sample. All of them.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>extract every number from the manuscript
        ↓
extract every number from the committed results
        ↓
look each manuscript number up in that pool
        ↓
report only the ones with no match
</code></pre></div></div>

<p>The comparison set is 20 committed files: 16 benchmark results and 4 cohort descriptors. Committed means the version is pinned, so the same file can be reopened later.</p>

<p>Two adjustments to keep it fair. Rounding counts as a match, so a source value of 0.8432 matches 0.843 in the text. And conventional constants like 0.05 are excluded, since a significance threshold has no business being in a results file.</p>

<h2 id="results">Results</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Unique numbers in manuscript   120
  traceable                     93 (78%)
  no source found               27 (22%)
</code></pre></div></div>

<p>Those 27 appear <strong>41 times</strong> in the text.</p>

<h2 id="what-the-27-are">What the 27 are</h2>

<p>Careful here. <strong>It does not mean 27 numbers are wrong.</strong> Opening them one by one, they fall into three groups.</p>

<table>
  <thead>
    <tr>
      <th>Group</th>
      <th>Count</th>
      <th>Examples</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Performance metrics (derived)</td>
      <td>21</td>
      <td>0.443, 0.671, 0.714</td>
    </tr>
    <tr>
      <td>Percentages computed in prose</td>
      <td>5</td>
      <td>21.4, 25.0, 58.9</td>
    </tr>
    <tr>
      <td>Sample size</td>
      <td>1</td>
      <td>n = 56</td>
    </tr>
  </tbody>
</table>

<p>The <strong>21 metrics</strong> are computed from raw data. Accuracy is correct-over-total, so of course it isn’t sitting in a results file in that form. The real problem is elsewhere: <strong>where that computation happened isn’t recorded</strong>, not in the manuscript and not in the repository.</p>

<p>The <strong>5 percentages</strong> bother me more. The value 21.4 appears five times, and you can’t tell from the text what was divided by what. A ratio without a denominator can’t be sized. 21 out of 100 and 3 out of 14 are both 21.4%, and they don’t mean the same thing.</p>

<h2 id="a-human-referee-and-a-machine-landed-on-the-same-spot">A human referee and a machine landed on the same spot</h2>

<p>The first review raised five must-fix points. Two of them were exactly here.</p>

<table>
  <thead>
    <tr>
      <th>What the referee found by reading</th>
      <th>What the checker found by counting</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Attach a confidence interval to every figure</td>
      <td>21 metrics carry no interval</td>
    </tr>
    <tr>
      <td>State the direction of the provisional adjudication</td>
      <td>21.4 appears five times with no denominator</td>
    </tr>
  </tbody>
</table>

<p>A confidence interval says roughly where the true value sits. Written bare, 0.843 looks precise; with a small sample the honest range might be 0.76 to 0.93.</p>

<p><strong>One found it by reading, the other by counting.</strong> Completely different methods, same conclusion.</p>

<h2 id="what-i-learned">What I learned</h2>

<p><strong>One: the abstention rule went into two places and skipped a third.</strong></p>

<table>
  <thead>
    <tr>
      <th>Where</th>
      <th>When evidence is missing</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>The system’s variant calls</td>
      <td>it abstains</td>
    </tr>
    <tr>
      <td>The manuscript’s claims about itself</td>
      <td>it concedes</td>
    </tr>
    <tr>
      <td><strong>The manuscript’s numbers</strong></td>
      <td><strong>they just sit there, unmarked</strong></td>
    </tr>
  </tbody>
</table>

<p>Why did numbers get skipped? <strong>Because numbers look sourced.</strong> Three decimal places reads as precisely computed. You interrogate a sentence; you rarely interrogate a figure. I suspect that’s also why a referee awarded full marks for reproducibility after checking a sample.</p>

<p><strong>A format that doesn’t invite suspicion passes review.</strong></p>

<p><strong>Two: 22% is not an error rate. It’s a traceability-failure rate.</strong></p>

<p>It doesn’t mean 27 numbers are wrong. It means there’s no path to confirm they’re right. Blur those two and you get “my paper has a 22% error rate,” which is false.</p>

<p>This is the trap in building a checker. The program distinguishes found from not-found. What “not found” <em>means</em> is not something the program decides. <strong>The meaning of a checker’s verdict has to be defined by whoever built it.</strong></p>

<p><strong>Three: a rule appears only where you felt you needed one.</strong></p>

<p>A fabricated citation becoming a patient-safety problem felt urgent. So that place got an abstention mechanism. The provenance of a number in my own paper never felt that urgent, so it got nothing. Writing a principle down doesn’t make it travel to the next room.</p>

<h2 id="where-this-leaves-me">Where this leaves me</h2>

<p>After two weeks, my original question has changed.</p>

<p><strong>Review isn’t the machinery that keeps an AI from being wrong. It’s the machinery that decides in advance what gets rejected automatically, what gets compared against a known answer, and what gets flagged as unknown.</strong></p>

<p>The third column is the one most often left empty, because marking something unknown makes your numbers look worse.</p>

<h2 id="next">Next</h2>

<ul>
  <li>Write the <strong>computation scripts</strong> for the 21 metrics. Right now there are values without a process.</li>
  <li>Attach <strong>denominators</strong> to the percentages: <code class="language-plaintext highlighter-rouge">21.4% (12/56)</code>, not <code class="language-plaintext highlighter-rouge">21.4%</code>.</li>
  <li>Add <strong>abstention marks to the manuscript</strong> itself. If a number’s derivation isn’t documented yet, say so.</li>
</ul>

<p>The checker is committed to the repository so it can be rerun. Each time I revise, I can watch whether 27 goes down.</p>

<p>The paper is unpublished, so no scientific results appear in this post. What’s here is the review process only.</p>]]></content><author><name>Ka-Kyung Kim</name></author><category term="AI &amp; Tooling" /><category term="Claude Code" /><category term="AI Agents" /><category term="Reproducibility" /><category term="Manuscript Review" /><category term="Harness" /><category term="GPTers" /><summary type="html"><![CDATA[I reconciled all 120 numbers in my manuscript against committed results. For 27 of them I couldn't trace where the value came from.]]></summary></entry><entry xml:lang="kr"><title type="html">지어내지 말라고 만든 시스템의 논문을, 그 규칙으로 검사했습니다</title><link href="https://kakyungkim.github.io/kr/2026/08/06/checking-my-own-manuscript/" rel="alternate" type="text/html" title="지어내지 말라고 만든 시스템의 논문을, 그 규칙으로 검사했습니다" /><published>2026-08-06T00:00:00+00:00</published><updated>2026-08-06T00:00:00+00:00</updated><id>https://kakyungkim.github.io/kr/2026/08/06/checking-my-own-manuscript</id><content type="html" xml:base="https://kakyungkim.github.io/kr/2026/08/06/checking-my-own-manuscript/"><![CDATA[<p class="lang-switch" style="margin-bottom:1.5em">
  
  <a href="/en/2026/08/06/checking-my-own-manuscript/" class="btn btn--primary btn--small">🇺🇸 Read this post in English</a>
  
</p>

<p><a href="/kr/2026/08/05/remeasuring-a-papers-claim/">앞선 글</a>에서 남의 논문이 내놓은 숫자를 재봤습니다. 그러면서 질문이 하나 생겼습니다. 남의 숫자를 재보는 방법을 익혔으면 내 숫자도 같은 방법으로 재봐야 하지 않을까.</p>

<p>이번 글은 그 이야기입니다.</p>

<h2 id="이-논문이-다루는-것">이 논문이 다루는 것</h2>

<p>제가 쓰고 있는 논문은 유전자 변이 해석에 AI를 쓸 때 생기는 문제를 다룹니다. 암 조직에서 유전자에 생긴 변화를 찾아 그것이 암을 일으키는 변화인지 판정하는 일인데, 판정에 따라 어떤 약을 쓸지가 달라지므로 병원에서 실제로 쓰입니다.</p>

<p>문제는 이렇습니다. 임상 보고서 초안을 AI에게 맡기면 문장은 잘 씁니다. 그런데 근거로 붙인 인용이 실재하지 않는 논문일 수 있습니다. 원고에 이런 문장이 있습니다.</p>

<blockquote>
  <p>In a clinical report, a fabricated reference is a patient-safety and medico-legal hazard, because the assertion it appears to support cannot be checked.</p>
</blockquote>

<p>임상 보고서에서 지어낸 인용은 환자 안전 문제이자 법적 문제라는 뜻입니다. 그 인용이 뒷받침하는 것처럼 보이는 주장을 확인할 방법이 없기 때문입니다.</p>

<p>그래서 이 시스템은 성능을 정확도가 아니라 <strong>정직성</strong>으로 잡았습니다.</p>

<blockquote>
  <p>A usable decision-support draft must instead be auditable line by line and <strong>must abstain rather than fabricate.</strong></p>
</blockquote>

<p>한 줄씩 감사할 수 있어야 하고, 지어내느니 기권해야 한다는 뜻입니다. 기권은 근거가 부족하면 판정을 내리지 않고 물러나는 동작입니다. 시험에서 모르는 문제를 찍지 않고 비워 두는 것과 같습니다. 정답률은 안 오르지만 틀린 답을 제출하지도 않습니다.</p>

<p>실제로 그렇게 만들었습니다. 근거 문서가 아예 없는 변이 10건을 넣었더니 시스템이 <strong>10건 전부 판단 보류</strong>로 처리했습니다.</p>

<h2 id="원고도-같은-태도로-썼습니다">원고도 같은 태도로 썼습니다</h2>

<p>논문 본문 자체도 같은 규칙을 따랐습니다. 자기 성과를 부풀리지 않으려는 문장이 곳곳에 있습니다.</p>

<table>
  <thead>
    <tr>
      <th>원고의 문장</th>
      <th>뜻</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">not claimed as a novel classifier</code></td>
      <td>규칙 엔진 부분은 새로 만든 것이 아니라고 못 박음</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">remains uncontrolled</code></td>
      <td>통제하지 못한 요인을 통제 못 했다고 그대로 씀</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">not powered for an accuracy claim</code></td>
      <td>표본이 작아 정확도를 주장할 수 없다고 미리 밝힘</td>
    </tr>
  </tbody>
</table>

<p>논문에서 이런 문장은 손해입니다. 새롭지 않다고 스스로 적으면 심사에서 점수가 깎일 수 있습니다. 그런데도 적은 이유는, 시스템에 넣은 규칙을 글쓴이가 어기면 그 시스템을 믿을 이유가 없어지기 때문입니다.</p>

<h2 id="출발점-리뷰어가-남긴-한-문장">출발점: 리뷰어가 남긴 한 문장</h2>

<p>이 원고에는 리뷰 하네스를 돌린 기록이 있습니다. 원고를 학술지 심사자처럼 읽고 지적 사항과 점수를 내놓는 장치입니다.</p>

<p>2회차 리뷰가 재현성 항목에 <strong>5점 만점</strong>을 줬습니다. 근거는 이랬습니다.</p>

<blockquote>
  <p>Offline-from-snapshots, 90 tests, scripts named per result; <strong>spot-checked</strong> headline numbers reconcile with committed JSONs.</p>
</blockquote>

<p>앞부분은 좋은 이야기입니다. 인터넷 없이 저장된 자료만으로 돌아가고, 시험 코드가 90개 있고, 결과마다 어떤 스크립트가 만들었는지 이름이 붙어 있다는 뜻입니다.</p>

<p>걸린 대목은 마지막입니다. <strong>spot-checked</strong>, 대표 수치 몇 개를 표본으로 확인했더니 저장된 결과 파일과 맞더라는 것입니다.</p>

<p>여기서 장면 하나가 겹쳤습니다. <strong>모르는 문제를 비워 두라고 가르쳐 놓고, 정작 자기 답안지는 그렇게 썼는지 확인해 본 적이 없는 상황입니다.</strong></p>

<h2 id="무엇을-만들었나">무엇을 만들었나</h2>

<p>원고의 모든 숫자를 저장된 결과 파일과 대조하는 검사기를 만들었습니다. 표본이 아니라 전수입니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>원고에서 숫자를 전부 뽑는다
        ↓
저장된 결과 파일에서도 숫자를 전부 뽑는다
        ↓
원고의 숫자가 결과 파일에 있는지 하나씩 찾는다
        ↓
못 찾은 것만 따로 모아 보고한다
</code></pre></div></div>

<p>대조 대상은 저장소에 커밋해 둔 결과 파일입니다. 벤치마크 16개와 코호트 정보 4개, 합쳐서 20개입니다. 커밋되어 있다는 것은 시점이 고정되어 나중에 같은 파일을 다시 열 수 있다는 뜻입니다.</p>

<p>공정하게 재려고 두 가지를 조정했습니다. 원본이 0.8432인데 원고에 0.843으로 적혔으면 <strong>반올림을 인정</strong>했고, 0.05처럼 통계에서 관례로 쓰는 값은 <strong>대조 대상에서 뺐습니다.</strong></p>

<h2 id="결과">결과</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>원고 고유 수치      120개
  근거 있음         93개 (78%)
  근거 못 찾음      27개 (22%)
</code></pre></div></div>

<p>못 찾은 27개는 본문에 <strong>41회</strong> 등장합니다.</p>

<h2 id="27개가-무엇인가">27개가 무엇인가</h2>

<p>조심해야 할 지점입니다. <strong>27개가 틀렸다는 뜻이 아닙니다.</strong> 하나씩 열어 보니 세 갈래였습니다.</p>

<table>
  <thead>
    <tr>
      <th>갈래</th>
      <th>개수</th>
      <th>예</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>성능 지표(계산해서 나온 값)</td>
      <td>21개</td>
      <td>0.443, 0.671, 0.714</td>
    </tr>
    <tr>
      <td>본문에서 계산한 퍼센트</td>
      <td>5개</td>
      <td>21.4, 25.0, 58.9</td>
    </tr>
    <tr>
      <td>표본 수</td>
      <td>1개</td>
      <td>n = 56</td>
    </tr>
  </tbody>
</table>

<p><strong>성능 지표 21개</strong>는 원자료를 가공해 얻은 값입니다. 정확도는 맞힌 개수를 전체로 나눠 계산하니 결과 파일에 그 형태로 저장되어 있지 않은 것이 자연스럽습니다. 문제는 다른 데 있습니다. <strong>그 계산을 어디서 했는지가 원고에도 저장소에도 안 적혀 있습니다.</strong></p>

<p><strong>퍼센트 5개</strong>가 더 걸립니다. 21.4라는 값은 본문에 다섯 번 나오는데, 무엇을 무엇으로 나눈 값인지 알 수 없습니다. 분모가 없는 비율은 크기를 가늠할 수 없습니다. 100건 중 21건과 14건 중 3건은 같은 21.4%지만 무게가 다릅니다.</p>

<h2 id="사람-심사자와-기계-검사가-같은-곳을-짚었습니다">사람 심사자와 기계 검사가 같은 곳을 짚었습니다</h2>

<p>1회차 리뷰에서 반드시 고치라고 한 지적이 다섯 개 있었습니다. 그중 둘이 정확히 이 자리였습니다.</p>

<table>
  <thead>
    <tr>
      <th>심사자가 읽고 지적한 것</th>
      <th>검사기가 세어 잡은 것</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>수치마다 신뢰구간을 붙이라</td>
      <td>성능 지표 21개에 구간이 없음</td>
    </tr>
    <tr>
      <td>잠정 판정의 방향을 밝히라</td>
      <td>21.4가 다섯 번 나오는데 분모가 없음</td>
    </tr>
  </tbody>
</table>

<p>신뢰구간은 이 값이 어느 범위에 있을 것 같은지를 나타내는 표기입니다. 0.843이라고만 쓰면 정밀해 보이지만, 표본이 작으면 실제로는 0.76에서 0.93 사이 어딘가일 수 있습니다.</p>

<p><strong>한쪽은 읽어서 찾았고 다른 쪽은 세어서 찾았습니다.</strong> 방법이 전혀 다른데 결론이 겹쳤습니다.</p>

<h2 id="배운-것">배운 것</h2>

<p><strong>하나, 기권 장치를 두 군데는 넣고 한 군데는 안 넣었습니다.</strong></p>

<table>
  <thead>
    <tr>
      <th>대상</th>
      <th>근거가 없을 때</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>시스템의 변이 판정</td>
      <td>기권한다</td>
    </tr>
    <tr>
      <td>원고의 자기 주장</td>
      <td>못 박는다</td>
    </tr>
    <tr>
      <td><strong>원고의 수치</strong></td>
      <td><strong>아무 표시 없이 그냥 적힌다</strong></td>
    </tr>
  </tbody>
</table>

<p>왜 숫자만 빠졌는지 생각해 봤습니다. <strong>숫자는 근거가 있어 보이기 때문입니다.</strong> 소수점 세 자리까지 적혀 있으면 어딘가에서 정확히 계산된 것처럼 읽힙니다. 문장은 정말인가 하고 의심하게 되는데, 숫자는 그런 의심을 잘 안 받습니다. 심사자가 재현성에 만점을 주면서 표본 확인으로 끝낸 것도 같은 이유로 보입니다.</p>

<p><strong>의심받지 않는 형식이 검수를 통과시킵니다.</strong></p>

<p><strong>둘, 22%는 오류율이 아니라 추적 실패율입니다.</strong></p>

<p>27개가 틀렸다는 것이 아니라 맞는지 확인할 경로가 없다는 뜻입니다. 이 둘을 섞으면 “내 논문에 오류가 22% 있다”는 잘못된 문장이 만들어집니다.</p>

<p>검사기를 만들 때 놓치기 쉬운 지점이 여기입니다. 프로그램은 찾았다와 못 찾았다만 구분합니다. 그 못 찾았다가 무엇을 뜻하는지는 프로그램이 정하지 않습니다. <strong>검사기가 내놓는 판정의 의미는 만든 사람이 정의해야 합니다.</strong></p>

<p><strong>셋, 규칙은 그것이 필요하다고 느낀 자리에만 생깁니다.</strong></p>

<p>지어낸 인용이 환자 안전 문제가 된다는 것은 절실했습니다. 그래서 그 자리에는 기권 장치를 넣었습니다. 논문 수치의 출처는 그만큼 절실하게 느껴지지 않았고, 그래서 장치가 없었습니다. 원칙을 만들어 두었다고 해서 그 원칙이 저절로 다른 자리까지 가지는 않습니다.</p>

<h2 id="출발점">출발점</h2>

<p>두 주를 지나고 보니 처음 질문이 바뀌었습니다.</p>

<p><strong>검수는 AI가 틀리지 않게 만드는 장치가 아니라, 무엇을 자동으로 거절하고 무엇을 정답과 대조하며 무엇을 모른다고 표시할지 미리 정하는 장치였습니다.</strong></p>

<p>그리고 그 세 번째 칸이 제일 자주 비어 있습니다. 모른다고 표시하는 것은 성능을 깎아 보이게 만들기 때문입니다.</p>

<h2 id="다음">다음</h2>

<ul>
  <li>성능 지표 21개의 <strong>계산 스크립트를 만듭니다.</strong> 지금은 값만 있고 과정이 없습니다.</li>
  <li>퍼센트에 <strong>분모를 붙입니다.</strong> <code class="language-plaintext highlighter-rouge">21.4%</code>가 아니라 <code class="language-plaintext highlighter-rouge">21.4%(12/56)</code>로 씁니다.</li>
  <li>원고에도 <strong>기권 표시를 넣습니다.</strong> 계산 근거가 아직 없는 수치는 그렇다고 적습니다.</li>
</ul>

<p>검사기는 다시 돌릴 수 있게 저장소에 넣어 뒀습니다. 원고를 고칠 때마다 27이 줄어드는지 확인하면 됩니다.</p>

<p>논문은 아직 발표 전이라 연구 결과 자체는 이 글에 담지 않았습니다. 여기 적은 것은 검수 과정에 관한 사실뿐입니다.</p>]]></content><author><name>Ka-Kyung Kim</name></author><category term="AI &amp; Tooling" /><category term="Claude Code" /><category term="AI Agents" /><category term="재현성" /><category term="논문검수" /><category term="하네스" /><category term="GPTers" /><summary type="html"><![CDATA[원고에 적힌 숫자 120개를 저장된 실험 결과와 대조했습니다. 27개는 어디서 나온 값인지 추적할 수 없었습니다.]]></summary></entry><entry xml:lang="en"><title type="html">I Re-measured a Paper’s Own Number</title><link href="https://kakyungkim.github.io/en/2026/08/05/remeasuring-a-papers-claim/" rel="alternate" type="text/html" title="I Re-measured a Paper’s Own Number" /><published>2026-08-05T00:00:00+00:00</published><updated>2026-08-05T00:00:00+00:00</updated><id>https://kakyungkim.github.io/en/2026/08/05/remeasuring-a-papers-claim</id><content type="html" xml:base="https://kakyungkim.github.io/en/2026/08/05/remeasuring-a-papers-claim/"><![CDATA[<p class="lang-switch" style="margin-bottom:1.5em">
  
  <a href="/kr/2026/08/05/remeasuring-a-papers-claim/" class="btn btn--primary btn--small">🇰🇷 이 글 한국어로 보기</a>
  
</p>

<p>I’m in a GPTers study group on reviewing AI output. Here’s what I did in week one: I borrowed someone else’s tool wholesale, and used the time it saved to re-measure a number another paper had published.</p>

<h2 id="the-problem">The problem</h2>

<p>Since 2025 there’s been a flood of “AI does science on its own” papers. Co-Scientist, The AI Scientist, AI-Researcher. From the titles they look interchangeable. Open them and they do quite different things: one generates hypotheses, one writes code, one drafts manuscripts.</p>

<p>I kept reading them and kept forgetting them. Finish one, start the next, and the first one blurs.</p>

<p>One sentence in particular stuck with me: nine domain experts had evaluated the AI-generated hypotheses. So what happens if you put an LLM in one of those nine chairs? That’s a question public data can answer.</p>

<h2 id="not-starting-from-scratch">Not starting from scratch</h2>

<p>The backbone here isn’t mine. I took <code class="language-plaintext highlighter-rouge">research-survey</code>, a Claude Code plugin published by the study lead, and built on it.</p>

<p>It runs five stages:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>topic → extract papers → summarize → triple-verify → insights/hypotheses → keep tracking
</code></pre></div></div>

<p>The third stage is the interesting one. <strong>Triple-verify</strong> checks the summary against the source three different ways. The most common failure when an LLM summarizes a paper is inventing something plausible that isn’t in the text, and that stage is built to block it.</p>

<p>Building this myself would have meant days on the fetcher, the classifier, and the evidence-tracking rules. Borrowing it freed all of that, and I spent the freed time <strong>testing the paper’s claim</strong>.</p>

<h2 id="what-i-did">What I did</h2>

<p>Four steps.</p>

<p><strong>One, build the corpus.</strong> Pull related work from arXiv, sort into two categories. Each refresh added more; 25 became 57.</p>

<p><strong>Two, turn the top seven into notes.</strong> One rule: nothing goes in without a source. An LLM summary reads smoothly, which is exactly the problem — smooth prose is hard to audit. So every claim had to carry a page or figure number.</p>

<p>This is where the baseline came from. The paper’s appendix records nine board-certified hematologists and oncologists <strong>split into two groups</strong>, scoring 78 hypotheses, with <strong>agreement between the two groups at Spearman ρ = 0.745</strong> (p &lt; 0.001).</p>

<p>Worth unpacking. At 1 the two groups ranked everything identically; at 0 they were unrelated. So 0.745 is strong but imperfect. <strong>The key point is that this is a ceiling.</strong> If humans only agree with each other at 0.745, an LLM in the same seat can’t meaningfully exceed it.</p>

<p>One caveat worth stating: this is agreement <em>between groups</em>, not between individuals. And the paper does not say <strong>how the nine raters were split, nor how scores were combined within a group</strong> — not the sizes, not the basis for the split, not whether both groups rated all 78 hypotheses. That matters. Averaging within a group cancels individual noise and pushes the figure up; consensus pushes it up further; splitting the 78 between groups would mean the correlation was computed on an overlap of unknown size. <strong>Whether 0.745 can serve as a ceiling depends on which of these it was.</strong> I use it as a reference point, not as a settled ceiling.</p>

<p><strong>Three, put the LLM in the judge’s chair.</strong> It scored hypotheses on five criteria: novelty, feasibility, specificity, non-triviality, grounding. The subjects were eight drugs evaluated for repurposing in acute myeloid leukemia, and I compared the scores against the wet-lab results in the paper.</p>

<table>
  <thead>
    <tr>
      <th>Comparison</th>
      <th>n</th>
      <th>Spearman ρ</th>
      <th>p</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>LLM scores vs wet-lab (binary)</td>
      <td>8</td>
      <td>0.447</td>
      <td>0.267</td>
    </tr>
    <tr>
      <td>LLM scores vs wet-lab (continuous)</td>
      <td>11</td>
      <td>0.642</td>
      <td>0.033</td>
    </tr>
    <tr>
      <td>Between the two expert groups</td>
      <td>78</td>
      <td>0.745</td>
      <td>&lt; 0.001</td>
    </tr>
  </tbody>
</table>

<p>I missed my 0.70 target. But 0.642 is <strong>86% of the human ceiling</strong>.</p>

<p><strong>Four, check the gap the paper claimed.</strong> The same paper argued that public databases hold almost no negative results. I searched PLOS and PubMed six different ways.</p>

<table>
  <thead>
    <tr>
      <th>Source</th>
      <th>Query</th>
      <th>Hits</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>PLOS</td>
      <td><code class="language-plaintext highlighter-rouge">drug repurposing</code> + <code class="language-plaintext highlighter-rouge">negative result</code></td>
      <td>248 (raw)</td>
    </tr>
    <tr>
      <td>PLOS</td>
      <td>strict filter (repurposing proper)</td>
      <td>~30</td>
    </tr>
    <tr>
      <td>PubMed</td>
      <td><code class="language-plaintext highlighter-rouge">"Negative Results"[pt] AND "Drug Repositioning"[MeSH]</code></td>
      <td><strong>0</strong></td>
    </tr>
    <tr>
      <td>PubMed</td>
      <td><code class="language-plaintext highlighter-rouge">"drug repurposing"[tiab] AND (negative result*)</code></td>
      <td>68</td>
    </tr>
  </tbody>
</table>

<p>Together that’s roughly <strong>50 to 60</strong> strict negative-result papers, which just clears the target. It cleared, but not easily. It took six separate queries, and <strong>the standard classification field returned zero</strong>. The publication type “Negative Results” exists in PubMed, and almost nobody tags anything with it. The collection process itself demonstrated the gap the paper described.</p>

<h2 id="what-i-learned">What I learned</h2>

<p><strong>One: of five criteria, one was doing the work.</strong></p>

<p>I examined the rubric itself to see which dimensions actually tracked the experimental outcome.</p>

<table>
  <thead>
    <tr>
      <th>Criterion</th>
      <th>r_pb</th>
      <th>p</th>
      <th>Reading</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Grounding</strong></td>
      <td><strong>0.707</strong></td>
      <td><strong>0.050</strong></td>
      <td>the only significant one</td>
    </tr>
    <tr>
      <td>Specificity</td>
      <td>0.500</td>
      <td>0.207</td>
      <td>right direction</td>
    </tr>
    <tr>
      <td>Non-triviality</td>
      <td>0.302</td>
      <td>0.468</td>
      <td>right direction</td>
    </tr>
    <tr>
      <td>Novelty</td>
      <td><strong>0.000</strong></td>
      <td>1.000</td>
      <td><strong>no discrimination at all</strong></td>
    </tr>
    <tr>
      <td>Feasibility</td>
      <td><strong>-0.146</strong></td>
      <td>0.730</td>
      <td><strong>runs backwards</strong></td>
    </tr>
  </tbody>
</table>

<p>Hypotheses with solid literature support also worked in the lab. Feasibility ran backwards: drugs withdrawn from market score low on feasibility, but withdrawal is often about side effects or economics rather than efficacy, so they can still work in a dish.</p>

<p><strong>I split the scorecard into five columns and one of them decided the verdict.</strong> The other four create a sense of thoroughness without explaining anything.</p>

<p><strong>Two: reading a low number takes care.</strong></p>

<p>Read the table alone and it’s simple. 0.642 missed the target, so LLMs can’t replace experts yet.</p>

<p>Read the design and it changes. In the original paper, the experts <strong>pre-filtered the obviously bad hypotheses</strong> before scoring. Everything left was already decent.</p>

<p>Put it in grading terms. Score a whole class and first and last are far apart, so two graders agree easily. Score only the top ten and the gaps are small, so the rankings wobble. Not because the graders are bad, but because the range narrowed. Statisticians call this range restriction.</p>

<p><strong>A low measurement and a low capability are not the same thing.</strong> Miss that distinction and you take the number as the conclusion.</p>

<p><strong>Three: borrowing a tool buys time for the question.</strong></p>

<p>Had I built the survey pipeline myself, I’d never have reached the experiment. Building tools and asking questions with tools are different jobs, and this time the second one was the point.</p>

<h2 id="where-this-started">Where this started</h2>

<p>When I signed up, my question was how to trust what an AI produces. After week one I had a second one. <strong>If I’ve learned how to re-measure someone else’s number, shouldn’t I run the same check on my own?</strong></p>

<h2 id="next">Next</h2>

<ul>
  <li>I plan to ask the original authors for the full appendix data. With all 78 expert scores I could rerun the experiment properly instead of on a sample of eight. The email is drafted but not yet sent.</li>
  <li>I plan to run three different models as independent judges on a fixed rubric and measure how much they agree, to check whether one model’s quirks are driving the result.</li>
</ul>

<p><a href="/en/2026/08/06/checking-my-own-manuscript/">The next post</a> covers what happened when I ran this on <strong>my own manuscript</strong>. In a paper about building a system that refuses to fabricate evidence, I found 27 numbers whose evidence I couldn’t trace.</p>

<hr />

<p><strong>References</strong></p>

<ul>
  <li>Gottweis et al. <em>Accelerating scientific discovery with Co-Scientist</em>, arXiv:2502.18864</li>
  <li>Bisht et al. <em>Agentic AI Scientists Are Not Built For Autonomous Scientific Discovery</em>, arXiv:2605.08956</li>
</ul>]]></content><author><name>Ka-Kyung Kim</name></author><category term="AI &amp; Tooling" /><category term="Claude Code" /><category term="AI Agents" /><category term="Literature Survey" /><category term="Research Automation" /><category term="GPTers" /><summary type="html"><![CDATA[Can an LLM stand in for an expert judge? I tested it on public data, missed the target, and found the reason wasn't the model.]]></summary></entry><entry xml:lang="kr"><title type="html">논문이 내놓은 숫자를 직접 재봤습니다</title><link href="https://kakyungkim.github.io/kr/2026/08/05/remeasuring-a-papers-claim/" rel="alternate" type="text/html" title="논문이 내놓은 숫자를 직접 재봤습니다" /><published>2026-08-05T00:00:00+00:00</published><updated>2026-08-05T00:00:00+00:00</updated><id>https://kakyungkim.github.io/kr/2026/08/05/remeasuring-a-papers-claim</id><content type="html" xml:base="https://kakyungkim.github.io/kr/2026/08/05/remeasuring-a-papers-claim/"><![CDATA[<p class="lang-switch" style="margin-bottom:1.5em">
  
  <a href="/en/2026/08/05/remeasuring-a-papers-claim/" class="btn btn--primary btn--small">🇺🇸 Read this post in English</a>
  
</p>

<p>GPTers 23기 “AI 결과물 검수” 스터디에 참여하고 있습니다. 1주차에 한 일을 정리했습니다. 남이 만든 도구를 그대로 얹고, 그 위에서 남의 논문이 내놓은 숫자를 다시 쟀습니다.</p>

<h2 id="문제">문제</h2>

<p>2025년 이후 “AI가 스스로 연구를 한다”는 논문이 쏟아졌습니다. Co-Scientist, The AI Scientist, AI-Researcher 같은 이름들입니다. 제목만 보면 다 같은 이야기 같은데, 열어 보면 하는 일이 다릅니다. 어떤 것은 가설을 만들고, 어떤 것은 코드를 짜고, 어떤 것은 논문 초안을 씁니다.</p>

<p>읽기는 읽는데 머릿속에 안 남았습니다. 한 편을 읽고 다음으로 넘어가면 앞 편이 흐려졌습니다.</p>

<p>특히 한 논문의 문장이 걸렸습니다. “AI가 만든 가설을 전문가 아홉 명이 평가했다”는 대목이었습니다. 그렇다면 그 전문가 자리에 AI를 앉히면 어떻게 되는가. 공개된 데이터로 확인할 수 있는 질문이었습니다.</p>

<h2 id="맨바닥에서-시작하지-않기">맨바닥에서 시작하지 않기</h2>

<p>이번 작업의 뼈대는 제가 만든 것이 아닙니다. 스터디장이 공개한 <code class="language-plaintext highlighter-rouge">research-survey</code>라는 Claude Code 플러그인을 그대로 얹었습니다.</p>

<p>이 도구가 하는 일은 다섯 단계입니다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>관심 주제 → 논문 추출 → 요약 → 삼중 검증 → 인사이트·가설 → 새 논문 추적
</code></pre></div></div>

<p>눈여겨볼 곳은 세 번째 칸입니다. <strong>삼중 검증</strong>은 요약이 원문과 어긋나지 않는지 세 겹으로 확인한다는 뜻입니다. AI가 논문을 요약할 때 가장 흔한 사고가 원문에 없는 내용을 그럴듯하게 지어내는 것인데, 그 자리를 막는 장치입니다.</p>

<p>직접 만들었다면 수집기부터 설계하고, 분류 규칙을 정하고, 근거를 어떻게 추적할지 정하느라 며칠을 썼을 것입니다. 얹었더니 그 시간이 통째로 남았고, 남은 시간을 <strong>논문의 주장을 재보는 실험</strong>에 썼습니다.</p>

<h2 id="어떻게-했나">어떻게 했나</h2>

<p>네 단계로 진행했습니다.</p>

<p><strong>첫째, 논문을 모았습니다.</strong> arXiv에서 관련 논문을 긁어와 두 갈래로 분류했습니다. 갱신 명령을 돌릴 때마다 새 논문이 붙어 25편에서 57편이 됐습니다.</p>

<p><strong>둘째, 핵심 7편을 노트로 옮겼습니다.</strong> 원칙을 하나만 걸었습니다. 출처 없는 내용은 한 줄도 넣지 않는다는 것입니다. AI에게 요약을 시키면 매끄러운 문장이 나오는데, 그 문장이 논문에 실제로 있는 말인지 확인하기 어렵습니다. 그래서 페이지 번호와 그림 번호를 반드시 달게 했습니다.</p>

<p>여기서 이후 실험의 기준선이 나왔습니다. 그 논문 부록에 혈액종양내과 전문의 아홉 명이 <strong>두 그룹으로 나뉘어</strong> 가설 78건을 채점한 기록이 있었고, <strong>두 그룹의 평가가 얼마나 일치하는지가 Spearman ρ = 0.745</strong> (p &lt; 0.001)였습니다.</p>

<p>이 값을 조금 풀어 쓸 필요가 있습니다. 1이면 두 그룹이 등수를 똑같이 매겼다는 뜻이고, 0이면 제각각이라는 뜻입니다. 0.745는 잘 맞는 편이지만 완벽하지 않습니다. <strong>중요한 것은 이 값이 상한선이라는 점입니다.</strong> 사람끼리도 0.745밖에 안 맞는 판에서 AI가 그보다 훨씬 높은 값을 낼 수는 없습니다.</p>

<p>다만 개인끼리가 아니라 <strong>그룹끼리의 일치도</strong>입니다. 그리고 논문을 뒤져도 <strong>아홉 명을 어떻게 두 그룹으로 나눴는지, 그룹 안에서 점수를 어떻게 합쳤는지가 안 나옵니다.</strong> 평균을 냈다면 개인의 잡음이 상쇄돼 값이 높아지고, 78건을 나눠 봤다면 겹치는 부분에서만 계산했을 텐데 그 개수를 알 수 없습니다. <strong>합치는 방식에 따라 이 값을 상한선으로 쓸 수 있는지가 갈립니다.</strong> 그래서 기준선으로는 쓰되 확정된 상한선으로 두지는 않았습니다.</p>

<p><strong>셋째, AI를 심판석에 앉혔습니다.</strong> 다섯 기준으로 가설을 채점하게 했습니다. 새로움, 실현 가능성, 구체성, 비자명성, 근거성입니다. 채점 대상은 급성 골수성 백혈병에 쓸 수 있는지 검토된 약 여덟 개였고, 논문에 실린 실제 실험 결과와 대 봤습니다.</p>

<table>
  <thead>
    <tr>
      <th>비교한 것</th>
      <th>n</th>
      <th>Spearman ρ</th>
      <th>p</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>AI 채점과 실험값 (두 갈래)</td>
      <td>8</td>
      <td>0.447</td>
      <td>0.267</td>
    </tr>
    <tr>
      <td>AI 채점과 실험값 (연속 척도)</td>
      <td>11</td>
      <td>0.642</td>
      <td>0.033</td>
    </tr>
    <tr>
      <td>전문가 두 그룹 사이</td>
      <td>78</td>
      <td>0.745</td>
      <td>&lt; 0.001</td>
    </tr>
  </tbody>
</table>

<p>목표로 잡은 0.70에는 못 미쳤습니다. 다만 0.642는 사람 상한선의 <strong>86%</strong>입니다.</p>

<p><strong>넷째, 논문이 말한 빈틈을 확인했습니다.</strong> 같은 논문이 공개 데이터베이스에 실패한 연구 기록이 거의 없다고 했습니다. 정말 없는지 PLOS와 PubMed를 여섯 갈래로 뒤졌습니다.</p>

<table>
  <thead>
    <tr>
      <th>경로</th>
      <th>검색식</th>
      <th>결과</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>PLOS</td>
      <td><code class="language-plaintext highlighter-rouge">drug repurposing</code> + <code class="language-plaintext highlighter-rouge">negative result</code></td>
      <td>248편 (원자료)</td>
    </tr>
    <tr>
      <td>PLOS</td>
      <td>엄밀 필터(약물 재배치 직접)</td>
      <td>약 30편</td>
    </tr>
    <tr>
      <td>PubMed</td>
      <td><code class="language-plaintext highlighter-rouge">"Negative Results"[pt] AND "Drug Repositioning"[MeSH]</code></td>
      <td><strong>0건</strong></td>
    </tr>
    <tr>
      <td>PubMed</td>
      <td><code class="language-plaintext highlighter-rouge">"drug repurposing"[tiab] AND (negative result*)</code></td>
      <td>68편</td>
    </tr>
  </tbody>
</table>

<p>합치면 엄밀한 실패 논문이 <strong>약 50~60편</strong>으로 목표 경계를 겨우 넘겼습니다. 채우기는 했는데 쉽게 채운 것이 아닙니다. 여섯 갈래로 나눠 긁어모아야 했고, <strong>표준 분류 항목은 아예 0건</strong>이었습니다. 문헌 종류에 “Negative Results”가 정의되어 있는데도 실제로 그 표시를 다는 사람이 거의 없다는 뜻입니다. 논문이 말한 빈틈이 실재한다는 것을 수집 과정 자체가 보여 주었습니다.</p>

<h2 id="배운-것">배운 것</h2>

<p><strong>하나, 다섯 기준 중 일하는 것은 하나였습니다.</strong></p>

<p>채점 기준 자체를 살펴봤습니다. 실제 실험 결과와 관계있는 것이 무엇인지 확인한 것입니다.</p>

<table>
  <thead>
    <tr>
      <th>차원</th>
      <th>r_pb</th>
      <th>p</th>
      <th>해석</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>근거성(Grounding)</strong></td>
      <td><strong>0.707</strong></td>
      <td><strong>0.050</strong></td>
      <td>유일하게 유의</td>
    </tr>
    <tr>
      <td>구체성(Specificity)</td>
      <td>0.500</td>
      <td>0.207</td>
      <td>방향은 맞음</td>
    </tr>
    <tr>
      <td>비자명성(Non-triviality)</td>
      <td>0.302</td>
      <td>0.468</td>
      <td>방향은 맞음</td>
    </tr>
    <tr>
      <td>새로움(Novelty)</td>
      <td><strong>0.000</strong></td>
      <td>1.000</td>
      <td><strong>변별력 없음</strong></td>
    </tr>
    <tr>
      <td>실현 가능성(Feasibility)</td>
      <td><strong>-0.146</strong></td>
      <td>0.730</td>
      <td><strong>역방향</strong></td>
    </tr>
  </tbody>
</table>

<p>문헌 근거가 탄탄한 가설이 실험실에서도 효과를 보였습니다. 그리고 실현 가능성은 오히려 반대 방향이었습니다. 시장에서 철수된 약은 실현 가능성 점수가 낮게 매겨지는데, 철수 사유가 약효 부족이 아니라 부작용이나 사업성인 경우가 많아 실험실에서는 잘 듣기도 합니다.</p>

<p><strong>채점표를 다섯 칸으로 나눴는데 판정을 가른 것은 한 칸이었습니다.</strong> 나머지 넷은 꼼꼼히 봤다는 느낌은 주지만 결과를 설명하지 않았습니다.</p>

<p><strong>둘, 낮은 숫자를 읽는 법이 따로 있습니다.</strong></p>

<p>표만 보면 결론은 간단합니다. 0.642는 목표에 못 미쳤으니 “AI는 아직 전문가를 대신할 수 없다”가 됩니다.</p>

<p>그런데 실험 설계를 다시 보면 다릅니다. 원논문에서 전문가들은 <strong>말이 안 되는 가설을 미리 걸러낸 뒤에</strong> 채점을 시작했습니다. 남은 가설은 전부 어느 정도 품질이 보장된 것들이었습니다.</p>

<p>채점 장면으로 옮기면 이렇습니다. 반 전체를 채점하면 1등과 꼴찌가 뚜렷이 갈리니 두 심판의 등수가 잘 맞습니다. 그런데 상위권 열 명만 남겨 놓고 채점하면 실력 차이가 작아 등수가 흔들립니다. 심판이 못해서가 아니라 대상의 폭이 좁아서입니다. 통계에서는 이를 범위 제한이라 부릅니다.</p>

<p><strong>측정값이 낮은 것과 능력이 낮은 것은 다릅니다.</strong> 이 구분을 못 하면 숫자를 그대로 결론으로 받게 됩니다.</p>

<p><strong>셋, 남의 도구를 얹으면 질문에 시간을 쓸 수 있습니다.</strong></p>

<p>조사 파이프라인을 직접 만들었다면 이 실험까지 가지 못했을 것입니다. 도구를 만드는 일과 도구로 무엇을 묻는 일은 다르고, 이번에는 뒤쪽이 목적이었습니다.</p>

<h2 id="출발점">출발점</h2>

<p>이 스터디를 신청할 때는 AI가 만든 결과물을 어떻게 믿을 것인가가 궁금했습니다. 1주차를 지나고 보니 질문이 하나 늘었습니다. <strong>남의 숫자를 재보는 방법을 익혔으면, 내 숫자도 같은 방법으로 재봐야 하지 않을까.</strong></p>

<h2 id="다음">다음</h2>

<ul>
  <li>원논문 저자에게 부록 전체 데이터를 요청할 계획입니다. 전문가 78건 채점 기록이 있으면 표본 8건짜리 실험을 제대로 다시 돌릴 수 있습니다. 메일 초안까지 써 두었고 아직 보내지 않았습니다.</li>
  <li>채점 AI를 하나만 쓰지 말고 셋을 독립으로 돌려 서로 얼마나 일치하는지 재 볼 계획입니다. 한 모델의 버릇이 결과를 좌우하지 않는지 확인하려 합니다.</li>
</ul>

<p><a href="/kr/2026/08/06/checking-my-own-manuscript/">다음 글</a>에서는 이 방법을 <strong>제 논문 원고에 적용한 이야기</strong>를 씁니다. 근거를 지어내지 말라고 만든 시스템의 논문에서, 근거를 추적할 수 없는 숫자를 27개 찾았습니다.</p>

<hr />

<p><strong>참고</strong></p>

<ul>
  <li>Gottweis et al. <em>Accelerating scientific discovery with Co-Scientist</em>, arXiv:2502.18864</li>
  <li>Bisht et al. <em>Agentic AI Scientists Are Not Built For Autonomous Scientific Discovery</em>, arXiv:2605.08956</li>
</ul>]]></content><author><name>Ka-Kyung Kim</name></author><category term="AI &amp; Tooling" /><category term="Claude Code" /><category term="AI Agents" /><category term="논문서베이" /><category term="연구자동화" /><category term="GPTers" /><summary type="html"><![CDATA[AI가 전문가 심판을 대신할 수 있는가. 공개 데이터로 재보니 목표치에 못 미쳤는데, 미달의 원인이 AI가 아니었습니다.]]></summary></entry><entry xml:lang="en"><title type="html">Beyond Biomedical Research, onto the AI Agent Stage: PseudoCon 2026</title><link href="https://kakyungkim.github.io/en/2026/07/27/pseudocon-2026/" rel="alternate" type="text/html" title="Beyond Biomedical Research, onto the AI Agent Stage: PseudoCon 2026" /><published>2026-07-27T00:00:00+00:00</published><updated>2026-07-27T00:00:00+00:00</updated><id>https://kakyungkim.github.io/en/2026/07/27/pseudocon-2026</id><content type="html" xml:base="https://kakyungkim.github.io/en/2026/07/27/pseudocon-2026/"><![CDATA[<p class="lang-switch" style="margin-bottom:1.5em">
  
  <a href="/kr/2026/07/27/pseudocon-2026/" class="btn btn--primary btn--small">🇰🇷 이 글 한국어로 보기</a>
  
</p>

<p>Hi, I’m Kakyung Kim, a data analyst at a biotech company.</p>

<p>On July 25, 2026, I presented at PseudoCon 2026 as part of the AutoBioX team. It was the first time we brought four months of research — two projects running in parallel — to a public stage. One on single-cell multiomics, one on pathology image analysis.</p>

<p>I’ve given a lot of presentations over the years: conferences, seminars, internal project reviews. But this one felt different. It was the first time I talked about the results of an AI agent research team I started myself, in front of an AI and tech community outside of biomedical circles. And more than anything, it wasn’t a presentation of polished results — it was a presentation that included failures and false starts, left in.</p>

<p>PseudoCon is the annual conference of PseudoLab (가짜연구소), a Korean AI and ML research community. This year marked the 10th edition, held at Sookmyung Women’s University with around 300 attendees. Sessions kept running over as audiences pulled speakers into extended Q&amp;A.</p>

<p><img src="/assets/images/pseudocon-2026/00_sookmyung.jpg" alt="Sookmyung Women's University, 100th Anniversary Hall" /></p>

<p><img src="/assets/images/pseudocon-2026/01_venue.jpg" alt="PseudoCon 2026 venue banner" /></p>

<p><img src="/assets/images/pseudocon-2026/02_badge.jpg" alt="Builder+Speaker badge" /></p>

<h2 id="the-days-sessions">The Day’s Sessions</h2>

<p>Looking back, what struck me most was how sessions from completely different domains converged on the same question: if AI handles execution, what should people be doing — and how do you deliberately design that boundary? Robotics researchers, a hiring platform founder, a biomedical team, agent platform developers — the framing varied, but the underlying tension was identical.</p>

<p><strong>Jinsoo Shin (KRAFTON)</strong> opened the 10th PseudoCon with a message about navigating uncertainty in the AI era not alone, but by staying connected and learning with others. The phrase “Planned Happenstance” threaded through the rest of the day — career-changing opportunities feel accidental, but they tend to find people who’ve been consistently in motion. Looking back, PseudoLab and AutoBioX were exactly that for me.</p>

<p><img src="/assets/images/pseudocon-2026/03_jinsoo_shin.jpg" alt="Jinsoo Shin (KRAFTON) — Opening" /></p>

<p><strong>Youngjeon Choi (AWS)</strong> gave the most systematic framing of the day. The shift from stateless (single request-response) to stateful (multi-step, persistent) AI is the defining transition of this period. He drew a clear line between soft guardrails (prompt-level instructions) and hard guardrails (system-level policy enforcement), arguing that agentic systems need both. The line that stayed with me: AI doesn’t replace people — it amplifies the best ones.</p>

<p><img src="/assets/images/pseudocon-2026/04_youngjeon_choi.jpg" alt="Youngjeon Choi (AWS) — Agentic AI: The Rise of Acting AI" /></p>

<p><strong>Jinha Lim (GroupBy HR)</strong> runs a hiring platform and has watched the job market shift in real time. The skill-checklist format is fading. At a hackathon with Musinsa, KakaoPay Securities, and Channel.talk, participants weren’t handed a problem — they were given data and told to find one. The scarce skill isn’t implementation; it’s problem definition. Her sharpest line: when AI gets something wrong, it apologizes. When a person makes a bad call that costs the company, someone is accountable. That accountability gap is where human judgment stays irreplaceable.</p>

<p><img src="/assets/images/pseudocon-2026/05_jinha_lim.jpg" alt="Jinha Lim (GroupBy HR) — What Companies Want in the AI Era" /></p>

<p><strong>Yuseek Yang (SK Telecom)</strong> compressed the Physical AI lineage into 15 minutes: RT1 → VLA → Open VLA, tracing where the bottlenecks moved and how each generation addressed them. Flow Matching cut denoising steps from around 40 to 4. He was also honest about his own project: 36% MSE reduction via Cosmos-based data augmentation, but the robot still can’t complete the task in real conditions.</p>

<p><img src="/assets/images/pseudocon-2026/06_yuseek_yang.jpg" alt="Yuseek Yang (SK Telecom) — Physical AI: From VLA to WAM" /></p>

<p><strong>Kenny Lee (RunPod)</strong> gave the day’s only English session. RunPod started with two GPUs in a basement; the pitch is 90% cost reduction versus traditional HPC. He walked through three tiers — Pod (virtualized GPU), Cluster (large-scale training), Serverless Endpoint (production deployment) — with a live demo. The company grew through Reddit word-of-mouth, no sales team.</p>

<p><img src="/assets/images/pseudocon-2026/07_kenny_lee.jpg" alt="Kenny Lee (RunPod)" /></p>

<p><strong>Junho Kong (SK On)</strong> walked through recent OpenAI updates in practice. GPT 5.6’s Sol, Terra, and Luna aren’t a performance ranking — they’re different tools for different contexts. He grounded Ultra mode’s parallel sub-agent execution, Sites, and Computer Use in concrete use cases. The framing shift he highlighted: from “how much code did Codex write” to “what can I actually ship with Codex.”</p>

<p><img src="/assets/images/pseudocon-2026/08_junho_kong.jpg" alt="Junho Kong (SK On) — OpenAI Codex Developer Update" /></p>

<p><strong>Soohyun Kim (HDC Labs)</strong> walked through the stumbles of attaching an A/B testing platform to the PseudoLab service. The key lesson: don’t start with the data, start with the question. Early weeks were spent looking for signals before locking down what success would even mean. She also brought real incidents to the stage: a 60-hour data outage in the first days of an experiment, a one-month bottleneck from PR merge to deployment. Her conclusion: an experiment platform alone isn’t enough — you need the full loop of deployment, monitoring, and incident recovery.</p>

<p><img src="/assets/images/pseudocon-2026/09_soohyun_kim.jpg" alt="Soohyun Kim (HDC Labs) — Making PseudoLab an Experiment-Ready Community" /></p>

<hr />

<h2 id="my-talk">My Talk</h2>

<p>I presented third in the afternoon block, with the title “Multi-Agent Research in the Wild: From Single-Cell to Pathology Images.”</p>

<p>This wasn’t a talk about what AI can do in biomedical research. It was closer to the opposite: what does it actually look like when AI gets attached to research — where does it work, where does it fail, and where does a person still have to step in?</p>

<p>I started with the known limitations of AI scientists. Reproducibility success rate of 1.8%, code failure rate of 40% — these numbers are already in the literature. AutoBioX tried to address them through a multi-agent structure: separate agents for planning, summarization, prediction, verification, and literature search, cross-checking each other. Humans focus on direction and final judgment; agents handle execution.</p>

<p><strong>The single-cell project</strong> was a chromatin multiomics study of human hematopoietic stem and progenitor cells. Our original target — a chromatin-to-transcription lag metric — came back at Spearman 0.04. Essentially zero. But a transcription velocity measure (α) that emerged through AI-assisted analysis held consistently at 0.82–0.88 across different methods. The signal we weren’t targeting turned out to be the more robust one.</p>

<p>What I consider the more important result isn’t that we found a new metric. It’s that we didn’t trust an untrustworthy result, and we were able to discard a failing hypothesis rather than rescue it. That discipline is itself a research output.</p>

<p><strong>The pathology imaging project</strong> predicted molecular markers (ER, PR, HER2, PAM50) from H&amp;E breast cancer whole-slide images. The picture was more complex than expected. Image-based prediction is sufficient for ER and PR. HER2 still needs molecular confirmation. PAM50 subtypes are predictable from images, but using those predictions directly in treatment decisions is a separate question. The key line from the talk: “‘We can predict it’ and ‘it can replace the existing test’ are entirely different claims.” What we built was closer to a treatment decision map — where AI can be used, where existing tests are still required, and where judgment should be withheld.</p>

<p>We kept numbers off the slides. The validation gate isn’t closed yet, so we stuck to methods and principles.</p>

<p><img src="/assets/images/pseudocon-2026/10a_autobiox_wide.jpg" alt="Presenting AutoBioX — full stage" /></p>

<p><img src="/assets/images/pseudocon-2026/10b_autobiox_intro.jpg" alt="Speaker intro slide" /></p>

<h2 id="we-put-failures-on-the-slides">We Put Failures on the Slides</h2>

<p>There was one deliberate choice about what not to hide: the failures and the false starts.</p>

<p>The initial metric failed. A GPU server had a physical hardware failure. A key team member left, leaving a gap in the workflow. Storage I/O bottlenecks meant expensive GPUs were sitting idle.</p>

<p>I think all of that is part of the research. In practice, results rarely come out clean. Knowing what failed is how you do better next time; knowing where the bottleneck was is how you fix the system. We audited before large tasks, automated repetitive work, routed around the storage bottleneck with SSDs, and kept redesigning the split between what agents handle and what people handle. Those failures turned into assets — automation and a clearer sense of where human judgment belongs.</p>

<p>If PseudoLab is a community where people put failures on stage to learn from them together, AutoBioX wanted to be part of that.</p>

<hr />

<p><strong>Minjoo Jwa (HF KREW)</strong> automated the Hugging Face English blog pipeline: translation, quality review, SEO, and PR review, all running as an agent loop. When a translation commit lands, SEO and quality skills run in parallel; their reports become PR comments; the PR agent reads the CI logs and decides whether to revise. GitHub PRs double as the agent’s state memory. The concept she introduced — “loop engineering” — is about designing how long and how many cycles to run, not just what to prompt.</p>

<p><img src="/assets/images/pseudocon-2026/11_minjoo_jwa.jpg" alt="Minjoo Jwa (HF KREW) — Hugging Face Blog Agent" /></p>

<p><strong>Chanran Kim (Pseudo Lab)</strong> — speaking as part of the organizing team — closed the main sessions with Betoken: “just as a token predicts what comes next, small contributions and connections can be early signs of growth.” Partnerships with NVIDIA, OpenAI, and others traced back to individual contributions that started without expectation of return. PseudoLab itself is the evidence, and so was the work the Season 12 builders had just put on stage.</p>

<p><img src="/assets/images/pseudocon-2026/12_chanran_kim.jpg" alt="Chanran Kim (Pseudo Lab) — Betoken: Signs of Growth" /></p>

<p>The Agent Ignite session had several short talks. Here are the ones I caught, in the order I heard them.</p>

<p><strong>Mina Kim (Worksphere)</strong> built a work wiki agent that structures scattered Slack and Notion entries into a résumé draft. She was honest about where it breaks: structuring and cleaning is one thing, but trusting the output is another. Her closing line — “the bottleneck was myself” — landed.</p>

<p><img src="/assets/images/pseudocon-2026/15_ignite_kimina.jpg" alt="Agent Ignite: Mina Kim (Worksphere) — Updating your résumé with a work wiki agent" /></p>

<p><strong>Sangjun Park’s Hyam</strong> distributes agents as encrypted packages — the harness stays private, only results are shared. When a demo tried to extract the internal structure, the verification logic refused directly. Sangjun is also an AutoBioX team member, so watching a teammate take the Ignite stage separately was its own kind of moment.</p>

<p><img src="/assets/images/pseudocon-2026/13_ignite_parksangjun.jpg" alt="Agent Ignite: Sangjun Park — How far should I share the agent I built?" /></p>

<p><strong>Youngwoong Park (SK Telecom)</strong> built a Personal LLM Knowledge Base connecting Obsidian, Confluence, and Slack into a continuously compiled knowledge graph — closer to an always-on wiki than a retrieval system that fetches on demand.</p>

<p><img src="/assets/images/pseudocon-2026/14_ignite_parkyoungwoong.jpg" alt="Agent Ignite: Youngwoong Park (SK Telecom) — Personal Knowledge Bases" /></p>

<p>PseudoLab is a voluntary learning community of AI/ML researchers, developers, and practitioners who form project teams each season. Alongside the talk sessions, Season 12 teams ran project booths. I was part of two teams this season: AutoBioX, and an experiment platform team focused on running actual A/B experiments within the PseudoLab community, where I worked as a data analyst. The experiment platform team staffed their booth for four hours that day — I was deep in presentation prep and couldn’t make it over, which I regretted.</p>

<p><img src="/assets/images/pseudocon-2026/16_booth_poster.jpg" alt="Season 12 booth — Cosmos × GROOT robot foundation model" /></p>

<p>One corner of the venue had a board with the question: “What’s the one real thing you want to take away from PseudoLab?” Post-its in every handwriting, each a different answer. That board probably captured the community better than any slide.</p>

<p><img src="/assets/images/pseudocon-2026/17_board.jpg" alt="&quot;What's the one real thing you want to take away from PseudoLab?&quot; — audience board" /></p>

<h2 id="after-the-conference">After the Conference</h2>

<p>The afterparty was a different kind of conversation. Some people I already knew — we finally had time to talk properly. Some I’d only seen at a distance before; this was the first real exchange. Some I’d only ever interacted with online and was meeting in person for the first time. The presentations created a shared context that made it easier to get into the actual substance faster.</p>

<p><img src="/assets/images/pseudocon-2026/18_afterparty.jpg" alt="Afterparty venue" /></p>

<h2 id="the-next-question">The Next Question</h2>

<p>Looking back at the two projects, what’s interesting is that they point toward the same question. The single-cell project looks at change over time. The pathology project looks at what’s visible right now. Connect them, and you might be able to see how treatment resistance develops with much more resolution than is currently possible. Not a finished answer yet — but the next question I want to work on.</p>

<p>Presenting before the papers are done meant sticking to methods and principles rather than results. That’s the standard we set: numbers stay private until the validation gate closes. The papers will be finished before the next event, not at it.</p>

<p>As I wrapped up this research, I found myself more interested in what happens after: open-sourcing the work, turning it into reusable knowledge, and making it accessible rather than just published. That’s the direction I want to keep moving in, alongside exploring new problems.</p>

<p><img src="/assets/images/pseudocon-2026/19_team.jpg" alt="AutoBioX team" /></p>

<hr />

<p><em>Thanks to AutoBioX team members Yongki Ji, Sejin Park, Jeonghan Seo, Jaemyeon Ryu, Geonkyu Lee, and Sangjun Park.</em></p>]]></content><author><name>Ka-Kyung Kim</name></author><category term="Research &amp; Community" /><category term="PseudoCon" /><category term="PseudoLab" /><category term="AutoBioX" /><category term="MultiAgent" /><category term="Bioinformatics" /><category term="Conference" /><summary type="html"><![CDATA[Our initial target metric came back at Spearman 0.04 — essentially a failure. We put that on the slides anyway.]]></summary></entry></feed>