지난 글에서
repairInboundLinks를 세 번 손본 다음, 완전히 다른 종류의 문제
두 개를 연달아 만났다. 둘 다 모델을 바꿔가며 원인을 추적했다는
공통점이 있는데, 결과는 정반대였다.
병합했다가, 다시 분할하라는데?
/refactor를 돌렸더니 서로 다른 네 개의 문서 — “모델 기반 엔지니어링
MBE”, “모델 기반 시스템 엔지니어링 MBSE”, “모델 기반 설계 MBD
Design”, “모델 기반 정의 MBD Definition” — 를 하나로 병합하라는
제안이 나왔다. 시키는 대로 병합했다. 그런데 /refactor를 다시
돌리니, 이번엔 방금 만든 그 통합 문서를 원래대로 네 개로 다시
쪼개라고 했다. 병합했다가 도로 분할하라니, 이러다 계속 왔다갔다
하는 거 아닌가 싶었다.
분할 제안이 준 근거를 읽어보니 “서로 다른 계층의 방법론을 하나의
모놀리식 문서에 담고 있어 노이즈가 발생한다”고 적혀 있었다. MBE는
상위 패러다임이고, MBSE·MBD Design·MBD Definition은 그 밑에 있는
서로 다른 세부 방법론이다. 실제로 /refactor가 쓰는 판단 매트릭스에는
“단순히 상위 카테고리가 유사하다는 이유로 병합하지 말 것”이라는
조항이 이미 있었다 — 그러니까 지금 상황은 처음 병합 자체가 오판이었고,
분할 제안이 그걸 뒤늦게 바로잡은 것에 가까워 보였다.
그러면 이 매트릭스 프롬프트를 어떻게 더 강화해야 하나 고민하다가, 일단 실제로 여러 모델에 똑같은 상황을 몇 번씩 반복해서 물어보기로 했다. 같은 카탈로그(MBE + MBSE + MBD Design + MBD Definition)를 두고, 가격대가 다른 여러 Gemini 모델에 각각 5번씩 판단을 시켜봤다. 결과가 꽤 놀라웠다. 가장 저렴한 경량 모델 하나는 5번 다 똑같이 병합을 추천했다 — 그것도 매번 “MBD라는 약어를 공유한다”는, 매트릭스가 이미 금지해둔 바로 그 이유로. 또 다른 경량 모델은 아예 답이 매번 달랐다 — 같은 입력인데 어떤 때는 병합, 어떤 때는 분할을 추천했다. 반면 더 크고 비싼 모델 둘은 다섯 번 다 정확히 같은 결론(그대로 두고 링크만 연결)을 냈다.
즉 이건 프롬프트가 애매해서 생기는 문제가 아니라, 모델에 따라 같은 프롬프트를 얼마나 충실히 따르는지가 크게 달랐던 것이었다. 프롬프트는 이미 맞는 말을 하고 있었는데, 저렴한 모델일수록 그 말을 무시하고 표면적인 단어 유사성에 끌리는 경향이 있었다.
모델을 하나씩 테스트하다가 별개의 문제를 하나 더 발견했다. 이 플러그인이 기본으로 쓰는 모델로 API를 호출했더니, 아예 “이 모델은 신규 사용자에게 더 이상 제공되지 않는다”는 오류가 떴다. 기본 모델 설정 자체가, 최근에 API 키를 발급받은 사용자에게는 처음부터 작동하지 않는 상태였던 것이다. 찾아보니 플러그인 코드 안에 이 기본 모델 이름이 하드코딩된 곳이 두 군데였다 — 설정값 하나, 그리고 모델 선택 드롭다운을 그리는 화면 쪽에 독립적으로 하나 더. 둘 다 신규 사용자에게는 작동하지 않는 값을 가리키고 있었다.
기본 모델을 바꾸는 김에, 처음에 매번 오판했던 그 경량 모델을 다시 살려보기로 했다. 매트릭스 프롬프트의 “상위 카테고리가 비슷하다고 병합하지 말 것”이라는 추상적인 문장 바로 뒤에, 실제 사례 하나를 구체적으로 적어 넣었다 — “MBD Design과 MBD Definition은 같은 약어를 쓰지만 서로 다른 작업을 다룬다”는 식으로. 이 한 문단을 추가했을 뿐인데, 매번 틀리던 그 경량 모델이 다섯 번 전부 정답을 냈다. 가장 저렴한 모델이 가장 비싼 모델과 똑같이 정확해진 것이다.
AI가 어떤 판단을 자꾸 틀린다고 해서, 항상 프롬프트를 손봐야 하는 건 아니었다. 이번엔 프롬프트가 이미 맞는 규칙을 갖고 있었는데도, 모델이 그 규칙을 지킬 만큼 정교하지 않아서 문제가 생겼다. 그리고 그 문제를 “더 비싼 모델을 강제로 써야 한다”가 아니라, 프롬프트에 구체적인 반례를 하나 추가하는 것만으로 저렴한 모델에서도 해결할 수 있었다 — 가격과 정확도 사이에서 하나를 포기해야 한다고 생각했는데, 실제로는 둘 다 챙길 방법이 있었다.
무관한 두 문서가 똑같은 링크 세트를 달고 나왔다
웹사이트 링크 점검을 하다가 곁다리로 실제 vault 화면을 다시 보게 됐다. 그런데 “계절성 투자” 노트와 “동료에서 매니저로의 전환” 노트 — 완전히 무관한 두 주제 — 가 정확히 똑같은 다섯 개의 Related pages 링크를 달고 있었다. 전부 “모델 기반 엔지니어링(MBE)” 계열 노트였다. 계절성 투자가 왜 MBE와 연관이 있다는 건지 짐작조차 안 갔다.
코드를 뒤져보니 /ingest는 원본 파일을 최대 3개씩 묶어(ingestChunkSize
기본값) 한 번의 LLM 호출로 처리한다. 원본 파일 하나가 여러 개체를
다루면 AI가 알아서 여러 문서로 쪼개도 되는 규칙도 있어서, 실제로는
원본 3개짜리 배치 하나에서 문서 10개가 한 번의 응답 안에 연달아
생성될 수 있다. 이 구조에서 “Related pages” 섹션을 채우는 방식을
보니, 그냥 AI가 자유 텍스트로 써넣는 거였다 — 결정론적 검색 결과가
아니라. 응답 하나 안에서 문서를 열 개 가까이 순서대로 써내려가다
보면, 완전히 무관한 문서끼리 “같은 응답에서 가까이 등장했다”는
이유만으로 서로를 연관 문서로 착각해 링크하는 일이 생길 수 있었다.
말로만 짐작하지 않고, 같은 상황(투자 메모 + MBE 계열 메모 + 커리어
메모, 원본 3개를 한 번의 ingest 호출로 처리)을 실제 Gemini API로
재현해봤다. 기본 모델(gemini-3.5-flash-lite)로 10번 반복하니 1번,
정확히 이 패턴의 오염이 나왔다 — 완전히 무관한 두 문서가 서로
링크됐다.
앞에서 해결한 문제(리팩토링 제안이 병합과 분할을 오락가락하던 것)를
프롬프트에 구체적 반례 하나 추가하는 것으로 완전히 해결한 적이 있다.
이번에도 같은 방법을 썼다 — “같은 배치에서 함께 생성됐다는 이유만으로
연관 문서로 취급하지 말라”는 금지 규칙과, 계절성 투자·팀장 승진처럼
무관한 메모가 우연히 나란히 생성되는 구체적 반례를 /ingest와
/refactor의 split 프롬프트에 넣었다.
수정된 프롬프트로 다시 10번 돌려봤다. 깨끗했다. 그런데 뭔가 찜찜해서 20번을 더 돌려 표본을 30개로 늘렸더니, 1번이 또 나왔다. 오염 발생률이 10%에서 6.7%로 줄긴 했지만, 완전히 없어지지는 않았다. 지난번엔 반례 하나로 5/5가 전부 정답으로 바뀌었는데, 이번엔 왜 절반만 통했을까.
같은 조건으로 다른 모델도 각각 10번씩 테스트해봤다. 결과가 뚜렷하게 갈렸다.
| 모델 | 가격($/1M 입력·출력) | 오염 발생 |
|---|---|---|
gemini-3.5-flash-lite | $0.30 / $2.50 | 30회 중 2회 |
gemini-3-flash-preview | $0.50 / $3.00 | 0/10 |
gemini-3.6-flash | $1.50 / $7.50 | 0/10 |
gemini-3.5-flash | $1.50 / $9.00 | 0/10 |
가격이 제일 저렴한 flash-lite에서만 문제가 남고, 그보다 한 단계
위인 flash 계열(버전과 무관하게, 3.5든 3.6이든)은 전부 깨끗했다.
버전 차이가 아니라 “flash”와 “flash-lite” 사이의 지시 준수 능력
차이였던 거다. gemini-3-flash-preview도 이번엔 깨끗했지만, 이
모델은 예전에 다른 작업(병합/분할 판단)에서 이미 불안정하다고 확인된
전적이 있어서 후보에서 뺐다.
앞서는 “가격과 정확도 사이에서 하나를 포기해야 한다고 생각했는데,
실제로는 둘 다 챙길 방법이 있었다”고 확인했었다. 이번엔 아니었다.
프롬프트를 아무리 다듬어도 가장 저렴한 모델의 잔여 위험은 안 없어졌고,
결국 기본 모델을 gemini-3.5-flash-lite에서 gemini-3.6-flash로
올렸다. 입력 토큰당 5배, 출력 토큰당 3배 비싸졌다. 저번엔 반례
하나로 싼 모델도 살릴 수 있었는데, 이번엔 그 방법의 한계를 만난
셈이다.
남는 생각
같은 증상(프롬프트에 구체적 반례 추가)이 저번엔 완치였고 이번엔 부분적 효과에 그쳤다. 차이를 가른 건 문제의 성격이었던 것 같다 — 저번 문제는 “판단 기준이 모호해서” 생긴 오류였고, 반례가 그 기준을 명확하게 만들어주니 싼 모델도 따라갈 수 있었다. 이번 문제는 “여러 문서를 한 번에 길게 써내려가는 동안 모델이 스스로 흐트러지는” 종류였고, 이건 규칙을 더 명확히 적어준다고 해결되는 게 아니라 모델 자체의 안정성 문제에 더 가까웠다.
프롬프트 수정이 잘 통했던 경험 하나로 “이 방법이면 다 된다”고 일반화하지 않아야겠다는 생각이 든다. 이번에도 실측으로 재검증했기 때문에 “반례를 넣었으니 끝”이라고 잘못 마무리하지 않을 수 있었다.