Agent 2.0 exdev 서버 배포 스택
- server-dev start/stop/deploy 및 Gitea push 자동 배포 - local-dev 로컬 개발 환경 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,416 @@
|
||||
# RAG 기반 QA 시스템 (외부 API 버전)
|
||||
|
||||
## 🎯 개요
|
||||
|
||||
**엑셀 파일의 질문-답변 쌍**을 기반으로 동작하는 경량 RAG(Retrieval Augmented Generation) 시스템입니다.
|
||||
|
||||
### 핵심 특징
|
||||
|
||||
- ⚡ **경량 버전**: 180MB (기존 2.5GB 대비 93% 감소)
|
||||
- 📊 **엑셀 지원**: 질문-답변 엑셀 파일을 직접 변환
|
||||
- 🚀 **외부 API**: 모든 AI 모델을 외부 API로 사용 (GPU 불필요)
|
||||
- 🔍 **고속 검색**: FAISS 벡터 검색 + TEI Reranking
|
||||
- 🤖 **LLM 통합**: 검색 결과 기반 자연스러운 답변 생성
|
||||
- 🐳 **Docker 지원**: 간편한 빌드 및 배포
|
||||
- 💾 **오프라인 배포**: 패키징 스크립트 제공
|
||||
|
||||
---
|
||||
|
||||
## 📋 시스템 요구사항
|
||||
|
||||
### 필수
|
||||
- **Docker**: 20.10+
|
||||
- **Docker Compose**: 1.29+
|
||||
- **디스크**: 2GB 이상
|
||||
- **RAM**: 4GB 이상
|
||||
|
||||
### 외부 API 서버 (별도 준비 필요)
|
||||
|
||||
다음 서버들이 실행 중이어야 합니다:
|
||||
|
||||
```bash
|
||||
# 1. SGLang (LLM 서비스) - port 16000
|
||||
docker run -d --gpus all --name sglang-80b-test \
|
||||
-p 16000:30000 \
|
||||
-v /DATA/exlink/models:/data \
|
||||
--ipc=host --restart always \
|
||||
lmsysorg/sglang:latest \
|
||||
python3 -m sglang.launch_server \
|
||||
--model-path /data/Qwen3-Next-80B-A3B-Instruct-Int4-GPTQ \
|
||||
--host 0.0.0.0 --port 30000 \
|
||||
--mem-fraction-static 0.92 --max-model-len 4096 \
|
||||
--trust-remote-code
|
||||
|
||||
# 2. TEI Embedding - port 16001
|
||||
docker run -d --gpus all --name tei-embedding \
|
||||
-p 16001:80 \
|
||||
-v /DATA/exlink/models:/data \
|
||||
--pull never --restart always \
|
||||
ghcr.io/huggingface/text-embeddings-inference:hopper-1.8 \
|
||||
--model-id /data/Qwen3-Embedding-8B --port 80
|
||||
|
||||
# 3. TEI Reranker - port 16002
|
||||
docker run -d --gpus all --name tei-reranker \
|
||||
-p 16002:80 \
|
||||
-v /DATA/exlink/models:/data \
|
||||
--pull never --restart always \
|
||||
ghcr.io/huggingface/text-embeddings-inference:hopper-1.8 \
|
||||
--model-id /data/Qwen3-Reranker-8B --port 80
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 5분 빠른 시작
|
||||
|
||||
### ⚡ 방법 1: 자동화 스크립트 (가장 쉬움!)
|
||||
|
||||
```bash
|
||||
# 기본: 자동 컬럼 감지 또는 1-2열 사용
|
||||
./run-with-excel.sh your_qa_data.xlsx
|
||||
|
||||
# 3열(C열), 4열(D열) 사용 시
|
||||
./run-with-excel-col34.sh your_qa_data.xlsx
|
||||
|
||||
# 수동 지정: 특정 열 사용
|
||||
python scripts/excel_to_jsonl.py data/your_file.xlsx 2 3
|
||||
# ↑ ↑
|
||||
# 3열(인덱스2) 4열(인덱스3)
|
||||
# 그 후 Docker 실행
|
||||
docker-compose -f docker-compose-slim.yml up
|
||||
```
|
||||
|
||||
**자동으로 실행:**
|
||||
1. ✅ 엑셀 → JSONL 변환 (지정한 열 사용)
|
||||
2. ✅ 환경 설정 확인
|
||||
3. ✅ Docker 이미지 빌드
|
||||
4. ✅ 전처리 (LLM 요약)
|
||||
5. ✅ 임베딩 생성 (TEI API)
|
||||
6. ✅ FAISS 인덱싱
|
||||
7. ✅ API 서비스 시작
|
||||
|
||||
➜ **상세 가이드**: [`DOCKER_DATA_GUIDE.md`](DOCKER_DATA_GUIDE.md)
|
||||
➜ **3-4열 사용**: [`COLUMN_GUIDE.md`](COLUMN_GUIDE.md)
|
||||
|
||||
---
|
||||
|
||||
### 📋 방법 2: 수동 단계별 실행
|
||||
|
||||
#### 1️⃣ 엑셀 파일 변환
|
||||
|
||||
```bash
|
||||
# data/ 폴더에 엑셀 파일 배치
|
||||
cp your_qa_data.xlsx data/
|
||||
|
||||
# JSONL 변환 - 자동 감지
|
||||
python scripts/excel_to_jsonl.py data/your_qa_data.xlsx
|
||||
|
||||
# 또는 특정 열 지정 (예: 3열=질문, 4열=답변)
|
||||
python scripts/excel_to_jsonl.py data/your_qa_data.xlsx 2 3
|
||||
# ↑ ↑
|
||||
# C열(인덱스2) D열(인덱스3)
|
||||
```
|
||||
|
||||
**엑셀 형식:**
|
||||
| A | B | C (질문) | D (답변) | E |
|
||||
|---|---|----------|----------|---|
|
||||
| 1 | 분류 | 카드 분실 시 어떻게 해야 하나요? | 모바일 앱 또는 고객센터를 통해... | 날짜 |
|
||||
| 2 | 충전 | 충전 후 정지 해제가 안 되는 경우는? | 한국도로공사 관리구간의 경우... | 날짜 |
|
||||
|
||||
**컬럼 인덱스:** A=0, B=1, C=2, D=3, E=4, ...
|
||||
|
||||
➜ **상세 가이드**: [`EXCEL_GUIDE.md`](EXCEL_GUIDE.md)
|
||||
➜ **3-4열 사용**: [`COLUMN_GUIDE.md`](COLUMN_GUIDE.md)
|
||||
|
||||
#### 2️⃣ 환경 설정
|
||||
|
||||
```bash
|
||||
cp env.template .env
|
||||
vi .env
|
||||
```
|
||||
|
||||
**필수 설정:**
|
||||
```bash
|
||||
# LLM 서버
|
||||
LLM_HOST=192.168.1.100
|
||||
LLM_PORT=16000
|
||||
LLM_MODEL_NAME=default
|
||||
|
||||
# TEI 서버
|
||||
TEI_EMBED_HOST=192.168.1.101
|
||||
TEI_EMBED_PORT=16001
|
||||
TEI_RERANK_HOST=192.168.1.101
|
||||
TEI_RERANK_PORT=16002
|
||||
|
||||
# 벡터 DB (FAISS 또는 qdrant)
|
||||
VECTOR_STORE=faiss
|
||||
```
|
||||
|
||||
#### 3️⃣ Docker 실행
|
||||
|
||||
```bash
|
||||
# 전체 파이프라인 실행 (전처리 → 임베딩 → 인덱싱 → API 서비스)
|
||||
docker-compose -f docker-compose-slim.yml up
|
||||
```
|
||||
|
||||
**자동 실행 단계:**
|
||||
1. ✅ 전처리 (LLM으로 질문 요약) - `data/qa_raw.jsonl` 읽기 → `data/qa.jsonl` 생성
|
||||
2. ✅ 임베딩 생성 (TEI API) - `data/qa.jsonl` 읽기 → `data/qa_vecs.jsonl` 생성
|
||||
3. ✅ FAISS 인덱싱 - `data/qa_vecs.jsonl` 읽기 → `data/qa.index` 생성
|
||||
4. ✅ API 서비스 시작
|
||||
|
||||
#### 4️⃣ 테스트
|
||||
|
||||
```bash
|
||||
# 헬스체크
|
||||
curl http://localhost:28012/health
|
||||
|
||||
# 질문하기
|
||||
curl -X POST http://localhost:28012/ask \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"query":"카드 분실 시 어떻게 해야 하나요?"}'
|
||||
```
|
||||
|
||||
**응답 예시:**
|
||||
```json
|
||||
{
|
||||
"answer": "카드를 분실하신 경우, 모바일 앱 또는 고객센터(1588-2504)를 통해 '카드분실신고'를 하신 후 재발급 신청 또는 환불 절차를 진행하실 수 있습니다...",
|
||||
"references": [
|
||||
{"q": "카드를 분실한 경우 어떻게 하나요?", "a": "모바일 앱 또는..."}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
➜ **빠른 시작 가이드**: [`QUICKSTART_EXCEL.md`](QUICKSTART_EXCEL.md)
|
||||
|
||||
---
|
||||
|
||||
## 📚 문서
|
||||
|
||||
### 🎯 시작하기
|
||||
- [`FLOW_DIAGRAM.md`](FLOW_DIAGRAM.md) - **전체 RAG 시스템 흐름도** ⭐⭐⭐
|
||||
- [`DOCKER_PHASE1_GUIDE.md`](DOCKER_PHASE1_GUIDE.md) - **Docker 환경 Phase 1 상세 가이드** ⭐⭐
|
||||
- [`DOCKER_DATA_GUIDE.md`](DOCKER_DATA_GUIDE.md) - **Docker 사용 시 데이터 위치 및 작동 방식** ⭐
|
||||
- [`COLUMN_GUIDE.md`](COLUMN_GUIDE.md) - **3열, 4열 등 특정 열 사용법** ⭐
|
||||
- [`EXCEL_GUIDE.md`](EXCEL_GUIDE.md) - 엑셀 데이터 준비 및 변환
|
||||
- [`QUICKSTART_EXCEL.md`](QUICKSTART_EXCEL.md) - 5분 빠른 시작
|
||||
- [`env.template`](env.template) - 환경 변수 설정
|
||||
|
||||
### 🚀 배포
|
||||
- [`DEPLOYMENT.md`](DEPLOYMENT.md) - 상세 배포 가이드
|
||||
- [`OFFLINE_DEPLOYMENT.md`](OFFLINE_DEPLOYMENT.md) - 오프라인 배포 (USB/SCP)
|
||||
- [`OFFLINE_QUICKSTART.md`](OFFLINE_QUICKSTART.md) - 오프라인 빠른 시작
|
||||
- [`SLIM_VERSION.md`](SLIM_VERSION.md) - 경량 버전 설명 (180MB)
|
||||
|
||||
### 🔧 기술
|
||||
- [`RAG_PIPELINE.md`](RAG_PIPELINE.md) - RAG 파이프라인 상세 설명
|
||||
- [`QWEN3_EMBEDDING_GUIDE.md`](QWEN3_EMBEDDING_GUIDE.md) - **Qwen3 Embedding (TEI) & Reranker (vLLM) 사용법** ⭐
|
||||
- [`MIGRATION_REPORT.md`](MIGRATION_REPORT.md) - 아키텍처 마이그레이션 리포트
|
||||
- [`INTERNAL_LLM_GUIDE.md`](INTERNAL_LLM_GUIDE.md) - 내부 LLM 사용 가이드
|
||||
- [`TROUBLESHOOTING.md`](TROUBLESHOOTING.md) - 문제 해결
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ 프로젝트 구조
|
||||
|
||||
```
|
||||
rag/
|
||||
├── scripts/
|
||||
│ ├── excel_to_jsonl.py # 엑셀 → JSONL 변환 (신규!)
|
||||
│ ├── preprocess_qa.py # LLM 질문 요약
|
||||
│ ├── ingest_qa.py # 임베딩 생성
|
||||
│ ├── build_index_qa.py # FAISS 인덱싱
|
||||
│ ├── run_service_qa.py # FastAPI 서비스
|
||||
│ ├── api_clients.py # 외부 API 클라이언트
|
||||
│ └── vector_store.py # 벡터 DB 추상화
|
||||
├── docker/
|
||||
│ ├── batch-slim.Dockerfile # 배치 작업용 (경량)
|
||||
│ └── service-slim.Dockerfile # API 서비스용 (경량)
|
||||
├── data/ # 데이터 디렉토리 ⭐ Docker 볼륨 마운트
|
||||
│ ├── your_qa_data.xlsx # [1] 엑셀 원본 (여기에 배치!)
|
||||
│ ├── qa_raw.jsonl # [2] 원본 QA (엑셀 변환 결과)
|
||||
│ ├── qa.jsonl # [3] 전처리된 QA (Docker 자동 생성)
|
||||
│ ├── qa_vecs.jsonl # [4] 벡터 데이터 (Docker 자동 생성)
|
||||
│ └── qa.index # [5] FAISS 인덱스 (Docker 자동 생성)
|
||||
├── docker-compose-slim.yml # Docker Compose (경량 버전)
|
||||
├── run-with-excel.sh # 엑셀 파일로 전체 자동 실행 ⭐
|
||||
├── create-offline-package-slim.sh # 오프라인 패키징
|
||||
└── env.template # 환경 변수 템플릿
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 전체 파이프라인
|
||||
|
||||
```
|
||||
엑셀 파일 (your_qa_data.xlsx)
|
||||
↓ excel_to_jsonl.py
|
||||
qa_raw.jsonl (원본 QA)
|
||||
↓ preprocess_qa.py (LLM API)
|
||||
qa.jsonl (질문 요약 추가)
|
||||
↓ ingest_qa.py (TEI Embedding API)
|
||||
qa_vecs.jsonl (벡터 데이터)
|
||||
↓ build_index_qa.py
|
||||
qa.index (FAISS 인덱스)
|
||||
↓
|
||||
FastAPI 서비스 (run_service_qa.py)
|
||||
├─ 사용자 질문 → TEI Embedding
|
||||
├─ FAISS 검색 (상위 30개)
|
||||
├─ TEI Reranker (상위 5개)
|
||||
└─ LLM 답변 생성
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💾 오프라인 배포
|
||||
|
||||
### 패키지 생성 (개발 환경)
|
||||
|
||||
```bash
|
||||
# 경량 패키지 생성 (180MB)
|
||||
./create-offline-package-slim.sh
|
||||
```
|
||||
|
||||
**결과:**
|
||||
- `~/rag-offline-package-slim.tar.gz` (180MB)
|
||||
|
||||
### 배포 (프로덕션 환경)
|
||||
|
||||
```bash
|
||||
# 1. 파일 전송
|
||||
scp ~/rag-offline-package-slim.tar.gz user@server:/home/user/
|
||||
|
||||
# 2. 압축 해제
|
||||
tar -xzf rag-offline-package-slim.tar.gz
|
||||
cd rag-offline-package-slim
|
||||
|
||||
# 3. 배포 스크립트 실행
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
➜ **상세 가이드**: [`OFFLINE_DEPLOYMENT.md`](OFFLINE_DEPLOYMENT.md)
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ 주요 설정
|
||||
|
||||
### 벡터 DB 선택
|
||||
|
||||
```bash
|
||||
# FAISS (기본) - 단순하고 빠름
|
||||
VECTOR_STORE=faiss
|
||||
|
||||
# Qdrant - 확장 가능, 메타데이터 필터링
|
||||
VECTOR_STORE=qdrant
|
||||
QDRANT_HOST=qdrant
|
||||
QDRANT_PORT=6333
|
||||
```
|
||||
|
||||
### 성능 튜닝
|
||||
|
||||
```bash
|
||||
# 검색 설정
|
||||
FAISS_TOP_K=30 # FAISS 검색 결과 수
|
||||
FAISS_THRESHOLD=0.55 # 유사도 임계값
|
||||
RERANK_CANDIDATES=20 # 재랭킹 대상 수
|
||||
TOP_N_FOR_LLM=5 # LLM에 전달할 최종 결과 수
|
||||
|
||||
# API 타임아웃
|
||||
API_TIMEOUT=60 # 초
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 API 사용 예시
|
||||
|
||||
### Python
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
response = requests.post(
|
||||
"http://localhost:28012/ask",
|
||||
json={"query": "카드 분실 시 어떻게 해야 하나요?"}
|
||||
)
|
||||
|
||||
print(response.json()["answer"])
|
||||
```
|
||||
|
||||
### JavaScript
|
||||
|
||||
```javascript
|
||||
const response = await fetch("http://localhost:28012/ask", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ query: "카드 분실 시 어떻게 해야 하나요?" })
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
console.log(data.answer);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 용량 비교
|
||||
|
||||
| 항목 | 기존 (PyTorch) | 경량 버전 | 개선도 |
|
||||
|------|----------------|-----------|--------|
|
||||
| Docker 이미지 | 2.5GB | **180MB** | **93%↓** |
|
||||
| 베이스 이미지 | PyTorch+CUDA 9GB | Python slim 200MB | **98%↓** |
|
||||
| 빌드 시간 | 10분+ | **8초** | **99%↓** |
|
||||
| 필요 공간 | 10GB+ | **2GB** | **80%↓** |
|
||||
|
||||
➜ **상세 설명**: [`SLIM_VERSION.md`](SLIM_VERSION.md)
|
||||
|
||||
---
|
||||
|
||||
## ❓ 문제 해결
|
||||
|
||||
### 엑셀 변환 실패
|
||||
|
||||
```bash
|
||||
pip install pandas openpyxl
|
||||
python scripts/excel_to_jsonl.py your_qa_data.xlsx
|
||||
```
|
||||
|
||||
### 외부 API 연결 실패
|
||||
|
||||
```bash
|
||||
# API 연결 테스트
|
||||
curl http://<LLM_HOST>:<LLM_PORT>/health
|
||||
curl http://<TEI_HOST>:<TEI_PORT>/health
|
||||
```
|
||||
|
||||
### Docker 빌드 실패
|
||||
|
||||
```bash
|
||||
# 이미지 정리 후 재빌드
|
||||
docker system prune -af
|
||||
docker-compose -f docker-compose-slim.yml build
|
||||
```
|
||||
|
||||
➜ **상세 가이드**: [`TROUBLESHOOTING.md`](TROUBLESHOOTING.md)
|
||||
|
||||
---
|
||||
|
||||
## 🤝 기여
|
||||
|
||||
이슈 및 PR은 언제나 환영합니다!
|
||||
|
||||
---
|
||||
|
||||
## 📄 라이선스
|
||||
|
||||
MIT License
|
||||
|
||||
---
|
||||
|
||||
## 🎯 다음 단계
|
||||
|
||||
1. **데이터 준비**: [`EXCEL_GUIDE.md`](EXCEL_GUIDE.md) 참고
|
||||
2. **로컬 테스트**: [`QUICKSTART_EXCEL.md`](QUICKSTART_EXCEL.md) 참고
|
||||
3. **프로덕션 배포**: [`OFFLINE_DEPLOYMENT.md`](OFFLINE_DEPLOYMENT.md) 참고
|
||||
4. **성능 튜닝**: `.env` 파일에서 파라미터 조정
|
||||
|
||||
---
|
||||
|
||||
**시작하세요!** ⚡
|
||||
Reference in New Issue
Block a user