본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 11. 27. · 4 Views
질의응답과 텍스트 요약 완벽 가이드
AI 모델을 활용한 Question Answering과 텍스트 요약 기술을 초급 개발자도 쉽게 이해할 수 있도록 설명합니다. 실무에서 바로 활용할 수 있는 코드 예제와 함께 추출적 요약과 생성적 요약의 차이점까지 다룹니다.
목차
1. Question Answering 구현
어느 날 김개발 씨는 회사의 방대한 기술 문서를 뒤지며 한숨을 쉬었습니다. "이 많은 문서에서 내가 원하는 정보를 어떻게 찾지?" 바로 그때 선배 박시니어 씨가 다가와 말했습니다.
"Question Answering 모델을 써보는 건 어때요?"
**Question Answering(QA)**은 한마디로 질문에 대한 답을 자동으로 찾아주는 AI 기술입니다. 마치 똑똑한 비서가 수천 페이지의 문서를 순식간에 읽고 핵심 답변을 뽑아주는 것과 같습니다.
이 기술을 익히면 챗봇, 검색 엔진, 고객 지원 시스템 등 다양한 분야에서 활용할 수 있습니다.
다음 코드를 살펴봅시다.
from transformers import pipeline
# QA 파이프라인 생성 - 사전 학습된 모델 사용
qa_pipeline = pipeline("question-answering")
# 문맥(context)과 질문 정의
context = """
파이썬은 1991년 귀도 반 로섬이 개발한 프로그래밍 언어입니다.
파이썬은 간결한 문법과 높은 가독성으로 유명합니다.
현재 데이터 과학과 인공지능 분야에서 가장 인기 있는 언어입니다.
"""
question = "파이썬을 개발한 사람은 누구인가요?"
# 질문에 대한 답변 추출
result = qa_pipeline(question=question, context=context)
print(f"답변: {result['answer']}")
print(f"신뢰도: {result['score']:.4f}")
김개발 씨는 입사 6개월 차 주니어 개발자입니다. 최근 회사에서 고객 문의를 자동으로 처리하는 시스템을 만들라는 과제를 받았습니다.
수백 개의 FAQ 문서가 있지만, 고객의 질문에 맞는 답변을 일일이 찾아주기엔 너무 비효율적이었습니다. "예전에는 이런 걸 어떻게 처리했나요?" 김개발 씨가 선배에게 물었습니다.
박시니어 씨는 웃으며 대답했습니다. "키워드 검색을 썼지.
근데 그건 한계가 있어요. 질문의 의미를 이해하지 못하니까." 그렇다면 Question Answering이란 정확히 무엇일까요?
쉽게 비유하자면, QA 시스템은 마치 도서관 사서와 같습니다. 여러분이 "조선 시대 세종대왕은 무엇을 만들었나요?"라고 물으면, 사서는 수많은 책을 뒤져서 "훈민정음을 창제했습니다"라는 정확한 답을 찾아줍니다.
QA 모델도 이와 똑같이 주어진 문서에서 질문에 해당하는 답을 정확히 집어냅니다. QA 기술이 없던 시절에는 어땠을까요?
개발자들은 단순한 키워드 매칭에 의존해야 했습니다. "개발자"라고 검색하면 "개발자"라는 단어가 포함된 모든 문서가 나왔습니다.
하지만 "프로그래머"나 "엔지니어"처럼 비슷한 의미의 단어는 찾지 못했습니다. 더 큰 문제는 질문의 맥락을 전혀 이해하지 못한다는 것이었습니다.
바로 이런 문제를 해결하기 위해 딥러닝 기반의 QA 모델이 등장했습니다. 최신 QA 모델은 BERT, RoBERTa 같은 트랜스포머 아키텍처를 기반으로 합니다.
이 모델들은 문장의 의미를 깊이 이해하고, 질문과 문맥 사이의 관계를 파악할 수 있습니다. 덕분에 키워드가 정확히 일치하지 않아도 의미적으로 관련 있는 답을 찾아낼 수 있습니다.
위의 코드를 한 줄씩 살펴보겠습니다. 먼저 pipeline("question-answering")으로 QA 파이프라인을 생성합니다.
이 한 줄이 사전 학습된 강력한 모델을 불러옵니다. 다음으로 context 변수에 답을 찾을 문서를 저장하고, question 변수에 질문을 담습니다.
마지막으로 qa_pipeline()을 호출하면 모델이 문맥을 분석하여 답변과 신뢰도 점수를 반환합니다. 실제 현업에서는 어떻게 활용할까요?
예를 들어 온라인 쇼핑몰의 고객센터를 생각해봅시다. 고객이 "반품은 며칠 이내에 가능한가요?"라고 질문하면, QA 시스템이 반품 정책 문서에서 "구매 후 14일 이내"라는 정확한 답을 찾아 응답합니다.
이렇게 하면 상담원의 업무 부담이 크게 줄어들고, 고객은 빠른 답변을 받을 수 있습니다. 하지만 주의할 점도 있습니다.
QA 모델은 주어진 문맥 안에서만 답을 찾습니다. 문맥에 없는 정보는 답할 수 없습니다.
또한 문맥이 너무 길면 처리 속도가 느려지고 정확도도 떨어질 수 있습니다. 따라서 적절한 크기로 문서를 분할하는 전처리 과정이 중요합니다.
다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 조언대로 QA 파이프라인을 구현한 김개발 씨는 감탄했습니다.
"와, 이렇게 간단하게 되는 거였어요?" Question Answering의 기본을 이해했다면, 이제 더 정교한 Context 기반 답변 추출을 배워볼 차례입니다.
실전 팁
💡 - Hugging Face의 pipeline을 사용하면 복잡한 설정 없이 바로 QA 시스템을 구현할 수 있습니다
- 신뢰도 점수가 낮으면 "답을 찾을 수 없습니다"라고 응답하도록 임계값을 설정하세요
- 한국어 QA에는 KoELECTRA나 KoBERT 기반 모델을 사용하면 더 좋은 성능을 얻을 수 있습니다
2. Context 기반 답변 추출
김개발 씨는 QA 시스템의 기본을 익힌 후, 새로운 고민에 빠졌습니다. "문서가 수십 페이지나 되는데, 어떤 부분을 context로 넣어야 하지?" 이때 박시니어 씨가 핵심을 짚어주었습니다.
"답변의 품질은 context 선택에 달려 있어요."
Context 기반 답변 추출은 관련 있는 문맥을 정확히 찾아내고, 그 안에서 답을 추출하는 과정입니다. 마치 시험 문제를 풀 때 지문에서 답의 근거를 찾는 것과 같습니다.
적절한 context를 선택하는 것이 QA 시스템의 성능을 좌우하는 핵심 요소입니다.
다음 코드를 살펴봅시다.
from transformers import AutoTokenizer, AutoModelForQuestionAnswering
import torch
# 모델과 토크나이저 로드
model_name = "deepset/roberta-base-squad2"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForQuestionAnswering.from_pretrained(model_name)
def extract_answer(question, context):
# 입력 토큰화 - context와 question을 함께 인코딩
inputs = tokenizer(question, context, return_tensors="pt",
truncation=True, max_length=512)
# 모델 추론
with torch.no_grad():
outputs = model(**inputs)
# 시작/끝 위치에서 가장 높은 점수를 가진 인덱스 찾기
start_idx = torch.argmax(outputs.start_logits)
end_idx = torch.argmax(outputs.end_logits)
# 토큰을 텍스트로 변환
tokens = tokenizer.convert_ids_to_tokens(inputs["input_ids"][0])
answer = tokenizer.convert_tokens_to_string(tokens[start_idx:end_idx+1])
return answer.strip()
김개발 씨는 QA 파이프라인이 어떻게 작동하는지 궁금해졌습니다. 단순히 pipeline()을 호출하는 것만으로는 성에 차지 않았습니다.
"내부에서 무슨 일이 벌어지는 거죠?" 박시니어 씨가 화이트보드에 그림을 그리며 설명을 시작했습니다. "QA 모델은 사실 두 가지를 예측해요.
답변이 시작되는 위치와 끝나는 위치를요." 쉽게 비유하자면, 이것은 마치 형광펜으로 밑줄을 긋는 것과 같습니다. 선생님이 "이 문단에서 핵심 내용에 밑줄을 그어보세요"라고 하면, 학생은 시작점과 끝점을 정해서 형광펜을 긋습니다.
QA 모델도 마찬가지입니다. 전체 context에서 답변에 해당하는 부분의 시작과 끝을 찾아 "밑줄"을 긋는 것입니다.
이 방식을 **추출적 QA(Extractive QA)**라고 부릅니다. 추출적 QA의 핵심은 context 안에 반드시 답이 존재해야 한다는 것입니다.
모델은 새로운 답을 만들어내지 않고, 오직 주어진 텍스트에서 답을 "추출"합니다. 이것이 장점이자 한계입니다.
답이 명확하게 문서에 있으면 정확하게 찾지만, 없으면 찾지 못합니다. 위의 코드를 자세히 살펴보겠습니다.
먼저 AutoTokenizer와 AutoModelForQuestionAnswering을 사용해 사전 학습된 모델을 불러옵니다. deepset/roberta-base-squad2는 SQuAD 2.0 데이터셋으로 훈련된 강력한 모델입니다.
토크나이저는 질문과 context를 모델이 이해할 수 있는 숫자로 변환합니다. outputs.start_logits와 outputs.end_logits가 핵심입니다.
모델은 각 토큰이 답변의 시작점일 확률과 끝점일 확률을 계산합니다. torch.argmax()를 사용해 가장 높은 확률을 가진 위치를 찾습니다.
그 후 해당 범위의 토큰들을 다시 텍스트로 변환하면 최종 답변이 완성됩니다. 실무에서는 context chunking이 중요합니다.
대부분의 모델은 512개의 토큰만 처리할 수 있습니다. 긴 문서는 여러 개의 chunk로 나누어야 합니다.
이때 chunk 사이에 중복(overlap)을 두면 답변이 chunk 경계에 걸치는 문제를 방지할 수 있습니다. 또한 no answer 상황을 처리해야 합니다.
SQuAD 2.0으로 훈련된 모델은 context에 답이 없을 때 이를 감지할 수 있습니다. start_logits와 end_logits의 최댓값이 특정 임계값보다 낮으면 "답을 찾을 수 없습니다"라고 응답하도록 구현합니다.
다시 김개발 씨의 이야기로 돌아가 봅시다. 코드를 직접 실행해본 김개발 씨는 이제 QA 모델의 내부 동작을 이해하게 되었습니다.
"시작과 끝 위치를 예측하는 거였군요! 이제 왜 context가 중요한지 알겠어요."
실전 팁
💡 - 긴 문서는 200-300 토큰 단위로 나누되, 50 토큰 정도 중복을 두세요
- start_logits + end_logits의 합이 가장 큰 구간을 답으로 선택하면 더 정확합니다
- 답변이 없는 경우를 대비해 confidence threshold를 설정하세요
3. 텍스트 요약 모델
어느 날 김개발 씨에게 새로운 업무가 주어졌습니다. "매일 쏟아지는 뉴스 기사를 한 줄로 요약해주는 기능을 만들어주세요." 수백 개의 기사를 사람이 일일이 읽고 요약하는 건 불가능했습니다.
이때 필요한 것이 바로 텍스트 요약 모델입니다.
**텍스트 요약(Text Summarization)**은 긴 문서의 핵심 내용을 짧게 압축하는 AI 기술입니다. 마치 두꺼운 소설의 줄거리를 한 문단으로 정리하는 것과 같습니다.
뉴스 요약, 논문 초록 생성, 회의록 정리 등 다양한 분야에서 필수적으로 사용되는 기술입니다.
다음 코드를 살펴봅시다.
from transformers import pipeline
# 요약 파이프라인 생성
summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
# 요약할 긴 텍스트
article = """
인공지능 기술이 빠르게 발전하면서 다양한 산업에 혁신을 가져오고 있습니다.
특히 자연어 처리 분야에서는 GPT, BERT 등의 대규모 언어 모델이 등장하여
기계번역, 문서 요약, 질의응답 등의 작업에서 인간 수준의 성능을 보여주고 있습니다.
이러한 기술은 고객 서비스, 의료 진단, 법률 문서 분석 등
실생활의 다양한 영역에서 활용되고 있으며,
앞으로 더욱 광범위하게 적용될 것으로 예상됩니다.
"""
# 요약 실행
summary = summarizer(article, max_length=50, min_length=20, do_sample=False)
print(f"요약 결과: {summary[0]['summary_text']}")
김개발 씨의 회사는 매일 수백 개의 뉴스 기사를 수집합니다. 마케팅팀은 이 중에서 자사와 관련된 기사를 빠르게 파악해야 했습니다.
하지만 모든 기사를 읽는 건 현실적으로 불가능했습니다. "한 줄 요약만 있으면 훨씬 빠르게 훑어볼 수 있을 텐데요." 마케팅팀장의 요청에 김개발 씨는 텍스트 요약 기술을 조사하기 시작했습니다.
텍스트 요약은 마치 뛰어난 비서가 회의록을 정리하는 것과 같습니다. 두 시간짜리 회의 내용을 핵심만 추려서 한 페이지로 정리해주는 비서를 상상해보세요.
중요한 결정 사항, 주요 논의 내용, 다음 액션 아이템만 깔끔하게 담아냅니다. 텍스트 요약 모델도 이와 같은 일을 합니다.
요약 기술은 크게 두 가지 접근 방식이 있습니다. 첫 번째는 **추출적 요약(Extractive Summarization)**입니다.
원문에서 중요한 문장을 그대로 뽑아서 조합합니다. 두 번째는 **생성적 요약(Abstractive Summarization)**입니다.
원문을 이해한 후 새로운 문장으로 다시 작성합니다. 위 코드에서 사용한 BART 모델은 생성적 요약을 수행합니다.
왜 BART가 요약에 적합할까요? **BART(Bidirectional and Auto-Regressive Transformers)**는 인코더-디코더 구조를 가진 모델입니다.
인코더가 원문을 깊이 이해하고, 디코더가 새로운 요약문을 생성합니다. 특히 facebook/bart-large-cnn은 CNN/DailyMail 뉴스 데이터셋으로 훈련되어 뉴스 요약에 뛰어난 성능을 보입니다.
코드를 살펴보면 몇 가지 중요한 파라미터가 있습니다. max_length는 생성할 요약의 최대 길이를, min_length는 최소 길이를 지정합니다.
do_sample=False는 가장 확률이 높은 단어만 선택하는 그리디 디코딩을 사용한다는 의미입니다. 이렇게 하면 결과가 일관되고 예측 가능합니다.
실무에서 요약 모델을 적용할 때 주의할 점이 있습니다. 요약 모델도 입력 길이에 제한이 있습니다.
BART는 약 1024개의 토큰까지 처리할 수 있습니다. 더 긴 문서는 여러 부분으로 나누어 각각 요약한 후, 다시 전체를 요약하는 계층적 요약 방식을 사용합니다.
또한 환각(Hallucination) 문제를 주의해야 합니다. 생성적 요약 모델은 때때로 원문에 없는 내용을 만들어낼 수 있습니다.
특히 숫자, 이름, 날짜 등의 구체적인 정보가 잘못될 위험이 있습니다. 따라서 중요한 정보는 원문과 대조하는 후처리 과정이 필요할 수 있습니다.
김개발 씨는 요약 파이프라인을 적용하여 뉴스 기사 요약 시스템을 완성했습니다. 마케팅팀은 이제 수백 개의 기사를 요약본만으로 빠르게 스캔할 수 있게 되었습니다.
실전 팁
💡 - 한국어 요약에는 KoBART나 KoT5 모델을 사용하세요
- 요약 품질을 평가할 때는 ROUGE 점수를 활용합니다
- 환각 문제를 줄이려면 beam search와 length penalty를 조절해보세요
4. 요약 길이 조절
김개발 씨가 만든 요약 시스템을 사용하던 마케팅팀에서 요청이 들어왔습니다. "어떤 기사는 한 줄로, 어떤 기사는 세 줄로 요약해주면 안 될까요?" 요약의 길이를 상황에 맞게 조절하는 것이 다음 과제가 되었습니다.
요약 길이 조절은 사용 목적에 따라 요약문의 길이를 유연하게 조정하는 기술입니다. 마치 영화 예고편이 15초짜리도 있고 2분짜리도 있는 것처럼, 같은 내용도 다양한 길이로 요약할 수 있어야 합니다.
적절한 파라미터 조정으로 원하는 길이의 요약을 생성할 수 있습니다.
다음 코드를 살펴봅시다.
from transformers import pipeline
summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
text = """
클라우드 컴퓨팅은 인터넷을 통해 컴퓨팅 리소스를 제공하는 서비스입니다.
사용자는 물리적 서버를 직접 관리할 필요 없이 필요한 만큼의 자원을
유연하게 사용할 수 있습니다. 주요 서비스 모델로는 IaaS, PaaS, SaaS가 있으며,
각각 인프라, 플랫폼, 소프트웨어 수준의 서비스를 제공합니다.
AWS, Azure, GCP가 대표적인 클라우드 서비스 제공업체입니다.
"""
# 짧은 요약 (1-2문장)
short_summary = summarizer(text, max_length=30, min_length=10, do_sample=False)
# 중간 길이 요약 (2-3문장)
medium_summary = summarizer(text, max_length=60, min_length=30, do_sample=False)
# 긴 요약 (3-4문장)
long_summary = summarizer(text, max_length=100, min_length=50, do_sample=False)
print(f"짧은 요약: {short_summary[0]['summary_text']}")
print(f"중간 요약: {medium_summary[0]['summary_text']}")
print(f"긴 요약: {long_summary[0]['summary_text']}")
마케팅팀의 요청은 합리적이었습니다. 뉴스 목록을 빠르게 훑어볼 때는 한 줄 요약이 필요하고, 관심 있는 기사를 좀 더 자세히 파악할 때는 세 줄 요약이 필요했습니다.
김개발 씨는 요약 길이를 조절하는 방법을 연구하기 시작했습니다. 요약 길이 조절은 마치 줌 렌즈와 같습니다.
사진을 찍을 때 줌을 당기면 디테일이 보이고, 줌을 빼면 전체 풍경이 한눈에 들어옵니다. 요약도 마찬가지입니다.
짧게 요약하면 핵심만, 길게 요약하면 더 많은 세부사항이 포함됩니다. 가장 기본적인 방법은 max_length와 min_length 파라미터입니다.
max_length는 생성할 요약의 최대 토큰 수를 제한합니다. 모델은 이 길이를 넘지 않도록 요약을 생성합니다.
min_length는 최소 길이를 보장합니다. 너무 짧은 요약이 생성되는 것을 방지합니다.
하지만 단순히 길이만 조절하면 문제가 생길 수 있습니다. max_length를 너무 짧게 설정하면 문장이 중간에 끊길 수 있습니다.
반대로 너무 길게 설정하면 불필요한 내용이 반복될 수 있습니다. 따라서 length_penalty 파라미터를 함께 사용하면 더 자연스러운 결과를 얻을 수 있습니다.
length_penalty는 생성되는 시퀀스의 길이에 패널티를 부여합니다. 1.0보다 큰 값은 더 긴 요약을, 1.0보다 작은 값은 더 짧은 요약을 유도합니다.
예를 들어 length_penalty=2.0으로 설정하면 모델은 가능한 한 길게 요약하려고 합니다. 또 다른 유용한 파라미터는 num_beams입니다.
Beam search는 여러 개의 후보 시퀀스를 동시에 탐색합니다. num_beams=4로 설정하면 4개의 후보 중 가장 좋은 요약을 선택합니다.
계산 비용은 증가하지만 품질이 향상됩니다. 실무에서는 상황별로 프리셋을 만들어두면 편리합니다.
"헤드라인용 한 줄 요약", "이메일 발송용 세 줄 요약", "리포트용 문단 요약" 같은 프리셋을 미리 정의해두면, 사용자가 선택만 하면 적절한 길이의 요약을 받을 수 있습니다. 김개발 씨는 세 가지 길이 옵션을 제공하는 API를 완성했습니다.
마케팅팀은 상황에 맞는 요약을 선택해서 사용할 수 있게 되었고, 업무 효율이 크게 향상되었습니다.
실전 팁
💡 - length_penalty를 0.8~1.2 사이에서 조절하며 최적값을 찾아보세요
- early_stopping=True를 설정하면 모든 beam이 종료 토큰에 도달했을 때 생성이 멈춥니다
- 요약 비율(원문 대비 요약 길이)을 10-30% 사이로 유지하면 좋습니다
5. 추출적 vs 생성적 요약
박시니어 씨가 코드 리뷰 중에 질문을 던졌습니다. "생성적 요약만 쓰고 있는데, 추출적 요약은 고려해봤어요?" 김개발 씨는 두 방식의 차이가 궁금해졌습니다.
각각 언제 사용해야 하는 걸까요?
**추출적 요약(Extractive)**은 원문에서 중요한 문장을 그대로 선택하는 방식이고, **생성적 요약(Abstractive)**은 원문을 이해한 후 새로운 문장으로 재구성하는 방식입니다. 마치 인용과 의역의 차이와 같습니다.
각 방식은 장단점이 있어 상황에 맞게 선택해야 합니다.
다음 코드를 살펴봅시다.
# 추출적 요약 - 중요 문장 선택
from transformers import pipeline
import nltk
from nltk.tokenize import sent_tokenize
from sklearn.feature_extraction.text import TfidfVectorizer
import numpy as np
def extractive_summary(text, num_sentences=2):
# 문장 분리
sentences = sent_tokenize(text)
# TF-IDF로 문장 중요도 계산
vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(sentences)
# 각 문장의 평균 TF-IDF 점수 계산
scores = np.array(tfidf_matrix.sum(axis=1)).flatten()
# 가장 중요한 문장 선택 (원래 순서 유지)
ranked_indices = np.argsort(scores)[-num_sentences:]
ranked_indices = sorted(ranked_indices)
return ' '.join([sentences[i] for i in ranked_indices])
# 생성적 요약 - 새로운 문장 생성
def abstractive_summary(text, max_length=50):
summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
result = summarizer(text, max_length=max_length, min_length=20)
return result[0]['summary_text']
김개발 씨는 지금까지 생성적 요약만 사용해왔습니다. BART나 T5 같은 모델이 새로운 문장을 만들어내는 것이 당연하다고 생각했습니다.
하지만 박시니어 씨의 질문은 새로운 관점을 제시했습니다. "두 방식은 근본적으로 철학이 달라요." 추출적 요약을 비유하자면, 책에서 중요한 문장에 형광펜을 긋는 것과 같습니다.
원저자의 표현을 그대로 사용하므로 의미가 왜곡될 위험이 없습니다. 반면 생성적 요약은 책을 읽고 자신의 말로 다시 정리하는 것과 같습니다.
더 간결하고 자연스럽지만, 원래 의미와 다르게 표현될 수 있습니다. 추출적 요약의 장점을 살펴봅시다.
첫째, 정확성이 보장됩니다. 원문을 그대로 인용하므로 환각(hallucination) 문제가 없습니다.
둘째, 계산 비용이 저렴합니다. 복잡한 생성 과정 없이 문장의 중요도만 계산하면 됩니다.
셋째, 인용 출처를 명확히 할 수 있습니다. 위 코드에서 추출적 요약은 TF-IDF를 사용합니다.
**TF-IDF(Term Frequency-Inverse Document Frequency)**는 단어의 중요도를 측정하는 통계적 방법입니다. 자주 등장하지만 흔하지 않은 단어를 포함한 문장이 높은 점수를 받습니다.
이렇게 계산된 점수를 기준으로 가장 중요한 문장들을 선택합니다. 생성적 요약의 장점도 있습니다.
첫째, 더 자연스럽고 읽기 쉬운 요약을 만들 수 있습니다. 추출적 요약은 때로 문맥이 끊기는 느낌을 줄 수 있습니다.
둘째, 더 간결한 표현이 가능합니다. 여러 문장의 내용을 하나의 문장으로 압축할 수 있습니다.
셋째, 질문에 맞춤화된 요약이 가능합니다. 그렇다면 언제 어떤 방식을 선택해야 할까요?
추출적 요약은 법률 문서, 과학 논문, 뉴스 기사 등 정확성이 중요한 경우에 적합합니다. 원문의 표현을 유지해야 할 때 사용합니다.
생성적 요약은 마케팅 콘텐츠, 소셜 미디어 포스트, 일반적인 정보 전달 등 가독성이 중요한 경우에 적합합니다. 최근에는 하이브리드 방식도 많이 사용됩니다.
먼저 추출적 방법으로 중요한 문장들을 선별한 후, 생성적 모델이 이를 다듬어 최종 요약을 만듭니다. 이렇게 하면 정확성과 가독성을 모두 확보할 수 있습니다.
김개발 씨는 두 가지 방식을 모두 제공하기로 했습니다. 법무팀은 추출적 요약을, 마케팅팀은 생성적 요약을 선호한다는 것을 알게 되었기 때문입니다.
실전 팁
💡 - 법률이나 의료 분야에서는 정확성을 위해 추출적 요약을 권장합니다
- 추출적 요약에는 TextRank, LexRank 같은 그래프 기반 알고리즘도 효과적입니다
- 하이브리드 방식을 사용하면 두 장점을 모두 취할 수 있습니다
6. 실전 문서 처리
김개발 씨는 드디어 실전 프로젝트를 맡게 되었습니다. 회사의 기술 문서 수천 개를 QA 시스템과 요약 기능으로 처리해야 합니다.
지금까지 배운 모든 것을 종합해서 실제 서비스를 구축할 차례입니다.
실전 문서 처리는 QA와 요약 기술을 실제 서비스에 적용하는 과정입니다. 대용량 문서 처리, 청크 분할, 벡터 검색, 파이프라인 구성 등 다양한 기술을 조합해야 합니다.
마치 레고 블록처럼 각 기술을 조합하여 완전한 시스템을 만드는 것입니다.
다음 코드를 살펴봅시다.
from transformers import pipeline
from langchain.text_splitter import RecursiveCharacterTextSplitter
from sentence_transformers import SentenceTransformer
import numpy as np
class DocumentProcessor:
def __init__(self):
# 모델 초기화
self.qa_pipeline = pipeline("question-answering")
self.summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
self.embedder = SentenceTransformer('all-MiniLM-L6-v2')
# 텍스트 분할기 설정
self.splitter = RecursiveCharacterTextSplitter(
chunk_size=500, chunk_overlap=50
)
def process_document(self, document):
# 문서를 청크로 분할
chunks = self.splitter.split_text(document)
# 각 청크의 임베딩 계산
embeddings = self.embedder.encode(chunks)
return chunks, embeddings
def find_relevant_context(self, question, chunks, embeddings, top_k=3):
# 질문 임베딩
q_embedding = self.embedder.encode([question])[0]
# 유사도 계산 및 상위 k개 선택
similarities = np.dot(embeddings, q_embedding)
top_indices = np.argsort(similarities)[-top_k:][::-1]
return ' '.join([chunks[i] for i in top_indices])
def answer_question(self, question, document):
chunks, embeddings = self.process_document(document)
context = self.find_relevant_context(question, chunks, embeddings)
return self.qa_pipeline(question=question, context=context)
def summarize_document(self, document, max_length=150):
return self.summarizer(document, max_length=max_length, min_length=50)
김개발 씨는 마침내 모든 퍼즐 조각을 맞출 때가 되었습니다. 개별 기술들을 배웠지만, 실제 서비스를 만들려면 이것들을 하나로 엮어야 합니다.
박시니어 씨가 조언했습니다. "실전에서는 '문서 → 청크 → 검색 → 처리'라는 파이프라인이 핵심이에요." 이 파이프라인은 마치 정수기의 여러 필터와 같습니다.
수돗물이 여러 필터를 거쳐 깨끗한 물이 되듯이, 원본 문서도 여러 단계를 거쳐 유용한 정보로 변환됩니다. 각 단계가 제 역할을 해야 최종 결과물의 품질이 보장됩니다.
첫 번째 단계는 **문서 청킹(Chunking)**입니다. 대부분의 모델은 긴 문서를 한 번에 처리할 수 없습니다.
RecursiveCharacterTextSplitter는 문서를 적절한 크기로 나눕니다. chunk_size=500은 각 조각의 최대 크기를, chunk_overlap=50은 조각 간 중복을 설정합니다.
중복이 있으면 문맥이 끊기는 것을 방지할 수 있습니다. 두 번째 단계는 **임베딩(Embedding)**입니다.
텍스트를 숫자 벡터로 변환하는 과정입니다. SentenceTransformer는 문장의 의미를 384차원(또는 모델에 따라 다름)의 벡터로 표현합니다.
의미가 비슷한 문장은 벡터 공간에서 가까이 위치합니다. 세 번째 단계는 유사도 검색입니다.
질문도 임베딩으로 변환한 후, 모든 청크 임베딩과 비교합니다. 내적(dot product)이나 코사인 유사도를 계산하여 가장 관련 있는 청크들을 찾습니다.
이것이 **벡터 검색(Vector Search)**의 핵심입니다. 마지막으로 QA 또는 요약을 수행합니다.
찾아낸 관련 청크들을 context로 사용하여 질문에 답하거나, 요약을 생성합니다. 전체 문서가 아닌 관련된 부분만 사용하므로 정확도가 높아지고 처리 속도도 빨라집니다.
실무에서는 추가로 고려할 사항이 있습니다. 대용량 문서를 처리할 때는 FAISS나 Pinecone 같은 벡터 데이터베이스를 사용합니다.
수백만 개의 벡터에서 밀리초 단위로 검색이 가능합니다. 또한 캐싱을 적용하여 같은 질문에 대한 반복 처리를 줄일 수 있습니다.
에러 처리도 중요합니다. 문서 형식 오류, 인코딩 문제, 모델 타임아웃 등 다양한 예외 상황을 처리해야 합니다.
프로덕션 환경에서는 로깅과 모니터링도 필수입니다. 김개발 씨는 완성된 시스템을 테스트했습니다.
수천 개의 기술 문서에서 원하는 정보를 즉시 찾을 수 있었고, 긴 문서도 순식간에 요약되었습니다. "드디어 완성이네요!" 박시니어 씨가 웃으며 말했습니다.
"축하해요. 이제 진짜 시작이에요.
실제 사용자 피드백을 받으면서 계속 개선해나가면 됩니다." 김개발 씨는 QA와 요약 기술의 기초부터 실전까지 모두 익혔습니다. 이제 여러분도 이 기술들을 활용해 멋진 서비스를 만들어보세요.
실전 팁
💡 - 프로덕션에서는 FAISS나 Pinecone 같은 벡터 DB를 사용하여 검색 속도를 높이세요
- 청크 크기는 모델의 최대 토큰 수와 문서 특성을 고려해 조절합니다
- LangChain이나 LlamaIndex 같은 프레임워크를 활용하면 파이프라인 구축이 더 쉬워집니다
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
실전 프로젝트: 시맨틱 검색 엔진
단순 키워드 매칭을 넘어 의미 기반으로 검색하는 시맨틱 검색 엔진을 처음부터 구현합니다. 문서 임베딩부터 벡터 검색, UI 설계, 성능 최적화까지 실전에서 바로 쓸 수 있는 검색 시스템을 만들어봅니다.
실전 프로젝트 이미지 분석 앱 만들기
드래그앤드롭으로 이미지를 업로드하고, AI 모델로 분석한 결과를 시각화하여 내보내는 완성형 웹 앱을 만들어봅니다. 초급 개발자도 따라할 수 있도록 단계별로 설명합니다.
실전 프로젝트 AI 챗봇 만들기 완벽 가이드
처음부터 끝까지 AI 챗봇을 직접 만들어보는 실전 프로젝트입니다. 아키텍처 설계부터 대화 모델 선택, UI 구현, 스트리밍 응답까지 단계별로 배워봅니다.
브라우저 환경 최적화 완벽 가이드
웹 브라우저에서 AI 모델을 효율적으로 실행하기 위한 최적화 기법을 다룹니다. 호환성 확인부터 Service Worker 캐싱까지, 실무에서 바로 적용할 수 있는 핵심 전략을 배워봅니다.
모델 최적화와 양자화 완벽 가이드
웹 브라우저에서 AI 모델을 효율적으로 실행하기 위한 최적화 기법을 다룹니다. 양자화부터 WebGPU 가속, Web Worker 활용까지 초급 개발자도 쉽게 따라할 수 있도록 설명합니다.