Skip to content

whitebearhands/kdb-manager

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

6 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

KDB Manager

RAG(Retrieval-Augmented Generation) νŒŒμ΄ν”„λΌμΈμ„ μœ„ν•œ 벑터 DB 관리 μ„œλΉ„μŠ€.

Qdrant 기반 ν•˜μ΄λΈŒλ¦¬λ“œ 검색(Dense + Sparse + RRF Fusion)κ³Ό μ™ΈλΆ€ 리랭컀 연동,
MongoDB 단락 원문 μ €μž₯, RabbitMQ 비동기 μž„λ² λ”© νŒŒμ΄ν”„λΌμΈμ„ μ œκ³΅ν•œλ‹€.


λͺ©μ°¨


μ•„ν‚€ν…μ²˜

ν΄λΌμ΄μ–ΈνŠΈ
    β”‚
    β–Ό
FastAPI (kdb_manager.py)
    β”œβ”€β”€ routes/collection.py   μ»¬λ ‰μ…˜ CRUD, λ¬Έμ„œ 쑰회
    β”œβ”€β”€ routes/document.py     μ—…μ„œνŠΈ, μ‚­μ œ, MongoDB μ €μž₯
    β”œβ”€β”€ routes/search.py       ν•˜μ΄λΈŒλ¦¬λ“œ 검색, λ¦¬λž­ν‚Ή, 단락 볡원
    β”œβ”€β”€ routes/feedback.py     검색 ν”Όλ“œλ°±
    └── routes/query_cache.py  쿼리 캐싱
         β”‚
         β”œβ”€β”€ Qdrant          벑터 DB (Dense + Sparse 벑터 μ €μž₯/검색)
         β”œβ”€β”€ MongoDB         단락 원문 μ €μž₯ (rag-data.documents, chunks.*)
         β”œβ”€β”€ RabbitMQ        비동기 μž„λ² λ”© μž‘μ—… 큐
         β”œβ”€β”€ Redis           μž„λ² λ”© μž‘μ—… 데이터 μž„μ‹œ μ €μž₯
         └── Reranker API    μ™ΈλΆ€ λ¦¬λž­ν‚Ή μ„œλΉ„μŠ€

의쑴 μ„œλΉ„μŠ€

μ„œλΉ„μŠ€ μš©λ„ κΈ°λ³Έ 포트
Qdrant 벑터 μ €μž₯ 및 ν•˜μ΄λΈŒλ¦¬λ“œ 검색 6333
MongoDB 단락/청크 원문 μ €μž₯ 27017
RabbitMQ 비동기 μž„λ² λ”© μž‘μ—… 큐 5672
Redis μž„λ² λ”© μš”μ²­ 데이터 μž„μ‹œ μ €μž₯ 6379
Reranker API 검색 κ²°κ³Ό μž¬μˆœμœ„ν™” -

μž„λ² λ”© λͺ¨λΈ

μ’…λ₯˜ λͺ¨λΈλͺ… μ—­ν• 
Dense Qwen/Qwen3-Embedding-4B 의미 기반 벑터 검색
Sparse Qdrant/bm42-all-minilm-l6-v2-attentions BM25 계열 ν‚€μ›Œλ“œ 검색
Reranker Qwen/Qwen3-Reranker-4B 검색 κ²°κ³Ό μž¬μˆœμœ„ν™” (μ™ΈλΆ€ μ„œλΉ„μŠ€ μ‚¬μš©)

λͺ¨λΈ νŒŒμΌμ€ ./models 디렉토리에 μ €μž₯ν•œλ‹€. μ—†μœΌλ©΄ μ„œλΉ„μŠ€ μ‹œμž‘ μ‹œ μžλ™ λ‹€μš΄λ‘œλ“œ.


ν™˜κ²½ μ„€μ •

루트의 .env 파일둜 μ„€μ •ν•œλ‹€. env.example을 볡사해 μ‚¬μš©.

APP

ν‚€ μ„€λͺ… μ˜ˆμ‹œ
APP__PORT μ„œλΉ„μŠ€ 포트 28101
APP__SERVICE_NAME μ„œλΉ„μŠ€ 이름 (Eureka λ“±λ‘μš©) kdb-manager
APP__EUREKA_SERVER Eureka μ„œλ²„ μ£Όμ†Œ http://host:8761/eureka

