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

LLM이 제안한 노트 병합을 버그로 보고 세 번 고쳤는데, 맞는 제안이었다

Read in English →

LLM 노트 정리를 실측으로 고친 기록 · 3/4편

만들고 있는 Obsidian 플러그인은 기사를 넣으면 LLM이 기사마다 개념·인물·회사별 노트를 만든다. 노트를 만든 직후에는 자동 정리 단계가 돌아 비슷한 노트 쌍을 찾고, LLM이 두 노트의 본문을 대조해 “합치자”는 제안 카드를 띄운다. 실제 병합은 사람이 카드의 실행 버튼을 눌러야 일어난다. 이번 글은 그 병합 제안을 버그로 보고 AI 코딩 에이전트와 함께 반나절을 쓴 이야기다. 결론부터 말하면 제안은 맞았고, 틀린 건 제안을 막은 감사 쪽이었다.

노트를 나눈 단계와 합치자는 단계가 반대로 말했다 — LLM 노트 병합 제안

테스트 실행 중에 자동 정리가 두 번 병합을 제안했다. 하나는 에이전트 하네스를 다룬 기사에서 나온 일반 정의 노트와, 같은 기사의 “코딩 버그 하나를 고치는 과정” 예시를 따로 뗀 노트였다. 다른 하나는 보상 해킹(reward hacking) 기사에서 나온 노트 세 개였다. 상위 개념 노트, 강화학습 편, LLM 에이전트 편이다.

실행 결과를 감사하던 에이전트는 둘 다 “범위가 다른 노트”라며 실행하지 않았다고 기록했다. 나중에 이 제안들을 다시 보자고 하자, 에이전트는 질문을 이렇게 세웠다. 노트를 만드는 단계가 일부러 나눈 걸 바로 다음 단계가 왜 합치자고 하나. 지난 2주 기록을 뒤지니 같은 기사에서 나온 형제 노트를 합치자는 제안이 다섯 번 있었고, 그중 두 번은 그때 실제로 병합까지 했다.

프롬프트를 세 번 고쳤고, 매번 반대쪽이 터졌다 — LLM 프롬프트 테스트

에이전트가 찾은 원인은 그럴듯했다. 노트를 합칠지 정하는 자동 정리에는 같은 대상을 다른 맥락으로 설명한 노트는 같은 개념이라는 규칙이 있는데(이전 글에서 정한 기준이다), 노트를 만드는 단계의 나누기 규칙에는 이 정의가 없었다. 두 단계가 다른 기준을 쓰니 반대 결론이 나온다는 것이다.

그래서 노트를 만드는 프롬프트를 고쳐 가며 쟀다. 기사 하나씩 실제 플러그인 코드로 LLM 요청을 만들고, 고치기 전과 후의 프롬프트로 기사마다 세 번씩 보냈다. 문제가 됐던 기사 5개 말고도, 노트가 따로 나뉘어야 맞는 기사들을 회귀 확인용으로 같이 돌렸다.

회차바꾼 것문제의 형제 노트가 생긴 횟수부작용
지금 프롬프트—15번 중 6번—
1차같은 개념 정의를 노트 만드는 규칙에도 넣음15번 중 3번남은 건 다른 모양
2차+ “원문 전체를 대표하는 노트를 따로 만들라”는 규칙 완화15번 중 0번노트가 굵어짐(4개 → 12개, 56개 → 2~3개)
3차+ “다른 기사가 와서 갱신할 대상이면 나눠라”15번 중 4번한두 문장짜리 노트가 늘어남

2차에서 완화한 규칙은 원래 기사 첫머리의 일화가 어느 노트에도 안 들어가고 사라지던 문제를 막으려고 넣은 것이었다. 그 규칙이 원문 전체를 대표하는 노트를 따로 만들게 해서, 기사가 사실상 한 주제일 때는 그 노트가 주제 노트와 겹쳤다. 완화하자 문제의 모양은 사라졌지만, 이번에는 “불안형 리더”, “회피형 리더”처럼 이름 있는 하위 유형까지 상위 노트의 절로 묻혔다. 이 플러그인이 따르는 카파시의 LLM Wiki는 새 원문이 오면 “integrates it into the existing wiki — updating entity pages”라고 하고, “A single source might touch 10-15 wiki pages”라고 쓴다. 다음 기사가 갱신할 개념 페이지가 있어야 위키가 쌓인다. 그래서 3차에 그 물음을 넣었는데, 이번에는 나누는 쪽 전체가 다시 밀렸다. 한쪽을 고치면 다른 쪽이 기준을 넘었다.

