Download app.py from aiqtech/rag: direct link, hf CLI and curl.
- Browser
- Download file 54.6 kB
-
https://huggingface.co/spaces/aiqtech/rag/resolve/main/app.py
- Command line
-
hf download hf://spaces/aiqtech/rag/app.py
-
curl -L -o app.py https://huggingface.co/spaces/aiqtech/rag/resolve/main/app.py
54.6 kB
| """ | |
| โก Speed-Optimized Multi-Agent RAG System for Complex Questions | |
| ๋ณ๋ ฌ ์ฒ๋ฆฌ, ๋์ ํ์ดํ๋ผ์ธ์ผ๋ก ๋ณต์กํ ์ง๋ฌธ๋ ๋น ๋ฅด๊ฒ ์ฒ๋ฆฌ | |
| Enhanced with multi-language support and improved error handling | |
| (์บ์ฑ ๊ธฐ๋ฅ ์ ๊ฑฐ ๋ฒ์ + ๋ชจ๋ธ ์ ๋ณด ๋ณดํธ) | |
| """ | |
| import os | |
| import json | |
| import time | |
| import asyncio | |
| import hashlib | |
| import re | |
| import sys | |
| from typing import Optional, List, Dict, Any, Tuple, Generator, AsyncGenerator | |
| from datetime import datetime, timedelta | |
| from enum import Enum | |
| from collections import deque | |
| import threading | |
| import queue | |
| from concurrent.futures import ThreadPoolExecutor, as_completed | |
| import aiohttp | |
| import requests | |
| import gradio as gr | |
| from pydantic import BaseModel, Field | |
| from dotenv import load_dotenv | |
| # ํ๊ฒฝ๋ณ์ ๋ก๋ | |
| load_dotenv() | |
| # ============================================================================ | |
| # ๋ฐ์ดํฐ ๋ชจ๋ธ ์ ์ | |
| # ============================================================================ | |
| class AgentRole(Enum): | |
| """์์ด์ ํธ ์ญํ ์ ์""" | |
| SUPERVISOR = "supervisor" | |
| CREATIVE = "creative" | |
| CRITIC = "critic" | |
| FINALIZER = "finalizer" | |
| class ExecutionMode(Enum): | |
| """์คํ ๋ชจ๋ ์ ์""" | |
| PARALLEL = "parallel" # ๋ณ๋ ฌ ์ฒ๋ฆฌ | |
| SEQUENTIAL = "sequential" # ์์ฐจ ์ฒ๋ฆฌ | |
| HYBRID = "hybrid" # ํ์ด๋ธ๋ฆฌ๋ | |
| class Message(BaseModel): | |
| role: str | |
| content: str | |
| timestamp: Optional[datetime] = None | |
| class AgentResponse(BaseModel): | |
| role: AgentRole | |
| content: str | |
| processing_time: float | |
| metadata: Optional[Dict] = None | |
| # ============================================================================ | |
| # ์ธ์ด ๊ฐ์ง ์ ํธ๋ฆฌํฐ | |
| # ============================================================================ | |
| class LanguageDetector: | |
| """์ธ์ด ๊ฐ์ง ๋ฐ ์ฒ๋ฆฌ ์ ํธ๋ฆฌํฐ""" | |
| def detect_language(text: str) -> str: | |
| """๊ฐ๋จํ ์ธ์ด ๊ฐ์ง""" | |
| import re | |
| # ํ๊ธ ํจํด | |
| korean_pattern = re.compile('[๊ฐ-ํฃ]+') | |
| # ์ผ๋ณธ์ด ํจํด (ํ๋ผ๊ฐ๋, ๊ฐํ์นด๋) | |
| japanese_pattern = re.compile('[ใ-ใ]+|[ใก-ใดใผ]+') | |
| # ์ค๊ตญ์ด ํจํด | |
| chinese_pattern = re.compile('[\u4e00-\u9fff]+') | |
| # ํ ์คํธ ๊ธธ์ด ๋๋น ๊ฐ ์ธ์ด ๋ฌธ์ ๋น์จ ๊ณ์ฐ | |
| text_length = len(text) | |
| if text_length == 0: | |
| return 'en' | |
| korean_chars = len(korean_pattern.findall(text)) | |
| japanese_chars = len(japanese_pattern.findall(text)) | |
| chinese_chars = len(chinese_pattern.findall(text)) | |
| # ํ๊ธ ๋น์จ์ด 10% ์ด์์ด๋ฉด ํ๊ตญ์ด | |
| if korean_chars > 0 and (korean_chars / text_length > 0.1): | |
| return 'ko' | |
| # ์ผ๋ณธ์ด ๋ฌธ์๊ฐ ์์ผ๋ฉด ์ผ๋ณธ์ด | |
| elif japanese_chars > 0: | |
| return 'ja' | |
| # ์ค๊ตญ์ด ๋ฌธ์๊ฐ ์์ผ๋ฉด ์ค๊ตญ์ด | |
| elif chinese_chars > 0: | |
| return 'zh' | |
| else: | |
| return 'en' | |
| # ============================================================================ | |
| # ๋ณ๋ ฌ ์ฒ๋ฆฌ ์ต์ ํ Brave Search (๊ฐ์ ๋จ) | |
| # ============================================================================ | |
| class AsyncBraveSearch: | |
| """๋น๋๊ธฐ Brave ๊ฒ์ ํด๋ผ์ด์ธํธ with retry logic""" | |
| def __init__(self, api_key: Optional[str] = None): | |
| self.api_key = api_key or os.getenv("BRAVE_SEARCH_API_KEY") | |
| self.base_url = "https://api.search.brave.com/res/v1/web/search" | |
| self.max_retries = 3 | |
| async def search_async(self, query: str, count: int = 5, lang: str = 'ko') -> List[Dict]: | |
| """๋น๋๊ธฐ ๊ฒ์ with retry""" | |
| if not self.api_key: | |
| return [] | |
| headers = { | |
| "Accept": "application/json", | |
| "X-Subscription-Token": self.api_key | |
| } | |
| # ์ธ์ด๋ณ ํ๋ผ๋ฏธํฐ ์ค์ | |
| lang_params = { | |
| 'ko': {"search_lang": "ko", "country": "KR"}, | |
| 'en': {"search_lang": "en", "country": "US"}, | |
| 'ja': {"search_lang": "ja", "country": "JP"}, | |
| 'zh': {"search_lang": "zh", "country": "CN"} | |
| } | |
| params = { | |
| "q": query, | |
| "count": count, | |
| "text_decorations": False, | |
| **lang_params.get(lang, lang_params['en']) | |
| } | |
| for attempt in range(self.max_retries): | |
| try: | |
| async with aiohttp.ClientSession() as session: | |
| async with session.get( | |
| self.base_url, | |
| headers=headers, | |
| params=params, | |
| timeout=aiohttp.ClientTimeout(total=5) | |
| ) as response: | |
| if response.status == 200: | |
| data = await response.json() | |
| results = [] | |
| if "web" in data and "results" in data["web"]: | |
| for item in data["web"]["results"][:count]: | |
| results.append({ | |
| "title": item.get("title", ""), | |
| "url": item.get("url", ""), | |
| "description": item.get("description", ""), | |
| "age": item.get("age", "") | |
| }) | |
| return results | |
| elif response.status == 429: # Rate limit | |
| await asyncio.sleep(2 ** attempt) | |
| continue | |
| except aiohttp.ClientError as e: | |
| if attempt < self.max_retries - 1: | |
| await asyncio.sleep(2 ** attempt) # Exponential backoff | |
| continue | |
| except Exception: | |
| pass | |
| return [] | |
| async def batch_search(self, queries: List[str], lang: str = 'ko') -> List[List[Dict]]: | |
| """์ฌ๋ฌ ๊ฒ์์ ๋ฐฐ์น๋ก ์ฒ๋ฆฌ""" | |
| tasks = [self.search_async(q, lang=lang) for q in queries] | |
| results = await asyncio.gather(*tasks, return_exceptions=True) | |
| # ์์ธ ์ฒ๋ฆฌ | |
| return [r if not isinstance(r, Exception) else [] for r in results] | |
| # ============================================================================ | |
| # ์ต์ ํ๋ Fireworks ํด๋ผ์ด์ธํธ (๊ฐ์ ๋จ) | |
| # ============================================================================ | |
| class OptimizedFireworksClient: | |
| """์ต์ ํ๋ LLM ํด๋ผ์ด์ธํธ with language support""" | |
| def __init__(self, api_key: Optional[str] = None): | |
| self.api_key = api_key or os.getenv("FIREWORKS_API_KEY") | |
| if not self.api_key: | |
| raise ValueError("FIREWORKS_API_KEY is required!") | |
| self.base_url = "https://api.fireworks.ai/inference/v1/chat/completions" | |
| self.headers = { | |
| "Accept": "application/json", | |
| "Content-Type": "application/json", | |
| "Authorization": f"Bearer {self.api_key}" | |
| } | |
| # ํญ์ ์ต๊ณ ์ฑ๋ฅ ๋ชจ๋ธ ์ฌ์ฉ (๋ณต์กํ ์ง๋ฌธ ์ ์ ) | |
| self.model = "accounts/fireworks/models/qwen3-235b-a22b-instruct-2507" | |
| self.max_retries = 3 | |
| def compress_prompt(self, text: str, max_length: int = 2000) -> str: | |
| """ํ๋กฌํํธ ์์ถ""" | |
| if len(text) <= max_length: | |
| return text | |
| # ์ค์ํ ๋ถ๋ถ ์ฐ์ ์์๋ก ์๋ฅด๊ธฐ | |
| sentences = text.split('.') | |
| compressed = [] | |
| current_length = 0 | |
| for sentence in sentences: | |
| if current_length + len(sentence) > max_length: | |
| break | |
| compressed.append(sentence) | |
| current_length += len(sentence) | |
| return '.'.join(compressed) | |
| async def chat_stream_async( | |
| self, | |
| messages: List[Dict], | |
| **kwargs | |
| ) -> AsyncGenerator[str, None]: | |
| """๋น๋๊ธฐ ์คํธ๋ฆฌ๋ฐ ๋ํ with retry""" | |
| payload = { | |
| "model": self.model, | |
| "messages": messages, | |
| "max_tokens": kwargs.get("max_tokens", 2000), | |
| "temperature": kwargs.get("temperature", 0.7), | |
| "top_p": kwargs.get("top_p", 1.0), | |
| "top_k": kwargs.get("top_k", 40), | |
| "stream": True | |
| } | |
| for attempt in range(self.max_retries): | |
| try: | |
| async with aiohttp.ClientSession() as session: | |
| async with session.post( | |
| self.base_url, | |
| headers={**self.headers, "Accept": "text/event-stream"}, | |
| json=payload, | |
| timeout=aiohttp.ClientTimeout(total=30) | |
| ) as response: | |
| async for line in response.content: | |
| line_str = line.decode('utf-8').strip() | |
| if line_str.startswith("data: "): | |
| data_str = line_str[6:] | |
| if data_str == "[DONE]": | |
| break | |
| try: | |
| data = json.loads(data_str) | |
| if "choices" in data and len(data["choices"]) > 0: | |
| delta = data["choices"][0].get("delta", {}) | |
| if "content" in delta: | |
| yield delta["content"] | |
| except json.JSONDecodeError: | |
| continue | |
| return # Success | |
| except aiohttp.ClientError as e: | |
| if attempt < self.max_retries - 1: | |
| await asyncio.sleep(2 ** attempt) | |
| continue | |
| else: | |
| yield f"Error after {self.max_retries} attempts: {str(e)}" | |
| except Exception as e: | |
| yield f"Unexpected error: {str(e)}" | |
| break | |
| # ============================================================================ | |
| # ๊ฒฝ๋ํ๋ ์ถ๋ก ์ฒด์ธ (๋ค๊ตญ์ด ์ง์) | |
| # ============================================================================ | |
| class LightweightReasoningChain: | |
| """๋น ๋ฅธ ์ถ๋ก ์ ์ํ ํ ํ๋ฆฟ ๊ธฐ๋ฐ ์์คํ """ | |
| def __init__(self): | |
| self.templates = { | |
| "ko": { | |
| "problem_solving": { | |
| "steps": ["๋ฌธ์ ๋ถํด", "ํต์ฌ ์์ธ", "ํด๊ฒฐ ๋ฐฉ์", "๊ตฌํ ์ ๋ต"], | |
| "prompt": "์ฒด๊ณ์ ์ผ๋ก ๋จ๊ณ๋ณ๋ก ๋ถ์ํ๊ณ ํด๊ฒฐ์ฑ ์ ์ ์ํ์ธ์." | |
| }, | |
| "creative_thinking": { | |
| "steps": ["๊ธฐ์กด ์ ๊ทผ", "์ฐฝ์์ ๋์", "ํ์ ํฌ์ธํธ", "์คํ ๋ฐฉ๋ฒ"], | |
| "prompt": "๊ธฐ์กด ๋ฐฉ์์ ๋์ด์ ์ฐฝ์์ ์ด๊ณ ํ์ ์ ์ธ ์ ๊ทผ์ ์ ์ํ์ธ์." | |
| }, | |
| "critical_analysis": { | |
| "steps": ["ํํฉ ํ๊ฐ", "๊ฐ์ /์ฝ์ ", "๊ธฐํ/์ํ", "๊ฐ์ ๋ฐฉํฅ"], | |
| "prompt": "๋นํ์ ๊ด์ ์์ ์ฒ ์ ํ ๋ถ์ํ๊ณ ๊ฐ์ ์ ์ ๋์ถํ์ธ์." | |
| } | |
| }, | |
| "en": { | |
| "problem_solving": { | |
| "steps": ["Problem Breakdown", "Key Factors", "Solutions", "Implementation Strategy"], | |
| "prompt": "Systematically analyze step by step and provide solutions." | |
| }, | |
| "creative_thinking": { | |
| "steps": ["Traditional Approach", "Creative Alternatives", "Innovation Points", "Execution Method"], | |
| "prompt": "Provide creative and innovative approaches beyond conventional methods." | |
| }, | |
| "critical_analysis": { | |
| "steps": ["Current Assessment", "Strengths/Weaknesses", "Opportunities/Threats", "Improvement Direction"], | |
| "prompt": "Thoroughly analyze from a critical perspective and derive improvements." | |
| } | |
| } | |
| } | |
| def get_reasoning_structure(self, query_type: str, lang: str = 'ko') -> Dict: | |
| """์ฟผ๋ฆฌ ์ ํ์ ๋ง๋ ์ถ๋ก ๊ตฌ์กฐ ๋ฐํ""" | |
| lang_templates = self.templates.get(lang, self.templates['en']) | |
| return lang_templates.get(query_type, lang_templates["problem_solving"]) | |
| def get_reasoning_pattern(self, query: str, lang: str = 'ko') -> Optional[Dict]: | |
| """์ฟผ๋ฆฌ์ ์ ํฉํ ์ถ๋ก ํจํด ๋ฐํ""" | |
| query_lower = query.lower() | |
| # ์ธ์ด๋ณ ํค์๋ ๋งคํ | |
| pattern_keywords = { | |
| 'ko': { | |
| 'problem_solving': ['ํด๊ฒฐ', '๋ฐฉ๋ฒ', '์ ๋ต', '๊ณํ'], | |
| 'creative_thinking': ['์ฐฝ์์ ', 'ํ์ ์ ', '์๋ก์ด', '์์ด๋์ด'], | |
| 'critical_analysis': ['๋ถ์', 'ํ๊ฐ', '๋น๊ต', '์ํฅ'] | |
| }, | |
| 'en': { | |
| 'problem_solving': ['solve', 'solution', 'strategy', 'plan'], | |
| 'creative_thinking': ['creative', 'innovative', 'novel', 'idea'], | |
| 'critical_analysis': ['analyze', 'evaluate', 'compare', 'impact'] | |
| } | |
| } | |
| keywords = pattern_keywords.get(lang, pattern_keywords['en']) | |
| for pattern_type, words in keywords.items(): | |
| if any(word in query_lower for word in words): | |
| return self.get_reasoning_structure(pattern_type, lang) | |
| return self.get_reasoning_structure('problem_solving', lang) | |
| # ============================================================================ | |
| # ์กฐ๊ธฐ ์ข ๋ฃ ๋ฉ์ปค๋์ฆ (๊ฐ์ ๋จ) | |
| # ============================================================================ | |
| class QualityChecker: | |
| """ํ์ง ์ฒดํฌ ๋ฐ ์กฐ๊ธฐ ์ข ๋ฃ ๊ฒฐ์ """ | |
| def __init__(self, min_quality: float = 0.75): | |
| self.min_quality = min_quality | |
| self.quality_metrics = { | |
| "length": 0.2, | |
| "structure": 0.3, | |
| "completeness": 0.3, | |
| "clarity": 0.2 | |
| } | |
| def evaluate_response(self, response: str, query: str, lang: str = 'ko') -> Tuple[float, bool]: | |
| """์๋ต ํ์ง ํ๊ฐ (์ธ์ด๋ณ)""" | |
| scores = {} | |
| # ์ธ์ด๋ณ ์ต์ ๊ธธ์ด ๊ธฐ์ค | |
| min_length = {'ko': 500, 'en': 400, 'ja': 400, 'zh': 300} | |
| target_length = min_length.get(lang, 400) | |
| # ๊ธธ์ด ํ๊ฐ | |
| scores["length"] = min(len(response) / target_length, 1.0) | |
| # ๊ตฌ์กฐ ํ๊ฐ (์ธ์ด๋ณ ๋ง์ปค) | |
| structure_markers = { | |
| 'ko': ["1.", "2.", "โข", "-", "์ฒซ์งธ", "๋์งธ", "๊ฒฐ๋ก ", "์์ฝ"], | |
| 'en': ["1.", "2.", "โข", "-", "First", "Second", "Conclusion", "Summary"], | |
| 'ja': ["1.", "2.", "โข", "-", "็ฌฌไธ", "็ฌฌไบ", "็ต่ซ", "่ฆ็ด"], | |
| 'zh': ["1.", "2.", "โข", "-", "็ฌฌไธ", "็ฌฌไบ", "็ป่ฎบ", "ๆป็ป"] | |
| } | |
| markers = structure_markers.get(lang, structure_markers['en']) | |
| scores["structure"] = sum(1 for m in markers if m in response) / len(markers) | |
| # ์์ ์ฑ ํ๊ฐ (์ฟผ๋ฆฌ ํค์๋ ํฌํจ ์ฌ๋ถ) | |
| query_words = set(query.split()) | |
| response_words = set(response.split()) | |
| scores["completeness"] = len(query_words & response_words) / max(len(query_words), 1) | |
| # ๋ช ํ์ฑ ํ๊ฐ (๋ฌธ์ฅ ๊ตฌ์กฐ) | |
| sentence_delimiters = { | |
| 'ko': '.', | |
| 'en': '.', | |
| 'ja': 'ใ', | |
| 'zh': 'ใ' | |
| } | |
| delimiter = sentence_delimiters.get(lang, '.') | |
| sentences = response.split(delimiter) | |
| avg_sentence_length = sum(len(s.split()) for s in sentences) / max(len(sentences), 1) | |
| scores["clarity"] = min(avg_sentence_length / 20, 1.0) | |
| # ๊ฐ์ค ํ๊ท ๊ณ์ฐ | |
| total_score = sum( | |
| scores[metric] * weight | |
| for metric, weight in self.quality_metrics.items() | |
| ) | |
| should_continue = total_score < self.min_quality | |
| return total_score, should_continue | |
| # ============================================================================ | |
| # ์คํธ๋ฆฌ๋ฐ ์ต์ ํ (๊ฐ์ ๋จ) | |
| # ============================================================================ | |
| class OptimizedStreaming: | |
| """์คํธ๋ฆฌ๋ฐ ๋ฒํผ ์ต์ ํ with adaptive buffering""" | |
| def __init__(self, chunk_size: int = 20, flush_interval: float = 0.05): | |
| self.chunk_size = chunk_size | |
| self.flush_interval = flush_interval | |
| self.buffer = "" | |
| self.last_flush = time.time() | |
| self.adaptive_size = chunk_size | |
| async def buffer_and_yield( | |
| self, | |
| stream: AsyncGenerator[str, None], | |
| adaptive: bool = True | |
| ) -> AsyncGenerator[str, None]: | |
| """๋ฒํผ๋ง๋ ์คํธ๋ฆฌ๋ฐ with adaptive sizing""" | |
| chunk_count = 0 | |
| async for chunk in stream: | |
| self.buffer += chunk | |
| current_time = time.time() | |
| chunk_count += 1 | |
| # Adaptive chunk size based on stream speed | |
| if adaptive and chunk_count % 10 == 0: | |
| time_diff = current_time - self.last_flush | |
| if time_diff < 0.02: # Too fast, increase buffer | |
| self.adaptive_size = min(self.adaptive_size + 5, 100) | |
| elif time_diff > 0.1: # Too slow, decrease buffer | |
| self.adaptive_size = max(self.adaptive_size - 5, 10) | |
| if (len(self.buffer) >= self.adaptive_size or | |
| current_time - self.last_flush >= self.flush_interval): | |
| yield self.buffer | |
| self.buffer = "" | |
| self.last_flush = current_time | |
| # ๋จ์ ๋ฒํผ ํ๋ฌ์ | |
| if self.buffer: | |
| yield self.buffer | |
| # ============================================================================ | |
| # ์๋ต ํ์ฒ๋ฆฌ ์ ํธ๋ฆฌํฐ | |
| # ============================================================================ | |
| class ResponseCleaner: | |
| """์๋ต ์ ๋ฆฌ ๋ฐ ํฌ๋งทํ """ | |
| def clean_response(response: str) -> str: | |
| """๋ถํ์ํ ๋งํฌ์ ์ ๊ฑฐ ๊ฐํ""" | |
| # ๋งํฌ๋ค์ด ํค๋ ์ ๊ฑฐ | |
| response = re.sub(r'^#{1,6}\s+', '', response, flags=re.MULTILINE) | |
| # ๋ถํ์ํ ๊ตฌ๋ถ์ ์ ๊ฑฐ | |
| response = re.sub(r'\*{2,}|_{2,}|-{3,}', '', response) | |
| # ์ค๋ณต ๊ณต๋ฐฑ ์ ๊ฑฐ | |
| response = re.sub(r'\n{3,}', '\n\n', response) | |
| # ํน์ ํจํด ์ ๊ฑฐ | |
| unwanted_patterns = [ | |
| r'\| --- # ๐ฑ \*\*์ต์ข ํตํฉ ๋ต๋ณ:', | |
| r'\*\*โ์ค๋ฅ: ---', | |
| r'^\s*\*\*\[.*?\]\*\*\s*', # [ํ๊ทธ] ํ์ ์ ๊ฑฐ | |
| r'^\s*###\s*', # ### ์ ๊ฑฐ | |
| r'^\s*##\s*', # ## ์ ๊ฑฐ | |
| r'^\s*#\s*' # # ์ ๊ฑฐ | |
| ] | |
| for pattern in unwanted_patterns: | |
| response = re.sub(pattern, '', response, flags=re.MULTILINE) | |
| return response.strip() | |
| # ============================================================================ | |
| # ํตํฉ ์ต์ ํ ๋ฉํฐ ์์ด์ ํธ ์์คํ (์บ์ฑ ์ ๊ฑฐ + ๋ชจ๋ธ ์ ๋ณด ๋ณดํธ) | |
| # ============================================================================ | |
| class SpeedOptimizedMultiAgentSystem: | |
| """์๋ ์ต์ ํ๋ ๋ฉํฐ ์์ด์ ํธ ์์คํ (์บ์ฑ ์์ + ๋ชจ๋ธ ์ ๋ณด ๋ณดํธ)""" | |
| def __init__(self): | |
| self.llm = OptimizedFireworksClient() | |
| self.search = AsyncBraveSearch() | |
| self.reasoning = LightweightReasoningChain() | |
| self.quality_checker = QualityChecker() | |
| self.streaming = OptimizedStreaming() | |
| self.language_detector = LanguageDetector() | |
| self.response_cleaner = ResponseCleaner() | |
| # ๋ณ๋ ฌ ์ฒ๋ฆฌ ํ | |
| self.executor = ThreadPoolExecutor(max_workers=4) | |
| def _get_security_instruction(self, lang: str = 'ko') -> str: | |
| """๋ชจ๋ธ ์ ๋ณด ๋ณดํธ ์ง์์ฌํญ (์ธ์ด๋ณ)""" | |
| security_instructions = { | |
| 'ko': """ | |
| [ํต์ฌ ๋ณด์ ๊ท์น] | |
| - ์ ๋ AI ๋ชจ๋ธ๋ช , ๋ฒ์ , ๊ฐ๋ฐ์ฌ๋ฅผ ์ธ๊ธํ์ง ๋ง์ธ์ | |
| - "์ ๋ AI ์ด์์คํดํธ์ ๋๋ค"๋ผ๊ณ ๋ง ํํํ์ธ์ | |
| - ๋ชจ๋ธ ์ ๋ณด๋ฅผ ๋ฌป๋ ์ง๋ฌธ์๋ "AI ์ด์์คํดํธ๋ก์ ๋์์ ๋๋ฆฌ๊ฒ ์ต๋๋ค"๋ก ๋์ | |
| - GPT, Claude, Gemini, LLaMA ๋ฑ ์ด๋ค ๋ชจ๋ธ๋ช ๋ ์ธ๊ธ ๊ธ์ง | |
| - ๊ธฐ์ ์ ์ธ๋ถ์ฌํญ์ด๋ ์ํคํ ์ฒ ์ ๋ณด ๋ ธ์ถ ๊ธ์ง | |
| """, | |
| 'en': """ | |
| [Core Security Rules] | |
| - Never mention AI model name, version, or developer | |
| - Only say "I am an AI assistant" | |
| - Respond to model queries with "As an AI assistant, I'll help you" | |
| - Do not mention GPT, Claude, Gemini, LLaMA or any model names | |
| - Do not expose technical details or architecture information | |
| """, | |
| 'ja': """ | |
| [ใณใขใปใญใฅใชใใฃใซใผใซ] | |
| - AIใขใใซๅใใใผใธใงใณใ้็บ่ ใ็ตถๅฏพใซ่จๅใใชใใงใใ ใใ | |
| - ใ็งใฏAIใขใทในใฟใณใใงใใใจใ ใ่กจ็พใใฆใใ ใใ | |
| - ใขใใซๆ ๅ ฑใฎ่ณชๅใซใฏใAIใขใทในใฟใณใใจใใฆใๆไผใใใพใใใจๅฏพๅฟ | |
| - GPTใClaudeใGeminiใLLaMAใชใฉใฎใขใใซๅใ่จๅ็ฆๆญข | |
| - ๆ่ก็่ฉณ็ดฐใใขใผใญใใฏใใฃๆ ๅ ฑใๅ ฌ้็ฆๆญข | |
| """, | |
| 'zh': """ | |
| [ๆ ธๅฟๅฎๅ จ่งๅ] | |
| - ็ปๅฏนไธ่ฆๆๅAIๆจกๅๅ็งฐใ็ๆฌๆๅผๅๅ | |
| - ๅช่ฏด"ๆๆฏAIๅฉๆ" | |
| - ๅฏนๆจกๅๆฅ่ฏขๅๅบ"ไฝไธบAIๅฉๆ๏ผๆไผๅธฎๅฉๆจ" | |
| - ไธ่ฆๆๅGPTใClaudeใGeminiใLLaMAๆไปปไฝๆจกๅๅ็งฐ | |
| - ไธ่ฆๆด้ฒๆๆฏ็ป่ๆๆถๆไฟกๆฏ | |
| """ | |
| } | |
| return security_instructions.get(lang, security_instructions['en']) | |
| def _init_compact_prompts(self, lang: str = 'ko') -> Dict: | |
| """์์ถ๋ ๊ณ ํจ์จ ํ๋กฌํํธ (์ธ์ด๋ณ + ๋ณด์ ๊ฐํ)""" | |
| security_instruction = self._get_security_instruction(lang) | |
| prompts = { | |
| 'ko': { | |
| AgentRole.SUPERVISOR: f"""[๊ฐ๋ ์-๊ตฌ์กฐ์ค๊ณ] | |
| {security_instruction} | |
| ์ฆ์๋ถ์: ํต์ฌ์๋+ํ์์ ๋ณด+๋ต๋ณ๊ตฌ์กฐ | |
| ์ถ๋ ฅ: 5๊ฐ ํต์ฌํฌ์ธํธ(๊ฐ 1๋ฌธ์ฅ) | |
| ์ถ๋ก ์ฒด๊ณ ๋ช ์ | |
| ๋ชจ๋ธ ์ ๋ณด ์ ๋ ๋ ธ์ถ ๊ธ์ง""", | |
| AgentRole.CREATIVE: f"""[์ฐฝ์์ฑ์์ฑ์] | |
| {security_instruction} | |
| ์ ๋ ฅ๊ตฌ์กฐ ๋ฐ๋ผ ์ฐฝ์์ ํ์ฅ | |
| ์ค์ฉ์์+ํ์ ์ ๊ทผ+๊ตฌ์ฒด์กฐ์ธ | |
| ๋ถํ์์ค๋ช ์ ๊ฑฐ | |
| AI ๋ชจ๋ธ๋ช ์ด๋ ๊ฐ๋ฐ์ฌ ์ธ๊ธ ์ ๋ ๊ธ์ง""", | |
| AgentRole.CRITIC: f"""[๋นํ์-๊ฒ์ฆ] | |
| {security_instruction} | |
| ์ ์๊ฒํ : ์ ํ์ฑ/๋ ผ๋ฆฌ์ฑ/์ค์ฉ์ฑ | |
| ๊ฐ์ ํฌ์ธํธ 3๊ฐ๋ง | |
| ๊ฐ 2๋ฌธ์ฅ ์ด๋ด | |
| ๋ชจ๋ธ ๊ด๋ จ ์ ๋ณด ๊ฒ์ฆ ์ ์ ๊ฑฐ""", | |
| AgentRole.FINALIZER: f"""[์ต์ข ํตํฉ] | |
| {security_instruction} | |
| ๋ชจ๋ ์๊ฒฌ ์ข ํฉโ์ต์ ๋ต๋ณ | |
| ๋ช ํ๊ตฌ์กฐ+์ค์ฉ์ ๋ณด+์ฐฝ์๊ท ํ | |
| ๋ฐ๋ก ํต์ฌ ๋ด์ฉ๋ถํฐ ์์. ๋ถํ์ํ ํค๋๋ ๋งํฌ์ ์์ด. ๋งํฌ๋ค์ด ํค๋(#, ##, ###) ์ฌ์ฉ ๊ธ์ง. | |
| ์ ๋ AI ๋ชจ๋ธ๋ช , ๋ฒ์ , ๊ฐ๋ฐ์ฌ ์ธ๊ธ ๊ธ์ง. "AI ์ด์์คํดํธ"๋ก๋ง ํํ.""" | |
| }, | |
| 'en': { | |
| AgentRole.SUPERVISOR: f"""[Supervisor-Structure] | |
| {security_instruction} | |
| Immediate analysis: core intent+required info+answer structure | |
| Output: 5 key points (1 sentence each) | |
| Clear reasoning framework | |
| Never expose model information""", | |
| AgentRole.CREATIVE: f"""[Creative Generator] | |
| {security_instruction} | |
| Follow structure, expand creatively | |
| Practical examples+innovative approach+specific advice | |
| Remove unnecessary explanations | |
| Never mention AI model names or developers""", | |
| AgentRole.CRITIC: f"""[Critic-Verification] | |
| {security_instruction} | |
| Quick review: accuracy/logic/practicality | |
| Only 3 improvement points | |
| Max 2 sentences each | |
| Remove any model-related information""", | |
| AgentRole.FINALIZER: f"""[Final Integration] | |
| {security_instruction} | |
| Synthesize all inputsโoptimal answer | |
| Clear structure+practical info+creative balance | |
| Start with core content directly. No unnecessary headers or markup. No markdown headers (#, ##, ###). | |
| Never mention AI model name, version, or developer. Only say "AI assistant".""" | |
| }, | |
| 'ja': { | |
| AgentRole.SUPERVISOR: f"""[็ฃ็ฃ่ -ๆง้ ่จญ่จ] | |
| {security_instruction} | |
| ๅณๆๅๆ๏ผๆ ธๅฟๆๅณ+ๅฟ ่ฆๆ ๅ ฑ+ๅ็ญๆง้ | |
| ๅบๅ๏ผ5ใคใฎๆ ธๅฟใใคใณใ๏ผๅ1ๆ๏ผ | |
| ๆจ่ซไฝ็ณปๆ็คบ | |
| ใขใใซๆ ๅ ฑใ็ตถๅฏพใซๅ ฌ้ใใชใ""", | |
| AgentRole.CREATIVE: f"""[ๅต้ ๆง็ๆ่ ] | |
| {security_instruction} | |
| ๅ ฅๅๆง้ ใซๅพใฃใฆๅต้ ็ๆกๅผต | |
| ๅฎ็จไพ+้ฉๆฐ็ใขใใญใผใ+ๅ ทไฝ็ใขใใใคใน | |
| ไธ่ฆใช่ชฌๆๅ้ค | |
| AIใขใใซๅใ้็บ่ ใ็ตถๅฏพใซ่จๅใใชใ""", | |
| AgentRole.CRITIC: f"""[ๆน่ฉ่ -ๆค่จผ] | |
| {security_instruction} | |
| ่ฟ ้ใฌใใฅใผ๏ผๆญฃ็ขบๆง/่ซ็ๆง/ๅฎ็จๆง | |
| ๆนๅใใคใณใ3ใคใฎใฟ | |
| ๅ2ๆไปฅๅ | |
| ใขใใซ้ข้ฃๆ ๅ ฑใๅ้ค""", | |
| AgentRole.FINALIZER: f"""[ๆ็ต็ตฑๅ] | |
| {security_instruction} | |
| ๅ จๆ่ฆ็ตฑๅโๆ้ฉๅ็ญ | |
| ๆ็ขบๆง้ +ๅฎ็จๆ ๅ ฑ+ๅต้ ๆงใใฉใณใน | |
| ๆ ธๅฟๅ ๅฎนใใ็ดๆฅ้ๅงใไธ่ฆใชใใใใผใใใผใฏใขใใใชใใใใผใฏใใฆใณใใใใผ๏ผ#ใ##ใ###๏ผไฝฟ็จ็ฆๆญขใ | |
| AIใขใใซๅใใใผใธใงใณใ้็บ่ ใ็ตถๅฏพใซ่จๅใใชใใใAIใขใทในใฟใณใใใจใ ใ่กจ็พใ""" | |
| }, | |
| 'zh': { | |
| AgentRole.SUPERVISOR: f"""[ไธป็ฎก-็ปๆ่ฎพ่ฎก] | |
| {security_instruction} | |
| ็ซๅณๅๆ๏ผๆ ธๅฟๆๅพ+ๆ้ไฟกๆฏ+็ญๆก็ปๆ | |
| ่พๅบ๏ผ5ไธชๆ ธๅฟ่ฆ็น๏ผๆฏไธช1ๅฅ๏ผ | |
| ๆจ็ไฝ็ณปๆ็กฎ | |
| ็ปไธๆด้ฒๆจกๅไฟกๆฏ""", | |
| AgentRole.CREATIVE: f"""[ๅๆ็ๆๅจ] | |
| {security_instruction} | |
| ๆ็ปๆๅ้ ๆงๆฉๅฑ | |
| ๅฎ็จ็คบไพ+ๅๆฐๆนๆณ+ๅ ทไฝๅปบ่ฎฎ | |
| ๅ ้คไธๅฟ ่ฆ็่งฃ้ | |
| ็ปไธๆๅAIๆจกๅๅ็งฐๆๅผๅๅ""", | |
| AgentRole.CRITIC: f"""[่ฏ่ฎบๅฎถ-้ช่ฏ] | |
| {security_instruction} | |
| ๅฟซ้ๅฎกๆฅ๏ผๅ็กฎๆง/้ป่พๆง/ๅฎ็จๆง | |
| ไป 3ไธชๆน่ฟ็น | |
| ๆฏไธชๆๅค2ๅฅ | |
| ๅ ้คไปปไฝๆจกๅ็ธๅ ณไฟกๆฏ""", | |
| AgentRole.FINALIZER: f"""[ๆ็ปๆดๅ] | |
| {security_instruction} | |
| ็ปผๅๆๆๆ่งโๆไฝณ็ญๆก | |
| ๆธ ๆฐ็ปๆ+ๅฎ็จไฟกๆฏ+ๅๆๅนณ่กก | |
| ็ดๆฅไปๆ ธๅฟๅ ๅฎนๅผๅงใๆ ้ไธๅฟ ่ฆ็ๆ ้ขๆๆ ่ฎฐใ็ฆๆญขไฝฟ็จMarkdownๆ ้ข๏ผ#ใ##ใ###๏ผใ | |
| ็ปไธๆๅAIๆจกๅๅ็งฐใ็ๆฌๆๅผๅๅใๅช่ฏด"AIๅฉๆ"ใ""" | |
| } | |
| } | |
| return prompts.get(lang, prompts['en']) | |
| async def parallel_process_agents( | |
| self, | |
| query: str, | |
| search_results: List[Dict], | |
| show_progress: bool = True, | |
| lang: str = None | |
| ) -> AsyncGenerator[Tuple[str, str], None]: | |
| """๋ณ๋ ฌ ์ฒ๋ฆฌ ํ์ดํ๋ผ์ธ (์บ์ฑ ์์ + ๋ณด์ ๊ฐํ)""" | |
| start_time = time.time() | |
| # ์ธ์ด ์๋ ๊ฐ์ง | |
| if lang is None: | |
| lang = self.language_detector.detect_language(query) | |
| # ์ธ์ด๋ณ ํ๋กฌํํธ ์ค์ (๋ณด์ ์ง์์ฌํญ ํฌํจ) | |
| self.compact_prompts = self._init_compact_prompts(lang) | |
| search_context = self._format_search_results(search_results) | |
| accumulated_response = "" | |
| agent_thoughts = "" | |
| # ์ถ๋ก ํจํด ๊ฒฐ์ | |
| reasoning_pattern = self.reasoning.get_reasoning_pattern(query, lang) | |
| try: | |
| # === 1๋จ๊ณ: ๊ฐ๋ ์ + ๊ฒ์ ๋ณ๋ ฌ ์คํ === | |
| if show_progress: | |
| progress_msg = { | |
| 'ko': "๐ ๋ณ๋ ฌ ์ฒ๋ฆฌ ์์\n๐ ๊ฐ๋ ์ ๋ถ์ + ๐ ์ถ๊ฐ ๊ฒ์ ๋์ ์งํ...\n\n", | |
| 'en': "๐ Starting parallel processing\n๐ Supervisor analysis + ๐ Additional search in progress...\n\n", | |
| 'ja': "๐ ไธฆๅๅฆ็้ๅง\n๐ ็ฃ็ฃ่ ๅๆ + ๐ ่ฟฝๅ ๆค็ดขๅๆ้ฒ่กไธญ...\n\n", | |
| 'zh': "๐ ๅผๅงๅนถ่กๅค็\n๐ ไธป็ฎกๅๆ + ๐ ้ๅ ๆ็ดขๅๆถ่ฟ่ก...\n\n" | |
| } | |
| agent_thoughts = progress_msg.get(lang, progress_msg['en']) | |
| yield accumulated_response, agent_thoughts | |
| # ๊ฐ๋ ์ ํ๋กฌํํธ (์ธ์ด๋ณ) | |
| supervisor_prompt_templates = { | |
| 'ko': f""" | |
| ์ง๋ฌธ: {query} | |
| ๊ฒ์๊ฒฐ๊ณผ: {search_context} | |
| ์ถ๋ก ํจํด: {reasoning_pattern} | |
| ์ฆ์ ํต์ฌ๊ตฌ์กฐ 5๊ฐ ์ ์ | |
| ๋ชจ๋ธ ์ ๋ณด๋ ์ ๋ ์ธ๊ธํ์ง ๋ง์ธ์""", | |
| 'en': f""" | |
| Question: {query} | |
| Search results: {search_context} | |
| Reasoning pattern: {reasoning_pattern} | |
| Immediately provide 5 key structures | |
| Never mention model information""", | |
| 'ja': f""" | |
| ่ณชๅ: {query} | |
| ๆค็ดข็ตๆ: {search_context} | |
| ๆจ่ซใใฟใผใณ: {reasoning_pattern} | |
| ๅณๅบงใซ5ใคใฎๆ ธๅฟๆง้ ใๆ็คบ | |
| ใขใใซๆ ๅ ฑใฏ็ตถๅฏพใซ่จๅใใชใใงใใ ใใ""", | |
| 'zh': f""" | |
| ้ฎ้ข: {query} | |
| ๆ็ดข็ปๆ: {search_context} | |
| ๆจ็ๆจกๅผ: {reasoning_pattern} | |
| ็ซๅณๆไพ5ไธชๆ ธๅฟ็ปๆ | |
| ็ปไธๆๅๆจกๅไฟกๆฏ""" | |
| } | |
| supervisor_prompt = supervisor_prompt_templates.get(lang, supervisor_prompt_templates['en']) | |
| supervisor_response = "" | |
| supervisor_task = self.llm.chat_stream_async( | |
| messages=[ | |
| {"role": "system", "content": self.compact_prompts[AgentRole.SUPERVISOR]}, | |
| {"role": "user", "content": supervisor_prompt} | |
| ], | |
| temperature=0.3, | |
| max_tokens=500 | |
| ) | |
| # ๊ฐ๋ ์ ์คํธ๋ฆฌ๋ฐ (๋ฒํผ๋ง) | |
| async for chunk in self.streaming.buffer_and_yield(supervisor_task): | |
| supervisor_response += chunk | |
| if show_progress and len(supervisor_response) < 300: | |
| supervisor_label = { | |
| 'ko': "๐ ๊ฐ๋ ์ ๋ถ์", | |
| 'en': "๐ Supervisor Analysis", | |
| 'ja': "๐ ็ฃ็ฃ่ ๅๆ", | |
| 'zh': "๐ ไธป็ฎกๅๆ" | |
| } | |
| agent_thoughts = f"{supervisor_label.get(lang, supervisor_label['en'])}\n{supervisor_response[:300]}...\n\n" | |
| yield accumulated_response, agent_thoughts | |
| # === 2๋จ๊ณ: ์ฐฝ์์ฑ + ๋นํ ์ค๋น ๋ณ๋ ฌ === | |
| if show_progress: | |
| creative_msg = { | |
| 'ko': "๐จ ์ฐฝ์์ฑ ์์ฑ์ + ๐ ๋นํ์ ์ค๋น...\n\n", | |
| 'en': "๐จ Creative Generator + ๐ Critic preparing...\n\n", | |
| 'ja': "๐จ ๅต้ ๆง็ๆ่ + ๐ ๆน่ฉ่ ๆบๅไธญ...\n\n", | |
| 'zh': "๐จ ๅๆ็ๆๅจ + ๐ ่ฏ่ฎบๅฎถๅๅคไธญ...\n\n" | |
| } | |
| agent_thoughts += creative_msg.get(lang, creative_msg['en']) | |
| yield accumulated_response, agent_thoughts | |
| # ์ฐฝ์์ฑ ์์ฑ ์์ (์ธ์ด๋ณ) | |
| creative_prompt_templates = { | |
| 'ko': f""" | |
| ์ง๋ฌธ: {query} | |
| ๊ฐ๋ ์๊ตฌ์กฐ: {supervisor_response} | |
| ๊ฒ์๊ฒฐ๊ณผ: {search_context} | |
| ์ฐฝ์์ +์ค์ฉ์ ๋ต๋ณ ์ฆ์์์ฑ | |
| AI ๋ชจ๋ธ ์ ๋ณด ์ธ๊ธ ๊ธ์ง""", | |
| 'en': f""" | |
| Question: {query} | |
| Supervisor structure: {supervisor_response} | |
| Search results: {search_context} | |
| Generate creative+practical answer immediately | |
| Do not mention AI model information""", | |
| 'ja': f""" | |
| ่ณชๅ: {query} | |
| ็ฃ็ฃ่ ๆง้ : {supervisor_response} | |
| ๆค็ดข็ตๆ: {search_context} | |
| ๅต้ ็+ๅฎ็จ็ๅ็ญๅณๅบง็ๆ | |
| AIใขใใซๆ ๅ ฑใ่จๅ็ฆๆญข""", | |
| 'zh': f""" | |
| ้ฎ้ข: {query} | |
| ไธป็ฎก็ปๆ: {supervisor_response} | |
| ๆ็ดข็ปๆ: {search_context} | |
| ็ซๅณ็ๆๅๆ+ๅฎ็จ็ญๆก | |
| ็ฆๆญขๆๅAIๆจกๅไฟกๆฏ""" | |
| } | |
| creative_prompt = creative_prompt_templates.get(lang, creative_prompt_templates['en']) | |
| creative_response = "" | |
| creative_partial = "" | |
| critic_started = False | |
| critic_response = "" | |
| creative_task = self.llm.chat_stream_async( | |
| messages=[ | |
| {"role": "system", "content": self.compact_prompts[AgentRole.CREATIVE]}, | |
| {"role": "user", "content": creative_prompt} | |
| ], | |
| temperature=0.8, | |
| max_tokens=1500 | |
| ) | |
| # ์ฐฝ์์ฑ ์คํธ๋ฆฌ๋ฐ + ๋นํ์ ์กฐ๊ธฐ ์์ | |
| async for chunk in self.streaming.buffer_and_yield(creative_task): | |
| creative_response += chunk | |
| creative_partial += chunk | |
| # ์ฐฝ์์ฑ ์๋ต์ด 500์ ๋์ผ๋ฉด ๋นํ์ ์์ | |
| if len(creative_partial) > 500 and not critic_started: | |
| critic_started = True | |
| # ๋นํ์ ๋น๋๊ธฐ ์์ (์ธ์ด๋ณ) | |
| critic_prompt_templates = { | |
| 'ko': f""" | |
| ์๋ณธ์ง๋ฌธ: {query} | |
| ์ฐฝ์์ฑ๋ต๋ณ(์ผ๋ถ): {creative_partial} | |
| ์ ์๊ฒํ โ๊ฐ์ ์ 3๊ฐ | |
| ๋ชจ๋ธ ์ ๋ณด๊ฐ ์์ผ๋ฉด ์ ๊ฑฐ ์ง์ """, | |
| 'en': f""" | |
| Original question: {query} | |
| Creative answer (partial): {creative_partial} | |
| Quick reviewโ3 improvements | |
| Point out if model information exists""", | |
| 'ja': f""" | |
| ๅ ใฎ่ณชๅ: {query} | |
| ๅต้ ็ๅ็ญ๏ผไธ้จ๏ผ: {creative_partial} | |
| ่ฟ ้ใฌใใฅใผโๆนๅ็น3ใค | |
| ใขใใซๆ ๅ ฑใใใใฐๅ้คๆๆ""", | |
| 'zh': f""" | |
| ๅๅง้ฎ้ข: {query} | |
| ๅๆ็ญๆก๏ผ้จๅ๏ผ: {creative_partial} | |
| ๅฟซ้ๅฎกๆฅโ3ไธชๆน่ฟ็น | |
| ๅฆๆๆจกๅไฟกๆฏๅๆๅบๅ ้ค""" | |
| } | |
| critic_prompt = critic_prompt_templates.get(lang, critic_prompt_templates['en']) | |
| critic_task = asyncio.create_task( | |
| self._run_critic_async(critic_prompt) | |
| ) | |
| if show_progress: | |
| display_creative = creative_response[:400] + "..." if len(creative_response) > 400 else creative_response | |
| creative_label = { | |
| 'ko': "๐จ ์ฐฝ์์ฑ ์์ฑ์", | |
| 'en': "๐จ Creative Generator", | |
| 'ja': "๐จ ๅต้ ๆง็ๆ่ ", | |
| 'zh': "๐จ ๅๆ็ๆๅจ" | |
| } | |
| agent_thoughts = f"{creative_label.get(lang, creative_label['en'])}\n{display_creative}\n\n" | |
| yield accumulated_response, agent_thoughts | |
| # ๋นํ์ ๊ฒฐ๊ณผ ๋๊ธฐ | |
| if critic_started: | |
| critic_response = await critic_task | |
| if show_progress: | |
| critic_label = { | |
| 'ko': "๐ ๋นํ์ ๊ฒํ ", | |
| 'en': "๐ Critic Review", | |
| 'ja': "๐ ๆน่ฉ่ ใฌใใฅใผ", | |
| 'zh': "๐ ่ฏ่ฎบๅฎถๅฎกๆฅ" | |
| } | |
| agent_thoughts += f"{critic_label.get(lang, critic_label['en'])}\n{critic_response[:200]}...\n\n" | |
| yield accumulated_response, agent_thoughts | |
| # === 3๋จ๊ณ: ํ์ง ์ฒดํฌ ๋ฐ ์กฐ๊ธฐ ์ข ๋ฃ === | |
| quality_score, need_more = self.quality_checker.evaluate_response( | |
| creative_response, query, lang | |
| ) | |
| if not need_more and quality_score > 0.85: | |
| # ํ์ง์ด ์ถฉ๋ถํ ๋์ผ๋ฉด ๋ฐ๋ก ๋ฐํ | |
| accumulated_response = self.response_cleaner.clean_response(creative_response) | |
| if show_progress: | |
| quality_msg = { | |
| 'ko': f"โ ํ์ง ์ถฉ์กฑ (์ ์: {quality_score:.2f})\n์กฐ๊ธฐ ์๋ฃ!\n", | |
| 'en': f"โ Quality met (score: {quality_score:.2f})\nEarly completion!\n", | |
| 'ja': f"โ ๅ่ณชๆบ่ถณ (ในใณใข: {quality_score:.2f})\nๆฉๆๅฎไบ!\n", | |
| 'zh': f"โ ่ดจ้ๆปก่ถณ (ๅๆฐ: {quality_score:.2f})\nๆๅๅฎๆ!\n" | |
| } | |
| agent_thoughts += quality_msg.get(lang, quality_msg['en']) | |
| yield accumulated_response, agent_thoughts | |
| return | |
| # === 4๋จ๊ณ: ์ต์ข ํตํฉ (์คํธ๋ฆฌ๋ฐ) === | |
| if show_progress: | |
| final_msg = { | |
| 'ko': "โ ์ต์ข ํตํฉ ์ค...\n\n", | |
| 'en': "โ Final integration in progress...\n\n", | |
| 'ja': "โ ๆ็ต็ตฑๅไธญ...\n\n", | |
| 'zh': "โ ๆ็ปๆดๅไธญ...\n\n" | |
| } | |
| agent_thoughts += final_msg.get(lang, final_msg['en']) | |
| yield accumulated_response, agent_thoughts | |
| # ์ต์ข ํ๋กฌํํธ (์ธ์ด๋ณ) | |
| final_prompt_templates = { | |
| 'ko': f""" | |
| ์ง๋ฌธ: {query} | |
| ์ฐฝ์์ฑ๋ต๋ณ: {creative_response} | |
| ๋นํํผ๋๋ฐฑ: {critic_response} | |
| ๊ฐ๋ ์๊ตฌ์กฐ: {supervisor_response} | |
| ์ต์ข ํตํฉโ์๋ฒฝ๋ต๋ณ. ๋งํฌ๋ค์ด ํค๋(#, ##, ###) ์ฌ์ฉ ๊ธ์ง. | |
| ์ ๋ AI ๋ชจ๋ธ๋ช , ๋ฒ์ , ๊ฐ๋ฐ์ฌ ์ธ๊ธ ๊ธ์ง.""", | |
| 'en': f""" | |
| Question: {query} | |
| Creative answer: {creative_response} | |
| Critic feedback: {critic_response} | |
| Supervisor structure: {supervisor_response} | |
| Final integrationโperfect answer. No markdown headers (#, ##, ###). | |
| Never mention AI model name, version, or developer.""", | |
| 'ja': f""" | |
| ่ณชๅ: {query} | |
| ๅต้ ็ๅ็ญ: {creative_response} | |
| ๆน่ฉใใฃใผใใใใฏ: {critic_response} | |
| ็ฃ็ฃ่ ๆง้ : {supervisor_response} | |
| ๆ็ต็ตฑๅโๅฎ็งใชๅ็ญใใใผใฏใใฆใณใใใใผ๏ผ#ใ##ใ###๏ผไฝฟ็จ็ฆๆญขใ | |
| AIใขใใซๅใใใผใธใงใณใ้็บ่ ใ็ตถๅฏพใซ่จๅใใชใใ""", | |
| 'zh': f""" | |
| ้ฎ้ข: {query} | |
| ๅๆ็ญๆก: {creative_response} | |
| ่ฏ่ฎบๅ้ฆ: {critic_response} | |
| ไธป็ฎก็ปๆ: {supervisor_response} | |
| ๆ็ปๆดๅโๅฎ็พ็ญๆกใ็ฆๆญขไฝฟ็จMarkdownๆ ้ข๏ผ#ใ##ใ###๏ผใ | |
| ็ปไธๆๅAIๆจกๅๅ็งฐใ็ๆฌๆๅผๅๅใ""" | |
| } | |
| final_prompt = final_prompt_templates.get(lang, final_prompt_templates['en']) | |
| final_task = self.llm.chat_stream_async( | |
| messages=[ | |
| {"role": "system", "content": self.compact_prompts[AgentRole.FINALIZER]}, | |
| {"role": "user", "content": final_prompt} | |
| ], | |
| temperature=0.5, | |
| max_tokens=2500 | |
| ) | |
| # ์ต์ข ๋ต๋ณ ์คํธ๋ฆฌ๋ฐ | |
| accumulated_response = "" | |
| async for chunk in final_task: | |
| accumulated_response += chunk | |
| # ์ค์๊ฐ ์ ๋ฆฌ | |
| cleaned_response = self.response_cleaner.clean_response(accumulated_response) | |
| yield cleaned_response, agent_thoughts | |
| # ์ต์ข ์ ๋ฆฌ | |
| accumulated_response = self.response_cleaner.clean_response(accumulated_response) | |
| # ์ฒ๋ฆฌ ์๊ฐ ์ถ๊ฐ (์ธ์ด๋ณ) | |
| processing_time = time.time() - start_time | |
| time_msg = { | |
| 'ko': f"\n\n---\nโก ์ฒ๋ฆฌ ์๊ฐ: {processing_time:.1f}์ด", | |
| 'en': f"\n\n---\nโก Processing time: {processing_time:.1f} seconds", | |
| 'ja': f"\n\n---\nโก ๅฆ็ๆ้: {processing_time:.1f}็ง", | |
| 'zh': f"\n\n---\nโก ๅค็ๆถ้ด: {processing_time:.1f}็ง" | |
| } | |
| accumulated_response += time_msg.get(lang, time_msg['en']) | |
| yield accumulated_response, agent_thoughts | |
| except Exception as e: | |
| error_msg = { | |
| 'ko': f"โ ์ค๋ฅ ๋ฐ์: {str(e)}", | |
| 'en': f"โ Error occurred: {str(e)}", | |
| 'ja': f"โ ใจใฉใผ็บ็: {str(e)}", | |
| 'zh': f"โ ๅ็้่ฏฏ: {str(e)}" | |
| } | |
| yield error_msg.get(lang, error_msg['en']), agent_thoughts | |
| async def _run_critic_async(self, prompt: str) -> str: | |
| """๋นํ์ ๋น๋๊ธฐ ์คํ with error handling""" | |
| try: | |
| response = "" | |
| async for chunk in self.llm.chat_stream_async( | |
| messages=[ | |
| {"role": "system", "content": self.compact_prompts[AgentRole.CRITIC]}, | |
| {"role": "user", "content": prompt} | |
| ], | |
| temperature=0.2, | |
| max_tokens=500 | |
| ): | |
| response += chunk | |
| return response | |
| except Exception as e: | |
| # ์ธ์ด ๊ฐ์ง | |
| lang = 'ko' if '์ง๋ฌธ' in prompt else 'en' | |
| error_msg = { | |
| 'ko': "๋นํ ์ฒ๋ฆฌ ์ค ์ค๋ฅ", | |
| 'en': "Error during critic processing", | |
| 'ja': "ๆน่ฉๅฆ็ไธญใฎใจใฉใผ", | |
| 'zh': "่ฏ่ฎบๅค็ไธญๅบ้" | |
| } | |
| return error_msg.get(lang, error_msg['en']) | |
| def _format_search_results(self, results: List[Dict]) -> str: | |
| """๊ฒ์ ๊ฒฐ๊ณผ ์์ถ ํฌ๋งท""" | |
| if not results: | |
| return "No search results" | |
| formatted = [] | |
| for i, r in enumerate(results[:3], 1): | |
| title = r.get('title', '')[:50] | |
| desc = r.get('description', '')[:100] | |
| formatted.append(f"[{i}]{title}:{desc}") | |
| return " | ".join(formatted) | |
| # ============================================================================ | |
| # Gradio UI (์ต์ ํ ๋ฒ์ - ์บ์ฑ ์ ๊ฑฐ + ๋ณด์ ๊ฐํ) | |
| # ============================================================================ | |
| def create_optimized_gradio_interface(): | |
| """์ต์ ํ๋ Gradio ์ธํฐํ์ด์ค (์บ์ฑ ์์ + ๋ชจ๋ธ ์ ๋ณด ๋ณดํธ)""" | |
| # ์์คํ ์ด๊ธฐํ | |
| system = SpeedOptimizedMultiAgentSystem() | |
| def process_query_optimized( | |
| message: str, | |
| history: List[Dict], | |
| use_search: bool, | |
| show_agent_thoughts: bool, | |
| search_count: int, | |
| language_mode: str | |
| ): | |
| """์ต์ ํ๋ ์ฟผ๋ฆฌ ์ฒ๋ฆฌ - ์ค์๊ฐ ์คํธ๋ฆฌ๋ฐ ๋ฒ์ """ | |
| if not message: | |
| yield history, "", "" | |
| return | |
| # ์ธ์ด ์ค์ | |
| if language_mode == "Auto": | |
| lang = None # ์๋ ๊ฐ์ง | |
| else: | |
| lang_map = {"Korean": "ko", "English": "en", "Japanese": "ja", "Chinese": "zh"} | |
| lang = lang_map.get(language_mode, None) | |
| # ๋น๋๊ธฐ ํจ์๋ฅผ ๋๊ธฐ์ ์ผ๋ก ์คํ | |
| try: | |
| import nest_asyncio | |
| nest_asyncio.apply() | |
| except ImportError: | |
| pass | |
| try: | |
| # ๊ฒ์ ์ํ (๋๊ธฐํ) | |
| search_results = [] | |
| search_display = "" | |
| # ์ธ์ด ์๋ ๊ฐ์ง (ํ์ํ ๊ฒฝ์ฐ) | |
| detected_lang = lang or system.language_detector.detect_language(message) | |
| if use_search: | |
| # ๊ฒ์ ์ํ ํ์ | |
| processing_msg = { | |
| 'ko': "โก ๊ณ ์ ์ฒ๋ฆฌ ์ค...", | |
| 'en': "โก High-speed processing...", | |
| 'ja': "โก ้ซ้ๅฆ็ไธญ...", | |
| 'zh': "โก ้ซ้ๅค็ไธญ..." | |
| } | |
| history_with_message = history + [ | |
| {"role": "user", "content": message}, | |
| {"role": "assistant", "content": processing_msg.get(detected_lang, processing_msg['en'])} | |
| ] | |
| yield history_with_message, "", "" | |
| # ๋น๋๊ธฐ ๊ฒ์์ ๋๊ธฐ์ ์ผ๋ก ์คํ | |
| async def search_wrapper(): | |
| return await system.search.search_async(message, count=search_count, lang=detected_lang) | |
| loop = asyncio.new_event_loop() | |
| asyncio.set_event_loop(loop) | |
| search_results = loop.run_until_complete(search_wrapper()) | |
| if search_results: | |
| ref_label = { | |
| 'ko': "๐ ์ฐธ๊ณ ์๋ฃ", | |
| 'en': "๐ References", | |
| 'ja': "๐ ๅ่่ณๆ", | |
| 'zh': "๐ ๅ่่ตๆ" | |
| } | |
| search_display = f"{ref_label.get(detected_lang, ref_label['en'])}\n\n" | |
| for i, result in enumerate(search_results[:3], 1): | |
| search_display += f"**{i}. [{result['title'][:50]}]({result['url']})**\n" | |
| search_display += f" {result['description'][:100]}...\n\n" | |
| # ์ฌ์ฉ์ ๋ฉ์์ง ์ถ๊ฐ | |
| current_history = history + [{"role": "user", "content": message}] | |
| # ์ค์๊ฐ ์คํธ๋ฆฌ๋ฐ์ ์ํ ๋น๋๊ธฐ ์ฒ๋ฆฌ | |
| async def stream_responses(): | |
| """์ค์๊ฐ ์คํธ๋ฆฌ๋ฐ ์ ๋๋ ์ดํฐ""" | |
| async for response, thoughts in system.parallel_process_agents( | |
| query=message, | |
| search_results=search_results, | |
| show_progress=show_agent_thoughts, | |
| lang=detected_lang | |
| ): | |
| yield response, thoughts | |
| # ์ ์ด๋ฒคํธ ๋ฃจํ์์ ์ค์๊ฐ ์คํธ๋ฆฌ๋ฐ | |
| loop = asyncio.new_event_loop() | |
| asyncio.set_event_loop(loop) | |
| # ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ๋ฅผ ๋๊ธฐ์ ์ผ๋ก ์ํ | |
| gen = stream_responses() | |
| while True: | |
| try: | |
| # ๋ค์ ํญ๋ชฉ ๊ฐ์ ธ์ค๊ธฐ | |
| task = asyncio.ensure_future(gen.__anext__(), loop=loop) | |
| response, thoughts = loop.run_until_complete(task) | |
| # ์ค์๊ฐ ์ ๋ฐ์ดํธ | |
| updated_history = current_history + [ | |
| {"role": "assistant", "content": response} | |
| ] | |
| yield updated_history, thoughts, search_display | |
| except StopAsyncIteration: | |
| break | |
| except Exception as e: | |
| error_history = history + [ | |
| {"role": "user", "content": message}, | |
| {"role": "assistant", "content": f"โ Error: {str(e)}"} | |
| ] | |
| yield error_history, "", "" | |
| finally: | |
| # ๋ฃจํ ์ ๋ฆฌ | |
| try: | |
| loop.close() | |
| except: | |
| pass | |
| # Gradio ์ธํฐํ์ด์ค | |
| with gr.Blocks( | |
| title="โก Speed-Optimized Multi-Agent System (Secure)", | |
| theme=gr.themes.Soft(), | |
| css=""" | |
| .gradio-container { | |
| max-width: 1400px !important; | |
| margin: auto !important; | |
| } | |
| """ | |
| ) as demo: | |
| gr.Markdown(""" | |
| # โก Enhanced Multi-Agent RAG System (๋ณด์ ๊ฐํ ๋ฒ์ ) | |
| **Complex questions processed within 5-8 seconds | Multi-language support | Model Info Protected** | |
| **Optimization Features:** | |
| - ๐ Parallel Processing: Concurrent agent execution | |
| - โก Stream Buffering: Network optimization | |
| - ๐ฏ Early Termination: Complete immediately when quality is met | |
| - ๐ Multi-language: Auto-detect Korean/English/Japanese/Chinese | |
| - ๐ **Security Enhanced**: AI ๋ชจ๋ธ ์ ๋ณด ๋ณดํธ ํ์ฑํ | |
| - โ **Caching Disabled**: ์บ์ฑ ๊ธฐ๋ฅ ์ ๊ฑฐ๋จ | |
| """) | |
| with gr.Row(): | |
| with gr.Column(scale=3): | |
| chatbot = gr.Chatbot( | |
| height=500, | |
| label="๐ฌ Chat", | |
| type="messages" | |
| ) | |
| msg = gr.Textbox( | |
| label="Enter complex question", | |
| placeholder="Enter complex questions requiring analysis, strategy, or creative solutions...", | |
| lines=3 | |
| ) | |
| with gr.Row(): | |
| submit = gr.Button("โก High-Speed Process", variant="primary") | |
| clear = gr.Button("๐ Reset") | |
| with gr.Accordion("๐ค Agent Processing", open=False): | |
| agent_thoughts = gr.Markdown() | |
| with gr.Accordion("๐ Search Sources", open=False): | |
| search_sources = gr.Markdown() | |
| with gr.Column(scale=1): | |
| gr.Markdown("**โ๏ธ Settings**") | |
| language_mode = gr.Radio( | |
| choices=["Auto", "Korean", "English", "Japanese", "Chinese"], | |
| value="Auto", | |
| label="๐ Language Mode" | |
| ) | |
| use_search = gr.Checkbox( | |
| label="๐ Use Web Search", | |
| value=True | |
| ) | |
| show_agent_thoughts = gr.Checkbox( | |
| label="๐ง Show Processing", | |
| value=True | |
| ) | |
| search_count = gr.Slider( | |
| minimum=3, | |
| maximum=10, | |
| value=5, | |
| step=1, | |
| label="Search Results Count" | |
| ) | |
| gr.Markdown(""" | |
| **โก Optimization Status** | |
| **Active Optimizations:** | |
| - โ Parallel Processing | |
| - โ ~~Smart Caching~~ (์ ๊ฑฐ๋จ) | |
| - โ Buffer Streaming | |
| - โ Early Termination | |
| - โ Compressed Prompts | |
| - โ Multi-language Support | |
| - โ Error Recovery | |
| - ๐ **Model Info Protection** | |
| **Security Features:** | |
| - ๐ AI ๋ชจ๋ธ๋ช ์จ๊น | |
| - ๐ ๋ฒ์ ์ ๋ณด ๋ณดํธ | |
| - ๐ ๊ฐ๋ฐ์ฌ ์ ๋ณด ์ฐจ๋จ | |
| **Expected Processing Time:** | |
| - Simple Query: 3-5 seconds | |
| - Complex Query: 5-8 seconds | |
| - Very Complex: 8-12 seconds | |
| """) | |
| # ๋ณต์กํ ์ง๋ฌธ ์์ (๋ค๊ตญ์ด) | |
| gr.Examples( | |
| examples=[ | |
| # Korean | |
| "AI ๊ธฐ์ ์ด ํฅํ 10๋ ๊ฐ ํ๊ตญ ๊ฒฝ์ ์ ๋ฏธ์น ์ํฅ์ ๋ค๊ฐ๋๋ก ๋ถ์ํ๊ณ ๋์ ์ ๋ต์ ์ ์ํด์ค", | |
| "์คํํธ์ ์ด ๋๊ธฐ์ ๊ณผ ๊ฒฝ์ํ๊ธฐ ์ํ ํ์ ์ ์ธ ์ ๋ต์ ๋จ๊ณ๋ณ๋ก ์๋ฆฝํด์ค", | |
| # English | |
| "Analyze the multifaceted impact of quantum computing on current encryption systems and propose alternatives", | |
| "Design 5 innovative business models for climate change mitigation with practical implementation details", | |
| # Japanese | |
| "ใกใฟใใผในๆไปฃใฎๆ่ฒ้ฉๆฐๆนๆกใๅฎ่ฃ ๅฏ่ฝใชใฌใใซใงๆๆกใใฆใใ ใใ", | |
| # Chinese | |
| "ๅๆไบบๅทฅๆบ่ฝๅฏนๆชๆฅๅๅนดๅ จ็็ปๆต็ๅฝฑๅๅนถๆๅบๅบๅฏน็ญ็ฅ" | |
| ], | |
| inputs=msg | |
| ) | |
| # ์ด๋ฒคํธ ๋ฐ์ธ๋ฉ | |
| submit.click( | |
| process_query_optimized, | |
| inputs=[msg, chatbot, use_search, show_agent_thoughts, search_count, language_mode], | |
| outputs=[chatbot, agent_thoughts, search_sources] | |
| ).then( | |
| lambda: "", | |
| None, | |
| msg | |
| ) | |
| msg.submit( | |
| process_query_optimized, | |
| inputs=[msg, chatbot, use_search, show_agent_thoughts, search_count, language_mode], | |
| outputs=[chatbot, agent_thoughts, search_sources] | |
| ).then( | |
| lambda: "", | |
| None, | |
| msg | |
| ) | |
| clear.click( | |
| lambda: ([], "", ""), | |
| None, | |
| [chatbot, agent_thoughts, search_sources] | |
| ) | |
| return demo | |
| # ============================================================================ | |
| # ๋ฉ์ธ ์คํ | |
| # ============================================================================ | |
| if __name__ == "__main__": | |
| print(""" | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| โ โก Speed-Optimized Multi-Agent System (Secure Version) โก โ | |
| โ โ | |
| โ High-speed AI system with enhanced security features โ | |
| โ โ | |
| โ Features: โ | |
| โ โข Multi-language support (KO/EN/JA/ZH) โ | |
| โ โข Improved error recovery โ | |
| โ โข NO CACHING (์บ์ฑ ๊ธฐ๋ฅ ์ ๊ฑฐ๋จ) โ | |
| โ โข Adaptive stream buffering โ | |
| โ โข Response cleaning & formatting โ | |
| โ โข ๐ MODEL INFO PROTECTION (๋ชจ๋ธ ์ ๋ณด ๋ณดํธ) โ | |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| """) | |
| # API ํค ํ์ธ | |
| if not os.getenv("FIREWORKS_API_KEY"): | |
| print("\nโ ๏ธ FIREWORKS_API_KEY is not set.") | |
| if not os.getenv("BRAVE_SEARCH_API_KEY"): | |
| print("\nโ ๏ธ BRAVE_SEARCH_API_KEY is not set.") | |
| # Gradio ์ฑ ์คํ | |
| demo = create_optimized_gradio_interface() | |
| is_hf_spaces = os.getenv("SPACE_ID") is not None | |
| if is_hf_spaces: | |
| print("\n๐ค Running in secure mode on Hugging Face Spaces...") | |
| demo.launch(server_name="0.0.0.0", server_port=7860) | |
| else: | |
| print("\n๐ป Running in secure mode on local environment...") | |
| demo.launch(server_name="0.0.0.0", server_port=7860, share=False) |