Skip to content
게으른 엔지니어의 기술 블로그
Go back

LLM이 만든 형제 노트끼리 같은 문단을 그대로 베끼고 있었다

Read in English →

AI 검증이 놓치는 것들 · 4/9편

만들고 있는 Obsidian 플러그인에는 기사 한 편을 넣으면 LLM이 그 안의 개념·인물·회사를 각각 별도 노트로 나눠 위키에 저장하는 기능(ingest)과, 쌓인 노트를 훑어서 중복을 합치거나 너무 큰 노트를 나누자고 제안하는 위키 정리 기능(refactor)이 있다. 이 글은 LLM이 같은 기사 한 편에서 함께 만들어낸 노트들(이 글에서는 ‘형제 노트’라고 부른다)이 서로 같은 문단을 중복해서 담고 있던 문제에 관한 이야기다. 이 두 기능을 실제 Obsidian 앱에서 원격으로 자동 실행하는 테스트 환경은 만들어놨는데, 그다음 문제는 “뭘 먹일까”였다. 처음 몇 라운드는 손으로 지어낸 가짜 노트 6개씩을 넣고 기사 넣기 → 위키 정리를 돌렸다. 편했다 — 원하는 구조를 마음대로 설계할 수 있으니까. 그런데 딱 그게 문제였다. 지어낸 노트는 내가 예상한 버그만 재현했다. 실제 사용자가 실제로 겪을 버그는, 내가 미리 상상하지 못한 형태로만 나온다. 그래서 방향을 바꿨다 — 이후로는 지어낸 문장 대신 실제로 클리핑해둔 뉴스 기사와 블로그 글만 ingest 대상으로 썼다.

지어낸 노트가 “실제 노트” 풀에 섞여 있었다 — 합성 테스트 데이터가 섞였다

전환 이후에도 한 가지 사고가 있었다. 매 라운드 소스를 고를 때 테스트 결과를 기록해 두는 저장소의 커밋을 뒤져서 아직 안 쓴 원문을 고르고 있었는데, 그렇게 고른 6개를 raw/ 폴더에 배포하기 직전에 frontmatter를 다시 열어보니 그중 3개에 source: "https://example.com/megabank-ai-loan-a" 같은 URL이 박혀 있었다. 회사명도 “메가뱅크”, 인물도 “제이든 파크”·“리나 오카포”처럼 지어낸 이름이었다 — 몇 주 전, 아직 “실제 노트만 쓰자”는 원칙이 없던 시절에 넣어둔 합성 테스트 픽스처가 커밋 히스토리 안에 그대로 남아 있다가 “진짜 원문 풀”인 줄 알고 다시 집힌 것이었다. 세 개를 걸러내고 실제 출처(Forbes, JoongAng, publy.co)가 있는 기사로 바꿔치기한 다음에야 라운드를 이어갔다.

형제 노트 두 개가 같은 문단을 그대로 복사하고 있었다 — LLM 노트 자동 생성의 중복

실제 기사로 완전히 바꾸고 몇 라운드가 지난 뒤, 한 구글 부사장 인터뷰 기사를 ingest한 결과에서 이상한 걸 봤다. “AI 과학 에이전트” 노트와 “코사이언티스트” 노트를 나란히 열어보니, “연구 사례” 섹션에 다음 문단이 글자 하나 안 틀리고 그대로 들어 있었다.

“영국 임페리얼 칼리지 런던 연구팀은 10년 동안 연구해 온 항생제 내성 과제를 코사이언티스트에 입력했다. 코사이언티스트는 단 이틀 만에 기존과 동일한 수준의 가설을 도출했으며, 새로운 연구 방향 네 가지를 추가로 제안했다.”

두 노트 다 classification: concept이었고, 서로 다른 각도(하나는 “AI 과학 에이전트”라는 상위 개념, 하나는 “코사이언티스트”라는 구체적 도구)로 설명하려는 의도는 분명했다. 그런데 정작 예시로 든 연구 사례는 요약도 재서술도 아니고 통째로 복사해 붙인 형태였다. ingest 하나가 한 원문에서 여러 개념 노트를 뽑아낼 때, 노트끼리 콘텐츠를 나눠 갖는 게 아니라 각자 자기 노트 안에 전체를 다시 채워 넣고 있었다.

13개로 잘게 쪼갠 노트는 오히려 깨끗했다 — 문제는 개수가 아니라 거리였다

처음엔 “노트가 너무 세분화되니까 겹치는구나” 하고 짐작했는데, 같은 라운드에 있던 다른 ingest 결과를 보니 그 짐작이 틀렸다는 게 바로 드러났다. 개발 가이드 원문 하나에서 13개 노트(Context Engineering, Critical Verification, Problem Decomposition, Vibe Coding, Code Overload 등)로 쪼갠 결과는 각 노트가 뚜렷이 구분된 스코프만 다루고 교차링크로만 연결돼 있었다. HBR 원문 하나에서 15개로 쪼갠 다른 결과도 마찬가지였다. 오히려 노트가 2~4개로 적게 나뉘고, 그 소수가 서로 아주 가까운 하위개념일 때(Dense Attention ↔ Quadratic Attention Bottleneck, MathWorks ↔ MATLAB MCP Server ↔ MATLAB Agentic Toolkit, AI 과학 에이전트 ↔ 코사이언티스트 ↔ 요시 마티아스) 이 중복이 반복해서 나타났다. 노트 개수가 많을수록 모델이 각 노트의 좁은 담당 영역을 더 분명히 인식하고, 소수의 밀접한 노트 사이에서는 오히려 “이 내용은 어느 노트에 넣어야 하지” 판단이 흔들리는 것처럼 보였다.