“rca 보다는 계속 주변부만 만지작거리고 있는 듯 한데” (근본 원인 분석)

세 번째 결과 뒤 에이전트는 같은 기사에서 나온 노트끼리는 병합 후보에서 코드로 빼자는 안을 냈다. 그 안이 무엇을 해결하지 못하는지 듣고 나서 에이전트에게 그렇게 말했다. 근본 원인 분석(RCA)을 하라고 해 놓고 증상 주변만 고치고 있다는 뜻이었다. 에이전트는 더 깊은 원인을 내놓았다. 노트를 만드는 단계는 기존 위키 노트를 전혀 보지 못한다. 7월에 기존 노트를 갱신하는 경로를 빼고 병합을 정리 단계에 몰아줬기 때문이다. 그러니 노트 경계를 두 단계가 따로 정한다는 설명이었다.

코드로 보면 사실이었다. 하지만 다시 따져 보라고 하자 에이전트가 스스로 뒤집었다. 세 번의 측정은 모두 빈 보관함에서 기사 하나만 넣고 돌렸다. 기존 노트가 하나도 없는데도 같은 기사 안의 쪼개기가 그대로 나왔다. 기존 노트를 보여 줘도 기사 하나를 어떻게 자를지는 바뀌지 않는다. 이 원인은 다른 기사끼리 생기는 중복에는 맞지만, 이번 문제에는 맞지 않았다.

설계를 다시 보니, 그건 버그가 아니었다 — 노트 병합 기준

에이전트는 원인을 다시 규칙 차이로 정리하고, 측정 횟수를 늘리자고 했다. 그 말을 듣고 내가 기억하던 설계를 말했다. 노트를 만드는 단계는 나누기만 하고, 병합은 그다음 자동 정리가 제안하고, 사람이 확인해서 실행한다. 7월에 일부러 그렇게 만들었다. 그렇다면 “만드는 단계가 나눈 걸 정리 단계가 합치자고 한다”는 모순이 아니라 설계된 경로다.

물었어야 할 질문은 하나였다. 그 제안이 맞았나. 그 규칙에는 “같은 개념을 특정 상황에 적용해 설명했을 뿐인 노트는 그 개념의 하위 개념이 아닙니다”라는 문장이 있다. 일반 정의와 그 적용 예시, 보상 해킹의 강화학습 편과 LLM 에이전트 편은 이 규칙으로 같은 개념이다. 두 제안 모두 맞았다. “범위가 다르다”는 규칙이 아니라 감사하던 에이전트의 감이었고, 나도 그 판정을 규칙에 대 보지 않았다.

실제로 바로잡은 것

노트를 만드는 프롬프트는 하나도 바꾸지 않았다. 세 번의 측정(LLM 호출 123번, 약 0.48달러)은 결론과 함께 기록만 남기고 접었다. 대신 이렇게 했다.

남는 생각

측정 자체는 꼼꼼했다. 실제 코드로 요청을 만들고, 기준을 미리 정하고, 회귀용 기사까지 같이 돌렸다. 그래도 질문이 틀리면 정교한 측정은 엉뚱한 곳을 정확히 잴 뿐이다. 이번에 빠진 건 맨 앞의 한 단계였다. 이 동작이 설계와 어긋나는가. 그걸 먼저 물었다면 첫 측정 전에 끝났을 일이다. 원인 후보를 내놓을 때마다 이미 모은 증거의 조건(이번에는 “빈 보관함”)과 맞는지 대 보는 것도 같은 이야기다.


Share this post:

LLM 노트 정리를 실측으로 고친 기록

  1. 1. LLM 판정에 걸린 노트를 고쳐 쓰게 했더니, 판정이 못 보던 손실이 통과했다
  2. 2. LLM 노트 수집 시간을 44% 줄이고, 결과가 같다는 건 재생으로 증명했다
  3. 3. LLM이 제안한 노트 병합을 버그로 보고 세 번 고쳤는데, 맞는 제안이었다
  4. 4. LLM에게 병합 노트 이름을 물었더니 판정이 흔들렸고, 이름 비교 몇 줄로 끝났다