작은 모델은 규칙을 지키지 않습니다 — 프롬프트 대신 출력을 검증하는 법
왜 이 주제가 중요한가
사내 문서 RAG 챗봇처럼 비용을 아껴야 하는 환경에서는 작은 모델을 쓰게 됩니다. 그런데 작은 모델은 시스템 프롬프트의 금지 규칙을 자주 어깁니다. 이때 흔히 하는 대응이 프롬프트를 더 강하게 쓰는 것입니다. "절대 하지 마세요", "반드시" 같은 말을 덧붙이고, 예시를 추가하고, 규칙 번호를 매깁니다.
문제는 이 방식의 성공 여부를 미리 알 수 없다는 점입니다. 배포하고, 며칠 쓰고, 여전히 어기는 것을 발견하고, 다시 프롬프트를 고칩니다. 이 글은 그 루프를 빠져나오는 방법에 대한 기록입니다. 결론부터 말하면 금지는 프롬프트로 요청하되, 준수는 코드로 보장해야 합니다.
프롬프트로 금지한 것이 지켜지지 않습니다
문서 챗봇의 답변 아래에는 근거 문서가 카드 형태로 따로 표시됩니다. 그래서 시스템 프롬프트에 이렇게 적어 두었습니다.
답변 마지막에 별도의 "출처" 목록을 만들지 않습니다. 출처 카드는 화면에서 따로 제공합니다.
명확한 문장입니다. 그리고 모델은 이 규칙을 무시하고 답변 끝에 출처 목록을 붙였습니다. 화면에는 같은 정보가 두 번 나오게 됩니다.
프롬프트를 다듬는 대신, 답변 본문에서 꼬리 출처 목록을 잘라내는 후처리를 넣기로 했습니다. 화면에 그리기 전과 데이터베이스에 저장하기 전에 같은 규칙을 적용하면 됩니다. 간단해 보이는 작업이었습니다.
형태를 쫓다가 배운 것
간단하지 않았습니다. 배포할 때마다 모델이 다른 형태를 내놓았습니다. 실제로 관측된 순서대로 적습니다.
1) 출처 목록: [1], [2], [3]
2) 출처 목록 (참고용):
[1] 배포 전략 문서 > 5. 체크리스트
3) ---
**출처**: 백업 가이드 > 추천 전략
4) > 출처: 백업 가이드 > 추천 전략, 데이터베이스 백업 정책첫 번째 형태를 보고 정규식을 만들었습니다. 두 번째가 나왔습니다. 콜론 앞에 괄호 덧말이 붙는 경우를 허용했습니다. 세 번째가 나왔습니다. 인용 번호 없이 문서 제목만 나열하고, 앞에 구분선과 굵은 글씨가 붙었습니다. 네 번째가 나왔습니다. 이번에는 인용문 기호였습니다.
세 번째까지는 발견할 때마다 정규식에 장식을 하나씩 추가하고 있었습니다. 네 번째를 보고서야 접근이 잘못되었다는 것을 인정했습니다. 모델이 만들어낼 수 있는 표현의 가짓수를 제가 미리 셀 수 없습니다. 열거로는 이길 수 없는 싸움이었습니다.
열거 대신 신호를 찾습니다
관점을 바꾸면 네 형태에는 공통점이 있습니다. 전부 본문과 시각적으로 분리되어 있습니다. 구분선, 헤딩, 굵은 글씨, 인용문, 글머리표는 모두 "여기부터는 본문이 아니다"라고 말하는 마크다운 장치입니다. 장식의 종류가 아니라 분리한다는 성질이 신호였습니다.
그래서 규칙을 이렇게 바꿨습니다. 줄 시작에서 출처 계열 머리말을 만났을 때, 본문과 분리하는 접두사가 붙어 있거나 뒤에 인용 번호가 따라오면 그 지점부터 끝까지 버립니다.
이 규칙은 새로운 장식 조합이 나와도 대체로 견딥니다. 모델이 굵게 쓰든 인용문으로 쓰든 헤딩으로 쓰든, 본문과 분리하려는 의도 자체는 같기 때문입니다.
잘라내면 안 되는 것을 지킵니다
후처리에서 진짜 위험한 것은 못 자르는 것이 아니라 지나치게 자르는 것입니다. 다음 문장을 보시면 됩니다.
출처: 사내 규정에 따르면 보관 기간은 3일입니다.이것은 꼬리 출처 목록이 아니라 답변 본문입니다. 여기서 잘라내면 사용자는 답을 잃습니다. 못 자른 중복은 눈에 거슬리는 정도지만, 잘못 자른 본문은 정보 손실입니다. 두 실패의 무게가 다릅니다.
그래서 "분리 표시가 있거나 인용 번호가 있을 때만" 이라는 조건이 중요합니다. 위 문장은 장식도 없고 인용 번호도 없으므로 그대로 남습니다. 관측된 네 형태와 이런 보존 사례를 모두 테스트로 고정해 두었습니다. 새 변형이 나오면 케이스를 하나 추가하면 됩니다.
정규식을 다듬을 때는 반드시 자르는 사례와 남기는 사례를 함께 테스트하시기를 권합니다. 자르는 쪽만 확인하면 정규식은 점점 탐욕스러워지고, 그 대가는 조용히 사라진 본문으로 나타납니다.
검색어 재작성도 같은 문제였습니다
같은 시스템에는 후속 질문을 독립적인 검색어로 바꿔 쓰는 단계가 있습니다. "그럼 그건 언제 바뀐 거야?" 같은 질문은 그대로 검색하면 아무것도 못 찾기 때문입니다.
여기에도 프롬프트로 규칙을 넣었습니다. "질문 형태로 쓸 것", "이전 답변의 설명 문장을 그대로 옮기지 말 것", "짧게 쓸 것". 그리고 모델은 이렇게 답했습니다.
배포 전/중 단계별 백업 계획에서 메인 데이터베이스 및 리포지토리를
완전한 상태로 보존하기 위해 매일 새벽 크론으로 백업 실행
(DB 수정일: 2026-06-01) [4]질문도 아니고, 짧지도 않고, 앞 답변에서 그대로 가져온 문장입니다. 인용 번호와 근거 주석까지 딸려 왔습니다.
여기서도 프롬프트를 더 강하게 쓰는 대신 결과값을 검증하기로 했습니다. 인용 번호나 근거 주석, 코드 울타리가 섞여 있으면 검색어가 아니라 답변 조각이라고 판단하고 버립니다. 길이 상한도 함께 겁니다.
이 판단을 쉽게 만들어 준 것은 폴백 비용이 없다는 사실이었습니다. 재작성을 거부하면 원래 질문으로 검색하면 됩니다. 검색이 약간 부정확해질 뿐 대화는 그대로 이어집니다. 실패했을 때 잃을 것이 없으면 기준을 넉넉하게 잡을 이유가 없습니다. 그래서 상한을 과감하게 짧게 잡았습니다.
한 가지 더 효과가 있었던 것은 재작성 프롬프트에 넣는 이전 대화를 짧게 자른 것입니다. 지시어를 풀어 쓸 이름은 답변 앞부분에 나오는데, 본문을 길게 넣어 주면 모델이 베낄 재료가 많아집니다. 원하지 않는 출력을 막는 가장 확실한 방법은 그 재료를 주지 않는 것입니다.
배포 확인에서 제가 저지른 실수
이 작업 도중 빌드를 한 번 깨뜨렸습니다. 원인 자체는 사소합니다. 정규식에 명명 캡처 그룹을 썼는데 프로젝트의 컴파일 타깃이 그 문법보다 낮았습니다.
문제는 그 다음입니다. 저는 빌드 결과를 이렇게 확인하고 있었습니다.
npm run build | grep "Compiled successfully"번들 컴파일은 성공했고 그 뒤 타입 검사에서 실패했습니다. 그런데 출력에는 이미 "Compiled successfully" 문자열이 찍혀 있었으므로 grep은 성공했습니다. 저는 통과했다고 판단하고 푸시했습니다.
출력 문자열이 아니라 종료 코드를 봐야 했습니다. 빌드 도구는 성공과 실패를 종료 코드로 알려 주는데, 중간 단계의 성공 메시지를 근거로 삼으면 뒷단계 실패를 놓칩니다.
npm run build > build.log 2>&1; echo "exit=$?"다행히 실제 피해는 없었습니다. 배포 파이프라인이 이미지 빌드 단계에서 실패했고, 실패한 이미지는 운영 컨테이너를 교체하지 못했기 때문입니다. 잘못된 코드를 밀어 넣었는데도 서비스가 멀쩡했던 것은 제 확인이 꼼꼼해서가 아니라 파이프라인이 한 번 더 검증했기 때문입니다. 사람의 확인 절차가 뚫려도 자동화된 관문이 남아 있으면 사고가 되지 않는다는 점을, 원하지 않는 방식으로 확인했습니다.
정리
- 작은 모델에게 금지 규칙을 지키게 만들 수는 없습니다. 프롬프트로 요청하되 준수는 코드로 보장하십시오.
- 모델 출력의 형태를 열거해서 쫓아가면 끝이 없습니다. 형태가 아니라 공통된 신호를 찾으십시오.
- 후처리는 못 자르는 것보다 지나치게 자르는 것이 위험합니다. 남겨야 할 사례를 반드시 함께 테스트하십시오.
- 실패했을 때 폴백 비용이 없다면 검증 기준을 과감하게 좁혀도 됩니다.
- 원하지 않는 출력은 그 재료를 주지 않는 것으로 줄일 수 있습니다.
- 빌드 확인은 출력 문자열이 아니라 종료 코드로 하십시오.
듀오랩스가 보는 관점
LLM을 제품에 넣을 때 가장 자주 보는 오해가 "프롬프트를 잘 쓰면 해결된다"는 기대입니다. 프롬프트는 모델의 행동 분포를 옮길 뿐이며 보장을 주지 않습니다. 사용자에게 보이는 화면에 대한 보장은 결국 코드가 만들어야 합니다.
그래서 저희는 LLM 기능을 설계할 때 "모델이 규칙을 어겼을 때 무엇이 사용자에게 도달하는가"를 함께 정의합니다. 잘라낼 것인지, 폴백할 것인지, 아니면 그대로 두되 표시할 것인지를 미리 정해 두면, 모델을 교체하거나 버전이 올라가도 화면의 품질은 유지됩니다. 모델은 바뀌지만 그 주변의 방어선은 남기 때문입니다.
함께 읽기
- RAG 챗봇이 "그건 언제 바뀐 거야?"에 답하게 만들기사내 문서를 근거로 답하는 RAG 챗봇을 도입하면 대부분 비슷한 지점에서 막힙니다. 첫 질문에는 그럴듯하게 답하는데, 이어서 "그럼 그건 언제 바뀐 거야?" 같은 질문을 던지면 갑자기 엉뚱한 문서를 근거로 들고 옵니다. 사용자는 "AI가 헛소리를 한다"고 느끼고, 도입은 거기서 멈춥니다.
- RAG 대표 기술 한눈에 보기: 검색부터 GraphRAG까지RAG(Retrieval-Augmented Generation)는 사용자의 질문과 관련된 외부 지식을 먼저 찾고, 그 근거를 언어 모델에 전달해 답변을 생성하는 방식입니다. 모델이 학습 과정에서 기억한 정보에만 의존하지 않으므로 조직의 최신 문서나 전문 자료를 답변에 반영하고 출처를 제시하기 좋습니다.
- 27B보다 2.4B가 더 나았던 문서 RAG 모델 선택기문서 검색과 질의응답을 결합한 RAG 시스템을 만들 때 가장 먼저 떠오르는 질문은 대개 비슷합니다.
- 로컬 LLM으로 업무 자동화를 만들 때, 모델을 몇 개 써야 할까사내에 AI를 도입하려는 회사가 가장 먼저 부딪히는 질문이 있습니다. "모델 하나면 되는 것 아닌가요?"
- AI를 잘 활용하려면 모델보다 구조가 중요하다AI를 잘 쓰는 핵심은 좋은 모델을 고르는 것만이 아닙니다. 모델에게 어떤 정보를 주고, 어떤 도구를 연결하고, 결과를 어떻게 검증할지까지 설계해야 실제 업무에 도움이 됩니다.