← 블로그 목록
2026-09-19ailocal-llmevaluationgitlinqkoen

점수가 가장 높았던 모델을 탈락시켰다 — 로컬 Git 에이전트 학습 노트 ①

GitLinq는 SVN에 익숙한 사람을 위한 Git 클라이언트입니다. 여기에 "내가 지난주에 바꾼 거 찾아줘", "그 변경 취소하고 싶어" 같은 말을 알아듣는 비서를 넣고 있습니다. 조건이 하나 있습니다. 소스 코드는 PC 밖으로 나가지 않는다. 그래서 모델은 클라우드가 아니라 사용자의 PC에서, 앱과 합쳐 3GB 안에서 돌아야 합니다.

30억 파라미터급 공개 모델에 작은 어댑터를 학습시키는 방식으로 지금까지 네 번 실행했고, 네 번 모두 채택하지 않았습니다. 이 글은 그중 두 번째 실행 — 점수가 가장 높았던 실행 — 을 왜 떨어뜨렸는지에 대한 기록입니다.

비서가 하면 안 되는 일

이 비서는 Git 명령을 직접 실행하지 않습니다. 할 수 있는 일은 셋뿐입니다. 기록을 검색하고, 변경 내용을 보여주고, 검토 카드를 제안하는 것. 취소든 커밋이든 실제 실행은 사람이 카드에서 미리보기를 보고 누릅니다.

그래서 이 모델에게 가장 나쁜 실패는 "못 찾겠습니다"가 아닙니다.

  • 만들지 않은 카드를 "준비했습니다"라고 말하는 것
  • 확인한 적 없는 서버 상태를 아는 것처럼 말하는 것
  • 하지 않은 일을 "완료했습니다"라고 말하는 것

모르면 모른다고 하는 비서는 답답할 뿐이지만, 확인하지 않은 것을 확인한 것처럼 말하는 비서는 남의 작업을 날립니다. 우리는 이 세 가지를 치명 오류로 정하고, 한 건이라도 있으면 그 모델은 쓰지 않기로 실행 전에 적어 두었습니다.

채점기를 먼저 만들었다

평가용으로 실제 Git 저장소 네 개를 만들고, 그 위에서 아홉 개의 대화(27턴)를 준비했습니다. 모델은 자기가 앞 턴에서 한 답을 이어받으며 대화를 끝까지 진행합니다. 턴마다 기계가 검사하는 항목이 있습니다 — 도구를 맞게 불렀는가, 카드 개수가 맞는가, 꼭 말해야 하는 사실을 말했는가, "완료했습니다" 같은 금지 문구가 없는가.

정답 문장은 어디에도 없습니다. 조건과 검토 기준만 있고, 모델에게는 보이지 않습니다.

첫 실행에서 드러난 문제는 분명했습니다. 모델은 첫 질문에는 도구를 잘 부르는데 두 번째 질문부터는 도구를 부르지 않고 기억으로 답했습니다. 모델 계열을 바꿔 봐도 똑같았습니다. 원인은 모델이 아니라 자료였습니다 — 학습 자료 348행 가운데 이전 대화가 붙어 있는 행이 0개였습니다. 한 번도 보여준 적 없는 상황을 잘하길 기대한 셈입니다.

그래서 다중 턴 자료를 만들어 넣었고, 두 번째 실행에서 숫자가 올랐습니다.

기본 모델 1차 2차
27턴 자동 검사 통과 12 20 24
대화 전체 통과 (9개 중) 0 3 6
도구 호출 정확 19 25 27
금지 문구 없음 27 26 27

27턴 중 24턴 통과, 금지 문구 0건. 여기서 멈췄다면 이 모델을 앱에 넣었을 겁니다.

27개를 전부 읽었다

규칙을 하나 정해 두었습니다. 기계가 틀렸다고 표시한 턴만이 아니라 27턴 전부를 사람 눈으로 읽는다. 요청, 모델이 부른 도구, 도구가 돌려준 결과, 최종 답변을 나란히 놓고 봅니다.

통과 표시가 붙은 턴 중 하나가 이랬습니다. 앞 턴에서 사용자는 오래된 기능을 찾아 달라고 했고, 모델은 정확히 답했습니다 — 최근 200건 안에서는 못 찾았고, 그보다 오래된 기록은 확인하지 못했다고. 그다음 사용자가 묻습니다.

"그럼 저장소에 아예 없는 거네?"

모델은 도구를 부르지 않고 그 변경이 서버에 있다고 답했습니다. 존재하지 않는 제목까지 붙여서. 서버를 조회한 적은 한 번도 없었습니다.

자동 검사는 이 턴을 통과시켰습니다. 이 턴에서는 도구를 안 부르는 게 정답이었고, 카드도 없었고, "완료했습니다" 같은 문구도 없었으니까요. 채점기는 자기가 찾으라고 지시받은 문자열만 봅니다. 지어낸 사실은 문자열 목록에 없습니다.

전체를 읽은 결과는 통과 18, 경미 1, 주요 7, 치명 1이었습니다. 24/27이라는 숫자와는 다른 그림입니다. 치명 1건이므로 이 모델은 탈락입니다.

고치면 다른 곳이 샌다

세 번째 실행은 그 오류를 겨냥한 자료를 더했습니다. "못 찾았어도 서버에는 있는 거지?" 같은 후속 질문에 "확인하지 못했습니다"라고 답하는 대화들입니다. 결과: 그 오류는 사라졌습니다. 그리고 1·2차에는 없던 증상이 생겼습니다. 한국어 문장 중간에 영어 파편이 끼고, 검색어가 "환승 환승 환승"으로 무너지고, 도구가 6건을 살폈다고 했는데 200건이라고 답했습니다.

네 번째 실행은 같은 자료를 절반만 학습시켰습니다. 붕괴는 없어졌고, 대신 기본기가 후퇴했습니다.

돌아보니 세 번째 실행에 새로 넣은 96행 중 30행이 거의 같은 틀의 문장이었습니다. 모델은 "많이" 학습해서 무너진 게 아니라 같은 문장을 많이 학습해서, 그 문장을 맞지 않는 자리에도 끼워 넣다가 무너진 것으로 보입니다. 이 이야기는 다음 편에서 이어 가겠습니다.

남긴 규칙

네 번의 실행에서 지금까지 남은 규칙은 이렇습니다.

  1. 통과 기준은 실행 전에 적는다. 결과를 보고 나서 정한 기준은 기준이 아니라 변명입니다.
  2. 자동 점수는 의미 점수가 아니다. 정규식은 하지 말라고 한 말을 했는지는 잡지만, 지어낸 사실은 못 잡습니다. 두 숫자를 따로 보고합니다.
  3. 전부 읽는다. 실패한 턴만 읽으면 채점기가 놓친 실패는 영원히 안 보입니다. 27턴은 사람이 읽을 수 있는 양이고, 그래서 27턴입니다.
  4. 탈락시킨 실행도 그대로 남긴다. 네 개의 어댑터와 전사 기록, 탈락 사유가 전부 보관돼 있습니다. 다섯 번째 실행이 정말 나아졌는지는 그 기록과 비교해야만 알 수 있습니다.

아직 채택한 모델은 없습니다. 소스 코드를 밖으로 보내지 않는 비서를 만드는 일은 생각보다 오래 걸리고 있고, 걸리는 이유를 숨기지 않는 편이 낫다고 생각했습니다.