Files
exAichatbot_agent/exAiChatBot-chatbot2.0-agent/old_docs/FLOW_DIAGRAM.md
T
Macbook 4b86b2a660 Agent 2.0 exdev 서버 배포 스택
- server-dev start/stop/deploy 및 Gitea push 자동 배포
- local-dev 로컬 개발 환경

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-21 22:57:30 +09:00

23 KiB

RAG 시스템 전체 흐름도

📊 시스템 아키텍처

┌─────────────────────────────────────────────────────────────────────┐
│                        RAG 시스템 전체 구조                           │
└─────────────────────────────────────────────────────────────────────┘

                          ┌──────────────────┐
                          │  외부 API 서버들  │
                          └──────────────────┘
                                   │
                ┌──────────────────┼──────────────────┐
                ↓                  ↓                  ↓
        ┌──────────────┐  ┌──────────────┐  ┌──────────────┐
        │ LLM (16000)  │  │ TEI Embed    │  │ vLLM Rerank  │
        │ SGLang/vLLM  │  │ (16001)      │  │ (16002)      │
        │ Qwen3-80B    │  │ Qwen3-Embed  │  │ Qwen3-Rerank │
        └──────────────┘  └──────────────┘  └──────────────┘
                │                  │                  │
                │                  │                  │
                └──────────────────┼──────────────────┘
                                   │
                          ┌────────▼────────┐
                          │  RAG 시스템      │
                          │  (Docker)       │
                          └─────────────────┘
                                   │
                    ┌──────────────┴──────────────┐
                    ↓                             ↓
            ┌──────────────┐            ┌──────────────┐
            │ Batch 처리    │            │ API 서비스    │
            │ (데이터 준비) │            │ (검색/답변)   │
            └──────────────┘            └──────────────┘
                    │
                    ↓
            ┌──────────────┐
            │ FAISS/Qdrant │
            │ 벡터 저장소   │
            └──────────────┘

🔄 Phase 1: 데이터 준비 (한 번만 실행)

1️⃣ 엑셀 파일 → JSONL 변환

┌─────────────────────────────────────────────────────────────┐
│ 엑셀 파일 (qa_data.xlsx)                                     │
│ ┌────┬──────┬─────────────────────┬────────────────────┐   │
│ │ A  │  B   │    C (질문)          │   D (답변)          │   │
│ ├────┼──────┼─────────────────────┼────────────────────┤   │
│ │ 1  │ 분류 │ 카드 분실 시?        │ 모바일 앱 또는...   │   │
│ │ 2  │ 충전 │ 충전 후 정지 해제?   │ 한국도로공사...     │   │
│ └────┴──────┴─────────────────────┴────────────────────┘   │
└─────────────────────────────────────────────────────────────┘
                         │
                         │ excel_to_jsonl.py
                         │ (3열=질문, 4열=답변)
                         ↓
┌─────────────────────────────────────────────────────────────┐
│ data/qa_raw.jsonl                                            │
│ {"q":"카드 분실 시?","a":"모바일 앱 또는..."}                 │
│ {"q":"충전 후 정지 해제?","a":"한국도로공사..."}              │
└─────────────────────────────────────────────────────────────┘

명령어:

python scripts/excel_to_jsonl.py data/qa_data.xlsx 2 3

2️⃣ 질문 요약 (LLM)

data/qa_raw.jsonl
    ↓
┌─────────────────────────────────────────────────────────────┐
│ preprocess_qa.py                                             │
│ ┌─────────────────────────────────────────────────────┐     │
│ │ 긴 질문 → LLM 요약 → 짧은 질문 (q_short)             │     │
│ │                                                       │     │
│ │ [LLM API - Port 16000]                               │     │
│ │ POST http://llm-server:16000/v1/chat/completions     │     │
│ │ {                                                     │     │
│ │   "messages": [                                       │     │
│ │     {"role": "system", "content": "질문을 요약..."},  │     │
│ │     {"role": "user", "content": "긴 질문 원문"}       │     │
│ │   ]                                                   │     │
│ │ }                                                     │     │
│ └─────────────────────────────────────────────────────┘     │
└─────────────────────────────────────────────────────────────┘
    ↓