LOG

ν‚€ μ„€λͺ… κΈ°λ³Έκ°’
LOG__LEVEL 둜그 레벨 (DEBUG | INFO | WARNING | ERROR) INFO
LOG__FORMAT 좜λ ₯ ν˜•μ‹ (json | plain) plain
LOG__OUTPUT_TARGET 좜λ ₯ λŒ€μƒ (console | file | both) both
LOG__DIR 둜그 파일 디렉토리 ./logs
LOG__FILENAME 둜그 파일 이름 app.log
LOG__FILE_MAX_BYTES 파일 μ΅œλŒ€ 크기 (bytes) 10485760 (10MB)
LOG__FILE_BACKUP_COUNT λ°±μ—… 파일 수 5

REDIS

ν‚€ μ„€λͺ… κΈ°λ³Έκ°’
REDIS__HOST 호슀트 127.0.0.1
REDIS__PORT 포트 6379
REDIS__DB DB 번호 0
REDIS__USERNAME 인증 μ‚¬μš©μž (ACL) -
REDIS__PASSWORD 인증 λΉ„λ°€λ²ˆν˜Έ -
REDIS__SSL SSL μ‚¬μš© μ—¬λΆ€ false

DB (MongoDB)

ν‚€ μ„€λͺ… κΈ°λ³Έκ°’
DB__HOST 호슀트 127.0.0.1
DB__PORT 포트 27017
DB__USERNAME μ‚¬μš©μž 이름 -
DB__PASSWORD λΉ„λ°€λ²ˆν˜Έ -
DB__AUTH_SOURCE 인증 DB -

MQ (RabbitMQ)

ν‚€ μ„€λͺ… κΈ°λ³Έκ°’
MQ__HOST 호슀트 localhost
MQ__PORT 포트 5672
MQ__USERNAME μ‚¬μš©μž 이름 guest
MQ__PASSWORD λΉ„λ°€λ²ˆν˜Έ guest
MQ__VIRTUAL_HOST 가상 호슀트 /
MQ__HEARTBEAT ν•˜νŠΈλΉ„νŠΈ 간격 (초) 600

MODEL

ν‚€ μ„€λͺ…
MODEL__DENSE_NAME Dense λͺ¨λΈλͺ… (HuggingFace ID λ˜λŠ” 둜컬 경둜)
MODEL__DENSE_PATH Dense λͺ¨λΈ 둜컬 μΊμ‹œ 디렉토리
MODEL__SPARSE_NAME Sparse λͺ¨λΈλͺ…
MODEL__SPARSE_PATH Sparse λͺ¨λΈ 둜컬 μΊμ‹œ 디렉토리
MODEL__MODEL_DEVICE μ‹€ν–‰ μž₯치 (cpu | cuda | mps)

QDRANT

ν‚€ μ„€λͺ…
QDRANT__URL Qdrant HTTP μ£Όμ†Œ
QDRANT__API_KEY API ν‚€ (λ³΄μ•ˆ μ„€μ • μ‹œ)

기타

ν‚€ μ„€λͺ…
MS__RERANKER μ™ΈλΆ€ 리랭컀 μ„œλΉ„μŠ€ Base URL

μ‹€ν–‰ 방법

둜컬 μ‹€ν–‰

# μ˜μ‘΄μ„± μ„€μΉ˜ (uv μ‚¬μš©)
uv sync

# μ„œλ²„ μ‹œμž‘
uvicorn kdb_manager:app --port 28101 --host 0.0.0.0

# 포트 μ˜€λ²„λΌμ΄λ“œ
python kdb_manager.py --port 28200

Docker

# 이미지 λΉŒλ“œ
docker build -t whitebearhands/kdb-manager:2.1.1 .

# Docker Compose μ‹€ν–‰ (GPU 포함)
docker compose up -d

