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,231 @@
|
||||
services:
|
||||
# ============================================
|
||||
# 경량 버전 (외부 API 사용 + 로컬 MongoDB)
|
||||
# ============================================
|
||||
|
||||
# 1) 임베딩 단계 (preprocess 생략, qa_raw.jsonl 직접 사용)
|
||||
embed:
|
||||
image: "${RAG_BATCH_IMAGE:-rag-batch-slim:latest}"
|
||||
network_mode: host
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/batch-slim.Dockerfile
|
||||
command: ["python", "/app/scripts/ingest_qa.py"]
|
||||
working_dir: /app
|
||||
depends_on:
|
||||
- qdrant
|
||||
# 모델 게이트웨이 호스트명 → IP 매핑 (DNS 미등록 대응)
|
||||
extra_hosts:
|
||||
- "llm-ai.ex.co.kr:${GATEWAY_IP:-172.16.163.96}"
|
||||
- "embedding-ai.ex.co.kr:${GATEWAY_IP:-172.16.163.96}"
|
||||
- "reranker-ai.ex.co.kr:${GATEWAY_IP:-172.16.163.96}"
|
||||
environment:
|
||||
# 프록시 비활성화 (명시적)
|
||||
HTTP_PROXY: ""
|
||||
HTTPS_PROXY: ""
|
||||
http_proxy: ""
|
||||
https_proxy: ""
|
||||
# Python 출력 버퍼링 비활성화 (실시간 로그)
|
||||
PYTHONUNBUFFERED: "1"
|
||||
# 임베딩(게이트웨이) 설정
|
||||
TEI_EMBED_URL: "${TEI_EMBED_URL:-https://embedding-ai.ex.co.kr}"
|
||||
EMBED_MODEL_NAME: "${EMBED_MODEL_NAME:-Qwen/Qwen3-Embedding-8B}"
|
||||
MODEL_API_KEY: "${MODEL_API_KEY:-}"
|
||||
MODEL_VERIFY_SSL: "${MODEL_VERIFY_SSL:-false}"
|
||||
API_TIMEOUT: "${API_TIMEOUT:-60}"
|
||||
EMBED_BATCH_SIZE: "${EMBED_BATCH_SIZE:-100}"
|
||||
# Qdrant 저장 배치 (4096차원 → 32MB 요청 한도 초과 방지, 100 권장)
|
||||
VECTOR_BATCH_SIZE: "${VECTOR_BATCH_SIZE:-100}"
|
||||
# 벡터 DB 설정
|
||||
VECTOR_STORE: "${VECTOR_STORE:-qdrant}"
|
||||
QDRANT_HOST: "${QDRANT_HOST:-127.0.0.1}"
|
||||
QDRANT_PORT: "${QDRANT_PORT:-6333}"
|
||||
QDRANT_COLLECTION: "${QDRANT_COLLECTION:-qa_vectors}"
|
||||
HYBRID_SEARCH_ENABLED: "${HYBRID_SEARCH_ENABLED:-false}"
|
||||
SPARSE_SEARCH_ENABLED: "${SPARSE_SEARCH_ENABLED:-true}"
|
||||
SPARSE_TOP_K: "${SPARSE_TOP_K:-30}"
|
||||
HYBRID_MERGE_TOP_K: "${HYBRID_MERGE_TOP_K:-40}"
|
||||
# 프록시 우회 (내부 IP 직접 연결)
|
||||
NO_PROXY: "${NO_PROXY:-localhost,127.0.0.1,172.16.0.0/12,192.168.0.0/16,10.0.0.0/8,.ex.co.kr}"
|
||||
no_proxy: "${no_proxy:-localhost,127.0.0.1,172.16.0.0/12,192.168.0.0/16,10.0.0.0/8,.ex.co.kr}"
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
- ./scripts:/app/scripts
|
||||
restart: "no"
|
||||
|
||||
# 2) 인덱싱 단계
|
||||
index:
|
||||
image: "${RAG_BATCH_IMAGE:-rag-batch-slim:latest}"
|
||||
network_mode: host
|
||||
command: ["python", "/app/scripts/build_index_qa.py"]
|
||||
working_dir: /app
|
||||
depends_on:
|
||||
embed:
|
||||
condition: service_completed_successfully
|
||||
environment:
|
||||
# 프록시 비활성화 (명시적)
|
||||
HTTP_PROXY: ""
|
||||
HTTPS_PROXY: ""
|
||||
http_proxy: ""
|
||||
https_proxy: ""
|
||||
# Python 출력 버퍼링 비활성화 (실시간 로그)
|
||||
PYTHONUNBUFFERED: "1"
|
||||
# 벡터 DB 설정
|
||||
VECTOR_STORE: "${VECTOR_STORE:-faiss}"
|
||||
# 프록시 우회
|
||||
NO_PROXY: "${NO_PROXY:-localhost,127.0.0.1,172.16.0.0/12,192.168.0.0/16,10.0.0.0/8}"
|
||||
no_proxy: "${no_proxy:-localhost,127.0.0.1,172.16.0.0/12,192.168.0.0/16,10.0.0.0/8}"
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
- ./scripts:/app/scripts
|
||||
restart: "no"
|
||||
|
||||
# 3) API 서비스
|
||||
api:
|
||||
image: "${RAG_API_IMAGE:-rag-api-slim:latest}"
|
||||
network_mode: host # embed/index/admin과 통일: 127.0.0.1로 qdrant/mongo 접근
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/service-slim.Dockerfile
|
||||
depends_on:
|
||||
- index
|
||||
- qdrant
|
||||
# 모델 게이트웨이 호스트명 → IP 매핑 (DNS 미등록 대응)
|
||||
extra_hosts:
|
||||
- "llm-ai.ex.co.kr:${GATEWAY_IP:-172.16.163.96}"
|
||||
- "embedding-ai.ex.co.kr:${GATEWAY_IP:-172.16.163.96}"
|
||||
- "reranker-ai.ex.co.kr:${GATEWAY_IP:-172.16.163.96}"
|
||||
environment:
|
||||
# 프록시 비활성화 (명시적)
|
||||
HTTP_PROXY: ""
|
||||
HTTPS_PROXY: ""
|
||||
http_proxy: ""
|
||||
https_proxy: ""
|
||||
# Python 출력 버퍼링 비활성화 (실시간 로그)
|
||||
PYTHONUNBUFFERED: "1"
|
||||
# 모델 게이트웨이 공통 인증/TLS
|
||||
MODEL_API_KEY: "${MODEL_API_KEY:-}"
|
||||
MODEL_VERIFY_SSL: "${MODEL_VERIFY_SSL:-false}"
|
||||
# LLM API (게이트웨이)
|
||||
LLM_BASE_URL: "${LLM_BASE_URL:-https://llm-ai.ex.co.kr}"
|
||||
LLM_MODEL_NAME: "${LLM_MODEL_NAME:-Qwen/Qwen3.6-27B-FP8}"
|
||||
LLM_API_KEY: "${LLM_API_KEY:-}"
|
||||
|
||||
# 임베딩 / 리랭커 (게이트웨이)
|
||||
TEI_EMBED_URL: "${TEI_EMBED_URL:-https://embedding-ai.ex.co.kr}"
|
||||
EMBED_MODEL_NAME: "${EMBED_MODEL_NAME:-Qwen/Qwen3-Embedding-8B}"
|
||||
TEI_RERANK_URL: "${TEI_RERANK_URL:-https://reranker-ai.ex.co.kr}"
|
||||
TEI_RERANK_MODEL: "${TEI_RERANK_MODEL:-Qwen/Qwen3-Reranker-8B}"
|
||||
EMBED_API_STYLE: "${EMBED_API_STYLE:-openai}"
|
||||
RERANK_API_STYLE: "${RERANK_API_STYLE:-gateway}"
|
||||
API_TIMEOUT: "${API_TIMEOUT:-60}"
|
||||
|
||||
# Agent tool loop → chatbotApi (WAS 동일 서버)
|
||||
AGENT_MODE: "${AGENT_MODE:-legacy}"
|
||||
AGENT_MAX_ROUNDS: "${AGENT_MAX_ROUNDS:-6}"
|
||||
CHATBOT_API_BASE_URL: "${CHATBOT_API_BASE_URL:-http://127.0.0.1:8086/api}"
|
||||
INTERNAL_TOOL_API_KEY: "${INTERNAL_TOOL_API_KEY:-}"
|
||||
CHATBOT_TOOL_TIMEOUT: "${CHATBOT_TOOL_TIMEOUT:-30}"
|
||||
|
||||
# MongoDB (로컬 호스트 - 데이터베이스별 인증)
|
||||
MONGO_HOST: "${MONGO_HOST:-127.0.0.1}"
|
||||
MONGO_PORT: "${MONGO_PORT:-27017}"
|
||||
MONGO_USER: "${MONGO_USER:-exlink}"
|
||||
MONGO_PASSWORD: "${MONGO_PASSWORD:-!wkcproqkf1}"
|
||||
MONGO_DATABASE: "${MONGO_DATABASE:-chat_history}"
|
||||
MONGO_COLLECTION: "${MONGO_COLLECTION:-rag_conversations}"
|
||||
|
||||
# 벡터 DB
|
||||
VECTOR_STORE: "${VECTOR_STORE:-qdrant}"
|
||||
QDRANT_HOST: "${QDRANT_HOST:-127.0.0.1}"
|
||||
QDRANT_PORT: "${QDRANT_PORT:-6333}"
|
||||
QDRANT_COLLECTION: "${QDRANT_COLLECTION:-qa_vectors}"
|
||||
HYBRID_SEARCH_ENABLED: "${HYBRID_SEARCH_ENABLED:-false}"
|
||||
SPARSE_SEARCH_ENABLED: "${SPARSE_SEARCH_ENABLED:-true}"
|
||||
SPARSE_TOP_K: "${SPARSE_TOP_K:-30}"
|
||||
HYBRID_MERGE_TOP_K: "${HYBRID_MERGE_TOP_K:-40}"
|
||||
|
||||
# 성능 튜닝
|
||||
FAISS_TOP_K: "${FAISS_TOP_K:-30}"
|
||||
FAISS_THRESHOLD: "${FAISS_THRESHOLD:-0.55}"
|
||||
FAISS_THRESHOLD_REWRITE: "${FAISS_THRESHOLD_REWRITE:-0.50}"
|
||||
RERANK_CANDIDATES: "${RERANK_CANDIDATES:-20}"
|
||||
RERANK_BATCH_SIZE: "${RERANK_BATCH_SIZE:-16}"
|
||||
LOW_CONFIDENCE_THRESHOLD: "${LOW_CONFIDENCE_THRESHOLD:-0.65}"
|
||||
HIGH_CONFIDENCE_THRESHOLD: "${HIGH_CONFIDENCE_THRESHOLD:-0.75}"
|
||||
TOP_N_FOR_LLM: "${TOP_N_FOR_LLM:-5}"
|
||||
LLM_MAX_TOKENS: "${LLM_MAX_TOKENS:-2048}"
|
||||
QUERY_REWRITE_ENABLED: "${QUERY_REWRITE_ENABLED:-true}"
|
||||
CHAT_HISTORY_LIMIT: "${CHAT_HISTORY_LIMIT:-10}"
|
||||
CHAT_HISTORY_HOURS: "${CHAT_HISTORY_HOURS:-24}"
|
||||
CHAT_HISTORY_ALWAYS_INCLUDE: "${CHAT_HISTORY_ALWAYS_INCLUDE:-true}"
|
||||
|
||||
# 프록시 우회 (내부 IP 직접 연결 + 게이트웨이 도메인)
|
||||
NO_PROXY: "${NO_PROXY:-localhost,127.0.0.1,172.16.0.0/12,192.168.0.0/16,10.0.0.0/8,.ex.co.kr}"
|
||||
no_proxy: "${no_proxy:-localhost,127.0.0.1,172.16.0.0/12,192.168.0.0/16,10.0.0.0/8,.ex.co.kr}"
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
- ./scripts:/app/scripts
|
||||
restart: unless-stopped
|
||||
|
||||
# Qdrant 벡터 DB (기본 벡터 스토어)
|
||||
# ※ profiles 제거 → 별도 플래그 없이 항상 기동
|
||||
qdrant:
|
||||
image: qdrant/qdrant:v1.18.2 # 폐쇄망에 docker load 한 이미지 태그와 반드시 일치시킬 것
|
||||
ports:
|
||||
- "6333:6333" # REST / gRPC
|
||||
- "6334:6334" # gRPC (선택)
|
||||
volumes:
|
||||
- ./qdrant_data:/qdrant/storage # 벡터 영속 저장 (컨테이너 재시작에도 유지)
|
||||
restart: unless-stopped
|
||||
|
||||
# 4) 큐레이션 어드민 (벡터DB 검색/조회/삭제/추가 웹 UI)
|
||||
# 실시간 api와 같은 이미지/모듈을 재사용하되 별도 프로세스로 분리
|
||||
admin:
|
||||
image: "${RAG_API_IMAGE:-rag-api-slim:latest}"
|
||||
network_mode: host
|
||||
command:
|
||||
- python
|
||||
- -m
|
||||
- uvicorn
|
||||
- scripts.admin_service:app
|
||||
- --host
|
||||
- 0.0.0.0
|
||||
- --port
|
||||
- "${ADMIN_PORT:-28013}"
|
||||
working_dir: /app
|
||||
depends_on:
|
||||
- qdrant
|
||||
# 모델 게이트웨이 호스트명 → IP 매핑 (어드민도 임베딩 호출)
|
||||
extra_hosts:
|
||||
- "embedding-ai.ex.co.kr:${GATEWAY_IP:-172.16.163.96}"
|
||||
- "reranker-ai.ex.co.kr:${GATEWAY_IP:-172.16.163.96}"
|
||||
- "llm-ai.ex.co.kr:${GATEWAY_IP:-172.16.163.96}"
|
||||
environment:
|
||||
HTTP_PROXY: ""
|
||||
HTTPS_PROXY: ""
|
||||
http_proxy: ""
|
||||
https_proxy: ""
|
||||
PYTHONUNBUFFERED: "1"
|
||||
# 임베딩(게이트웨이) — 어드민 검색/추가 시 사용
|
||||
TEI_EMBED_URL: "${TEI_EMBED_URL:-https://embedding-ai.ex.co.kr}"
|
||||
EMBED_MODEL_NAME: "${EMBED_MODEL_NAME:-Qwen/Qwen3-Embedding-8B}"
|
||||
MODEL_API_KEY: "${MODEL_API_KEY:-}"
|
||||
MODEL_VERIFY_SSL: "${MODEL_VERIFY_SSL:-false}"
|
||||
API_TIMEOUT: "${API_TIMEOUT:-60}"
|
||||
VECTOR_STORE: "${VECTOR_STORE:-qdrant}"
|
||||
QDRANT_HOST: "${QDRANT_HOST:-127.0.0.1}"
|
||||
QDRANT_PORT: "${QDRANT_PORT:-6333}"
|
||||
QDRANT_COLLECTION: "${QDRANT_COLLECTION:-qa_vectors}"
|
||||
HYBRID_SEARCH_ENABLED: "${HYBRID_SEARCH_ENABLED:-false}"
|
||||
SPARSE_SEARCH_ENABLED: "${SPARSE_SEARCH_ENABLED:-true}"
|
||||
SPARSE_TOP_K: "${SPARSE_TOP_K:-30}"
|
||||
HYBRID_MERGE_TOP_K: "${HYBRID_MERGE_TOP_K:-40}"
|
||||
ADMIN_CORS_ORIGINS: "${ADMIN_CORS_ORIGINS:-*}" # 별도 프론트 origin 제한 시 콤마 구분으로 지정
|
||||
NO_PROXY: "${NO_PROXY:-localhost,127.0.0.1,172.16.0.0/12,192.168.0.0/16,10.0.0.0/8,.ex.co.kr}"
|
||||
no_proxy: "${no_proxy:-localhost,127.0.0.1,172.16.0.0/12,192.168.0.0/16,10.0.0.0/8,.ex.co.kr}"
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
- ./scripts:/app/scripts
|
||||
restart: unless-stopped
|
||||
|
||||
Reference in New Issue
Block a user