11장. 폐쇄망 문서 파이프라인과 폐쇄형 RAG
문서 정제
장 본 채소는 흙을 털고 시든 잎을 떼고 씻은 뒤에 요리합니다. 수집한 글에도 답에 쓸모없는 것이 붙어 있습니다. 메뉴와 꼬리말, PDF 의 쪽 번호와 머리말, 중간에 끊긴 줄, 그리고 색인에 들어가면 안 되는 개인정보입니다.
네 카드는 정제의 손질 네 가지입니다. 틀 걷기는 쪽마다 되풀이되는 글을 빼고, 줄 잇기는 PDF 에서 폭에 맞춰 끊긴 줄을 문장으로 되돌리고, 개인정보 가리기는 전화번호와 메일을 자리표시로 바꾸고, 빈칸 정리는 겹친 빈칸과 빈 줄을 줄입니다. 여기서 흙과 시든 잎이 쓸모없는 글, 씻기가 정제입니다.
흠과 고치는 법
| 흠 | 생긴 까닭 | 그대로 두면 | 고치는 법 |
|---|---|---|---|
| 메뉴, 꼬리말 | html 화면의 틀 | 모든 조각에 같은 글이 섞여 검색이 흐려진다 | 태그의 class 로 건너뛴다 |
| 쪽 머리말, 쪽 번호 | PDF 의 쪽마다 찍힌 글 | 조항 가운데에 "- 1 -" 이 끼인다 | 되풀이되는 줄과 쪽 번호 꼴의 줄을 뺀다 |
| 끊긴 줄 | PDF 의 줄 폭 | "정산" 과 "하는 방법" 이 따로 논다 | 앞 줄이 문장 끝(.)이 아니면 잇는다 |
| 개인정보 | 담당자 연락처 | 아무나 묻고 받아 갈 수 있다 | 정규식으로 찾아 [전화번호] 로 바꾼다 |
정규식으로 가리기
import re
line = "보안 문의는 김하늘 책임(010-2468-1357, haneul.kim@example.com)에게 합니다."
# 휴대폰 번호 꼴(010-0000-0000)과 메일 주소 꼴을 찾아 자리표시로 바꾼다
line = re.sub(r"01[016789]-\d{3,4}-\d{4}", "[전화번호]", line)
line = re.sub(r"[\w.-]+@[\w-]+\.[\w.]+", "[메일]", line)
print(line)코드에 나오는 함수
| 코드 | 쉬운 뜻 |
|---|---|
re | regular expression(정규 표현식, 정규식)의 줄임이다. 글자의 꼴로 찾고 바꾸는 표준 라이브러리다 |
re.sub(꼴, 바꿀 글, 원래 글) | substitute(바꾸다)의 줄임이다. 꼴에 맞는 부분을 모두 바꿀 글로 바꾼다 |
r"…" | raw(날것) 문자열이다. \d 의 역슬래시를 파이썬이 따로 해석하지 않고 그대로 정규식에 넘긴다 |
01[016789] | 01 다음에 0, 1, 6, 7, 8, 9 가운데 한 글자가 온다 |
\d{3,4} | \d 는 digit(숫자) 한 글자, {3,4} 는 그것이 3개나 4개 이어진다는 뜻이다 |
[\w.-]+ | \w 는 word(낱말) 글자로 글자·숫자·밑줄이다. 이것과 점, 하이픈이 하나 이상(+) 이어진다 |
\. | 점 글자 그 자체다. 정규식에서 맨 점(.)은 "아무 글자"라서 역슬래시를 붙인다 |
이 코드가 뜻하는 것
서류를 복사해 돌리기 전에 연락처에 검은 매직을 칠하는 일로 읽어 봅니다. 칠하는 사람은 "010 으로 시작하는 숫자 줄", "@ 가 든 낱말"처럼 생김새를 보고 찾아 칠합니다. 여기서 검은 매직이 [전화번호], [메일] 같은 자리표시, 생김새의 규칙이 정규식입니다.
| 줄 | 하는 일 | 쉽게 말하면 |
|---|---|---|
line = "보안 문의는 …" | 연락처가 든 문장을 준비한다 | 복사할 서류 |
re.sub(r"01[016789]-…", "[전화번호]", line) | 휴대폰 번호 꼴을 자리표시로 바꾼다 | 전화번호에 매직 칠하기 |
re.sub(r"[\w.-]+@…", "[메일]", line) | 메일 주소 꼴을 자리표시로 바꾼다 | 메일 주소에 매직 칠하기 |
print(line) | 가린 문장을 찍는다 | 칠한 뒤의 서류 |
교안을 만든 PC 에서 이 블록은 보안 문의는 김하늘 책임([전화번호], [메일])에게 합니다. 를 찍었습니다. 번호와 메일은 가려졌지만 이름 "김하늘"은 그대로입니다. 정규식은 정해 둔 꼴만 찾기 때문입니다. 예시의 이름과 연락처는 지어낸 것입니다.
작게 줄여서 눈으로 보기
같은 전화번호 꼴이 어떤 글은 찾고 어떤 글은 놓치는지 봅니다. 번호는 모두 설명을 위해 지어낸 것입니다.
import re
pattern = r"01[016789]-\d{3,4}-\d{4}"
for s in ["010-0000-1234", "011-000-1234", "02-0000-1234", "010 0000 1234", "01000001234"]:
print(f"{s:15s}", "찾음" if re.search(pattern, s) else "못 찾음")010-0000-1234 찾음
011-000-1234 찾음
02-0000-1234 못 찾음
010 0000 1234 못 찾음
01000001234 못 찾음| 결과 | 읽는 법 |
|---|---|
010-0000-1234 찾음 | 01, 0, 하이픈, 숫자 4개, 하이픈, 숫자 4개로 꼴에 맞는다 |
011-000-1234 찾음 | 가운데 숫자가 3개여도 {3,4} 라서 맞는다 |
02-0000-1234 못 찾음 | 지역 번호는 01 로 시작하지 않아 꼴 밖이다 |
010 0000 1234 못 찾음 | 하이픈 대신 빈칸을 써서 꼴 밖이다 |
01000001234 못 찾음 | 하이픈 없이 붙여 써서 꼴 밖이다 |
re.search 는 글 안 어디에서든 꼴에 맞는 곳이 하나라도 있으면 찾아 줍니다. 실제 문서에는 빈칸이나 붙여 쓴 번호도 섞여 있으므로, 가린 결과를 표본으로 보고 놓친 꼴이 있으면 규칙을 더합니다.
주의할 점
- 정제 규칙은 문서의 형식마다 따로 겁니다. 줄 잇기를 모든 문서에 걸면, 번호 제목 다음 줄이나 표의 행까지 이어 붙어 버립니다(실습 3).
- 정규식은 정해 둔 꼴만 찾습니다. 이름, 주민등록번호, 주소처럼 꼴이 다양한 개인정보는 따로 규칙을 더하고, 가린 결과를 사람이 표본으로 확인합니다. 개인정보를 다루는 더 넓은 방법은 21장에서 봅니다.