회사 노트와 제품 노트도 같은 문단을 나눠 갖는 대신 통째로 복사했다 — Uber의 Claude Code 도입 기사

이 패턴이 concept 노트끼리만의 문제가 아니라는 것도 다음 라운드에서 드러났다. Uber가 Claude Code를 도입한 이야기를 다룬 영문·국문 기사 한 쌍을 ingest했더니, “Uber” entity 노트와 “Claude Code” entity 노트 양쪽에 도입 초기 수치들(엔지니어 사용률 32%→84%, 약 5,000명 확산, 커밋의 70%가 AI 도구발, 백엔드 업데이트의 11%가 사람 개입 없이 작성됨)이 거의 어순만 바뀐 채 그대로 반복돼 있었다. 회사와 그 회사가 쓰는 제품처럼 본질적으로 얽힌 두 엔티티가, 같은 “도입 스토리”를 각자 처음부터 서술하다 보니 벌어진 일이었다.

다른 중복은 다음 정리 단계가 잡아냈지만, 이건 못 잡았다 — 임베딩 유사도 중복 탐지

같은 라운드에서 있었던 노트 분할(split) 실행도 비슷한 실수를 저질렀다. 이미 원래 ingest 때 독립 노트로 존재하던 “암묵지 공유”, “최종 수비”, “책임 총대”를 분할 결과가 인식하지 못하고, “AI 시대 팀장의 암묵지 공유”처럼 다른 파일명으로 거의 같은 내용의 노트를 새로 만들어버렸다. 그런데 그 직후 위키 정리를 한 번 더 돌리자, 파일명이 완전히 달라도 임베딩 유사도로 잡아내는 비제목 중복 탐지 로직이 세 쌍 전부를 정확히 “자동 감지: 중복 노트 병합” 후보로 집어냈다. 제목이 같은 노트만 찾는 단계는 피해 갔지만, 임베딩 유사도 계산까지는 피해 가지 못한 셈이었다. 근본 원인(분할 실행이 기존 노트 목록을 제대로 인지하지 못하는 것)은 아직 안 고쳐졌지만, 적어도 그게 vault에 영구히 남지는 않는다는 걸 확인한 건 소득이었다.

다만 이 탐지는 “노트 두 개가 통째로 같은 개념인가”를 보는 장치다. “AI 과학 에이전트”와 “코사이언티스트”처럼 서로 다른 개념을 다루는 노트 안에 같은 문단이 박혀 있는 경우는, 노트 단위로는 다른 노트가 맞기 때문에 잡을 이유가 없다. 앞에서 본 문단 복사는 그래서 어떤 검증 장치에도 걸리지 않았다. 이 문제는 몇 라운드를 더 거쳐, ingest가 한 원문에서 만든 형제 노트를 한꺼번에 모아 놓고 겹치는 구체적 사실을 찾아 한쪽만 남기고 나머지는 링크로 바꿔 쓰게 하는 후처리 단계를 넣고서야 고쳐졌다. 그 과정은 이어지는 글에서 다룬다.

남는 생각

지어낸 노트로 테스트할 때는 “concept 노트 여러 개가 한 원문에서 나올 수 있다”는 것까지는 설계할 수 있어도, “그 노트들이 서로 같은 문단을 베낄 수 있다”는 건 애초에 상상하지 못했다. 실제 기사로 바꾸고 나서야, 그것도 내용을 원문 하나하나와 대조하는 게 아니라 형제 노트끼리 직접 나란히 놓고 읽어야만 보이는 종류의 버그였다. 테스트 데이터를 현실적으로 만드는 일 자체가 검증의 일부라는 걸, 매번 다시 배운다.


Share this post:

AI 검증이 놓치는 것들

  1. 1. 몇 주 뒤, 그 감사 장치가 못 보는 경우를 찾았다
  2. 2. 리스트 밀도 상위 4개 중, 서브에이전트가 2개를 놓쳤다
  3. 3. 검증은 다른 쌍으로 했는데, 원래 그 사례는 다시 안 봤다
  4. 4. LLM이 만든 형제 노트끼리 같은 문단을 그대로 베끼고 있었다
  5. 5. 임베딩 모델을 바꾸니 순서가 뒤집혔다
  6. 6. 임베딩 필터를 걷어내니, 중복이 오히려 더 많이 잡혔다
  7. 7. LLM 노트 병합 규칙에서 틀린 예시는 지웠는데, 규칙은 남아 있었다
  8. 8. LLM 노트 병합 테스트는 통과했는데, 고친 코드는 한 번도 실행되지 않았다
  9. 9. LLM이 노트 중복을 지우자, 남은 문장이 가리킬 곳을 잃었다