AI 워크플로우를 자동화하고 싶은 개발자라면 Dify는 선택지가 아니라 필수 도구입니다. 그러나 기본 제공 노드만으로는 부족한 순간이 반드시 옵니다. 이 튜토리얼에서는 Dify에서 HolySheep AI를 활용해 커스텀 도구와 커스텀 노드를 개발하는 방법을 저의 실전 경험을 바탕으로 설명드리겠습니다.
왜 HolySheep AI인가?
저는 여러 AI 게이트웨이를 사용해봤지만, HolySheep AI는 개발자 경험에서 명확한 차이를 보여줍니다. 월 1,000만 토큰 기준으로 비용을 비교해보겠습니다.
| 모델 | 단가 ($/MTok) | 월 1,000만 토큰 비용 | Dify 기본 대비 절감 |
|---|---|---|---|
| DeepSeek V3.2 | $0.42 | $4.20 | 약 97% 절감 |
| Gemini 2.5 Flash | $2.50 | $25.00 | 약 83% 절감 |
| GPT-4.1 | $8.00 | $80.00 | 약 46% 절감 |
| Claude Sonnet 4.5 | $15.00 | $150.00 | 참고용 |
DeepSeek V3.2의 경우 월 1,000만 토큰에 단 $4.20이면 충분합니다. 저는 이전에 다른 게이트웨이에서 같은 사용량에 월 $180을 부과받은 경험이 있는데, HolySheep AI로 변경 후 같은 품질의 응답을 받으면서 비용을 97% 이상 절감했습니다. 특히 해외 신용카드 없이 로컬 결제가 가능하다는 점이 저처럼 한국 개발자에게는 매우 큰 장점입니다.
Dify 커스텀 도구 개발
Dify의 가장 강력한 기능 중 하나는 커스텀 도구(Function Calling Tool)를 만들어 워크플로우에 통합할 수 있다는 점입니다. HolySheep AI API를 Dify 커스텀 도구로 등록하면 Dify 워크플로우에서 직접 다중 모델을 호출할 수 있습니다.
사전 준비
- Dify 설치 (Docker 또는 소스 빌드)
- HolySheep AI API 키 발급
- 커스텀 도구용 JSON 스키마 정의
HolySheep AI 기반 Dify 커스텀 도구 스키마
{
"openapi": "3.0.0",
"info": {
"title": "HolySheep AI Multi-Model API",
"description": "HolySheep AI 게이트웨이를 통해 GPT-4.1, Claude Sonnet 4.5, Gemini 2.5 Flash, DeepSeek V3.2를 호출합니다.",
"version": "1.0.0"
},
"servers": [
{
"url": "https://api.holysheep.ai/v1",
"description": "HolySheep AI 게이트웨이"
}
],
"paths": {
"/chat/completions": {
"post": {
"operationId": "multiModelChat",
"summary": "다중 모델 채팅 완료",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["model", "messages"],
"properties": {
"model": {
"type": "string",
"enum": [
"gpt-4.1",
"claude-sonnet-4.5",
"gemini-2.5-flash",
"deepseek-v3.2"
],
"description": "호출할 모델 선택"
},
"messages": {
"type": "array",
"description": "대화 메시지 배열",
"items": {
"type": "object",
"properties": {
"role": {
"type": "string",
"enum": ["system", "user", "assistant"]
},
"content": {
"type": "string"
}
}
}
},
"temperature": {
"type": "number",
"minimum": 0,
"maximum": 2,
"default": 0.7,
"description": "응답 창의성 조절 (0: 정확, 2: 창의적)"
},
"max_tokens": {
"type": "integer",
"default": 2048,
"description": "최대 토큰 수"
}
}
}
}
}
},
"responses": {
"200": {
"description": "성공적 응답",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": { "type": "string" },
"model": { "type": "string" },
"choices": {
"type": "array",
"items": {
"type": "object",
"properties": {
"message": {
"type": "object",
"properties": {
"role": { "type": "string" },
"content": { "type": "string" }
}
},
"finish_reason": { "type": "string" }
}
}
},
"usage": {
"type": "object",
"properties": {
"prompt_tokens": { "type": "integer" },
"completion_tokens": { "type": "integer" },
"total_tokens": { "type": "integer" }
}
},
"cost_usd": { "type": "number", "description": "이번 호출 비용 (USD)" }
}
}
}
}
}
}
}
}
}
}
이 스키마를 Dify의 커스텀 도구 정의에 붙여넣으면 됩니다. 중요한 점은 servers.url을 반드시 https://api.holysheep.ai/v1으로 설정해야 하며, 절대로 api.openai.com이나 api.anthropic.com을 사용하면 안 됩니다.
커스텀 Python 노드 개발
Dify의 워크플로우 노드는 Python으로 커스텀 노드를 만들어 확장할 수 있습니다. 저는 실무에서 Dify의LLM 노드만으로는 처리하기 어려운 전처리와 후처리를 커스텀 노드로 구현하여 워크플로우 효율을 크게 높인 경험이 있습니다.
# dify_custom_nodes/holy_sheep_gateway.py
"""
Dify 커스텀 Python 노드: HolySheep AI 다중 모델 라우팅
작성자: HolySheep AI 기술 블로그
"""
import json
import time
from typing import Any, Dict, List, Optional
모델별 가격표 (HolySheep AI 2026년 공식 데이터)
MODEL_PRICING = {
"gpt-4.1": {
"input": 0.50, # $/MTok (입력)
"output": 8.00, # $/MTok (출력)
"latency_ms": 850 # 평균 응답 시간
},
"claude-sonnet-4.5": {
"input": 3.00,
"output": 15.00,
"latency_ms": 920
},
"gpt-4.1-mini": {
"input": 0.15,
"output": 0.60,
"latency_ms": 420
},
"gemini-2.5-flash": {
"input": 0.10,
"output": 2.50,
"latency_ms": 380
},
"deepseek-v3.2": {
"input": 0.07,
"output": 0.42,
"latency_ms": 410
}
}
HolySheep AI API 설정
HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1"
HOLYSHEEP_API_KEY = "YOUR_HOLYSHEEP_API_KEY" # 실제 키로 교체
class HolySheepRouter:
"""다중 모델 라우팅 및 비용 최적화 노드"""
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = HOLYSHEEP_BASE_URL
self.call_history: List[Dict] = []
def estimate_cost(self, model: str, input_tokens: int, output_tokens: int) -> float:
"""호출 비용 예측 (USD)"""
if model not in MODEL_PRICING:
raise ValueError(f"지원하지 않는 모델: {model}")
pricing = MODEL_PRICING[model]
cost = (input_tokens / 1_000_000 * pricing["input"] +
output_tokens / 1_000_000 * pricing["output"])
return round(cost, 6)
def select_optimal_model(
self,
task_type: str,
budget_priority: bool = True
) -> str:
"""작업 유형에 따른 최적 모델 선택"""
model_selection = {
"fast_response": "gemini-2.5-flash",
"code_generation": "gpt-4.1",
"long_context": "claude-sonnet-4.5",
"budget_friendly": "deepseek-v3.2",
"balanced": "gpt-4.1-mini"
}
return model_selection.get(task_type, "deepseek-v3.2")
def build_request_payload(
self,
model: str,
messages: List[Dict],
temperature: float = 0.7,
max_tokens: int = 2048
) -> Dict[str, Any]:
"""HolySheep AI API 요청 페이로드 구성"""
return {
"model": model,
"messages": messages,
"temperature": temperature,
"max_tokens": max_tokens
}
def log_call(
self,
model: str,
input_tokens: int,
output_tokens: int,
latency_ms: float,
success: bool
) -> None:
"""호출 기록 저장 및 월간 비용 보고"""
cost = self.estimate_cost(model, input_tokens, output_tokens)
self.call_history.append({
"model": model,
"input_tokens": input_tokens,
"output_tokens": output_tokens,
"cost_usd": cost,
"latency_ms": latency_ms,
"success": success,
"timestamp": time.time()
})
def get_monthly_report(self) -> Dict[str, Any]:
"""월간 사용량 및 비용 보고서 생성"""
total_cost = sum(c["cost_usd"] for c in self.call_history)
total_tokens = sum(
c["input_tokens"] + c["output_tokens"]
for c in self.call_history
)
model_usage = {}
for call in self.call_history:
model_usage[call["model"]] = model_usage.get(call["model"], 0) + 1
return {
"total_calls": len(self.call_history),
"total_tokens": total_tokens,
"total_cost_usd": round(total_cost, 4),
"model_usage_breakdown": model_usage,
"avg_latency_ms": round(
sum(c["latency_ms"] for c in self.call_history) /
len(self.call_history), 2
) if self.call_history else 0
}
Dify 워크플로우 노드 실행 함수
def node_execute(
variables: Dict[str, Any],
context: Dict[str, Any]
) -> Dict[str, Any]:
"""
Dify Python 노드 실행 엔트리 포인트
Args:
variables: Dify 워크플로우에서 전달된 입력 변수
context: 실행 컨텍스트 (세션 정보 등)
Returns:
노드 실행 결과 딕셔너리
"""
router = HolySheepRouter(api_key=HOLYSHEEP_API_KEY)
task_type = variables.get("task_type", "budget_friendly")
user_message = variables.get("message", "")
budget_limit = variables.get("budget_limit_usd", 10.0)
# 최적 모델 자동 선택
selected_model = router.select_optimal_model(
task_type=task_type,
budget_priority=True
)
# 요청 페이로드 구성
payload = router.build_request_payload(
model=selected_model,
messages=[
{"role": "system", "content": "당신은 유용한 AI 어시스턴트입니다."},
{"role": "user", "content": user_message}
],
temperature=0.7,
max_tokens=2048
)
# 비용 예측
estimated_cost = router.estimate_cost(
model=selected_model,
input_tokens=100, # 대략적 입력 토큰 수
output_tokens=500 # 예상 출력 토큰 수
)
return {
"selected_model": selected_model,
"api_endpoint": f"{HOLYSHEEP_BASE_URL}/chat/completions",
"payload": payload,
"estimated_cost_usd": estimated_cost,
"within_budget": estimated_cost <= budget_limit,
"model_pricing": MODEL_PRICING[selected_model],
"message": f"선택된 모델: {selected_model}, "
f"예상 비용: ${estimated_cost:.6f}"
}
if __name__ == "__main__":
# 테스트 실행
test_variables = {
"task_type": "code_generation",
"message": "Python으로 REST API 서버를 만들어줘",
"budget_limit_usd": 0.50
}
test_context = {"session_id": "test-001"}
result = node_execute(test_variables, test_context)
print(json.dumps(result, ensure_ascii=False, indent=2))
Dify 워크플로우 통합 예시
이제 위에서 개발한 커스텀 노드를 Dify 워크플로우에 통합하는 전체 파이프라인을 보여드리겠습니다.
# examples/dify_workflow_pipeline.py
"""
Dify 워크플로우 + HolySheep AI 통합 파이프라인
다중 모델Fallback 전략 및 비용 추적 포함
"""
import json
import time
import httpx
from datetime import datetime
from typing import Optional
HolySheep AI 설정
HOLYSHEEP_API_KEY = "YOUR_HOLYSHEEP_API_KEY"
BASE_URL = "https://api.holysheep.ai/v1"
모델별 장애 복구(Fallback) 체인
FALLBACK_CHAINS = {
"high_quality": ["gpt-4.1", "claude-sonnet-4.5", "gemini-2.5-flash"],
"fast_response": ["gemini-2.5-flash", "gpt-4.1-mini", "deepseek-v3.2"],
"budget_optimized": ["deepseek-v3.2", "gemini-2.5-flash", "gpt-4.1-mini"]
}
class DifyHolySheepPipeline:
"""Dify 워크플로우용 HolySheep AI 파이프라인"""
def __init__(self, api_key: str):
self.api_key = api_key
self.client = httpx.Client(
base_url=BASE_URL,
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
},
timeout=60.0
)
def call_with_fallback(
self,
messages: list,
chain: str = "budget_optimized",
task_description: str = ""
) -> dict:
"""
Fallback 체인을 활용한 모델 호출
주 모델이 실패하면 다음 모델로 자동 전환합니다.
"""
models = FALLBACK_CHAINS.get(chain, FALLBACK_CHAINS["budget_optimized"])
last_error = None
for attempt, model in enumerate(models):
try:
print(f"[Attempt {attempt + 1}] 모델: {model}")
start_time = time.time()
response = self.client.post(
"/chat/completions",
json={
"model": model,
"messages": messages,
"temperature": 0.7,
"max_tokens": 2048
}
)
latency_ms = (time.time() - start_time) * 1000
if response.status_code == 200:
result = response.json()
return {
"success": True,
"model_used": model,
"response": result["choices"][0]["message"]["content"],
"latency_ms": round(latency_ms, 2),
"total_tokens": result.get("usage", {}).get("total_tokens", 0),
"fallback_attempts": attempt
}
else:
print(f"[{model}] 오류: {response.status_code} - {response.text}")
last_error = f"HTTP {response.status_code}"
except httpx.TimeoutException:
print(f"[{model}] 타임아웃")
last_error = "Timeout"
continue
except Exception as e:
print(f"[{model}] 예외: {str(e)}")
last_error = str(e)
continue
return {
"success": False,
"error": f"모든 모델 호출 실패. 마지막 오류: {last_error}",
"fallback_attempts": len(models)
}
def batch_process_with_routing(
self,
requests: list,
route_strategy: str = "budget_optimized"
) -> list:
"""
여러 요청을 일괄 처리하고 모델 라우팅 전략을 적용
Args:
requests: {"id": str, "prompt": str, "priority": str} 리스트
route_strategy: 라우팅 전략 (high_quality, fast_response, budget_optimized)
Returns:
처리 결과 리스트 (각 요청별 응답)
"""
results = []
for req in requests:
req_id = req.get("id", "unknown")
prompt = req.get("prompt", "")
priority = req.get("priority", "normal")
# 우선순위에 따른 Fallback 체인 선택
if priority == "high":
chain = "high_quality"
elif priority == "low":
chain = "budget_optimized"
else:
chain = route_strategy
print(f"[{datetime.now().isoformat()}] 처리 중: {req_id} (우선순위: {priority})")
messages = [{"role": "user", "content": prompt}]
result = self.call_with_fallback(
messages=messages,
chain=chain,
task_description=req_id
)
result["request_id"] = req_id
results.append(result)
return results
Dify 워크플로우 웹훅 핸들러 예시
def dify_webhook_handler(request_data: dict) -> dict:
"""
Dify 워크플로우 웹훅에서 호출되는 핸들러
Dify 워크플로우의 HTTP 요청 노드에서 이 엔드포인트를 호출합니다.
"""
pipeline = DifyHolySheepPipeline(api_key=HOLYSHEEP_API_KEY)
task_type = request_data.get("task_type", "chat")
user_input = request_data.get("user_input", "")
priority = request_data.get("priority", "normal")
if task_type == "batch":
# 일괄 처리 모드
requests = request_data.get("requests", [])
results = pipeline.batch_process_with_routing(
requests=requests,
route_strategy="budget_optimized"
)
return {
"status": "batch_completed",
"total_requests": len(requests),
"results": results
}
else:
# 단일 요청 모드
chain = "high_quality" if priority == "high" else "budget_optimized"
messages = [{"role": "user", "content": user_input}]
result = pipeline.call_with_fallback(
messages=messages,
chain=chain
)
return result
실행 예시
if __name__ == "__main__":
pipeline = DifyHolySheepPipeline(api_key=HOLYSHEEP_API_KEY)
# 단일 요청 테스트
print("=" * 50)
print("단일 요청 테스트")
print("=" * 50)
single_result = pipeline.call_with_fallback(
messages=[
{"role": "user", "content": "Docker-compose로 Redis 클러스터를 구성하는 방법을 알려줘"}
],
chain="high_quality",
task_description="docker-compose-redis"
)
print(json.dumps(single_result, ensure_ascii=False, indent=2))
# 일괄 처리 테스트
print("\n" + "=" * 50)
print("일괄 처리 테스트")
print("=" * 50)
batch_requests = [
{"id": "req-001", "prompt": "Kubernetes 기본 명령어를 알려줘", "priority": "normal"},
{"id": "req-002", "prompt": "Git 워크플로우를 설명해줘", "priority": "low"},
{"id": "req-003", "prompt": "高性能 REST API 아키텍처 설계", "priority": "high"},
]
batch_results = pipeline.batch_process_with_routing(
requests=batch_requests,
route_strategy="budget_optimized"
)
for r in batch_results:
print(f"요청 {r['request_id']}: "
f"모델={r.get('model_used', 'N/A')}, "
f"성공={r.get('success', False)}, "
f"지연시간={r.get('latency_ms', 0)}ms")
커스텀 노드 설치 및 등록
Dify에서 커스텀 Python 노드를 사용하려면 다음 단계를 진행합니다.
- 1단계:
~/.dycribe/nodes/디렉토리 생성 - 2단계: Python 노드 파일을 해당 디렉토리에 배치
- 3단계: Dify 재시작 후 커스텀 노드가 노드 팔레트에 표시되는지 확인
- 4단계: 워크플로우 캔버스에서 커스텀 노드를 드래그하여 사용
# Dify 커스텀 노드 디렉토리 구조
~/.dycribe/
└── nodes/
├── holy_sheep_gateway.py # 메인 라우팅 노드
├── cost_tracker.py # 비용 추적 노드
├── model_selector.py # 모델 선택 노드
└── __init__.py
# Dify 워크플로우 YAML 설정 (workflow.yaml)
워크플로우 설정 파일로 커스텀 노드 파라미터 정의
name: "HolySheep AI Multimodel Pipeline"
version: "1.0.0"
nodes:
- id: "model-selector"
type: "HolySheepGateway"
config:
api_key_env: "HOLYSHEEP_API_KEY"
base_url: "https://api.holysheep.ai/v1"
default_model: "deepseek-v3.2"
fallback_chain:
- "deepseek-v3.2"
- "gemini-2.5-flash"
- "gpt-4.1"
- id: "cost-tracker"
type: "CostTracker"
config:
budget_limit_usd: 50.0
alert_threshold: 0.80
report_interval: "daily"
edges:
- source: "model-selector"
target: "cost-tracker"
data_flow: "response_with_metadata"
자주 발생하는 오류와 해결책
오류 1: API 키 인증 실패 (401 Unauthorized)
가장 빈번하게 발생하는 오류입니다. HolySheep AI에서 발급받은 API 키가 정확하지 않거나 환경 변수가 제대로 설정되지 않았을 때 발생합니다.
# ❌ 잘못된 예시
client = httpx.Client(
base_url="https://api.holysheep.ai/v1",
headers={"Authorization": "Bearer YOUR_API_KEY"} # 하드코딩
)
✅ 올바른 예시 - 환경 변수 사용
import os
client = httpx.Client(
base_url="https://api.holysheep.ai/v1",
headers={
"Authorization": f"Bearer {os.environ.get('HOLYSHEEP_API_KEY')}",
"Content-Type": "application/json"
}
)
환경 변수 설정 확인
print(f"API 키 로드됨: {'YES' if os.environ.get('HOLYSHEEP_API_KEY') else 'NO'}")
print(f"Base URL: https://api.holysheep.ai/v1")
.env 파일 사용 시 (python-dotenv)
pip install python-dotenv
from dotenv import load_dotenv
load_dotenv()
api_key = os.environ.get("HOLYSHEEP_API_KEY")
if not api_key:
raise ValueError("HOLYSHEEP_API_KEY 환경 변수가 설정되지 않았습니다.")
오류 2: Rate Limit 초과 (429 Too Many Requests)
짧은 시간 내에 너무 많은 요청을 보내면Rate Limit이 적용됩니다. HolySheep AI의Rate Limit 정책에 맞춰 요청 빈도를 조절하고, 지수적 백오프(Exponential Backoff)를 구현해야 합니다.
import time
import httpx
from tenacity import retry, stop_after_attempt, wait_exponential
class HolySheepClient:
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://api.holysheep.ai/v1"
self.request_count = 0
self.last_reset = time.time()
def _check_rate_limit(self):
"""Rate Limit 모니터링 (분당 요청 수 제한)"""
current_time = time.time()
if current_time - self.last_reset >= 60:
self.request_count = 0
self.last_reset = current_time
MAX_REQUESTS_PER_MINUTE = 60
if self.request_count >= MAX_REQUESTS_PER_MINUTE:
wait_time = 60 - (current_time - self.last_reset)
print(f"Rate Limit 임박. {wait_time:.1f}초 대기...")
time.sleep(wait_time)
self.request_count = 0
self.last_reset = time.time()
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=10)
)
def chat_with_retry(self, messages: list, model: str = "deepseek-v3.2") -> dict:
"""재시도 로직이 포함된 채팅 요청"""
self._check_rate_limit()
try:
with httpx.Client(
base_url=self.base_url,
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
},
timeout=30.0
) as client:
self.request_count += 1
response = client.post(
"/chat/completions",
json={
"model": model,
"messages": messages,
"max_tokens": 2048
}
)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 5))
print(f"Rate Limit 도달. {retry_after}초 후 재시도...")
time.sleep(retry_after)
raise httpx.HTTPStatusError(
"Rate Limit Exceeded",
request=response.request,
response=response
)
response.raise_for_status()
return response.json()
except httpx.HTTPStatusError as e:
print(f"HTTP 오류: {e.response.status_code} - {e.response.text}")
raise
사용 예시
client = HolySheepClient(api_key="YOUR_HOLYSHEEP_API_KEY")
result = client.chat_with_retry(
messages=[{"role": "user", "content": "Hello!"}],
model="deepseek-v3.2"
)
오류 3: 지원하지 않는 모델指定的 (400 Bad Request)
Dify 커스텀 도구에서 잘못된 모델 이름을 지정하면 400 오류가 반환됩니다. HolySheep AI가 지원하는 모델 목록을 검증하는 로직을 추가해야 합니다.
# HolySheep AI 지원 모델 목록
SUPPORTED_MODELS = {
"gpt-4.1",
"gpt-4.1-mini",
"gpt-4o",
"gpt-4o-mini",
"claude-sonnet-4.5",
"claude-opus-4",
"gemini-2.5-flash",
"gemini-2.5-pro",
"deepseek-v3.2",
"deepseek-coder"
}
def validate_model(model: str) -> str:
"""모델 이름 유효성 검증"""
if model not in SUPPORTED_MODELS:
available = ", ".join(sorted(SUPPORTED_MODELS))
raise ValueError(
f"지원하지 않는 모델: '{model}'\n"
f"사용 가능한 모델: {available}"
)
return model
def get_model_info(model: str) -> dict:
"""모델 정보 조회"""
validate_model(model)
return {
"model": model,
"supported": True,
"context_window": {
"gpt-4.1": 128000,
"claude-sonnet-4.5": 200000,
"gemini-2.5-flash": 1000000,
"deepseek-v3.2": 64000
}.get(model, 32000),
"price_per_mtok": {
"gpt-4.1": 8.00,
"claude-sonnet-4.5": 15.00,
"gemini-2.5-flash": 2.50,
"deepseek-v3.2": 0.42
}.get(model, 0)
}
검증 실행
try:
info = get_model_info("gpt-4.1")
print(f"모델: {info['model']}, "
f"컨텍스트: {info['context_window']:,} 토큰, "
f"가격: ${info['price_per_mtok']}/MTok")
except ValueError as e:
print(f"모델 검증 실패: {e}")
오류 4: 컨텍스트 윈도우 초과
긴 대화 히스토리를 보낼 때 컨텍스트 윈도우를 초과하는 경우가 있습니다. 메시지를 자동 요약하거나 오래된 메시지를 trimming하는 전처리 로직이 필요합니다.
import tiktoken
class MessageTrimmer:
"""긴 대화 메시지를 컨텍스트 윈도우에 맞게 조정"""
def __init__(self, model: str = "deepseek-v3.2"):
self.model = model
self.context_limits = {
"gpt-4.1": 128000,
"claude-sonnet-4.5": 200000,
"gemini-2.5-flash": 1000000,
"deepseek-v3.2": 64000
}
self.context_limit = self.context_limits.get(model, 32000)
# 안전 마진 (응답 생성을 위한 공간)
self.safety_margin = 2000
def count_tokens(self, text: str) -> int:
"""토큰 수估算 (cl100k_base 인코더 사용)"""
try:
encoding = tiktoken.get_encoding("cl100k_base")
return len(encoding.encode(text))
except Exception:
# tiktoken 사용 불가 시 대략적估算 (한글 기준 1토큰 ≈ 2글자)
return len(text) // 2
def trim_messages(
self,
messages: list,
max_tokens: int = None
) -> list:
"""메시지 목록을 컨텍스트 윈도우에 맞게 trimming"""
effective_limit = self.context_limit - self.safety_margin
if max_tokens and max_tokens < effective_limit:
effective_limit = max_tokens
total_tokens = sum(
self.count_tokens(m.get("content", ""))
for m in messages
)
if total_tokens <= effective_limit:
return messages
# 오래된 메시지부터 제거 (system 메시지는 보존)
trimmed = [m for m in messages if m.get("role") == "system"]
remaining_messages = [
m for m in messages if m.get("role") != "system"
]
for msg in reversed(remaining_messages):
msg_tokens = self.count_tokens(msg.get("content", ""))
if total_tokens + self.count_tokens(
trimmed[-1].get("content", "")
if trimmed else ""
) <= effective_limit:
trimmed.append(msg)
else:
break
# 순서 보존을 위해 재정렬
system_msgs = [m for m in trimmed if m.get("role") == "system"]
other_msgs = [m for m in trimmed if m.get("role") != "system"]
trimmed = system_msgs + list(reversed(other_msgs))
final_tokens = sum(
self.count_tokens(m.get("content", ""))
for m in trimmed
)
print(f"[Trimmer] {total_tokens} → {final_tokens} 토큰 "
f"(제한: {effective_limit})")
return trimmed
사용 예시
trimmer = MessageTrimmer(model="deepseek-v3.2")
long_messages = [
{"role": "system", "content": "당신은 전문 번역가입니다."},
{"role": "user", "content": "다음 문장을 영어로 번역해주세요." * 100},
{"role": "assistant", "content": "I'll translate it for you."},
{"role": "user", "content": "감사합니다. 한 번 더 확인해주세요." * 200},
]
trimmed = trimmer.trim_messages(long_messages)
print(f"최종 메시지 수: {len(trimmed)}")