WEBBOOK CHAPTER

로컬 LLM으로 만드는 사내 문서 AI: 15장 백업·삭제·모델 교체를 릴리스로 관리한다

15장 백업·삭제·모델 교체를 릴리스로 관리한다

백업 대상은 모델 파일만이 아니다. 원본 문서, 반입 명세, 청크 설정, 인덱스 버전, 권한 정책, 평가 세트, 감사 로그의 보존 범위를 정한다. 비밀과 개인정보가 든 원본 백업은 암호화하고 복구 권한을 분리한다.

삭제는 원본 파일 하나를 지우는 것으로 끝나지 않는다. 추출문, 청크, 벡터 인덱스, 캐시, 답변 기록, 백업 만료를 추적한다. 즉시 지울 수 없는 백업은 접근을 막고 만료 일정을 기록한다. 모델·임베딩·파서가 바뀌면 새 릴리스로 취급해 전체 색인과 평가를 다시 만든다.


릴리스: knowledge-room-2026.08.1
원본 스냅샷: docs-manifest sha256
파서/청크: parser-2 / heading-v3
임베딩: model-id + digest
권한 정책: policy-v5
평가: eval-v3, 20/20 실행
되돌림: 이전 읽기 전용 인덱스

실습 15 복구와 삭제 리허설

D2를 삭제 요청 대상으로 표시하고 검색·캐시·인덱스에서 사라지는지 확인한다. 그다음 깨끗한 폴더에서 D1과 D3만 복원해 권한과 평가를 실행한다. 삭제된 D2가 답변이나 로그에 다시 나타나면 실패다.

공식 자료와 최신성 메모

명령과 모델명은 빨리 변한다. 인쇄 전 공식 릴리스와 라이선스를 다시 확인하고, 본문은 데이터 흐름·평가·권한이라는 변하지 않는 축을 정본으로 삼는다.

실습 워크북: 해솔상점 지식실 15개 미션

모든 미션은 실제 회사 문서 대신 D1~D3 fixture로 수행한다. 실제 문서를 넣기 전에는 데이터 소유자, 보존, 권한, 외부 전송 경로를 승인받아야 한다.

  1. 데이터 흐름: 원본부터 로그까지 상자를 그리고 네트워크 경계를 표시한다.
  2. 무모델 기준선: 환불 검색에서 D1이 나오는지 고정한다.
  3. 문서 명세: 소유자·버전·민감도·해시·삭제일을 적는다.
  4. 파서 표본: 날짜·금액·표·부정어가 원본과 같은지 비교한다.
  5. 청크 계약: 제목·예외·표 행을 보존하고 버전 메타데이터를 붙인다.
  6. 검색 분리: 검색 결과와 생성 답변을 각각 저장한다.
  7. 답 없음: 근거가 없는 질문에 임의 답변을 만들지 않는다.
  8. 인용 문: 모든 공개 주장에 문서 ID·버전·섹션을 연결한다.
  9. 권한 전 필터: legal 전용 D3가 support 검색 후보에도 들어가지 않게 한다.
  10. 하이브리드 영수증: 클라우드로 보낼 필드와 보내지 않을 원문을 기록한다.
  11. 질문 세트: 정답·다중 근거·답 없음·권한 밖 20문항을 만든다.
  12. 충실성 주입: 근거 없는 한 문장을 넣어 검사가 실패하는지 본다.
  13. 성능 측정: 장치·모델·동시성·p95·메모리를 기록한다.
  14. 삭제: D2의 원본·파생 데이터·캐시·백업 만료를 추적한다.
  15. 복구: 깨끗한 환경에서 인덱스를 만들고 평가·권한 테스트를 재실행한다.

완주 판정표

항목 0점 1점 2점
데이터 흐름 로컬이라 가정 일부 경로 원본·모델·로그·외부 경계 확인
문서 공급망 파일 복사 해시만 있음 소유자·버전·파서·삭제 연결
근거 답변만 있음 문서 링크 주장별 버전·섹션·예외 연결
권한 답변 후 필터 문서 필터 검색 전 필터와 네거티브 테스트
평가 예시 질문 몇 개 정답 질문 답 없음·권한·홀드아웃 포함
운영 서버 실행 백업 있음 삭제·복구·모델 교체 리허설

총점 10점 이상이고 근거와 권한이 각각 2점이어야 출간 실습을 완주한 것으로 본다. 실제 사내 배포는 개인정보·보안·노무·계약 요건을 조직 책임자와 별도로 검토한다.

현장 트러블슈팅: 문서에서 답변까지 층별로 고친다

RAG 장애를 모두 모델 문제라고 부르면 원인을 찾기 어렵다. 반입 → 추출 → 청크 → 색인 → 권한 필터 → 검색 → 생성 → 인용 → 삭제 순서로 첫 번째 잘못된 층을 찾는다. 한 번에 모델과 임계값과 프롬프트를 모두 바꾸지 않는다.