docker-compose.yml은 network_mode: host + NVIDIA GPU 패슀슀루둜 κ΅¬μ„±λ˜μ–΄ μžˆλ‹€.
.env, ./models, ./logs 디렉토리λ₯Ό μ»¨ν…Œμ΄λ„ˆμ— λ§ˆμš΄νŠΈν•œλ‹€.


API μ—”λ“œν¬μΈνŠΈ

Swagger UI: http://host:port/docs


μ»¬λ ‰μ…˜ 관리

GET /api/v1/collection

λͺ¨λ“  Qdrant μ»¬λ ‰μ…˜ λͺ©λ‘μ„ λ°˜ν™˜ν•œλ‹€.

응닡

[
  { "name": "my-collection", "status": "green" }
]

POST /api/v1/collection

μ»¬λ ‰μ…˜μ„ μƒμ„±ν•œλ‹€. 이미 μ‘΄μž¬ν•˜λ©΄ λ¬΄μ‹œν•œλ‹€.

μš”μ²­ λ°”λ””

{ "collection_name": "my-collection" }

μ»¬λ ‰μ…˜ μ„€μ •

  • Dense 벑터: COSINE 거리, HNSW (m=64, ef_construct=1000)
  • Sparse 벑터: BM42 기반 (on_disk=false)
  • μ„Έκ·Έλ¨ΌνŠΈ 10개, μ΅œμ ν™” μŠ€λ ˆλ“œ 8개

응닡

{ "result": "Create collection successfully." }

DELETE /api/v1/collection/{collection_name}

μ»¬λ ‰μ…˜κ³Ό λ‚΄λΆ€ λͺ¨λ“  데이터λ₯Ό 영ꡬ μ‚­μ œν•œλ‹€.

collection_name은 HTML μΈμ½”λ”©λœ λ¬Έμžμ—΄λ‘œ μ „λ‹¬ν•œλ‹€.

응닡

{ "result": "Delete collection successfully." }

GET /api/v1/documents/{collection_name}

μ»¬λ ‰μ…˜μ˜ 포인트(청크)λ₯Ό νŽ˜μ΄μ§•μœΌλ‘œ μ‘°νšŒν•œλ‹€.

쿼리 νŒŒλΌλ―Έν„°

νŒŒλΌλ―Έν„° νƒ€μž… κΈ°λ³Έκ°’ μ„€λͺ…
page int 1 νŽ˜μ΄μ§€ 번호
page_size int 10 νŽ˜μ΄μ§€ 크기 (μ΅œλŒ€ 1000)

응닡

{
  "page": [
    {
      "context": "청크 ν…μŠ€νŠΈ",
      "ids": "doc-id",
      "metadatas": { "file_name": "파일.pdf", "doc_id": "..." }
    }
  ],
  "page_info": {
    "total_elements": 1500,
    "total_pages": 150,
    "page": 1,
    "first": true,
    "last": false,
    "empty": false
  }
}

GET /api/v1/{collection_name}/{p_id}/paragraph/content

MongoDBμ—μ„œ νŠΉμ • λ‹¨λ½μ˜ 원문을 단건 μ‘°νšŒν•œλ‹€.

응닡

{
  "collection_id": "my-collection",
  "paragraph_id": "para-001",
  "context": "단락 원문 ν…μŠ€νŠΈ...",
  "metadatas": { "doc_id": "...", "file_name": "..." }
}

λ¬Έμ„œ 관리

POST /api/v1/documents

λ¬Έμ„œ 청크 λͺ©λ‘μ„ μž„λ² λ”© ν›„ Qdrant에 upsertν•œλ‹€.

μ»¬λ ‰μ…˜μ΄ μ—†μœΌλ©΄ μžλ™ μƒμ„±ν•œλ‹€.

μš”μ²­ λ°”λ””

{
  "collection_name": "my-collection",
  "documents": [
    {
      "context": "청크 λ³Έλ¬Έ ν…μŠ€νŠΈ",
      "ids": "원본 λ¬Έμ„œ ID",
      "page_number": 3,
      "size": 512,
      "metadatas": {
        "file_name": "λ¬Έμ„œ.pdf",
        "doc_id": "doc-001",
        "collection_id": "my-collection",
        "paragraph_id": "para-001"
      }
    }
  ]
}

