작성자: HolySheep AI 시니어 엔지니어링팀
최종 업데이트: 2025년 6월
예상 읽기 시간: 15분

개요: 왜 Embedding 게이트웨이가 필요한가

저는 3년 넘게 RAG(Retrieval-Augmented Generation) 시스템을 프로덕션 환경에서 운영해왔습니다.初期에는 각 Embedding 제공자를 직접 호출했지만, API 키 관리의 복잡성, 지역별 가용성 문제, 그리고 비용 통제의 어려움이 지속됐습니다. 특히 국내 개발자 분들이라면 OpenAI 서버와의 지연 시간(평균 150-250ms),时而 발생하는 타임아웃, 그리고 해외 신용카드 결제의 번거로움에 공감하실 것입니다.

HolySheep AI는 이러한 문제를 단일 게이트웨이 하나로 해결합니다. 지금 가입하시면:

지원 모델 비교

모델 차원 컨텍스트 가격 (per 1M tokens) 적합한 사용 사례 한국어 지원
text-embedding-3-small 1536 (downscalable) 8,191 tokens $0.02 대량 임베딩, 비용 최적화 ⭐⭐⭐
text-embedding-3-large 3072 (downscalable) 8,191 tokens $0.13 고품질 검색, 시맨틱 매칭 ⭐⭐⭐
voyage-3-lite 1024 32,768 tokens $0.10 장문 검색, 코드 임베딩 ⭐⭐⭐⭐
voyage-3 1024 32,768 tokens $0.50 최고 품질 검색 ⭐⭐⭐⭐
cohere-embed-english-v3.0 1024 512 tokens $0.10 영문 중심 RAG ⭐⭐
embed-multilingual-v3.0 1024 512 tokens $0.10 다국어 지원 ⭐⭐⭐⭐

이런 팀에 적합

✅ HolySheep Embedding이 적합한 경우

❌ HolySheep Embedding이 비적합한 경우

실전 통합: Python SDK 완전 가이드

1. 기본 설정 및 의존성

# requirements.txt
openai>=1.12.0
voyageai>=0.1.6
cohere>=5.3.0
qdrant-client>=1.7.0
chromadb>=0.4.22
tiktoken>=0.5.2
tenacity>=8.2.3

설치

pip install -r requirements.txt

2. HolySheep Unified Embedding Client

"""
HolySheep AI Embedding Gateway Client
단일 API 키로 OpenAI, Voyage, Cohere 임베딩 통합 호출
"""

import os
from typing import List, Optional, Union
from dataclasses import dataclass
from enum import Enum
import tiktoken

import openai
import voyageai
import cohere

HolySheep API Configuration

HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1" HOLYSHEEP_API_KEY = os.getenv("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY") class EmbeddingModel(Enum): """지원되는 임베딩 모델 목록""" TEXT_EMBEDDING_3_SMALL = "text-embedding-3-small" TEXT_EMBEDDING_3_LARGE = "text-embedding-3-large" VOYAGE_3_LITE = "voyage-3-lite" VOYAGE_3 = "voyage-3" COHERE_EMBED_ENGLISH = "cohere-embed-english-v3.0" COHERE_EMBED_MULTILINGUAL = "cohere-embed-multilingual-v3.0" @dataclass class EmbeddingResult: """임베딩 결과 데이터 클래스""" embeddings: List[List[float]] model: str tokens_used: int latency_ms: float provider: str class HolySheepEmbeddingClient: """ HolySheep AI Embedding 게이트웨이 클라이언트 Usage: client = HolySheepEmbeddingClient() result = client.embed("안녕하세요", model=EmbeddingModel.VOYAGE_3_LITE) """ def __init__(self, api_key: str = HOLYSHEEP_API_KEY): self.api_key = api_key # OpenAI 클라이언트 (text-embedding-3) self.openai_client = openai.OpenAI( api_key=api_key, base_url=HOLYSHEEP_BASE_URL ) # Voyage AI 클라이언트 self.voyage_client = voyageai.Client( api_key=api_key, base_url=HOLYSHEEP_BASE_URL ) # Cohere 클라이언트 self.cohere_client = cohere.Client( api_key=api_key, base_url=HOLYSHEEP_BASE_URL.replace("/v1", "/") ) # 토큰 카운터 self.encoders = { "cl100k_base": tiktoken.get_encoding("cl100k_base"), } def _count_tokens(self, texts: Union[str, List[str]]) -> int: """토큰 수 계산""" if isinstance(texts, str): texts = [texts] encoder = self.encoders["cl100k_base"] return sum(len(encoder.encode(text)) for text in texts) def _route_to_provider(self, model: EmbeddingModel) -> str: """모델로부터 provider 결정""" if model.value.startswith("text-embedding"): return "openai" elif model.value.startswith("voyage"): return "voyage" elif model.value.startswith("cohere") or model.value.startswith("embed-"): return "cohere" else: raise ValueError(f"Unknown model: {model}") def embed( self, texts: Union[str, List[str]], model: EmbeddingModel = EmbeddingModel.TEXT_EMBEDDING_3_SMALL, batch_size: int = 100, dimensions: Optional[int] = None, timeout: float = 30.0 ) -> EmbeddingResult: """ 임베딩 생성 Args: texts: 임베딩할 텍스트 (문자열 또는 리스트) model: 사용할 임베딩 모델 batch_size: 배치 크기 dimensions: 출력 차원 (text-embedding-3만 지원) timeout: 타임아웃 (초) Returns: EmbeddingResult: 임베딩 결과 """ import time if isinstance(texts, str): texts = [texts] provider = self._route_to_provider(model) start_time = time.time() all_embeddings = [] tokens_used = 0 # 배치 처리 for i in range(0, len(texts), batch_size): batch = texts[i:i + batch_size] try: if provider == "openai": response = self.openai_client.embeddings.create( model=model.value, input=batch, dimensions=dimensions, timeout=timeout ) embeddings = [item.embedding for item in response.data] tokens_used += response.usage.total_tokens elif provider == "voyage": response = self.voyage_client.embed( texts=batch, model=model.value, timeout=timeout ) embeddings = response.embeddings tokens_used += response.usage.total_tokens elif provider == "cohere": response = self.cohere_client.embed( texts=batch, model=model.value, input_type="search_document", timeout=timeout ) embeddings = response.embeddings # Cohere는 토큰 사용량 미제공 시 추정치 tokens_used += self._count_tokens(batch) all_embeddings.extend(embeddings) except Exception as e: print(f"Batch {i//batch_size} failed: {e}") raise latency_ms = (time.time() - start_time) * 1000 return EmbeddingResult( embeddings=all_embeddings, model=model.value, tokens_used=tokens_used, latency_ms=latency_ms, provider=provider ) def embed_with_retry( self, texts: Union[str, List[str]], model: EmbeddingModel = EmbeddingModel.TEXT_EMBEDDING_3_SMALL, max_retries: int = 3, **kwargs ) -> EmbeddingResult: """재시도 로직이 포함된 임베딩 생성""" from tenacity import retry, stop_after_attempt, wait_exponential @retry( stop=stop_after_attempt(max_retries), wait=wait_exponential(multiplier=1, min=2, max=10) ) def _embed_with_backoff(): return self.embed(texts, model, **kwargs) return _embed_with_backoff()

단일 텍스트 임베딩 헬퍼 함수

def embed_single( text: str, model: EmbeddingModel = EmbeddingModel.TEXT_EMBEDDING_3_SMALL, api_key: Optional[str] = None ) -> List[float]: """단일 텍스트 임베딩 (간편 함수)""" client = HolySheepEmbeddingClient(api_key or HOLYSHEEP_API_KEY) result = client.embed(text, model) return result.embeddings[0] if __name__ == "__main__": # 사용 예시 client = HolySheepEmbeddingClient() # 단일 텍스트 result = client.embed("한국어 RAG 시스템 구축하기", EmbeddingModel.VOYAGE_3_LITE) print(f"Model: {result.model}") print(f"Latency: {result.latency_ms:.2f}ms") print(f"Tokens: {result.tokens_used}") print(f"Embedding dim: {len(result.embeddings[0])}") # 배치 임베딩 docs = [ "向量数据库基础概念", "RAG系统架构设计", "Embedding模型比较", "Korean language processing", "문서 임베딩 최적화 방법" ] results = client.embed(docs, EmbeddingModel.VOYAGE_3_LITE) print(f"\nBatch processed: {len(results.embeddings)} documents") print(f"Total latency: {results.latency_ms:.2f}ms") print(f"Avg per doc: {results.latency_ms/len(docs):.2f}ms")

3. Qdrant 벡터DB 연동

"""
HolySheep Embedding + Qdrant 벡터DB 통합 파이프라인
RAG 시스템의 검색 계층 구현
"""

from typing import List, Dict, Any, Optional
import numpy as np
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct, Filter
from qdrant_client.http.exceptions import UnexpectedResponse

from holysheep_embedding import HolySheepEmbeddingClient, EmbeddingModel


class RAGVectorStore:
    """
    HolySheep Embedding 기반 RAG 벡터 스토어
    
    Features:
    - 자동 임베딩 및 벡터화
    - 메타데이터 필터링
    - 하이브리드 검색 지원
    - 벌크 인서트 및 실시간 업데이트
    """
    
    def __init__(
        self,
        host: str = "localhost",
        port: int = 6333,
        collection_name: str = "documents",
        embedding_model: EmbeddingModel = EmbeddingModel.VOYAGE_3_LITE,
        api_key: Optional[str] = None,
        vector_size: Optional[int] = None
    ):
        self.client = QdrantClient(host=host, port=port)
        self.collection_name = collection_name
        self.embedding_client = HolySheepEmbeddingClient(api_key)
        
        # 모델별 벡터 크기 매핑
        self.vector_sizes = {
            EmbeddingModel.TEXT_EMBEDDING_3_SMALL: 1536,
            EmbeddingModel.TEXT_EMBEDDING_3_LARGE: 3072,
            EmbeddingModel.VOYAGE_3_LITE: 1024,
            EmbeddingModel.VOYAGE_3: 1024,
            EmbeddingModel.COHERE_EMBED_ENGLISH: 1024,
            EmbeddingModel.COHERE_EMBED_MULTILINGUAL: 1024,
        }
        
        self.vector_size = vector_size or self.vector_sizes.get(
            embedding_model, 1024
        )
        self.embedding_model = embedding_model
        
        self._init_collection()
    
    def _init_collection(self):
        """컬렉션 초기화"""
        try:
            self.client.get_collection(self.collection_name)
        except (UnexpectedResponse, Exception):
            self.client.create_collection(
                collection_name=self.collection_name,
                vectors_config=VectorParams(
                    size=self.vector_size,
                    distance=Distance.COSINE
                )
            )
            print(f"Created collection: {self.collection_name}")
    
    def add_documents(
        self,
        documents: List[Dict[str, Any]],
        batch_size: int = 100,
        show_progress: bool = True
    ) -> Dict[str, int]:
        """
        문서 추가 (자동 임베딩)
        
        Args:
            documents: [{"id": str, "text": str, "metadata": dict}]
            batch_size: 배치 크기
            show_progress: 진행률 표시
        
        Returns:
            인서트 통계
        """
        import time
        
        texts = [doc["text"] for doc in documents]
        ids = [doc["id"] for doc in documents]
        metadatas = [doc.get("metadata", {}) for doc in documents]
        
        start_time = time.time()
        total_tokens = 0
        total_latency = 0
        points = []
        
        for i in range(0, len(texts), batch_size):
            batch_texts = texts[i:i + batch_size]
            batch_ids = ids[i:i + batch_size]
            batch_metas = metadatas[i:i + batch_size]
            
            # HolySheep를 통한 임베딩
            result = self.embedding_client.embed(
                batch_texts,
                model=self.embedding_model,
                batch_size=len(batch_texts)
            )
            
            total_tokens += result.tokens_used
            total_latency += result.latency_ms
            
            # 포인트 생성
            for j, embedding in enumerate(result.embeddings):
                point = PointStruct(
                    id=batch_ids[j],
                    vector=embedding,
                    payload={
                        "text": batch_texts[j],
                        "metadata": batch_metas[j]
                    }
                )
                points.append(point)
            
            # 배치 인서트
            self.client.upsert(
                collection_name=self.collection_name,
                points=points[-len(batch_texts):]
            )
            
            if show_progress:
                progress = min((i + batch_size) / len(texts) * 100, 100)
                print(f"\rProgress: {progress:.1f}%", end="")
        
        elapsed = time.time() - start_time
        
        stats = {
            "total_documents": len(documents),
            "total_tokens": total_tokens,
            "embedding_latency_ms": total_latency,
            "total_time_seconds": elapsed,
            "avg_latency_per_doc_ms": total_latency / len(documents)
        }
        
        if show_progress:
            print(f"\n인서트 완료: {stats}")
        
        return stats
    
    def search(
        self,
        query: str,
        top_k: int = 5,
        filter_conditions: Optional[Filter] = None,
        score_threshold: Optional[float] = None
    ) -> List[Dict[str, Any]]:
        """
        유사도 검색
        
        Args:
            query: 검색 쿼리
            top_k: 반환할 결과 수
            filter_conditions: 필터 조건
            score_threshold: 최소 유사도 점수
        
        Returns:
            검색 결과 리스트
        """
        # 쿼리 임베딩
        result = self.embedding_client.embed(query, self.embedding_model)
        query_vector = result.embeddings[0]
        
        # 검색 실행
        search_results = self.client.search(
            collection_name=self.collection_name,
            query_vector=query_vector,
            limit=top_k,
            query_filter=filter_conditions,
            score_threshold=score_threshold
        )
        
        return [
            {
                "id": hit.id,
                "score": hit.score,
                "text": hit.payload["text"],
                "metadata": hit.payload["metadata"]
            }
            for hit in search_results
        ]
    
    def hybrid_search(
        self,
        query: str,
        top_k: int = 5,
        bm25_weight: float = 0.3,
        vector_weight: float = 0.7
    ) -> List[Dict[str, Any]]:
        """
        하이브리드 검색 (BM25 + 벡터 유사도)
        
        Note: Qdrant의 splitted_score 조회 필요
        """
        # 벡터 검색
        vector_results = self.search(query, top_k * 2)
        
        # BM25 스코어 계산 (단순 버전)
        from collections import Counter
        import re
        
        query_terms = re.findall(r'\w+', query.lower())
        results = []
        
        for item in vector_results:
            text_terms = Counter(re.findall(r'\w+', item["text"].lower()))
            bm25_score = sum(text_terms.get(term, 0) for term in query_terms)
            bm25_score = bm25_score / (len(query_terms) + 1)
            
            # 가중 평균
            combined_score = (
                bm25_weight * bm25_score / (max(bm25_score) + 1) +
                vector_weight * item["score"]
            )
            
            item["combined_score"] = combined_score
            item["bm25_score"] = bm25_score
            results.append(item)
        
        # 정렬
        results.sort(key=lambda x: x["combined_score"], reverse=True)
        
        return results[:top_k]
    
    def get_stats(self) -> Dict[str, Any]:
        """컬렉션 통계 조회"""
        info = self.client.get_collection(self.collection_name)
        return {
            "vectors_count": info.vectors_count,
            "indexed_vectors_count": info.indexed_vectors_count,
            "points_count": info.points_count,
            "status": info.status,
            "vector_size": self.vector_size
        }


사용 예시

if __name__ == "__main__": # 초기화 vector_store = RAGVectorStore( host="localhost", collection_name="holySheep_rag_demo", embedding_model=EmbeddingModel.VOYAGE_3_LITE ) # 문서 추가 sample_docs = [ { "id": "doc_001", "text": "한국어 자연어 처리에서 BERT 기반 모델의 성능", "metadata": {"category": "NLP", "lang": "ko"} }, { "id": "doc_002", "text": "RAG 시스템에서 벡터 데이터베이스의 역할과 선택 기준", "metadata": {"category": "RAG", "lang": "ko"} }, { "id": "doc_003", "text": "Embedding model comparison: OpenAI vs Voyage vs Cohere", "metadata": {"category": "Embedding", "lang": "en"} } ] stats = vector_store.add_documents(sample_docs) print(f"인서트 통계: {stats}") # 검색 results = vector_store.search("벡터 데이터베이스 비교", top_k=2) print("\n검색 결과:") for r in results: print(f" [{r['score']:.4f}] {r['text']}") # 통계 print(f"\n벡터 스토어 통계: {vector_store.get_stats()}")

성능 벤치마크: HolySheep vs 직접 API 호출

시나리오 HolySheep (평균) 직접 API (평균) 개선율
한국 → OpenAI 임베딩 65ms 180ms 🚀 64% 개선
한국 → Voyage API 72ms 210ms 🚀 66% 개선
Cohere 다국어 임베딩 58ms 195ms 🚀 70% 개선
배치 100개 문서 1.2초 3.8초 🚀 68% 개선
동시성 50 요청/초 99.8% 성공 94.2% 성공 ✅ 안정성 향상

테스트 환경: 서울 리전, 100회 반복 평균값, 2025년 6월 측정

동시성 제어 및 비용 최적화

rate_limit과 비용 모니터링

"""
HolySheep Embedding 동시성 제어 및 비용 최적화 모듈
프로덕션 환경용 Rate Limiter와 Budget Alert 구현
"""

import asyncio
import time
import threading
from typing import Dict, Optional, Callable
from dataclasses import dataclass, field
from collections import deque
from datetime import datetime, timedelta
import logging

logger = logging.getLogger(__name__)


@dataclass
class CostAlert:
    """비용 알림 설정"""
    daily_limit: float = 100.0  # 일일 한도 (USD)
    monthly_limit: float = 1000.0  # 월간 한도 (USD)
    alert_threshold: float = 0.8  # 80% 도달 시 알림
    
    # 가격표 (per 1M tokens)
    prices: Dict[str, float] = field(default_factory=lambda: {
        "text-embedding-3-small": 0.02,
        "text-embedding-3-large": 0.13,
        "voyage-3-lite": 0.10,
        "voyage-3": 0.50,
        "cohere-embed-english-v3.0": 0.10,
        "cohere-embed-multilingual-v3.0": 0.10,
    })


@dataclass
class UsageStats:
    """사용량 통계"""
    total_tokens: int = 0
    total_cost: float = 0.0
    request_count: int = 0
    error_count: int = 0
    last_reset: datetime = field(default_factory=datetime.now)
    
    # 시간별 버킷 (최근 24시간)
    hourly_tokens: deque = field(default_factory=lambda: deque(maxlen=24))


class RateLimiter:
    """
    토큰 기반 Rate Limiter
    -滑动窗口 알고리즘 사용
    - 동시 요청 수 제한
    - Burst 허용
    """
    
    def __init__(
        self,
        requests_per_minute: int = 100,
        tokens_per_minute: int = 1000000,
        burst_size: int = 10
    ):
        self.requests_per_minute = requests_per_minute
        self.tokens_per_minute = tokens_per_minute
        self.burst_size = burst_size
        
        self.request_timestamps = deque()
        self.token_buckets = deque()
        self._lock = threading.Lock()
    
    def acquire(self, tokens_needed: int = 0) -> bool:
        """
        Rate Limit 확인 및 획득
        
        Returns:
            True: 허가됨
            False: 제한 초과
        """
        now = time.time()
        window_start = now - 60  # 1분 윈도우
        
        with self._lock:
            # 오래된 요청 제거
            while self.request_timestamps and self.request_timestamps[0] < window_start:
                self.request_timestamps.popleft()
            
            while self.token_buckets and self.token_buckets[0]["timestamp"] < window_start:
                self.token_buckets.popleft()
            
            # 요청 수 제한 확인
            if len(self.request_timestamps) >= self.requests_per_minute:
                return False
            
            # 토큰 제한 확인
            total_tokens_in_window = sum(b["tokens"] for b in self.token_buckets)
            if total_tokens_in_window + tokens_needed > self.tokens_per_minute:
                return False
            
            # 허가
            self.request_timestamps.append(now)
            self.token_buckets.append({"timestamp": now, "tokens": tokens_needed})
            
            return True
    
    def wait_and_acquire(self, tokens_needed: int = 0, timeout: float = 60.0) -> bool:
        """사용 가능해질 때까지 대기"""
        start = time.time()
        while time.time() - start < timeout:
            if self.acquire(tokens_needed):
                return True
            time.sleep(0.1)
        return False


class CostMonitor:
    """
    비용 모니터링 및 알림
    - 실시간 사용량 추적
    - 일일/월간 한도 관리
    - Alert 콜백 지원
    """
    
    def __init__(
        self,
        alert_config: CostAlert,
        on_alert: Optional[Callable[[str, float, float], None]] = None
    ):
        self.config = alert_config
        self.on_alert = on_alert
        
        self.daily_stats = UsageStats()
        self.monthly_stats = UsageStats()
        self.model_stats: Dict[str, UsageStats] = {}
        
        self._lock = threading.Lock()
    
    def record_usage(
        self,
        model: str,
        tokens: int,
        cost: float,
        success: bool = True
    ):
        """사용량 기록"""
        price = self.config.prices.get(model, 0.10)
        actual_cost = (tokens / 1_000_000) * price
        
        with self._lock:
            # 일일 통계
            self.daily_stats.total_tokens += tokens
            self.daily_stats.total_cost += actual_cost
            self.daily_stats.request_count += 1
            self.daily_stats.error_count += 0 if success else 1
            self.daily_stats.hourly_tokens.append(tokens)
            
            # 월간 통계
            self.monthly_stats.total_tokens += tokens
            self.monthly_stats.total_cost += actual_cost
            self.monthly_stats.request_count += 1
            
            # 모델별 통계
            if model not in self.model_stats:
                self.model_stats[model] = UsageStats()
            self.model_stats[model].total_tokens += tokens
            self.model_stats[model].total_cost += actual_cost
            self.model_stats[model].request_count += 1
            
            # 알림 체크
            self._check_alerts()
    
    def _check_alerts(self):
        """알림 조건 체크"""
        # 일일 한도
        daily_pct = self.daily_stats.total_cost / self.config.daily_limit
        if daily_pct >= self.config.alert_threshold:
            msg = f"일일 비용 한도의 {daily_pct*100:.0f}% 도달: ${self.daily_stats.total_cost:.2f}"
            logger.warning(msg)
            if self.on_alert:
                self.on_alert("daily", self.daily_stats.total_cost, daily_pct)
        
        # 월간 한도
        monthly_pct = self.monthly_stats.total_cost / self.config.monthly_limit
        if monthly_pct >= self.config.alert_threshold:
            msg = f"월간 비용 한도의 {monthly_pct*100:.0f}% 도달: ${self.monthly_stats.total_cost:.2f}"
            logger.warning(msg)
            if self.on_alert:
                self.on_alert("monthly", self.monthly_stats.total_cost, monthly_pct)
    
    def get_stats(self) -> Dict:
        """통계 조회"""
        with self._lock:
            return {
                "daily": {
                    "tokens": self.daily_stats.total_tokens,
                    "cost": self.daily_stats.total_cost,
                    "requests": self.daily_stats.request_count,
                    "errors": self.daily_stats.error_count,
                    "avg_tokens_per_request": (
                        self.daily_stats.total_tokens / self.daily_stats.request_count
                        if self.daily_stats.request_count > 0 else 0
                    )
                },
                "monthly": {
                    "tokens": self.monthly_stats.total_tokens,
                    "cost": self.monthly_stats.total_cost,
                    "requests": self.monthly_stats.request_count,
                    "limit": self.config.monthly_limit,
                    "usage_pct": (
                        self.monthly_stats.total_cost / self.config.monthly_limit * 100
                    )
                },
                "by_model": {
                    model: {
                        "tokens": stats.total_tokens,
                        "cost": stats.total_cost,
                        "requests": stats.request_count
                    }
                    for model, stats in self.model_stats.items()
                }
            }
    
    def reset_daily(self):
        """일일 통계 리셋"""
        with self._lock:
            self.daily_stats = UsageStats()


class AsyncEmbeddingProcessor:
    """
    비동기 임베딩 프로세서
    - 동시성 제어
    - Rate Limiting
    - 비용 모니터링
    - 자동 재시도
    """
    
    def __init__(
        self,
        api_key: str,
        rate_limiter: Optional[RateLimiter] = None,
        cost_monitor: Optional[CostMonitor] = None,
        max_concurrent: int = 10
    ):
        self.api_key = api_key
        self.rate_limiter = rate_limiter or RateLimiter()
        self.cost_monitor = cost_monitor or CostMonitor(CostAlert())
        self.semaphore = asyncio.Semaphore(max_concurrent)
        self.client = None  # HolySheepEmbeddingClient
    
    async def process_batch(
        self,
        texts: List[str],
        model: str,
        batch_size: int = 100
    ) -> List[List[float]]:
        """배치 처리 (비동기)"""
        results = []
        total_tokens = 0
        
        for i in range(0, len(texts), batch_size):
            batch = texts[i:i + batch_size]
            
            async with self.semaphore:
                # Rate Limit 확인
                estimated_tokens = sum(len(t) // 4 for t in batch)  # 대략적