data/qa.jsonl
{"q":"카드 분실 시?","q_short":"카드 분실","a":"모바일..."}

명령어:

docker-compose -f docker-compose-slim.yml up preprocess

3️⃣ 임베딩 생성 (TEI)

data/qa.jsonl
    ↓
┌─────────────────────────────────────────────────────────────┐
│ ingest_qa.py                                                 │
│ ┌─────────────────────────────────────────────────────┐     │
│ │ 각 질문을 벡터로 변환 (Document 모드)                │     │
│ │                                                       │     │
│ │ [TEI Embedding API - Port 16001]                     │     │
│ │ POST http://tei-server:16001/embed                   │     │
│ │ {                                                     │     │
│ │   "inputs": "카드 분실 시 어떻게 해야 하나요?",       │     │
│ │   "normalize": true,                                 │     │
│ │   "truncate": true                                   │     │
│ │ }                                                     │     │
│ │                                                       │     │
│ │ ⚠️ 주의: Document 모드 (is_query=False)              │     │
│ │ → Instruct 문구 없이 원문만 전송                      │     │
│ │                                                       │     │
│ │ 응답: [[0.123, -0.456, ...], ...]                    │     │
│ └─────────────────────────────────────────────────────┘     │
└─────────────────────────────────────────────────────────────┘
    ↓
메모리에 벡터 저장
all_vectors = [[vec1], [vec2], ...]
all_metadatas = [{"q": "...", "a": "..."}, ...]

명령어:

docker-compose -f docker-compose-slim.yml up embed

4️⃣ 인덱스 빌드 (FAISS/Qdrant)

메모리의 벡터들
    ↓
┌─────────────────────────────────────────────────────────────┐
│ build_index_qa.py                                            │
│ ┌─────────────────────────────────────────────────────┐     │
│ │ FAISS 사용 시:                                        │     │
│ │ - IndexFlatIP (Inner Product) 생성                   │     │
│ │ - 벡터 추가 (add_vectors)                            │     │
│ │ - 인덱스 저장 → data/qa.index                        │     │
│ │ - 메타데이터 저장 → data/qa_meta.pkl                 │     │
│ │                                                       │     │
│ │ Qdrant 사용 시:                                       │     │
│ │ - 실시간 인덱싱 (별도 빌드 불필요)                    │     │
│ └─────────────────────────────────────────────────────┘     │
└─────────────────────────────────────────────────────────────┘
    ↓
data/qa.index (FAISS)
data/qa_meta.pkl (메타데이터)

명령어:

docker-compose -f docker-compose-slim.yml up index

🔍 Phase 2: 검색 및 답변 생성 (실시간)

전체 흐름

사용자 질문: "카드를 잃어버렸어요"
    ↓
┌─────────────────────────────────────────────────────────────┐
│ Step 1: 질문 임베딩 (TEI - Query 모드)                       │
│ ┌─────────────────────────────────────────────────────┐     │
│ │ [TEI Embedding API - Port 16001]                     │     │
│ │ POST http://tei-server:16001/embed                   │     │
│ │ {                                                     │     │
│ │   "inputs": "Instruct: Given a web search query,     │     │
│ │              retrieve relevant passages that         │     │
│ │              answer the query\n                      │     │
│ │              Query: 카드를 잃어버렸어요"              │     │
│ │ }                                                     │     │
│ │                                                       │     │
│ │ ⚠️ 주의: Query 모드 (is_query=True)                  │     │
│ │ → Instruct 문구 자동 추가                             │     │
│ │                                                       │     │
│ │ 응답: [[0.789, -0.234, ...]]                         │     │
│ └─────────────────────────────────────────────────────┘     │
└─────────────────────────────────────────────────────────────┘
    ↓
질문 벡터: [0.789, -0.234, ...]
    ↓