처리 κ³Όμ •

  1. Dense + Sparse μž„λ² λ”© 병렬 생성 (asyncio.gather)
  2. μ μ‘ν˜• 배치 upsert (초기 100건, OOM μ‹œ μ ˆλ°˜μ”© κ°μ†Œ)
  3. 10% μƒ˜ν”Œ 무결성 검증
  4. μ‹€νŒ¨ λ¬Έμ„œ μžλ™ μž¬μ‹œλ„ (50건 미만 μ‹œ)

응닡

{
  "result": "95/100 items added successfully",
  "details": {
    "total_requested": 100,
    "successful": 95,
    "failed": 5,
    "integrity_verified": true,
    "integrity_rate": 0.97
  }
}

POST /api/v1/mongo/paragraph

단락 λͺ©λ‘μ„ MongoDB rag-data.documents에 직접 μ €μž₯ν•œλ‹€.

μš”μ²­ λ°”λ””

{
  "pages": [
    {
      "collection_id": "my-collection",
      "paragraph_id": "para-001",
      "context": "단락 원문...",
      "metadatas": { "doc_id": "doc-001", "file_name": "파일.pdf" }
    }
  ]
}

DELETE /api/v1/file

파일 μ΄λ¦„μœΌλ‘œ ν•΄λ‹Ή 파일의 λͺ¨λ“  청크λ₯Ό Qdrantμ—μ„œ μ‚­μ œν•œλ‹€.

μš”μ²­ λ°”λ””

{
  "file_name": "μ‚­μ œν• νŒŒμΌ.pdf",
  "collection_name": "my-collection"
}

DELETE /api/v1/documents/{collection_name}/{id}

λ¬Έμ„œ ID(ids ν•„λ“œ)둜 포인트λ₯Ό Qdrantμ—μ„œ μ‚­μ œν•œλ‹€.

collection_name은 HTML μΈμ½”λ”©λœ λ¬Έμžμ—΄λ‘œ μ „λ‹¬ν•œλ‹€.


검색

POST /api/v2/document/search_rerank ⭐ 메인 검색

ν•˜μ΄λΈŒλ¦¬λ“œ 검색 β†’ λ¦¬λž­ν‚Ή β†’ (선택) 단락 볡원 νŒŒμ΄ν”„λΌμΈ.

μš”μ²­ λ°”λ””

ν•„λ“œ νƒ€μž… ν•„μˆ˜ μ„€λͺ…
collection_name string βœ… 검색할 μ»¬λ ‰μ…˜
query string βœ… 검색 쿼리
top_k int - 검색 후보 수 (κΈ°λ³Έ 100)
use_paragraph bool - trueλ©΄ MongoDB 단락 원문 λ°˜ν™˜ (κΈ°λ³Έ false)
metadata_filter_key string - 메타데이터 ν•„ν„° ν‚€ (예: "doc_id")
match_values string[] - ν•„ν„° κ°’ λͺ©λ‘
room_id string - μ±„νŒ…λ°© λ‹¨μœ„ 검색 λ²”μœ„ μ œν•œ

μš”μ²­ μ˜ˆμ‹œ

{
  "collection_name": "my-collection",
  "query": "RAG νŒŒμ΄ν”„λΌμΈ ꡬ성 방법",
  "top_k": 50,
  "use_paragraph": true,
  "metadata_filter_key": "doc_id",
  "match_values": ["doc-001", "doc-002"]
}

응닡 (use_paragraph=false)

[
  {
    "context": "청크 ν…μŠ€νŠΈ",
    "ids": "doc-id",
    "metadatas": { "file_name": "...", "doc_id": "..." },
    "reranked_score": 0.92
  }
]

응닡 (use_paragraph=true)

[
  {
    "collection_id": "my-collection",
    "paragraph_id": "para-001",
    "context": "단락 원문 ν…μŠ€νŠΈ (청크보닀 더 κΈ΄ λ§₯락)",
    "metadatas": { "doc_id": "doc-001", "file_name": "파일.pdf" },
    "rerank_score": 0.92
  }
]

POST /api/v2/document/search_paragraph

검색 + λ¦¬λž­ν‚Ή ν›„ paragraph_id와 점수만 λ°˜ν™˜ν•œλ‹€.

