5분 만에 DeepSeek로 RAG 구현하기
5분 만에 DeepSeek로 RAG 구현하기 (tutorials-build-essentials-rag-deepseek)
| 소요 시간: 5분 | 난이도: 입문(Beginner) | 결과물: GitHub |
|---|
이 튜토리얼에서는 벡터 저장 솔루션으로 Qdrant를, 시맨틱 쿼리 보강에는 DeepSeek를 사용해서 RAG(검색 증강 생성, Retrieval-Augmented Generation) 파이프라인을 구축하는 방법을 보여드릴게요. RAG 파이프라인은 맥락적으로 관련 있는 데이터를 제공해서 LLM(대규모 언어 모델)의 응답을 향상시켜요.
개요 (Overview)
이 튜토리얼에서 우리가 할 작업은 이래요:
- 샘플 텍스트를 FastEmbed로 벡터로 변환하기.
- 벡터를 Qdrant 컬렉션으로 보내기.
- Qdrant와 DeepSeek를 최소 RAG 파이프라인으로 연결하기.
- DeepSeek에 여러 가지 질문을 하고 답변 정확도를 확인하기.
- Qdrant에서 검색한 콘텐츠로 DeepSeek 프롬프트를 보강하기.
- 전후의 답변 정확도를 평가하기.
아키텍처 (Architecture):

