Originally published at bedrock-audit.ibnweb3lab.workers.dev/blog. Built for the Graph Hacks hackathon (WeMakeDevs x FalkorDB), Track 01.
논문 검토를 위해 1년을 보냈다고 상상해 보세요. 목록에 있는 모든 출처가 문제가 없어 보입니다. 참고 문헌 관리 도구는 아무것도 표시하지 않습니다. 하지만 두 단계 뒤로 거슬러 올라가 보니, 그 출처 중 하나가 몇 년 전에 철회된 논문을 기반으로 하고 있었고, 여러분이 사용하는 어떤 도구도 이를 알려주지 못했습니다.
바로 이 간극을 Bedrock이 해결합니다. DOI 목록을 붙여넣으면, Bedrock은 사용자의 논문부터 최대 두 단계까지 모든 인용 경로를 추적하여 철회된 연구 여부를 확인합니다. 발견되는 각 항목에 대해 정확한 체인(chain), 철회 날짜 및 기록된 사유를 보여줍니다. AI 에이전트가 결과를 설명하고 수정 사항을 제안할 수 있지만, 실제로 적용할 수는 없습니다.
이는 3일 만에 Bedrock을 구축하는 과정의 이야기입니다: 잘 된 부분, 잘못된 부분, 그리고 제가 직접 만든 에이전트가 개수를 잘못 센 부분들입니다.
아이디어: 행(row)이 아닌 경로(path)에 대한 질문
철회 여부를 표시하는 도구들은 일반적으로 여러분이 인용한 논문들을 확인합니다. 그 논문들이 무엇을 인용했는지는 묻지 않습니다. 이 두 번째 질문이야말로 그래프(graph) 문제입니다: 하나의 논문에서 시작하여 CITES 간선(edges)을 따라가다가, 철회된 노드에 도달하면 멈추고 해당 경로를 보고하는 것입니다.
다음은 코퍼스에서 가져온 실제 경로입니다:
your reference ──cites──▶ not flagged ──cites──▶ RETRACTED 2014-10-01
10.1016/j.neubiorev 10.1111/ejn.13603 10.1016/j.jpsychires
.2019.09.040 .2014.06.018
중간의 논문은 철회되지 않았기 때문에, 아무런 경고도 뜨지 않는 것이 바로 문제입니다.
두 가지 규칙이 모든 것을 형성했습니다. 첫째, Bedrock은 고정된 코퍼스에 대한 사실을 진술하며 추측하지 않습니다. '노 노출(no exposure found)'이라는 논문은 안전하다고 절대 간주되지 않으며, 단지 두 단계 이내에서 발견되지 않았다는 의미일 뿐입니다. 둘째, 사람이 결정합니다. 에이전트가 제안하고, 사람이 승인합니다.
데이터: 공개적이며 그렇게 유지됨
철회(retractions)는 Crossref가 배포하는 Retraction Watch 데이터베이스에서 가져왔습니다. 인용은 CC0 라이선스인 OpenAlex에서 가져왔습니다. 저는 213개 저널의 251,645개 논문을 모두 가져와 61,299개의 철회된 논문과 연결했습니다. 해커톤 규칙은 공개 데이터만 요구하므로, 작가들은 디스크에 어떤 것이 닿기 전에 메모리에서 비밀 솔트로 해시되었고, 이름, 이메일 및 ORCID는 삭제되었습니다. 제가 발표하는 그래프에는 작가 데이터가 전혀 없습니다.
Retraction Watch ─┐
├─▶ FalkorDB (Cypher) ─▶ audit queries ─▶ read-only agent ─▶ you approve
OpenAlex (CC0) ───┘
이 그래프는 모든 발견을 생성합니다. 모델은 요약만 작성하고, 사람은 모든 변경 사항을 승인합니다.
그래프: 작고 날카로운 쿼리
모델은 의도적으로 단순합니다: Paper 노드는 doi, retracted_at, retraction_reasons를 가지고 있고, Venue 노드가 있으며, 두 개의 관계, CITES와 PUBLISHED_IN이 있습니다. 철회는 자체 노드가 아니라 속성(property)이며, 이는 그래프를 작게 유지하고 '현재 시점 기준' 필터를 사소하게 만듭니다. 두 단계 간의 질문은 하나의 쿼리입니다:
UNWIND $ids AS i
MATCH (p:Paper {id: i})
WITH p
...
이것을 소리 내어 읽으면 다음과 같습니다: 이 논문은 x를 인용하는데, x는 철회되지 않았고, x는 철회된 r을 인용하며, 이 논문은 이미 r을 직접 인용하고 있지 않다. Bedrock이 보여주는 모든 것, 즉 직접적인 히트(direct hits), 두 단계 경로, 그리고 대체할 '함께 인용된 논문' 제안들은 FalkorDB에 의해 실행되는 이러한 크기의 쿼리입니다.
59초 쿼리: 플래너가 잘못된 곳에서 시작했다
9편의 논문을 감사하는 첫 시도는 59초가 걸렸습니다. 데이터 양이 적고 질문도 단순했기 때문에 뭔가 잘못되었다는 생각이 들었습니다. 원인은 FalkorDB의 플래너(planner)가 제가 요청한 소수의 논문부터 시작하기는커녕, 61,299편의 철회된 논문에서 출발하여 제 입력 방향으로 역추적을 했기 때문입니다. 해결책은 위에 보시는 사소한 WITH p 구문이었습니다. 이 구문은 탐색(traversal)이 입력 논문부터 시작하여 그 참고 문헌들을 확장하도록 강제합니다.
수정 후 재측정 결과: 9편의 논문은 0.05초에서 0.4초가 걸렸고, 150편의 논문은 0.15초에서 0.4초가 걸렸습니다.
제가 얻은 교훈: 그래프 데이터베이스는 쿼리의 크기보다 그 모양이 더 중요합니다. 인덱싱된 조회(indexed lookup)가 탐색을 고정시킬 수 있다면, 쿼리에 그렇게 명시해야 합니다. 이것이 데모와 제품의 차이를 만듭니다.
실패한 테스트: 철회 예측 시도
Bedrock의 첫 아이디어는 야심적이었습니다. 논문이 인용한 출처, 공동 저자, 속한 커뮤니티 등 그래프 신호(graph signals)를 사용하여 어떤 논문들이 철회될지 예측하는 것이었습니다. 어떠한 결과도 보기 전에 저는 합격 기준을 정했습니다. 즉, 그래프 방식은 최고의 단순 기준선(simple baseline)을 능가해야 했고, 그 격차는 가장 큰 저널이 제외되어도 유지되어야 했습니다. 이에 따라 철회 이력이 있는 저널의 134,798개 논문을 대상으로 테스트를 진행했고, 이 중 140편이 향후 2년(최종 마감일 2020-12-31) 내에 철회되었습니다.
| 방법 | 평균 정밀도 (Average precision) |
|---|
| 무작위 순위 지정 (Random ranking) | 0.0012 |
| ... | |
| 결론: 신뢰할 만한 개선 없음. 최고의 조합은 저널 기준선보다 불확실성(uncertainty) 미만으로 높았습니다. 140건의 철회는 20개에서 27개 저널에 집중되어 있어 연구의 검정력(power)이 낮았고, 다단계 신호(multi-hop signals)가 단일 단계 버전보다 우수하지 않았습니다. 유독 두드러진 단일 신호인 | |
어차피 '철회 위험 점수(retraction risk score)'를 출시할 수도 있었습니다. 인상적으로 보였겠지만 실질적인 근거는 없었을 겁니다. 대신 제품 자체를 바꿨습니다. Bedrock이 예측하는 것을 멈추고 증명하기 시작한 거죠. 실패 테스트가 첫 페이지에 올라온, 정확한 출처(Exact provenance)입니다. 그 결정이야말로 어떤 질의보다도 제가 누구 앞에서든 변호할 수 있는 부분입니다.
에이전트: 유용하지만 짧은 끈에 매달려 있다
이 에이전트는 Groq의 무료 티어에서 openai/gpt-oss-120b를 사용합니다. 세 가지 도구, 즉 audit_bibliography, explain_finding, 그리고 find_dois를 가지고 있으며, 이들 모두 읽기 전용입니다. 수정하는 도구는 없고, 테스트가 이를 확실히 지켜줍니다. 이러한 안전장치(guardrails)들은 에이전트가 오작동하는 것을 관찰하면서 만들어졌습니다:
- 근거 기반(Grounding). 답변에 포함된 모든 DOI는 사용자의 텍스트나 도구의 결과에서 나와야 합니다. 모델들이 DOI를 잘못 입력하거나 일부를 손상시켰기 때문에, 이제는 꾸며낸 DOI가 발견되면 눈에 띄는 경고가 발생합니다.
- 완전성(Completeness). 한때 플래그 지정된 논문을 건너뛰기도 했습니다. 요약에서 하나라도 빠지면 에이전트에게 단 한 번의 재시도 기회가 주어지고, 여전히 누락된 내용은 일반 문장으로 추가됩니다.
- 개수(Counts). 감사 과정에서 두 개의 철회된 논문을 발견했음에도 불구하고, 같은 실행에서는
그래서 저는 논문, 학회지(venues), 그리고 해당 논문들 간의 인용 관계만을 담은 슬림 그래프를 만들었습니다: 노드 318,942개와 엣지 530,894개. 그러고 나서 주장을 펼치는 것만이 아니라 실제로 검증했습니다. 스크립트를 이용해 두 그래프 모두에서 2,501개의 DOI를 감사(audit)했고 전체 결과를 비교했습니다: 상태(statuses), 경로(paths), 이유(reasons), 커버리지(coverage), 그리고 대안들(alternatives). 차이가 전혀 없었습니다. (이 테스트 과정에서 실제 버그도 발견했습니다. 자가 인용(self-citations)이 37개 논문에서 참고 문헌 수를 정확히 하나씩 부풀리고 있었습니다.)
이 슬림 그래프는 리포지토리에서 17 MB 크기의 DUMP 스냅샷으로 제공됩니다. 512 MB로 제한되고 CPU의 1/10만 사용하는 컨테이너 환경에서도 약 1분 만에 복원되며, 용량은 대략 300 MB 정도입니다. 심사위원(judge)은 다음 명령어로 전체 시스템을 실행할 수 있습니다:
git clone https://github.com/ibnweb3/bedrock && cd bedrock
docker compose --profile demo up --build app
# open http://127.0.0.1:8765
저는 키가 없는 상태에서 새로 클론한 환경에서 직접 테스트해 보았습니다. 캐시를 사용하지 않은 빌드는 2분 조금 넘었고, 앱은 시작 후 5초 만에 응답했습니다.
솔직한 한계점 (Honest limits)
- 이 시스템은 자신이 가진 코퍼스(corpus)만을 알고 있습니다: 213개 저널, 251,645개의 논문, 그리고 이들이 인용한 논문들로 구성되어 있으며, Retraction Watch의 2026년 10월 15일 스냅샷을 사용합니다.
- 두 단계(two hops) 전까지만 살펴봅니다. '노출된 것 없음(No exposure found)'은 그 범위 내에서 아무것도 발견되지 않았다는 의미이지, 논문 자체가 건전하다는 뜻은 아닙니다.
- 이유와 날짜 정보는 Retraction Watch에서 가져옵니다. 플래그는 사람이 읽어보도록 유도하는 알림일 뿐이며, 저자에 대한 발견(finding)을 의미하지 않습니다.
- 실시간 데모는 제가 직접 사용하는 컴퓨터에서 실행되므로, 위에 제시된 한 줄 명령어 설정 방식이 신뢰할 수 있는 방법입니다.
제가 배운 점 (What I learned)
- 테스트를 돌리기 전에 합격 기준(pass mark)을 작성하세요. 이것만이 실패가 주장이 아닌 결과임을 입증하는 유일한 이유였습니다.
- 그래프 데이터베이스에서는 트래버설(traversals)의 닻(anchor)을 내리세요. 쿼리 형태(Query shape)가 데이터 크기보다 중요합니다.
- 코드가 사실을 말하게 하고, 모델이 산문(prose)을 쓰게 하세요. 그래도 숫자는 반드시 확인하세요.
- 자신만의 지름길(shortcuts)을 증명하세요.
저는 3일 만에 혼자서 구축했습니다. Claude Code가 제 지침을 바탕으로 대부분의 코드와 문서를 작성해 주었습니다. 저는 아이디어를 선택하고, 규칙을 설정했으며, 실험 규모를 승인했고, 예측(prediction)에서 출처(provenance)로 방향을 전환하기로 결정했으며, 에이전트용으로 Groq을 선택했고, 모든 출판 및 배포에 서명했습니다. 의사결정 기록은 리포지토리의 docs/DECISIONS.md에 있습니다. 코드는 MIT 라이선스이며, 데이터는 자체 약관(Crossref를 통한 Retraction Watch, OpenAlex CC0)을 유지합니다.
사진: Brigitte Werner가 촬영한 Death Valley의 Zabriskie Point 퇴적암층 (CC0) (Wikimedia Commons).