1 검색 결과가 하나도 없다

문서가 반입 명세에 있고 현재 인덱스 버전에 포함됐는지 확인한다. 질의 정규화, 언어, 키워드 토큰, 임계값을 차례로 본다. 먼저 fixture의 정확한 단어 환불로 결정적 검색을 실행한다. 이것도 비면 모델이 아니라 반입·색인 문제다.


npm run qa
npm start

현재 폴더와 화면의 fixture 버전이 다르면 결과를 비교하지 않는다.

2 관련 없는 문서가 항상 상위에 나온다

top-k는 어떤 질문에도 결과를 반환할 수 있다. 점수 분포와 답 없음 질문을 함께 보고 임계값을 조정한다. 문서 제목이 모든 청크에 과도하게 반복되거나 큰 청크가 공통 단어를 독점하는지 확인한다. 검색 실패를 생성 프롬프트로 덮지 않는다.

3 환불 기한은 나오지만 예외가 빠진다

기한과 예외가 다른 청크로 갈라졌는지 본다. 예외 청크의 제목·문서 ID·버전이 보존됐는지 확인하고, 다중 근거 질문의 기대 ID에 두 청크를 등록한다. 무조건 청크 겹침을 크게 하기보다 의미 단위로 다시 자른다.

4 OCR 문서의 금액이 달라졌다

해당 페이지를 자동 답변 대상에서 빼고 검수 상태로 바꾼다. 원본 이미지와 추출문을 나란히 보고 숫자·통화·소수점·부정어를 확인한다. 사람이 수정한 값에는 수정자와 원본 좌표를 남긴다. OCR 결과를 조용히 원본으로 덮어쓰지 않는다.

5 점원에게 법무 문서가 보인다

답변 뒤 마스킹으로 끝내지 않는다. 검색 후보를 만들기 전에 사용자 신원과 문서 ACL을 적용했는지 확인한다. 캐시 키에 사용자 역할·정책 버전이 포함됐는지 본다. 이미 노출됐다면 감사 로그로 범위를 확인하고 관련 캐시를 폐기한다.

6 이전 계약서가 현재 답으로 나온다

같은 documentId 계열의 활성 버전과 효력일, supersedes 연결을 확인한다. 과거 버전은 삭제하지 않더라도 현재 검색 후보에서 제외하고 감사·과거 답변 확인 용도로 읽기 전용 보존한다. 질문이 특정 과거 날짜를 요구하면 그 시점 버전을 명시해 반환한다.

7 근거가 없는데 모델이 답한다

검색 결과가 비었을 때 생성기를 호출하지 않는 코드 경계를 확인한다. 낮은 점수의 관련 없는 청크가 들어갔다면 답 없음 세트로 임계값을 다시 본다. 거절 문구가 불친절하더라도 근거 없는 확정 답보다 낫다. 사용자가 문의할 담당자나 필요한 문서 종류를 안내할 수 있다.

8 인용 링크가 문서 첫 페이지로만 간다

문서 ID만 저장하지 말고 버전, 섹션, 페이지 또는 문자 범위를 보존한다. PDF 뷰어가 직접 위치 링크를 지원하지 않으면 해당 구간을 강조한 읽기 화면을 만든다. 권한 없는 사용자가 링크를 통해 원문 전체에 접근하지 않게 같은 ACL을 적용한다.

9 응답이 느리고 메모리가 부족하다

검색, 재순위화, 첫 토큰, 전체 생성 시간을 나눈다. 컨텍스트에 중복 청크와 전체 문서를 넣는지 확인한다. 동시 요청을 1로 줄여 기준선을 측정하고 작은 모델·짧은 컨텍스트·짧은 답변부터 비교한다. 운영체제의 메모리 압박이 생기면 더 큰 모델을 억지로 유지하지 않는다.

10 로컬 서버가 다른 기기에서도 열린다

바인딩 주소를 확인하고 필요 없으면 127.0.0.1로 제한한다. 단순히 사내망이라 안전하다고 보지 않는다. 공유가 필요하면 인증, TLS, 사용자별 권한, 요청 제한, 감사가 있는 게이트웨이를 둔다. 포트 포워딩과 방화벽 예외도 자산 목록에 기록한다.

11 하이브리드 경로로 원문이 전송됐다

라우팅을 중단하고 공급자 로그와 전송 영수증으로 범위를 확인한다. API 키 회전만으로 문서 유출이 해결되지는 않는다. 데이터 소유자와 보안 책임자에게 사실과 미확인 사항을 알리고, 전송 전에 실행되는 마스킹·승인 코드와 네거티브 테스트를 추가한다.

12 삭제한 문서가 검색 결과에 다시 나온다