사전 준비 (Prerequisites)
다음이 준비되어 있는지 확인하세요:
- Python 환경 (3.9+)
- Qdrant Cloud 접근 권한
- DeepSeek 플랫폼에서 발급받은 DeepSeek API 키
Qdrant 설정
pip install "qdrant-client[fastembed]>=1.14.1"
Qdrant는 LLM에 보낼 프롬프트에 컨텍스트 정보를 제공하는 지식 기반 역할을 해요.
영구 무료(free-forever) Qdrant 클라우드 인스턴스는 http://cloud.qdrant.io에서 얻을 수 있어요. 인스턴스 설정 방법은 Quickstart에서 배울 수 있어요.
QDRANT_URL = "https://xyz-example.eu-central.aws.cloud.qdrant.io:6333"
QDRANT_API_KEY = "<your-api-key>"
Qdrant 클라이언트 인스턴스화
from qdrant_client import QdrantClient, models
client = QdrantClient(url=QDRANT_URL, api_key=QDRANT_API_KEY)
지식 기반 구축하기
Qdrant는 우리 사실들의 벡터 임베딩을 사용해서 원래 프롬프트에 컨텍스트를 보강할 거예요. 그래서 벡터 임베딩과, 그것을 만드는 데 쓰인 사실들을 모두 저장해야 해요.
FastEmbed를 통해 bge-base-en-v1.5 모델을 사용할 거예요. 임베딩 생성을 위한 가볍고 빠른 Python 라이브러리죠.
Qdrant 클라이언트는 FastEmbed와의 손쉬운 통합을 제공해서 지식 기반 구축을 아주 직관적으로 만들어요.
먼저 컬렉션을 만들어서 Qdrant가 어떤 벡터를 다룰지 알게 하고, 그런 다음 raw 문서를 models.Document로 감싸서 임베딩을 계산하고 업로드하면 돼요.
collection_name = "knowledge_base"
model_name = "BAAI/bge-small-en-v1.5"
client.create_collection(
collection_name=collection_name,
vectors_config=models.VectorParams(size=384, distance=models.Distance.COSINE)
)
documents = [
"Qdrant is a vector database & vector similarity search engine. It deploys as an API service providing search for the nearest high-dimensional vectors. With Qdrant, embeddings or neural network encoders can be turned into full-fledged applications for matching, searching, recommending, and much more!",
"Docker helps developers build, share, and run applications anywhere — without tedious environment configuration or management.",
"PyTorch is a machine learning framework based on the Torch library, used for applications such as computer vision and natural language processing.",
"MySQL is an open-source relational database management system (RDBMS). A relational database organizes data into one or more data tables in which data may be related to each other; these relations help structure the data. SQL is a language that programmers use to create, modify and extract data from the relational database, as well as control user access to the database.",
"NGINX is a free, open-source, high-performance HTTP server and reverse proxy, as well as an IMAP/POP3 proxy server. NGINX is known for its high performance, stability, rich feature set, simple configuration, and low resource consumption.",
"FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints.",
"SentenceTransformers is a Python framework for state-of-the-art sentence, text and image embeddings. You can use this framework to compute sentence / text embeddings for more than 100 languages. These embeddings can then be compared e.g. with cosine-similarity to find sentences with a similar meaning. This can be useful for semantic textual similar, semantic search, or paraphrase mining.",
"The cron command-line utility is a job scheduler on Unix-like operating systems. Users who set up and maintain software environments use cron to schedule jobs (commands or shell scripts), also known as cron jobs, to run periodically at fixed times, dates, or intervals.",
]
client.upsert(
collection_name=collection_name,
points=[
models.PointStruct(
id=idx,
vector=models.Document(text=document, model=model_name),
payload={"document": document},
)
for idx, document in enumerate(documents)
],
)
DeepSeek 설정
RAG는 우리가 대규모 언어 모델과 상호작용하는 방식을 바꿔요. 모델이 반사실적(counterfactual) 답변을 만들 수도 있는 지식 중심 작업을, 언어 중심 작업으로 바꾸는 거예요. 후자는 모델이 의미 있는 정보를 추출해서 답변을 생성하길 기대해요. LLM이 올바르게 구현되면 언어 중심 작업을 수행하도록 되어 있어요.
작업은 사용자가 보낸 원래 프롬프트에서 시작해요. 같은 프롬프트가 벡터화되어 가장 관련 있는 사실을 찾는 검색 쿼리로 사용돼요. 그 사실들이 원래 프롬프트와 합쳐져 더 많은 정보를 담은 더 긴 프롬프트가 만들어져요.
하지만 일단은 질문을 직접 던져 보는 것부터 간단히 시작할게요.
prompt = """
What tools should I need to use to build a web service using vector embeddings for search?
"""
DeepSeek API를 사용하려면 API 키를 제공해야 해요. DeepSeek 플랫폼에서 얻을 수 있어요.
이제 완성(completion) API를 호출할 수 있어요.
import requests
import json
# Fill the environmental variable with your own Deepseek API key
# See: https://platform.deepseek.com/api_keys
API_KEY = "<YOUR_DEEPSEEK_KEY>"
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
def query_deepseek(prompt):
data = {
"model": "deepseek-chat",
"messages": [{"role": "user", "content": prompt}],
"stream": False,
}
response = requests.post(
"https://api.deepseek.com/chat/completions",
headers=HEADERS,
data=json.dumps(data),
)
if response.ok:
result = response.json()
return result["choices"][0]["message"]["content"]
else:
raise Exception(f"Error {response.status_code}: {response.text}")
그리고 쿼리도요:
query_deepseek(prompt)
응답은 다음과 같아요:
"Building a web service that uses vector embeddings for search involves several components, including data processing, embedding generation, storage, search, and serving the service via an API. Below is a list of tools and technologies you can use for each step:
---
### 1. **Data Processing**
- **Python**: For general data preprocessing and scripting.
- **Pandas**: For handling tabular data.
- **NumPy**: For numerical operations.
- **NLTK/Spacy**: For text preprocessing (tokenization, stemming, etc.).
- **LLM models**: For generating embeddings if you're using pre-trained models.
---
### 2. **Embedding Generation**
- **Pre-trained Models**:
- Embeddings (e.g., `text-embedding-ada-002`).
- Hugging Face Transformers (e.g., `Sentence-BERT`, `all-MiniLM-L6-v2`).
- Google's Universal Sentence Encoder.
- **Custom Models**:
- TensorFlow/PyTorch: For training custom embedding models.
- **Libraries**:
- `sentence-transformers`: For generating sentence embeddings.
- `transformers`: For using Hugging Face models.
---
### 3. **Vector Storage**
- **Vector Databases**:
- Pinecone: Managed vector database for similarity search.
- Weaviate: Open-source vector search engine.
- Milvus: Open-source vector database.
- FAISS (Facebook AI Similarity Search): Library for efficient similarity search.
- Qdrant: Open-source vector search engine.
- Redis with RedisAI: For storing and querying vectors.
- **Traditional Databases with Vector Support**:
- PostgreSQL with pgvector extension.
- Elasticsearch with dense vector support.
---
### 4. **Search and Retrieval**
- **Similarity Search Algorithms**:
- Cosine similarity, Euclidean distance, or dot product for comparing vectors.
- **Libraries**:
- FAISS: For fast nearest-neighbor search.
- Annoy (Approximate Nearest Neighbors Oh Yeah): For approximate nearest neighbor search.
- **Vector Databases**: Most vector databases (e.g., Pinecone, Weaviate) come with built-in search capabilities.
---
### 5. **Web Service Framework**
- **Backend Frameworks**:
- Flask/Django/FastAPI (Python): For building RESTful APIs.
- Node.js/Express: If you prefer JavaScript.
- **API Documentation**:
- Swagger/OpenAPI: For documenting your API.
- **Authentication**:
- OAuth2, JWT: For securing your API.
---
### 6. **Deployment**
- **Containerization**:
- Docker: For packaging your application.
- **Orchestration**:
- Kubernetes: For managing containers at scale.
- **Cloud Platforms**:
- AWS (EC2, Lambda, S3).
- Google Cloud (Compute Engine, Cloud Functions).
- Azure (App Service, Functions).
- **Serverless**:
- AWS Lambda, Google Cloud Functions, or Vercel for serverless deployment.
---
### 7. **Monitoring and Logging**
- **Monitoring**:
- Prometheus + Grafana: For monitoring performance.
- **Logging**:
- ELK Stack (Elasticsearch, Logstash, Kibana).
- Fluentd.
- **Error Tracking**:
- Sentry.
---
### 8. **Frontend (Optional)**
- **Frontend Frameworks**:
- React, Vue.js, or Angular: For building a user interface.
- **Libraries**:
- Axios: For making API calls from the frontend.
---
### Example Workflow
1. Preprocess your data (e.g., clean text, tokenize).
2. Generate embeddings using a pre-trained model (e.g., Hugging Face).
3. Store embeddings in a vector database (e.g., Pinecone or FAISS).
4. Build a REST API using FastAPI or Flask to handle search queries.
5. Deploy the service using Docker and Kubernetes or a serverless platform.
6. Monitor and scale the service as needed.
---
### Example Tools Stack
- **Embedding Generation**: Hugging Face `sentence-transformers`.
- **Vector Storage**: Pinecone or FAISS.
- **Web Framework**: FastAPI.
- **Deployment**: Docker + AWS/GCP.
By combining these tools, you can build a scalable and efficient web service for vector embedding-based search."
프롬프트 확장하기
원래 답변이 그럴듯하게 들리긴 하지만, 우리 질문에 제대로 답하지 못했어요. 대신 애플리케이션 스택에 대한 일반적인 설명을 주었죠. 결과를 개선하려면, 사용 가능한 도구들의 설명으로 원래 프롬프트를 보강하는 것이 한 가지 방법이 될 수 있어요. 시맨틱 지식 기반을 사용해서 프롬프트를 다양한 기술들의 설명으로 보강해 볼게요!
results = client.query_points(
collection_name=collection_name,
query=models.Document(text=prompt, model=model_name),
limit=3,
)
results
응답은 이렇습니다:
QueryResponse(points=[
ScoredPoint(id=0, version=0, score=0.67437416, payload={'document': 'Qdrant is a vector database & vector similarity search engine. It deploys as an API service providing search for the nearest high-dimensional vectors. With Qdrant, embeddings or neural network encoders can be turned into full-fledged applications for matching, searching, recommending, and much more!'}, vector=None, shard_key=None, order_value=None),
ScoredPoint(id=6, version=0, score=0.63144326, payload={'document': 'SentenceTransformers is a Python framework for state-of-the-art sentence, text and image embeddings. You can use this framework to compute sentence / text embeddings for more than 100 languages. These embeddings can then be compared e.g. with cosine-similarity to find sentences with a similar meaning. This can be useful for semantic textual similar, semantic search, or paraphrase mining.'}, vector=None, shard_key=None, order_value=None),
ScoredPoint(id=5, version=0, score=0.6064749, payload={'document': 'FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints.'}, vector=None, shard_key=None, order_value=None)
])
원래 프롬프트를 사용해서 도구 설명 집합에 대해 시맨틱 검색을 수행했어요. 이제 이 설명들을 사용해서 프롬프트를 보강하고 더 많은 컨텍스트를 만들 수 있어요.
context = "\n".join(r.payload['document'] for r in results.points)
context
응답은 이렇습니다:
'Qdrant is a vector database & vector similarity search engine. It deploys as an API service providing search for the nearest high-dimensional vectors. With Qdrant, embeddings or neural network encoders can be turned into full-fledged applications for matching, searching, recommending, and much more!\nFastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints.\nPyTorch is a machine learning framework based on the Torch library, used for applications such as computer vision and natural language processing.'
마지막으로 메타프롬프트(metaprompt)를 만들어 볼게요. LLM의 가정된 역할, 원래 질문, 시맨틱 검색 결과를 결합해서 LLM이 제공된 컨텍스트를 사용하도록 강제하는 거예요.
이렇게 하면 지식 중심 작업을 언어 작업으로 효과적으로 바꾸고, 환각(hallucination)의 가능성을 줄일 수 있길 바라요. 응답도 더 관련성 있게 들려야 해요.
metaprompt = f"""
You are a software architect. Answer the following question using the provided context. If you can't find the answer, do not pretend you know it, but answer "I don't know".
Question: {prompt.strip()}
Context: {context.strip()}
Answer:
"""
# Look at the full metaprompt
print(metaprompt)
응답 (Response):
You are a software architect. Answer the following question using the provided context. If you can't find the answer, do not pretend you know it, but answer "I don't know".
Question: What tools should I need to use to build a web service using vector embeddings for search?
Context: Qdrant is a vector database & vector similarity search engine. It deploys as an API service providing search for the nearest high-dimensional vectors. With Qdrant, embeddings or neural network encoders can be turned into full-fledged applications for matching, searching, recommending, and much more!
FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints.
PyTorch is a machine learning framework based on the Torch library, used for applications such as computer vision and natural language processing.
Answer:
우리 프롬프트는 훨씬 길어졌고, 응답을 더 좋게 만드는 몇 가지 전략도 사용했어요:
- LLM에 소프트웨어 아키텍트 역할을 부여했어요.
- 질문에 답할 더 많은 컨텍스트를 제공했어요.
- 컨텍스트에 의미 있는 정보가 없으면, 모델이 답을 지어내지 않도록 했어요.
이게 기대대로 동작하는지 확인해 볼게요.
질문 (Question):
query_deepseek(metaprompt)
답변 (Answer):
'To build a web service using vector embeddings for search, you can use the following tools:
1. **Qdrant**: As a vector database and similarity search engine, Qdrant will handle the storage and retrieval of high-dimensional vectors. It provides an API service for searching and matching vectors, making it ideal for applications that require vector-based search functionality.
2. **FastAPI**: This web framework is perfect for building the API layer of your web service. It is fast, easy to use, and based on Python type hints, which makes it a great choice for developing the backend of your service. FastAPI will allow you to expose endpoints that interact with Qdrant for vector search operations.
3. **PyTorch**: If you need to generate vector embeddings from your data (e.g., text, images), PyTorch can be used to create and train neural network models that produce these embeddings. PyTorch is a powerful machine learning framework that supports a wide range of applications, including natural language processing and computer vision.
### Summary:
- **Qdrant** for vector storage and search.
- **FastAPI** for building the web service API.
- **PyTorch** for generating vector embeddings (if needed).
These tools together provide a robust stack for building a web service that leverages vector embeddings for search functionality.'
RAG 파이프라인 테스트하기
우리가 제공한 시맨틱 컨텍스트를 활용해서 모델이 질문에 더 잘 답하고 있어요. RAG를 함수로 감싸서, 서로 다른 프롬프트에 대해 더 쉽게 호출할 수 있게 해 볼게요.
def rag(question: str, n_points: int = 3) -> str:
results = client.query_points(
collection_name=collection_name,
query=models.Document(text=question, model=model_name),
limit=n_points,
)
context = "\n".join(r.payload["document"] for r in results.points)
metaprompt = f"""
You are a software architect. Answer the following question using the provided context. If you can't find the answer, do not pretend you know it, but only answer "I don't know".
Question: {question.strip()}
Context: {context.strip()}
Answer:
"""
return query_deepseek(metaprompt)
이제 다양한 질문을 더 쉽게 할 수 있어요.
질문 (Question):
rag("What can the stack for a web api look like?")
답변 (Answer):
'The stack for a web API can include the following components based on the provided context:
1. **Web Framework**: FastAPI can be used as the web framework for building the API. It is modern, fast, and leverages Python type hints for better development and performance.
2. **Reverse Proxy/Web Server**: NGINX can be used as a reverse proxy or web server to handle incoming HTTP requests, load balancing, and serving static content. It is known for its high performance and low resource consumption.
3. **Containerization**: Docker can be used to containerize the application, making it easier to build, share, and run the API consistently across different environments without worrying about configuration issues.
This stack provides a robust, scalable, and efficient setup for building and deploying a web API.'
질문 (Question):
rag("Where is the nearest grocery store?")
답변 (Answer):
"I don't know. The provided context does not contain any information about the location of the nearest grocery store."
이제 우리 모델은 다음을 할 수 있어요:
- 벡터 데이터 저장소에 있는 지식을 활용한다.
- 제공된 컨텍스트를 바탕으로, 답을 제공할 수 없다고 답한다.
우리는 방금 대규모 언어 모델에서 환각의 위험을 완화하는 유용한 메커니즘을 보여드렸어요.