LLM을 활용한 질의응답 모델 구축: 단계별 가이드
요약
비공개 텍스트 코퍼스를 활용하여 검색 증강 질의응답(RAG) 에이전트를 구축하는 단계별 가이드를 제공합니다. 로컬 임베딩 모델과 Oxlo.ai LLM을 결합하여 효율적이고 근거 있는 답변 시스템을 만드는 방법을 다룹니다.
핵심 포인트
- Oxlo.ai API를 활용한 LLM 클라이언트 설정 방법
- 문서 로드 및 효과적인 청킹(Chunking) 전략
- sentence-transformers를 이용한 로컬 임베딩 인덱스 구축
- 코사인 유사도 기반의 관련 컨텍스트 검색 구현
- 환각 방지를 위한 시스템 프롬프트 설계
우리는 비공개 텍스트 코퍼스(text corpus)로부터 질문에 답하는 검색 증강 질의응답 (Retrieval-Augmented Question Answering, RAG) 에이전트를 구축할 것입니다. 이는 지원 팀, 법률 연구자, 또는 미세 조정 (fine-tuning) 없이 근거 있는 답변이 필요한 모든 이들에게 유용합니다. 우리는 검색을 위해 로컬 임베딩 (embedding) 모델을 사용하고, 생성 (generation)을 위해 Oxlo.ai LLM을 사용할 것입니다.
필요한 사항
- Python 3.10 이상.
- OpenAI SDK 및 몇 가지 헬퍼 도구:
pip install openai sentence-transformers numpy. - https://portal.oxlo.ai에서 발급받은 Oxlo.ai API 키.
1단계: Oxlo.ai 클라이언트 설정
OpenAI SDK를 임포트(import)하고 이를 Oxlo.ai로 지정합니다. 코드 스니펫을 바로 복사하여 사용할 수 있도록 베이스 URL (base URL)과 키를 인라인으로 유지했습니다.
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
2단계: 문서 로드 및 청킹 (chunking)
외부 파일 없이 스크립트가 실행될 수 있도록 짧은 기사를 하드코딩했습니다. 실제 운영 환경에서는 디스크에서 PDF 또는 Markdown 파일을 로드하게 됩니다. 문단을 온전하게 유지하기 위해 이중 줄바꿈을 기준으로 분할했습니다.
DOCUMENT = """Apollo 11 was the spaceflight that landed the first humans on the Moon.
Commander Neil Armstrong and lunar module pilot Buzz Aldrin landed the Apollo Lunar Module Eagle on July 20, 1969.
Armstrong became the first person to step onto the lunar surface six and a half hours later on July 21.
...
3단계: 로컬 임베딩 인덱스 구축
청크 (chunks)를 인코딩하기 위해 로컬에서 실행되는 sentence-transformers를 사용합니다. 이를 통해 검색 단계를 무료이며 빠르게 유지하는 동시에, 무거운 생성 작업은 Oxlo.ai로 전송합니다.
from sentence_transformers import SentenceTransformer
import numpy as np
...
4단계: 관련 컨텍스트 검색
질문이 들어오면 동일한 모델로 질문을 임베딩하고 인덱스에 대해 코사인 유사도 (cosine similarity)를 계산합니다. 컨텍스트 윈도우 (context window)를 집중시키기 위해 상위 3개의 청크를 반환합니다.
def retrieve(query: str, top_k: int = 3):
query_embedding = embedder.encode([query], convert_to_numpy=True)
similarities = np.dot(chunk_embeddings, query_embedding.T).squeeze()
...
Step 5: QA 시스템 프롬프트 정의
시스템 프롬프트 (system prompt)는 모델이 검색된 증거에만 집중하도록 제한하여 환각 (hallucination)을 방지합니다. 또한, 답변을 쉽게 훑어볼 수 있도록 간결함을 강제합니다.
SYSTEM_PROMPT = (
"You are a strict question-answering assistant. "
"Answer using ONLY the context provided below. "
...
Step 6: Oxlo.ai를 사용하여 답변 생성하기
이제 검색 (retrieval)과 생성 (generation)을 하나로 연결합니다. 상위 청크들을 하나의 컨텍스트 (context) 블록으로 결합하여 질문과 함께 모델에 전달하고, 생성된 답변을 반환합니다. Oxlo.ai는 요청당 고정 가격제 (flat per-request pricing)를 사용하므로, 토큰 길이에 따른 비용 상승을 걱정하지 않고 매 호출마다 전체 검색 컨텍스트를 전달할 수 있습니다.
def answer_question(question: str) -> str:
context = "\n\n".join(retrieve(question))
user_message = f"Context:\n{context}\n\nQuestion: {question}"
...
실행하기
텍스트에서 답을 찾을 수 있는 질문으로 함수를 호출합니다. 추론 모델 (reasoning models)을 실험해보고 싶다면, 다른 코드를 변경할 필요 없이 llama-3.3-70b를 deepseek-v3.2나 qwen-3-32b로 교체하면 됩니다.
if __name__ == "__main__":
q = "What did Neil Armstrong say when he stepped onto the Moon?"
print(f"Q: {q}")
...
예상 출력:
Q: What did Neil Armstrong say when he stepped onto the Moon?
A: Neil Armstrong said, "That's one small step for [a] man, one giant leap for mankind."
다음 단계
하드코딩된 문자열을 PyPDF 또는 Unstructured와 같은 실제 문서 로더 (document loader)로 교체하여 에이전트가 PDF나 마크다운 (Markdown) 폴더를 가리키도록 할 수 있습니다. 멀티턴 대화 (multi-turn conversations)가 필요한 경우, 각 대화 내용을 messages 리스트에 추가하여 사용자가 동일한 코퍼스 (corpus)에 대해 후속 질문을 할 수 있도록 만드세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기