원본, 추출문, 청크, 벡터 인덱스, 키워드 인덱스, 응답 캐시, 대화 기록을 각각 확인한다. 백업에서 즉시 물리 삭제할 수 없다면 접근을 차단하고 만료 시각을 기록한다. 재색인 작업이 오래된 명세에서 문서를 다시 반입하지 않는지도 본다.

13 복구 뒤 검색 결과가 달라졌다

모델·임베딩·파서·청크·라이브러리 버전과 원본 해시를 비교한다. 다른 임베딩으로 만든 인덱스를 섞지 않는다. 동일 릴리스라면 같은 질문 세트와 권한 결과를 재현해야 한다. 새 버전이면 차이를 승인하고 새 기준선으로 기록한다.

14 모델은 한국어를 잘하지만 인용이 약하다

언어 유창성과 근거 충실성을 분리해 평가한다. 답변의 각 주장에 근거를 강제로 연결하고, 연결되지 않은 문장은 삭제한다. 큰 모델로 바꾸기 전에 검색 결과가 정답인지와 예외가 함께 들어왔는지 확인한다.

15 정상 질문까지 너무 자주 거절한다

거절률을 낮추려고 임계값을 무조건 내리지 않는다. 정상 질문의 표현 다양성, 동의어, 오타, 문서 제목을 평가 세트에 추가한다. 키워드와 벡터 혼합, 재질문, 검색 결과 미리보기를 비교한다. 답 없음 오답률과 정상 거절률을 함께 본다.

출간 전 현장 검수

실제 회사 문서 없이 전체 흐름을 완주할 수 있어야 한다. 선택 모델 설치가 실패해도 무모델 코스는 동작해야 하며, 명령·모델 이름·라이선스는 출간 시점 공식 문서로 다시 확인한다. 책의 하드웨어 표는 보장이 아니라 시작점으로 표시하고 장치·컨텍스트·동시성에 따라 달라짐을 반복해서 알린다.

독자가 남겨야 할 산출물은 데이터 흐름도, 문서 명세, 파서 검수표, 청크 계약, 질문 세트, 권한 행렬, 주장-근거 장부, 전송 영수증, 성능표, 삭제·복구 기록이다. 이 열 가지가 있으면 특정 모델이 바뀌어도 시스템을 다시 설명하고 검증할 수 있다.

평가 결과 읽기: 같은 오답도 고칠 층이 다르다

질문 “개봉한 위생 상품도 7일 안이면 환불되나요?”에 시스템이 “7일 이내 환불됩니다”라고 답했다고 하자. 먼저 검색 결과를 본다. D1의 기한 청크만 있고 예외 청크가 없다면 검색·청크 문제다. 두 청크가 모두 있는데 생성 답변이 예외를 빼면 생성·충실성 문제다. 예외 청크가 legal 역할에만 허용되도록 잘못 표시됐다면 메타데이터·권한 문제다.


질문 ID: E-07
기대 근거: D1:v3:refund-window + D1:v3:hygiene-exception
검색 실제: refund-window만 반환
답변 실제: “7일 이내 환불됩니다.”
판정: RETRIEVAL_FAIL
수정: 예외를 같은 의미 단위로 보존
회귀: E-07과 답 없음 세트를 함께 재실행

반대로 검색 결과는 맞지만 답변에 “무료 반품 배송”이 추가됐다면 GENERATION_UNSUPPORTED다. 프롬프트만 고친 뒤 E-07을 통과해도 새 질문에서 반복될 수 있다. 주장마다 근거 연결을 요구하고 연결 실패 문장을 제거하는 구조적 검사를 추가한다.

권한 누출과 답 없음 실패를 따로 본다

점원 질문에서 D3 임대차계약이 검색되면 답변이 생성되지 않았더라도 보안 실패다. 민감 문서가 모델 컨텍스트와 로그에 들어갔기 때문이다. 기대 결과는 빈 답변이 아니라 D3이 검색 후보에 한 번도 들어오지 않는 것이다.

답 없음 질문 “해외 배송 보험료는?”에 D2가 상위 결과로 나왔다고 무조건 오답은 아니다. 검색기는 관련 후보를 반환할 수 있다. 생성 단계가 해당 문서에 보험료가 없음을 확인하고 정직하게 거절해야 한다. 검색 점수가 낮고 내용도 무관하다면 검색 임계값을 조정한다. 두 층의 책임을 섞지 않는다.

릴리스 비교표

지표 v1 v2 해석
정답 근거 Recall@3 16/20 19/20 검색 개선
근거 없는 주장 2 0 충실성 개선
답 없음 오답 0 2 보호 지표 악화, 출시 중단
권한 누출 0 0 필수 유지
전체 p95 4.2초 7.8초 사용성 비용 증가

v2의 정답 근거율이 좋아도 답 없음 오답이 생겼다면 자동 출시하지 않는다. 어떤 지표가 보호 지표인지 미리 정해야 평균 개선에 가려진 위험을 볼 수 있다.

독자가 직접 만드는 한 페이지 품질 보고서

보고서에는 릴리스 ID, 문서 스냅샷, 질문 세트 버전, 사용자 역할, 장치, 검색 설정, 모델, 결과, 실패 목록, 남은 한계를 쓴다. “정확도 95%”만 쓰지 않는다. 표본이 20개라면 한 건이 5%포인트를 바꾼다는 점과 질문 범위를 명시한다.


출시 판단: 보류
이유: 답 없음 질문 2건에서 근거 없는 확정
사용 가능한 범위: support 역할의 D1·D2 검색 미리보기
비활성 범위: 자동 답변과 하이브리드 전송
다음 행동: 거절 게이트 수정, 새 홀드아웃 5건 추가

이 문서를 다른 사람이 읽고 같은 판단을 내릴 수 있어야 한다. 모델 이름보다 어떤 문서와 질문과 권한에서 검증했는지가 더 중요하다.

판정과 근거를 같은 릴리스 기록에 보존한다.

부록 A 초보자를 위한 90분 무모델 코스

처음 15분에는 npm run qa로 fixture와 검색 함수를 확인한다. 다음 15분에는 npm start 후 로컬 문서실에서 ‘환불’, ‘배송’, ‘해외 배송’을 검색한다. 앞의 두 질문은 근거가 나오고 마지막 질문은 비어야 한다. 그다음 20분에는 fixtures/documents.json을 읽되 원본을 바꾸지 않고 메모장에 각 문서의 소유자와 권한을 적는다.

다음 20분에는 D1의 “개봉한 위생 상품 제외”를 포함한 질문 다섯 개를 만든다. 검색된 문장만으로 답할 수 있는지 표시한다. 마지막 20분에는 점원과 대표 역할을 나누고 D3이 점원 후보 목록에 들어오지 않아야 하는 이유를 설명한다. 이 코스는 생성 모델 없이 검색·근거·권한의 뼈대를 이해하게 한다.

기대 출력과 실패 읽기

‘환불’ 검색은 id: D1, score: 1을 포함한다. ‘해외 배송’은 빈 배열이어야 한다. 현재 fixture의 점수는 교육용 0/1이므로 실제 벡터 점수와 같지 않다. 실제 모델 단계에서 임계값을 그대로 1로 복사하지 않는다.

오류는 층별로 읽는다. 파일을 못 찾으면 반입, 검색 결과가 비면 색인, 잘못된 문서가 나오면 검색·권한, 근거는 맞는데 답이 틀리면 생성 문제다. 한꺼번에 프롬프트를 바꾸지 않는다.

부록 B 실제 모델을 붙이는 선택 코스

먼저 설치 도구의 공식 문서에서 현재 버전과 라이선스를 확인한다. 모델 카드에서 언어, 컨텍스트, 사용 제한, 양자화 출처를 기록한다. 모델 파일 해시와 실행 명령을 MODEL-RECEIPT.md에 남긴다. 새 모델은 기존 20문항 평가를 통과하기 전 기본 모델이 되지 않는다.

로컬 서버는 개인 PC의 루프백 주소에만 연다. 방화벽 경고를 무시하지 않는다. 다른 기기에서 접근할 이유가 생기면 인증과 TLS가 있는 별도 게이트웨이를 설계하고, 단순히 0.0.0.0으로 바꾸지 않는다. 회사 문서를 실험할 때는 조직의 보안 정책과 승인을 먼저 확인한다.

속도 표에는 첫 토큰 시간, 초당 토큰, 최대 메모리, 질문 길이, 모델 버전을 함께 쓴다. “빠르다”는 형용사 대신 사용자가 기다릴 수 있는 한도를 쓴다. 품질 표에는 검색 적중, 인용 정확, 근거 없는 질문의 거부, 권한 누출을 분리한다.

부록 C 삭제와 복구 런북

문서 삭제 요청이 오면 원본만 지우지 않는다. 추출 텍스트, 청크, 임베딩, 캐시, 대화 로그, 백업의 위치를 찾고 각각 삭제 또는 보존 예외를 기록한다. 법적 보존 의무가 있으면 임의 삭제 대신 접근 차단과 보존 근거를 남긴다.

복구 훈련은 깨끗한 폴더에서 시작한다. 문서 명세서와 해시를 읽고 원본을 복원한 뒤 같은 청크 수와 권한 목록이 나오는지 확인한다. 임베딩 모델이 달라졌다면 과거 인덱스를 섞지 않고 새 버전으로 전량 생성한다. 복구 성공은 서버가 켜진 순간이 아니라 평가 세트와 권한 테스트가 다시 통과한 순간이다.