┌─────────────────────────────────────────────────────────────┐
│ Step 2: FAISS 유사도 검색 (TOP_K=30)                         │
│ ┌─────────────────────────────────────────────────────┐     │
│ │ FAISS IndexFlatIP.search(query_vec, k=30)           │     │
│ │                                                       │     │
│ │ - Inner Product 계산 (코사인 유사도)                  │     │
│ │ - FAISS_THRESHOLD=0.55 이상만 필터링                 │     │
│ │ - 상위 30개 후보 반환                                 │     │
│ └─────────────────────────────────────────────────────┘     │
└─────────────────────────────────────────────────────────────┘
    ↓
30개 후보: [
  {"q": "카드 분실 시?", "a": "모바일 앱...", "score": 0.89},
  {"q": "카드 재발급?", "a": "고객센터...", "score": 0.85},
  ...
]
    ↓
┌─────────────────────────────────────────────────────────────┐
│ Step 3: 재랭킹 (vLLM - Qwen3-Reranker)                       │
│ ┌─────────────────────────────────────────────────────┐     │
│ │ 상위 20개만 선택 (RERANK_CANDIDATES=20)              │     │
│ │                                                       │     │
│ │ [vLLM Reranker API - Port 16002]                     │     │
│ │ POST http://vllm-server:16002/rerank                 │     │
│ │ {                                                     │     │
│ │   "query": "카드를 잃어버렸어요",                     │     │
│ │   "documents": [                                     │     │
│ │     "카드 분실 시 어떻게 해야 하나요?",               │     │
│ │     "카드 재발급은 어떻게 하나요?",                   │     │
│ │     ...                                              │     │
│ │   ]                                                   │     │
│ │ }                                                     │     │
│ │                                                       │     │
│ │ ⚠️ 주의: "documents" 키 사용 (vLLM 커스텀 서버)       │     │
│ │                                                       │     │
│ │ 응답 (score 내림차순 정렬):                           │     │
│ │ [                                                     │     │
│ │   {"index": 0, "score": 0.9834},  ← 가장 관련 높음   │     │
│ │   {"index": 5, "score": 0.8721},                     │     │
│ │   {"index": 2, "score": 0.7543},                     │     │
│ │   ...                                                │     │
│ │ ]                                                     │     │
│ └─────────────────────────────────────────────────────┘     │
└─────────────────────────────────────────────────────────────┘
    ↓
상위 5개 선택 (TOP_N_FOR_LLM=5)
    ↓
┌─────────────────────────────────────────────────────────────┐
│ Step 4: LLM 답변 생성                                         │
│ ┌─────────────────────────────────────────────────────┐     │
│ │ [LLM API - Port 16000]                               │     │
│ │ POST http://llm-server:16000/v1/chat/completions     │     │
│ │ {                                                     │     │
│ │   "messages": [                                       │     │
│ │     {                                                 │     │
│ │       "role": "system",                              │     │
│ │       "content": "당신은 고객 문의에 답변하는..."     │     │
│ │     },                                                │     │
│ │     {                                                 │     │
│ │       "role": "user",                                │     │
│ │       "content": "고객 질문: 카드를 잃어버렸어요\n    │     │
│ │                                                       │     │
│ │         참고자료:                                     │     │
│ │         [참고자료 1]                                  │     │
│ │         질문: 카드 분실 시 어떻게 해야 하나요?        │     │
│ │         답변: 모바일 앱 또는 고객센터...              │     │
│ │                                                       │     │
│ │         [참고자료 2]                                  │     │
│ │         질문: 카드 재발급은?                          │     │
│ │         답변: 고객센터를 통해...                      │     │
│ │                                                       │     │
│ │         ... (총 5개)                                  │     │
│ │                                                       │     │
│ │         위 참고자료를 바탕으로 답변해주세요."         │     │
│ │     }                                                 │     │
│ │   ],                                                  │     │
│ │   "max_tokens": 512,                                 │     │
│ │   "temperature": 0.3                                 │     │
│ │ }                                                     │     │
│ │                                                       │     │
│ │ 응답:                                                 │     │
│ │ "카드를 잃어버리셨다면 즉시 모바일 앱이나..."         │     │
│ └─────────────────────────────────────────────────────┘     │
└─────────────────────────────────────────────────────────────┘
    ↓
최종 응답
{
  "answer": "카드를 잃어버리셨다면 즉시 모바일 앱이나...",
  "matched_questions": ["카드 분실 시?", "카드 재발급?", ...],
  "scores": [0.9834, 0.8721, 0.7543],
  "num_references": 5
}

🔧 핵심 기술 포인트

1. TEI Embedding - Query/Document 구분

시점 모드 형식 예시
데이터 저장 Document (is_query=False) 원문만 "카드 분실 시 어떻게 해야 하나요?"
검색 Query (is_query=True) Instruct 추가 ct: Given...\nQuery: 카드 분실?""Instru

정확도 향상: 10-20% ↑


2. vLLM Reranker - 빠른 재랭킹

# 요청
{
  "query": "질문",
  "documents": ["문서1", "문서2", ...]  # "texts" 아님!
}

# 응답 (score 내림차순 정렬)
[
  {"index": 0, "score": 0.98},  # 가장 관련 높음
  {"index": 5, "score": 0.87},
  ...
]

특징:

  • ✅ vLLM 기반 빠른 추론
  • ✅ Yes/No 확률 내부 계산
  • ✅ score 내림차순 정렬

3. 파이프라인 파라미터

# .env 파일
FAISS_TOP_K=30              # 빠른 임베딩 검색 (넓은 범위)
RERANK_CANDIDATES=20        # 재랭킹 후보 (비용 절감)
TOP_N_FOR_LLM=5            # LLM 참고자료 (정확도 + 비용)

# 흐름
30개 검색 → 20개 재랭킹 → 5개 LLM 입력

📋 전체 명령어 순서

1회 설정 (데이터 준비)

cd /Users/parkjiwon/src/rag

# 1. 엑셀 → JSONL (3열=질문, 4열=답변)
python scripts/excel_to_jsonl.py data/qa_data.xlsx 2 3

# 2. 환경 설정
cp env.template .env
vi .env  # 서버 주소 입력

# 3. 전처리 (LLM 요약)
docker-compose -f docker-compose-slim.yml up preprocess

# 4. 임베딩 (TEI, Document 모드)
docker-compose -f docker-compose-slim.yml up embed

# 5. 인덱싱 (FAISS)
docker-compose -f docker-compose-slim.yml up index

서비스 시작 (실시간 검색)

# API 서버 시작
docker-compose -f docker-compose-slim.yml up api

# 테스트
curl -X POST http://localhost:28012/ask \
  -H "Content-Type: application/json" \
  -d '{"query":"카드를 잃어버렸어요"}'

🎯 요약

데이터 흐름

엑셀 (3-4열)
    ↓ excel_to_jsonl.py
JSONL
    ↓ preprocess_qa.py (LLM)
요약된 JSONL
    ↓ ingest_qa.py (TEI Document 모드)
벡터 + 메타데이터
    ↓ build_index_qa.py
FAISS 인덱스
    ↓ run_service_qa.py
실시간 검색 서비스

검색 흐름

사용자 질문
    ↓ TEI Embed (Query 모드) → Instruct 추가
질문 벡터
    ↓ FAISS 검색
30개 후보
    ↓ vLLM Reranker → 20개 재랭킹
상위 5개
    ↓ LLM 답변 생성
최종 답변

핵심 API

API 포트 기술 역할
LLM 16000 SGLang/vLLM 요약 + 답변 생성
Embedding 16001 TEI 벡터 변환 (Query/Document 구분)
Reranker 16002 vLLM 재랭킹 (빠른 추론)

이제 전체 흐름이 명확하시죠? 🎉

질문이 있으시면 언제든 물어보세요!