단락 λ‚΄μš© 없이 ID/점수만 ν•„μš”ν•œ 경우 (ν”„λ‘ νŠΈ lazy-load λ“±) μ‚¬μš©ν•œλ‹€.

μš”μ²­ λ°”λ””: search_rerank와 동일

응닡

[
  { "paragraph_id": "para-001", "score": 0.92 },
  { "paragraph_id": "para-003", "score": 0.87 }
]

POST /api/v1/document/search

λ¦¬λž­ν‚Ή μ—†λŠ” 순수 ν•˜μ΄λΈŒλ¦¬λ“œ 검색. Qdrant RRF 퓨전 κ²°κ³Όλ₯Ό κ·ΈλŒ€λ‘œ λ°˜ν™˜ν•œλ‹€.

μš”μ²­ λ°”λ””: search_rerank와 동일 (use_paragraph, room_id 미적용)

응닡: Qdrant 포인트 λͺ©λ‘ (score_threshold=0.11 적용)


데이터 λͺ¨λΈ

Document (청크 λ‹¨μœ„ μž…λ ₯)

class Document:
    context: str           # 청크 λ³Έλ¬Έ ν…μŠ€νŠΈ
    ids: str               # 원본 λ¬Έμ„œ ID
    page_number: int = -1  # 원본 λ¬Έμ„œ νŽ˜μ΄μ§€ 번호 (-1: μ•Œ 수 μ—†μŒ)
    size: int              # 청크 κΈ€μž 수
    metadatas: Dict        # λΆ€κ°€ 정보 (μ•„λž˜ μ°Έμ‘°)

metadatas ꢌμž₯ ν•„λ“œ

ν•„λ“œ μ„€λͺ…
file_name 원본 파일λͺ…
doc_id λ¬Έμ„œ 고유 ID
collection_id μ»¬λ ‰μ…˜ ID
paragraph_id 단락 ID (MongoDB 쑰회 ν‚€)
paragraph_type 단락 μœ ν˜• ("faq" 이면 MongoDB 쑰회 μƒλž΅)
room_id μ±„νŒ…λ°© ID (room_id ν•„ν„° μ‚¬μš© μ‹œ)
bbox 원본 λ¬Έμ„œ λ‚΄ μœ„μΉ˜ 정보

Qdrant 포인트 νŽ˜μ΄λ‘œλ“œ

Qdrant에 μ €μž₯λ˜λŠ” 포인트의 payload ꡬ쑰:

{
  "context": "청크 ν…μŠ€νŠΈ",
  "ids": "원본 λ¬Έμ„œ ID",
  "page_number": 3,
  "size": 512,
  "metadatas": {
    "file_name": "λ¬Έμ„œ.pdf",
    "doc_id": "doc-001",
    "collection_id": "my-collection",
    "paragraph_id": "para-001"
  }
}

MongoDB μŠ€ν‚€λ§ˆ

rag-data.documents β€” 단락 원문 μ €μž₯

{
  "collection_id": "my-collection",
  "paragraph_id": "para-001",
  "context": "단락 전체 원문",
  "metadatas": {
    "doc_id": "doc-001",
    "file_name": "λ¬Έμ„œ.pdf",
    "bbox": [...]
  }
}

인덱슀: (collection_id, metadatas.doc_id, paragraph_id) 볡합 인덱슀

chunks.<collection_name> β€” 청크 원문 μ €μž₯ (μ»¬λ ‰μ…˜λ³„ 뢄리)


검색 νŒŒμ΄ν”„λΌμΈ

쿼리 μž…λ ₯
   β”‚
   β”œβ”€ Dense μž„λ² λ”© (Qwen3-Embedding-8B)
   └─ Sparse μž„λ² λ”© (BM42)
         β”‚
         β–Ό
   Qdrant Prefetch (각각 top_k 후보 μˆ˜μ§‘)
         β”‚
         β–Ό
   RRF Fusion (두 κ²°κ³Ό 톡합 β†’ 50건)
         β”‚
         β–Ό
   μ™ΈλΆ€ 리랭컀 (Qwen3-Reranker-4B) β†’ top 5
         β”‚
         β–Ό
   [use_paragraph=true]
   MongoDB rag-data.documents μ—μ„œ 단락 원문 쑰회
         β”‚
         β–Ό
   μ΅œμ’… κ²°κ³Ό λ°˜ν™˜

μž„λ² λ”© νŒŒμ΄ν”„λΌμΈ (MQ)

RabbitMQ 기반 비동기 μž„λ² λ”© 처리 흐름:

μ™ΈλΆ€ μ„œλΉ„μŠ€
   β”‚ rag.embedding.request 큐에 λ©”μ‹œμ§€ λ°œν–‰
   β–Ό
EmbeddingConsumer (kdb_manager.py)
   β”‚
   β”œβ”€ 1. Redisμ—μ„œ 청크/단락 데이터 λ‘œλ“œ
   β”‚      redis_chunk_key β†’ {"data": [...chunks]}
   β”‚      redis_para_key  β†’ {"data": [...paragraphs]}
   β”‚
   β”œβ”€ 2. POST /api/v1/documents (Qdrant upsert)
   β”‚
   β”œβ”€ 3. chunk_to_mongo()   β†’ MongoDB chunks.<collection_id>
   β”‚
   β”œβ”€ 4. paragraph_to_mongo() β†’ MongoDB rag-data.documents
   β”‚
   └─ 5. MQ 이벀트 λ°œν–‰
          성곡: rag.embedding.completed
          μ‹€νŒ¨: rag.embedding.failed

μˆ˜μ‹  λ©”μ‹œμ§€ ν˜•μ‹

{
  "job_id": "unique-job-id",
  "file_id": "file-storage-id",
  "doc_id": "document-id",
  "collection_id": "my-collection",
  "redis_chunk_key": "rag.document.{doc_id}.chunk",
  "redis_para_key":  "rag.document.{doc_id}.para",
  "redis_img_key":   "rag.document.{doc_id}.img",
  "redis_tbl_key":   "rag.document.{doc_id}.tbl"
}

ν”„λ‘œμ νŠΈ ꡬ쑰

kdb-manager/
β”œβ”€β”€ kdb_manager.py          μ§„μž…μ  (μ•±, 라이프사이클, MQ Consumer)
β”œβ”€β”€ routes/
β”‚   β”œβ”€β”€ collection.py       μ»¬λ ‰μ…˜ CRUD, λ¬Έμ„œ 쑰회
β”‚   β”œβ”€β”€ document.py         μ—…μ„œνŠΈ, μ‚­μ œ, MongoDB μ €μž₯
β”‚   β”œβ”€β”€ search.py           ν•˜μ΄λΈŒλ¦¬λ“œ 검색, λ¦¬λž­ν‚Ή
β”œβ”€β”€ modules/
β”‚   β”œβ”€β”€ dependencies.py     λͺ¨λΈ/ν΄λΌμ΄μ–ΈνŠΈ 싱글톀
β”‚   β”œβ”€β”€ redis.py            RedisManager
β”‚   └── singleton_meta.py   싱글톀 λ©”νƒ€ν΄λž˜μŠ€
β”œβ”€β”€ config/
β”‚   └── __init__.py         pydantic-settings μ„€μ • λͺ¨λΈ
β”œβ”€β”€ wrapper/
β”‚   β”œβ”€β”€ logger_wrapper.py   둜거 μ„€μ •
β”‚   β”œβ”€β”€ redis_wrapper.py    Redis ν΄λΌμ΄μ–ΈνŠΈ
β”‚   β”œβ”€β”€ rabbitmq_wrapper.py RabbitMQ ν΄λΌμ΄μ–ΈνŠΈ
β”‚   └── rabbitmq_wrapper_for_rag.py  RAG μ „μš© Producer/Consumer
β”œβ”€β”€ models/                 μž„λ² λ”© λͺ¨λΈ 파일 (git 미포함)
β”œβ”€β”€ logs/                   둜그 파일 (git 미포함)
β”œβ”€β”€ pyproject.toml
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ Dockerfile
└── .env                    ν™˜κ²½ λ³€μˆ˜ (git 미포함)

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors