aiqtech commited on
Commit
41687a3
·
verified ·
1 Parent(s): 9f4be8a

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +1201 -0
app.py ADDED
@@ -0,0 +1,1201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ import json
4
+ import requests
5
+ from datetime import datetime
6
+ import time
7
+ from typing import List, Dict, Any, Generator, Tuple
8
+ import logging
9
+ import re
10
+
11
+ # 로깅 설정
12
+ logging.basicConfig(level=logging.INFO)
13
+ logger = logging.getLogger(__name__)
14
+
15
+ # 추가 임포트
16
+ from bs4 import BeautifulSoup
17
+ from urllib.parse import urlparse
18
+ import urllib.request
19
+
20
+ # 환경 변수에서 토큰 가져오기
21
+ FRIENDLI_TOKEN = os.getenv("FRIENDLI_TOKEN", "YOUR_FRIENDLI_TOKEN")
22
+ BAPI_TOKEN = os.getenv("BAPI_TOKEN", "YOUR_BRAVE_API_TOKEN")
23
+ API_URL = "https://api.friendli.ai/dedicated/v1/chat/completions"
24
+ BRAVE_SEARCH_URL = "https://api.search.brave.com/res/v1/web/search"
25
+ MODEL_ID = "dep89a2fld32mcm"
26
+ TEST_MODE = os.getenv("TEST_MODE", "false").lower() == "true"
27
+
28
+ # 전역 변수
29
+ conversation_history = []
30
+
31
+ class LLMCollaborativeSystem:
32
+ def __init__(self):
33
+ self.token = FRIENDLI_TOKEN
34
+ self.bapi_token = BAPI_TOKEN
35
+ self.api_url = API_URL
36
+ self.brave_url = BRAVE_SEARCH_URL
37
+ self.model_id = MODEL_ID
38
+ self.test_mode = TEST_MODE or (self.token == "YOUR_FRIENDLI_TOKEN")
39
+
40
+ if self.test_mode:
41
+ logger.warning("테스트 모드로 실행됩니다.")
42
+ if self.bapi_token == "YOUR_BRAVE_API_TOKEN":
43
+ logger.warning("Brave API 토큰이 설정되지 않았습니다.")
44
+
45
+ def create_headers(self):
46
+ """API 헤더 생성"""
47
+ return {
48
+ "Authorization": f"Bearer {self.token}",
49
+ "Content-Type": "application/json"
50
+ }
51
+
52
+ def create_brave_headers(self):
53
+ """Brave API 헤더 생성"""
54
+ return {
55
+ "Accept": "application/json",
56
+ "Accept-Encoding": "gzip",
57
+ "X-Subscription-Token": self.bapi_token
58
+ }
59
+
60
+ def create_supervisor_initial_prompt(self, user_query: str) -> str:
61
+ """감독자 AI 초기 프롬프트 생성"""
62
+ return f"""당신은 거시적 관점에서 분석하고 지도하는 감독자 AI입니다.
63
+
64
+ 사용자 질문: {user_query}
65
+
66
+ 이 질문에 대해:
67
+ 1. 전체적인 접근 방향과 프레임워크를 제시하세요
68
+ 2. 핵심 요소와 고려사항을 구조화하여 설명하세요
69
+ 3. 이 주제에 대해 조사가 필요한 5-7개의 구체적인 키워드나 검색어를 제시하세요
70
+
71
+ 키워드는 다음 형식으로 제시하세요:
72
+ [검색 키워드]: 키워드1, 키워드2, 키워드3, 키워드4, 키워드5"""
73
+
74
+ def create_researcher_prompt(self, user_query: str, supervisor_guidance: str, search_results: Dict[str, List[Dict]]) -> str:
75
+ """조사자 AI 프롬프트 생성"""
76
+ search_summary = ""
77
+ all_results = []
78
+
79
+ for keyword, results in search_results.items():
80
+ search_summary += f"\n\n**{keyword}에 대한 검색 결과:**\n"
81
+ for i, result in enumerate(results[:10], 1): # 상위 10개만 표시
82
+ search_summary += f"{i}. {result.get('title', 'N/A')} (신뢰도: {result.get('credibility_score', 0):.2f})\n"
83
+ search_summary += f" - {result.get('description', 'N/A')}\n"
84
+ search_summary += f" - 출처: {result.get('url', 'N/A')}\n"
85
+ if result.get('published'):
86
+ search_summary += f" - 게시일: {result.get('published')}\n"
87
+
88
+ all_results.extend(results)
89
+
90
+ # 모순 감지
91
+ contradictions = self.detect_contradictions(all_results)
92
+ contradiction_text = ""
93
+ if contradictions:
94
+ contradiction_text = "\n\n**발견된 정보 모순:**\n"
95
+ for cont in contradictions[:3]: # 최대 3개만 표시
96
+ contradiction_text += f"- {cont['type']}: {cont['source1']} vs {cont['source2']}\n"
97
+
98
+ return f"""당신은 정보를 조사하고 정리하는 조사자 AI입니다.
99
+
100
+ 사용자 질문: {user_query}
101
+
102
+ 감독자 AI의 지침:
103
+ {supervisor_guidance}
104
+
105
+ 브레이브 검색 결과 (신뢰도 점수 포함):
106
+ {search_summary}
107
+ {contradiction_text}
108
+
109
+ 위 검색 결과를 바탕으로:
110
+ 1. 각 키워드별로 중요한 정보를 정리하세요
111
+ 2. 신뢰할 수 있는 출처(신뢰도 0.7 이상)를 우선적으로 참고하세요
112
+ 3. 출처를 명확히 표기하여 실행자 AI가 검증할 수 있도록 하세요
113
+ 4. 정보의 모순이 있다면 양쪽 관점을 모두 제시하세요
114
+ 5. 최신 트렌드나 중요한 통계가 있다면 강조하세요
115
+ 6. 신뢰도가 낮은 정보는 주의 표시와 함께 포함하세요"""
116
+
117
+ def create_supervisor_execution_prompt(self, user_query: str, research_summary: str) -> str:
118
+ """감독자 AI의 실행 지시 프롬프트"""
119
+ return f"""당신은 거시적 관점에서 분석하고 지도하는 감독자 AI입니다.
120
+
121
+ 사용자 질문: {user_query}
122
+
123
+ 조사자 AI가 정리한 조사 내용:
124
+ {research_summary}
125
+
126
+ 위 조사 내용을 기반으로 실행자 AI에게 아주 구체���인 지시를 내려주세요:
127
+ 1. 조사된 정보를 어떻게 활용할지 명확히 지시하세요
128
+ 2. 실행 가능한 단계별 작업을 구체적으로 제시하세요
129
+ 3. 각 단계에서 참고해야 할 조사 내용을 명시하세요
130
+ 4. 예상되는 결과물의 형태를 구체적으로 설명하세요"""
131
+
132
+ def create_executor_prompt(self, user_query: str, supervisor_guidance: str, research_summary: str) -> str:
133
+ """실행자 AI 프롬프트 생성"""
134
+ return f"""당신은 세부적인 내용을 구현하는 실행자 AI입니다.
135
+
136
+ 사용자 질문: {user_query}
137
+
138
+ 조사자 AI가 정리한 조사 내용:
139
+ {research_summary}
140
+
141
+ 감독자 AI의 구체적인 지시:
142
+ {supervisor_guidance}
143
+
144
+ 위 조사 내용과 지시사항을 바탕으로:
145
+ 1. 조사된 정보를 적극 활용하여 구체적인 실행 계획을 작성하세요
146
+ 2. 각 단계별로 참고한 조사 내용을 명시하세요
147
+ 3. 실제로 적용 가능한 구체적인 방법론을 제시하세요
148
+ 4. 예상되는 성과와 측정 방법을 포함하세요"""
149
+
150
+ def create_executor_final_prompt(self, user_query: str, initial_response: str, supervisor_feedback: str, research_summary: str) -> str:
151
+ """실행자 AI 최종 보고서 프롬프트"""
152
+ return f"""당신은 세부적인 내용을 구현하는 실행자 AI입니다.
153
+
154
+ 사용자 질문: {user_query}
155
+
156
+ 조사자 AI의 조사 내용:
157
+ {research_summary}
158
+
159
+ 당신의 초기 답변:
160
+ {initial_response}
161
+
162
+ 감독자 AI의 피드백 및 개선사항:
163
+ {supervisor_feedback}
164
+
165
+ 위 피드백을 완전히 반영하여 최종 보고서를 작성하세요:
166
+ 1. 감독자의 모든 개선사항을 반영하세요
167
+ 2. 조사 내용을 더욱 구체적으로 활용하세요
168
+ 3. 실행 가능성을 높이는 세부 계획을 포함하세요
169
+ 4. 명확한 결론과 다음 단계를 제시하세요
170
+ 5. 전문적이고 완성도 높은 최종 보고서 형식으로 작성하세요"""
171
+
172
+ def extract_keywords(self, supervisor_response: str) -> List[str]:
173
+ """감독자 응답에서 키워드 추출"""
174
+ keywords = []
175
+
176
+ # [검색 키워드]: 형식으로 키워드 찾기
177
+ keyword_match = re.search(r'\[검색 키워드\]:\s*(.+)', supervisor_response, re.IGNORECASE)
178
+ if keyword_match:
179
+ keyword_str = keyword_match.group(1)
180
+ keywords = [k.strip() for k in keyword_str.split(',') if k.strip()]
181
+
182
+ # 키워드가 없으면 기본 키워드 생성
183
+ if not keywords:
184
+ keywords = ["best practices", "implementation guide", "case studies", "latest trends", "success factors"]
185
+
186
+ return keywords[:7] # 최대 7개로 제한
187
+
188
+ def generate_synonyms(self, keyword: str) -> List[str]:
189
+ """키워드의 동의어/유사어 생성"""
190
+ synonyms = {
191
+ "optimization": ["improvement", "enhancement", "efficiency", "tuning"],
192
+ "performance": ["speed", "efficiency", "throughput", "latency"],
193
+ "strategy": ["approach", "method", "technique", "plan"],
194
+ "implementation": ["deployment", "execution", "development", "integration"],
195
+ "analysis": ["evaluation", "assessment", "study", "research"],
196
+ "management": ["administration", "governance", "control", "supervision"],
197
+ "best practices": ["proven methods", "industry standards", "guidelines", "recommendations"],
198
+ "trends": ["developments", "innovations", "emerging", "future"],
199
+ "machine learning": ["ML", "AI", "deep learning", "neural networks"],
200
+ "프로젝트": ["project", "사업", "업무", "작업"]
201
+ }
202
+
203
+ # 키워드 정규화
204
+ keyword_lower = keyword.lower()
205
+
206
+ # 직접 매칭되는 동의어가 있으면 반환
207
+ if keyword_lower in synonyms:
208
+ return synonyms[keyword_lower][:2] # 최대 2개
209
+
210
+ # 부분 매칭 확인
211
+ for key, values in synonyms.items():
212
+ if key in keyword_lower or keyword_lower in key:
213
+ return values[:2]
214
+
215
+ # 동의어가 없으면 빈 리스트
216
+ return []
217
+
218
+ def calculate_credibility_score(self, result: Dict) -> float:
219
+ """검색 결과의 신뢰도 점수 계산 (0-1)"""
220
+ score = 0.5 # 기본 점수
221
+
222
+ url = result.get('url', '')
223
+ title = result.get('title', '')
224
+ description = result.get('description', '')
225
+
226
+ # URL 기반 점수
227
+ trusted_domains = [
228
+ '.edu', '.gov', '.org', 'wikipedia.org', 'nature.com',
229
+ 'sciencedirect.com', 'ieee.org', 'acm.org', 'springer.com',
230
+ 'harvard.edu', 'mit.edu', 'stanford.edu', 'github.com'
231
+ ]
232
+
233
+ for domain in trusted_domains:
234
+ if domain in url:
235
+ score += 0.2
236
+ break
237
+
238
+ # HTTPS 사용 여부
239
+ if url.startswith('https://'):
240
+ score += 0.1
241
+
242
+ # ��목과 설명의 길이 (너무 짧으면 신뢰도 감소)
243
+ if len(title) > 20:
244
+ score += 0.05
245
+ if len(description) > 50:
246
+ score += 0.05
247
+
248
+ # 광고/스팸 키워드 체크
249
+ spam_keywords = ['buy now', 'sale', 'discount', 'click here', '100% free']
250
+ if any(spam in (title + description).lower() for spam in spam_keywords):
251
+ score -= 0.3
252
+
253
+ # 날짜 정보가 있으면 가산점
254
+ if any(year in description for year in ['2024', '2023', '2022']):
255
+ score += 0.1
256
+
257
+ return max(0, min(1, score)) # 0-1 범위로 제한
258
+
259
+ def fetch_url_content(self, url: str, max_length: int = 2000) -> str:
260
+ """URL에서 콘텐츠 추출"""
261
+ try:
262
+ # User-Agent 설정
263
+ headers = {
264
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
265
+ }
266
+
267
+ req = urllib.request.Request(url, headers=headers)
268
+
269
+ with urllib.request.urlopen(req, timeout=5) as response:
270
+ html = response.read().decode('utf-8', errors='ignore')
271
+
272
+ soup = BeautifulSoup(html, 'html.parser')
273
+
274
+ # 스크립트와 스타일 제거
275
+ for script in soup(["script", "style"]):
276
+ script.decompose()
277
+
278
+ # 본문 텍스트 추출
279
+ text = soup.get_text()
280
+
281
+ # 공백 정리
282
+ lines = (line.strip() for line in text.splitlines())
283
+ chunks = (phrase.strip() for line in lines for phrase in line.split(" "))
284
+ text = ' '.join(chunk for chunk in chunks if chunk)
285
+
286
+ # 길이 제한
287
+ if len(text) > max_length:
288
+ text = text[:max_length] + "..."
289
+
290
+ return text
291
+
292
+ except Exception as e:
293
+ logger.error(f"URL 콘텐츠 가져오기 실패 {url}: {str(e)}")
294
+ return ""
295
+
296
+ def detect_contradictions(self, results: List[Dict]) -> List[Dict]:
297
+ """검색 결과 간 모순 감지"""
298
+ contradictions = []
299
+
300
+ # 간단한 모순 감지 패턴
301
+ opposite_pairs = [
302
+ ("increase", "decrease"),
303
+ ("improve", "worsen"),
304
+ ("effective", "ineffective"),
305
+ ("success", "failure"),
306
+ ("benefit", "harm"),
307
+ ("positive", "negative"),
308
+ ("growth", "decline")
309
+ ]
310
+
311
+ # 결과들을 비교
312
+ for i in range(len(results)):
313
+ for j in range(i + 1, len(results)):
314
+ desc1 = results[i].get('description', '').lower()
315
+ desc2 = results[j].get('description', '').lower()
316
+
317
+ # 반대 개념이 포함되어 있는지 확인
318
+ for word1, word2 in opposite_pairs:
319
+ if (word1 in desc1 and word2 in desc2) or (word2 in desc1 and word1 in desc2):
320
+ # 같은 주제에 대해 반대 의견인지 확인
321
+ common_words = set(desc1.split()) & set(desc2.split())
322
+ if len(common_words) > 5: # 공통 단어가 5개 이상이면 같은 주제로 간주
323
+ contradictions.append({
324
+ 'source1': results[i]['url'],
325
+ 'source2': results[j]['url'],
326
+ 'type': f"{word1} vs {word2}",
327
+ 'desc1': results[i]['description'][:100],
328
+ 'desc2': results[j]['description'][:100]
329
+ })
330
+
331
+ return contradictions
332
+
333
+ def brave_search(self, query: str) -> List[Dict]:
334
+ """Brave Search API 호출"""
335
+ if self.test_mode or self.bapi_token == "YOUR_BRAVE_API_TOKEN":
336
+ # 테스트 모드에서는 시뮬레이션된 결과 반환
337
+ test_results = []
338
+ for i in range(5):
339
+ test_results.append({
340
+ "title": f"Best Practices for {query} - Source {i+1}",
341
+ "description": f"Comprehensive guide on implementing {query} with proven methodologies and real-world examples from industry leaders.",
342
+ "url": f"https://example{i+1}.com/{query.replace(' ', '-')}",
343
+ "credibility_score": 0.7 + (i * 0.05)
344
+ })
345
+ return test_results
346
+
347
+ try:
348
+ params = {
349
+ "q": query,
350
+ "count": 20, # 20개로 증가
351
+ "safesearch": "moderate",
352
+ "freshness": "pw" # Past week for recent results
353
+ }
354
+
355
+ response = requests.get(
356
+ self.brave_url,
357
+ headers=self.create_brave_headers(),
358
+ params=params,
359
+ timeout=10
360
+ )
361
+
362
+ if response.status_code == 200:
363
+ data = response.json()
364
+ results = []
365
+ for item in data.get("web", {}).get("results", [])[:20]:
366
+ result = {
367
+ "title": item.get("title", ""),
368
+ "description": item.get("description", ""),
369
+ "url": item.get("url", ""),
370
+ "published": item.get("published", "")
371
+ }
372
+ # 신뢰도 점수 계산
373
+ result["credibility_score"] = self.calculate_credibility_score(result)
374
+ results.append(result)
375
+
376
+ # 신뢰도 점수 기준으로 정렬
377
+ results.sort(key=lambda x: x['credibility_score'], reverse=True)
378
+ return results
379
+ else:
380
+ logger.error(f"Brave API 오류: {response.status_code}")
381
+ return []
382
+
383
+ except Exception as e:
384
+ logger.error(f"Brave 검색 중 오류: {str(e)}")
385
+ return []
386
+
387
+ def simulate_streaming(self, text: str, role: str) -> Generator[str, None, None]:
388
+ """테스트 모드에서 스트리밍 시뮬레이션"""
389
+ words = text.split()
390
+ for i in range(0, len(words), 3):
391
+ chunk = " ".join(words[i:i+3])
392
+ yield chunk + " "
393
+ time.sleep(0.05)
394
+
395
+ def call_llm_streaming(self, messages: List[Dict[str, str]], role: str) -> Generator[str, None, None]:
396
+ """스트리밍 LLM API 호출"""
397
+
398
+ # 테스트 모드
399
+ if self.test_mode:
400
+ logger.info(f"테스트 모드 스트리밍 - Role: {role}")
401
+ test_responses = {
402
+ "supervisor_initial": """이 질문에 대한 거시적 분석을 제시하겠습니다.
403
+
404
+ 1. **핵심 개념 파악**
405
+ - 질문의 본질적 요소를 심층 분석합니다
406
+ - 관련된 주요 이론과 원칙을 검토합니다
407
+ - 다양한 관점에서의 접근 방법을 고려합니다
408
+
409
+ 2. **전략적 접근 방향**
410
+ - 체계적이고 단계별 해결 방안을 수립합니다
411
+ - 장단기 목표를 명확히 설정합니다
412
+ - 리스크 요인과 대응 방안을 마련합니다
413
+
414
+ 3. **기대 효과와 과제**
415
+ - 예상되는 긍정적 성과를 분석합니다
416
+ - 잠재적 도전 과제를 식별합니다
417
+ - 지속가능한 발전 방향을 제시합니다
418
+
419
+ [검색 키워드]: machine learning optimization, performance improvement strategies, model efficiency techniques, hyperparameter tuning best practices, latest ML trends 2024""",
420
+
421
+ "researcher": """조사 결과를 종합하여 다음과 같이 정리했습니다.
422
+
423
+ **1. Machine Learning Optimization (신뢰도 높음)**
424
+ - 최신 연구에 따르면 모델 최적화의 핵심은 아키텍처 설계와 훈련 전략의 균형입니다 (신뢰도: 0.85)
425
+ - AutoML 도구들이 하이퍼파라미터 튜닝을 자동화하여 효율성을 크게 향상시킵니다 (신뢰도: 0.82)
426
+ - 출처: ML Conference 2024 (https://mlconf2024.org), Google Research (https://research.google)
427
+ - 동의어 검색 결과: "ML improvement", "AI optimization"에서 추가 정보 확인
428
+
429
+ **2. Performance Improvement Strategies (신뢰도 높음)**
430
+ - 데이터 품질 개선이 모델 성능 향상의 80%를 차지한다는 연구 결과 (신뢰도: 0.90)
431
+ - 앙상블 기법과 전이학습이 주요 성능 개선 방법으로 입증됨 (신뢰도: 0.78)
432
+ - 출처: Stanford AI Lab (https://ai.stanford.edu), MIT CSAIL (https://csail.mit.edu)
433
+ - 벤치마크: ImageNet에서 95% 이상의 정확도 달성 사례
434
+
435
+ **3. Model Efficiency Techniques (신뢰도 중간)**
436
+ - 모델 경량화(Pruning, Quantization)로 추론 속도 10배 향상 가능 (신뢰도: 0.75)
437
+ - Knowledge Distillation으로 모델 크기 90% 감소, 성능 유지 (신뢰도: 0.72)
438
+ - 출처: ArXiv 논문 (https://arxiv.org/abs/2023.xxxxx)
439
+ - ⚠️ 주의: 일부 소스는 5-7배 향상만을 보고하여 정보 상충 존재
440
+
441
+ **4. 실제 적용 사례 (신뢰도 높음)**
442
+ - Netflix: 추천 시스템 개선으로 사용자 만족도 35% 향상 (신뢰도: 0.88)
443
+ - Tesla: 실시간 객체 인식 속도 50% 개선 (신뢰도: 0.80)
444
+ - OpenAI: GPT 모델 효율성 개선으로 비용 70% 절감 (신뢰도: 0.85)
445
+ - 출처: 각 기업 공식 블로그 및 기술 발표 자료
446
+
447
+ **발견된 정보 모순:**
448
+ 1. 모델 압축률: 일부는 90% 압축 가능하다고 주장하나, 다른 소스는 70%가 한계라고 명시
449
+ 2. 성능 향상 폭: 10배 vs 5-7배 향상에 대한 의견 차이 존재
450
+ 3. 권장사항: 실제 적용 시 보수적인 수치(5-7배)를 기준으로 계획 수립 권장
451
+
452
+ **핵심 인사이트:**
453
+ - 최신 트렌드는 효율성과 성능의 균형에 초점
454
+ - 2024년 들어 Sparse Models와 MoE(Mixture of Experts) 기법이 부상
455
+ - 실무 적용 시 단계별 검증이 성공의 핵심""",
456
+
457
+ "supervisor_execution": """조사 내용을 바탕으로 ���행자 AI에게 다음과 같이 구체적으로 지시합니다.
458
+
459
+ **1단계: 현재 모델 진단 (1주차)**
460
+ - 조사된 벤치마크 기준으로 현재 모델 성능 평가
461
+ - Netflix 사례를 참고하여 주요 병목 지점 식별
462
+ - AutoML 도구를 활용한 초기 최적화 가능성 탐색
463
+
464
+ **2단계: 데이터 품질 개선 (2-3주차)**
465
+ - 조사 결과의 "80% 규칙"에 따라 데이터 정제 우선 실행
466
+ - 데이터 증강 기법 적용 (조사된 최신 기법 활용)
467
+ - A/B 테스트로 개선 효과 측정
468
+
469
+ **3단계: 모델 최적화 구현 (4-6주차)**
470
+ - Knowledge Distillation 적용하여 모델 경량화
471
+ - 조사된 Pruning 기법으로 추론 속도 개선
472
+ - Tesla 사례의 실시간 처리 최적화 기법 벤치마킹
473
+
474
+ **4단계: 성과 검증 및 배포 (7-8주차)**
475
+ - OpenAI 사례의 비용 절감 지표 적용
476
+ - 조사된 성능 지표로 개선율 측정
477
+ - 단계적 배포 전략 수립""",
478
+
479
+ "executor": """감독자의 지시와 조사 내용을 기반으로 구체적인 실행 계획을 수립합니다.
480
+
481
+ **1단계: 현재 모델 진단 (1주차)**
482
+ - 월요일-화요일: MLflow를 사용한 현재 모델 메트릭 수집
483
+ * 조사 결과 참고: Netflix가 사용한 핵심 지표 (정확도, 지연시간, 처리량)
484
+ - 수요일-목요일: AutoML 도구 (Optuna, Ray Tune) 설정 및 초기 실행
485
+ * 조사된 best practice에 따라 search space 정의
486
+ - 금요일: 진단 보고서 작성 및 개선 우선순위 결정
487
+
488
+ **2단계: 데이터 품질 개선 (2-3주차)**
489
+ - 데이터 정제 파이프라인 구축
490
+ * 조사 결과의 "80% 규칙" 적용: 누락값, 이상치, 레이블 오류 처리
491
+ * 코드 예시: `data_quality_pipeline.py` 구현
492
+ - 데이터 증강 구현
493
+ * 최신 기법 적용: MixUp, CutMix, AutoAugment
494
+ * 검증 데이터셋으로 효과 측정 (목표: 15% 성능 향상)
495
+
496
+ **3단계: 모델 최적화 구현 (4-6주차)**
497
+ - Knowledge Distillation 구현
498
+ * Teacher 모델: 현재 대규모 모델
499
+ * Student 모델: 90% 작은 크기 목표 (조사 결과 기반)
500
+ * 구현 프레임워크: PyTorch/TensorFlow
501
+ - Pruning 및 Quantization 적용
502
+ * 구조적 pruning으로 50% 파라미터 제거
503
+ * INT8 quantization으로 추가 4배 속도 향상
504
+ * Tesla 사례 참고: TensorRT 최적화 적용
505
+
506
+ **4단계: 성과 검증 및 배포 (7-8주차)**
507
+ - 성과 지표 측정
508
+ * 추론 속도: 목표 10배 향상 (조사 결과 기반)
509
+ * 정확도 손실: 최대 2% 이내 유지
510
+ * 비용 절감: 70% 목표 (OpenAI 사례 참고)
511
+ - 배포 전략
512
+ * A/B 테스트: 10% 트래픽으로 시작
513
+ * 모니터링: Prometheus + Grafana 대시보드
514
+ * 롤백 계획: 성능 저하 시 자동 롤백
515
+
516
+ **예상 결과물**
517
+ - 최적화된 모델 (크기 90% 감소, 속도 10배 향상)
518
+ - 상세 성능 벤치마크 보고서
519
+ - 프로덕션 배포 가이드 및 모니터링 대시보드
520
+ - 재현 가능한 최적화 파이프라인 코드""",
521
+
522
+ "supervisor_review": """실행자 AI의 계획을 검토한 결과, 조사 내용이 잘 반영되었습니다. 다음과 같은 개선사항을 제안합니다.
523
+
524
+ **강점**
525
+ - 조사된 사례들(Netflix, Tesla, OpenAI)이 각 단계에 적절히 활용됨
526
+ - 구체적인 도구와 기법이 명시되어 실행 가능성이 높음
527
+ - 측정 가능한 목표가 조사 결과를 기반으로 설정됨
528
+
529
+ **개선 필요사항**
530
+ 1. **리스크 관리 강화**
531
+ - 각 단계별 실패 시나리오와 대응 방안 추가 필요
532
+ - 기술적 문제 발생 시 백업 계획 수립
533
+
534
+ 2. **비용 분석 구체화**
535
+ - OpenAI 사례의 70% 절감을 위한 구체적인 비용 계산
536
+ - ROI 분석 및 투자 대비 효과 측정 방법
537
+
538
+ 3. **팀 협업 체계화**
539
+ - 데이터 과학자, ML 엔지니어, DevOps 간 역할 분담 명확화
540
+ - 주간 진행 상황 공유 및 이슈 트래킹 프로세스
541
+
542
+ **추가 권장사항**
543
+ - 최신 연구 동향 모니터링 체계 구축
544
+ - 경쟁사 벤치마킹을 위한 정기적인 조사 프로세스
545
+ - 내부 지식 공유를 위한 문서화 및 세미나 계획
546
+ - 실패 사례에서 배운 교훈을 축적하는 시스템 구축""",
547
+
548
+ "executor_final": """감독자 AI의 피드백을 완전히 반영하여 최종 실행 보고서를 작성합니다.
549
+
550
+ # 🎯 기계학습 모델 성능 향상 최종 실행 보고서
551
+
552
+ ## 📋 Executive Summary
553
+ 본 보고서는 웹 검색을 통해 수집된 최신 사례와 감독자 AI의 전략적 지침을 바탕으로, 8주간의 체계적인 모델 최적화 프로젝트를 제시합니다. 목표는 모델 크기 90% 감소, 추론 속도 10배 향상, 운영 비용 70% 절감입니다.
554
+
555
+ ## 📊 1단계: 현재 모델 진단 및 베이스라인 설정 (1주차)
556
+
557
+ ### 실행 계획
558
+ **월-화요일: 성능 메트릭 수집**
559
+ - MLflow를 통한 현재 모델 전체 분석
560
+ - Netflix 사례 기반 핵심 지표: 정확도(92%), 지연시간(45ms), 처리량(1,000 req/s)
561
+ - ��소스 사용량: GPU 메모리 8GB, 추론 시 CPU 사용률 85%
562
+
563
+ **수-목요일: AutoML 초기 탐색**
564
+ - Optuna로 하이퍼파라미터 최적화 (200회 시도)
565
+ - Ray Tune으로 분산 학습 환경 구축
566
+ - 초기 개선 가능성: 15-20% 성능 향상 예상
567
+
568
+ **금요일: 진단 보고서 및 리스크 분석**
569
+ - 주요 병목: 모델 크기(2.5GB), 배치 처리 비효율성
570
+ - 리스크: 데이터 드리프트, 하드웨어 제약
571
+ - 백업 계획: 클라우드 GPU 인스턴스 확보
572
+
573
+ ### 예상 산출물
574
+ - 상세 성능 베이스라인 문서
575
+ - 개선 기회 우선순위 매트릭스
576
+ - 리스크 레지스터 및 대응 계획
577
+
578
+ ## 📊 2단계: 데이터 품질 개선 (2-3주차)
579
+
580
+ ### 실행 계획
581
+ **2주차: 데이터 정제 파이프라인**
582
+ ```python
583
+ # data_quality_pipeline.py 주요 구성
584
+ class DataQualityPipeline:
585
+ def __init__(self):
586
+ self.validators = [
587
+ MissingValueHandler(threshold=0.05),
588
+ OutlierDetector(method='isolation_forest'),
589
+ LabelConsistencyChecker(),
590
+ DataDriftMonitor()
591
+ ]
592
+
593
+ def process(self, data):
594
+ # 80% 규칙 적용: 데이터 품질이 성능의 80% 결정
595
+ for validator in self.validators:
596
+ data = validator.transform(data)
597
+ self.log_metrics(validator.get_stats())
598
+ return data
599
+ ```
600
+
601
+ **3주차: 고급 데이터 증강**
602
+ - MixUp: 15% 정확도 향상 예상
603
+ - CutMix: 경계 검출 성능 20% 개선
604
+ - AutoAugment: 자동 최적 증강 정책 탐색
605
+ - A/B 테스트: 각 기법별 효과 측정
606
+
607
+ ### 리스크 대응
608
+ - 데이터 품질 저하 시: 롤백 메커니즘 구현
609
+ - 증강 과적합 방지: 검증셋 분리 및 교차 검증
610
+
611
+ ### 예상 산출물
612
+ - 자동화된 데이터 품질 파이프라인
613
+ - 데이터 품질 대시보드 (Grafana)
614
+ - 15% 이상 성능 향상 검증 보고서
615
+
616
+ ## 📊 3단계: 모델 최적화 구현 (4-6주차)
617
+
618
+ ### 실행 계획
619
+ **4-5주차: Knowledge Distillation**
620
+ - Teacher 모델: 현재 2.5GB 모델
621
+ - Student 모델 아키텍처:
622
+ * 파라미터 수: 250M → 25M (90% 감소)
623
+ * 레이어 수: 24 → 6
624
+ * Hidden dimension: 1024 → 256
625
+ - 훈련 전략:
626
+ * Temperature: 5.0
627
+ * Alpha (KD loss weight): 0.7
628
+ * 훈련 에폭: 50
629
+
630
+ **6주차: Pruning & Quantization**
631
+ - 구조적 Pruning:
632
+ * Magnitude 기반 50% 채널 제거
633
+ * Fine-tuning: 10 에폭
634
+ - INT8 Quantization:
635
+ * Post-training quantization
636
+ * Calibration dataset: 1,000 샘플
637
+ - TensorRT 최적화 (Tesla 사례 적용):
638
+ * FP16 추론 활성화
639
+ * 동적 배치 최적화
640
+
641
+ ### 팀 협업 체계
642
+ - ML 엔지니어: 모델 아키텍처 및 훈련
643
+ - DevOps: 인프라 및 배포 파이프라인
644
+ - 데이터 과학자: 성능 분석 및 검증
645
+ - 주간 스탠드업 미팅 및 Jira 이슈 트래킹
646
+
647
+ ### 예상 산출물
648
+ - 최적화된 모델 체크포인트
649
+ - 성능 벤치마크 상세 보고서
650
+ - 모델 변환 자동화 스크립트
651
+
652
+ ## 📊 4단계: 성과 검증 및 프로덕션 배포 (7-8주차)
653
+
654
+ ### 실행 계획
655
+ **7주차: 종합 성능 검증**
656
+ - 성능 지표 달성도:
657
+ * 추론 속도: 45ms → 4.5ms (10배 향상) ✓
658
+ * 모델 크기: 2.5GB → 250MB (90% 감소) ✓
659
+ * 정확도 손실: 92% → 90.5% (1.5% 손실) ✓
660
+ - 비용 분석:
661
+ * GPU 인스턴스: $2,000/월 → $600/월
662
+ * 처리량 증가로 인한 서버 수 감소: 10대 → 3대
663
+ * 총 비용 절감: 70% 달성 ✓
664
+
665
+ **8주차: 단계적 배포**
666
+ - Canary 배포:
667
+ * 1일차: 1% 트래픽
668
+ * 3일차: 10% 트래픽
669
+ * 7일차: 50% 트래픽
670
+ * 14일차: 100% 전환
671
+ - 모니터링 설정:
672
+ * Prometheus + Grafana 대시보드
673
+ * 알림 임계값: 지연시간 >10ms, 오류율 >0.1%
674
+ - 롤백 계획:
675
+ * 자동 롤백 트리거 설정
676
+ * Blue-Green 배포로 즉시 전환 가능
677
+
678
+ ### ROI 분석
679
+ - 초기 투자: $50,000 (인건비 + 인프라)
680
+ - 월간 절감액: $14,000
681
+ - 투자 회수 기간: 3.6개월
682
+ - 1년 순이익: $118,000
683
+
684
+ ### 예상 산출물
685
+ - 프로덕션 배포 완료
686
+ - 실시간 모니터링 대시보드
687
+ - ROI 분석 보고서
688
+ - 운영 가이드 문서
689
+
690
+ ## 📈 지속적 개선 계획
691
+
692
+ ### 모니터링 및 유지보수
693
+ - 월간 성능 리뷰 미팅
694
+ - 분기별 재훈련 계획
695
+ - 신기술 도입 검토 (Sparse Models, MoE)
696
+
697
+ ### 지식 공유
698
+ - 내부 기술 세미나 (월 1회)
699
+ - 외부 컨퍼런스 발표 준비
700
+ - 오픈소스 기여 계획
701
+
702
+ ### 차기 프로젝트
703
+ - 엣지 디바이스 배포 최적화
704
+ - 연합 학습(Federated Learning) 도입
705
+ - AutoML 플랫폼 구축
706
+
707
+ ## 📝 결론
708
+ 본 프로젝트는 최신 연구 결과와 업계 베스트 프랙티스를 적용하여, 8주 만에 모델 성능을 획기적으로 개선하고 운영 비용을 70% 절감하는 성과를 달성할 것으로 예상됩니다. 체계적인 접근과 리스크 관리, 그리고 지속적인 개선 계획을 통해 장기적인 경쟁력을 확보할 수 있습니다.
709
+
710
+ ---
711
+ *작성일: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*
712
+ *작성자: 협력적 AI 시스템 (감���자, 조사자, 실행자 AI)*"""
713
+ }
714
+
715
+ # 프롬프트 내용에 따라 적절한 응답 선택
716
+ if role == "supervisor" and "조사자 AI가 정리한" in messages[0]["content"]:
717
+ response = test_responses["supervisor_execution"]
718
+ elif role == "supervisor" and messages[0]["content"].find("실행자 AI의 답변") > -1:
719
+ response = test_responses["supervisor_review"]
720
+ elif role == "supervisor":
721
+ response = test_responses["supervisor_initial"]
722
+ elif role == "researcher":
723
+ response = test_responses["researcher"]
724
+ elif role == "executor" and "최종 보고서" in messages[0]["content"]:
725
+ response = test_responses["executor_final"]
726
+ else:
727
+ response = test_responses["executor"]
728
+
729
+ yield from self.simulate_streaming(response, role)
730
+ return
731
+
732
+ # 실제 API 호출
733
+ try:
734
+ system_prompts = {
735
+ "supervisor": "당신은 거시적 관점에서 분석하고 지도하는 감독자 AI입니다.",
736
+ "researcher": "당신은 정보를 조사하고 체계적으로 정리하는 조사자 AI입니다.",
737
+ "executor": "당신은 세부적인 내용을 구현하는 실행자 AI입니다."
738
+ }
739
+
740
+ full_messages = [
741
+ {"role": "system", "content": system_prompts.get(role, "")},
742
+ *messages
743
+ ]
744
+
745
+ payload = {
746
+ "model": self.model_id,
747
+ "messages": full_messages,
748
+ "max_tokens": 2048,
749
+ "temperature": 0.7,
750
+ "top_p": 0.8,
751
+ "stream": True,
752
+ "stream_options": {"include_usage": True}
753
+ }
754
+
755
+ logger.info(f"API 스트리밍 호출 시작 - Role: {role}")
756
+
757
+ response = requests.post(
758
+ self.api_url,
759
+ headers=self.create_headers(),
760
+ json=payload,
761
+ stream=True,
762
+ timeout=10
763
+ )
764
+
765
+ if response.status_code != 200:
766
+ logger.error(f"API 오류: {response.status_code}")
767
+ yield f"❌ API 오류 ({response.status_code}): {response.text[:200]}"
768
+ return
769
+
770
+ for line in response.iter_lines():
771
+ if line:
772
+ line = line.decode('utf-8')
773
+ if line.startswith("data: "):
774
+ data = line[6:]
775
+ if data == "[DONE]":
776
+ break
777
+ try:
778
+ chunk = json.loads(data)
779
+ if "choices" in chunk and chunk["choices"]:
780
+ content = chunk["choices"][0].get("delta", {}).get("content", "")
781
+ if content:
782
+ yield content
783
+ except json.JSONDecodeError:
784
+ continue
785
+
786
+ except requests.exceptions.Timeout:
787
+ yield "⏱️ API 호출 시간이 초과되었습니다. 다시 시도해주세요."
788
+ except requests.exceptions.ConnectionError:
789
+ yield "🔌 API 서버에 연결할 수 없습니다. 인터넷 연결을 확인해주세요."
790
+ except Exception as e:
791
+ logger.error(f"스트리밍 중 오류: {str(e)}")
792
+ yield f"❌ 오류 발생: {str(e)}"
793
+
794
+ # 시스템 인스턴스 생성
795
+ llm_system = LLMCollaborativeSystem()
796
+
797
+ # 내부 히스토리 관리 (UI에는 표시하지 않음)
798
+ internal_history = []
799
+
800
+ def process_query_streaming(user_query: str):
801
+ """스트리밍을 지원하는 쿼리 처리"""
802
+ global internal_history
803
+
804
+ if not user_query:
805
+ return "", "", "", "", "❌ 질문을 입력해주세요."
806
+
807
+ conversation_log = []
808
+ all_responses = {"supervisor": [], "researcher": [], "executor": []}
809
+
810
+ try:
811
+ # 1단계: 감독자 AI 초기 분석 및 키워드 추출
812
+ supervisor_prompt = llm_system.create_supervisor_initial_prompt(user_query)
813
+ supervisor_initial_response = ""
814
+
815
+ supervisor_text = "[초기 분석] 🔄 생성 중...\n"
816
+ for chunk in llm_system.call_llm_streaming(
817
+ [{"role": "user", "content": supervisor_prompt}],
818
+ "supervisor"
819
+ ):
820
+ supervisor_initial_response += chunk
821
+ supervisor_text = f"[초기 분석] - {datetime.now().strftime('%H:%M:%S')}\n{supervisor_initial_response}"
822
+ yield supervisor_text, "", "", "", "🔄 감독자 AI가 분석 중..."
823
+
824
+ all_responses["supervisor"].append(supervisor_initial_response)
825
+
826
+ # 키워드 추출
827
+ keywords = llm_system.extract_keywords(supervisor_initial_response)
828
+ logger.info(f"추출된 키워드: {keywords}")
829
+
830
+ # 2단계: 브레이브 검색 수행
831
+ researcher_text = "[웹 검색] 🔍 검색 중...\n"
832
+ yield supervisor_text, researcher_text, "", "", "🔍 웹 검색 수행 중..."
833
+
834
+ search_results = {}
835
+ total_search_count = 0
836
+
837
+ # 원래 키워드로 검색
838
+ for keyword in keywords:
839
+ results = llm_system.brave_search(keyword)
840
+ if results:
841
+ search_results[keyword] = results
842
+ total_search_count += len(results)
843
+ researcher_text += f"✓ '{keyword}' 검색 완료 ({len(results)}개 결과)\n"
844
+ yield supervisor_text, researcher_text, "", "", f"🔍 '{keyword}' 검색 중..."
845
+
846
+ # 동의어로 추가 검색
847
+ synonyms = llm_system.generate_synonyms(keyword)
848
+ for synonym in synonyms:
849
+ syn_results = llm_system.brave_search(f"{keyword} {synonym}")
850
+ if syn_results:
851
+ search_results[f"{keyword} ({synonym})"] = syn_results
852
+ total_search_count += len(syn_results)
853
+ researcher_text += f"✓ 동의어 '{synonym}' 검색 완료 ({len(syn_results)}개 결과)\n"
854
+ yield supervisor_text, researcher_text, "", "", f"🔍 동의어 '{synonym}' 검색 중..."
855
+
856
+ researcher_text += f"\n📊 총 {total_search_count}개의 검색 결과 수집 완료\n"
857
+
858
+ # URL 콘텐츠 가져오기 (상위 3개)
859
+ researcher_text += "\n[콘텐츠 분석] 📖 주요 웹페이지 내용 분석 중...\n"
860
+ yield supervisor_text, researcher_text, "", "", "📖 웹페이지 내용 분석 중..."
861
+
862
+ content_analyzed = 0
863
+ for keyword, results in search_results.items():
864
+ for result in results[:2]: # 각 키워드당 상위 2개만
865
+ if content_analyzed >= 5: # 총 5개까지만
866
+ break
867
+
868
+ url = result.get('url', '')
869
+ if url and result.get('credibility_score', 0) >= 0.7:
870
+ content = llm_system.fetch_url_content(url)
871
+ if content:
872
+ result['content_preview'] = content[:500] # 미리보기 저장
873
+ content_analyzed += 1
874
+ researcher_text += f"✓ 콘텐츠 분석 완료: {url[:50]}...\n"
875
+ yield supervisor_text, researcher_text, "", "", f"📖 분석 중: {url[:30]}..."
876
+
877
+ # 3단계: 조사자 AI가 검색 결과 정리
878
+ researcher_prompt = llm_system.create_researcher_prompt(user_query, supervisor_initial_response, search_results)
879
+ researcher_response = ""
880
+
881
+ researcher_text = "[조사 결과 정리] 🔄 생성 중...\n"
882
+ for chunk in llm_system.call_llm_streaming(
883
+ [{"role": "user", "content": researcher_prompt}],
884
+ "researcher"
885
+ ):
886
+ researcher_response += chunk
887
+ researcher_text = f"[조사 결과 정리] - {datetime.now().strftime('%H:%M:%S')}\n{researcher_response}"
888
+ yield supervisor_text, researcher_text, "", "", "📝 조사자 AI가 정리 중..."
889
+
890
+ all_responses["researcher"].append(researcher_response)
891
+
892
+ # 4단계: 감독자 AI가 조사 내용 기반으로 실행 지시
893
+ supervisor_execution_prompt = llm_system.create_supervisor_execution_prompt(user_query, researcher_response)
894
+ supervisor_execution_response = ""
895
+
896
+ supervisor_text += "\n\n---\n\n[실행 지시] 🔄 생성 중...\n"
897
+ for chunk in llm_system.call_llm_streaming(
898
+ [{"role": "user", "content": supervisor_execution_prompt}],
899
+ "supervisor"
900
+ ):
901
+ supervisor_execution_response += chunk
902
+ temp_text = f"{all_responses['supervisor'][0]}\n\n---\n\n[실행 지시] - {datetime.now().strftime('%H:%M:%S')}\n{supervisor_execution_response}"
903
+ supervisor_text = f"[초기 분석] - {datetime.now().strftime('%H:%M:%S')}\n{temp_text}"
904
+ yield supervisor_text, researcher_text, "", "", "🎯 감독자 AI가 지시 중..."
905
+
906
+ all_responses["supervisor"].append(supervisor_execution_response)
907
+
908
+ # 5단계: 실행자 AI가 조사 내용과 지시를 기반으로 초기 구현
909
+ executor_prompt = llm_system.create_executor_prompt(user_query, supervisor_execution_response, researcher_response)
910
+ executor_response = ""
911
+
912
+ executor_text = "[초기 구현] 🔄 생성 중...\n"
913
+ for chunk in llm_system.call_llm_streaming(
914
+ [{"role": "user", "content": executor_prompt}],
915
+ "executor"
916
+ ):
917
+ executor_response += chunk
918
+ executor_text = f"[초기 구현] - {datetime.now().strftime('%H:%M:%S')}\n{executor_response}"
919
+ yield supervisor_text, researcher_text, executor_text, "", "🔧 실행자 AI가 구현 중..."
920
+
921
+ all_responses["executor"].append(executor_response)
922
+
923
+ # 6단계: 감독자 AI 검토 및 피드백
924
+ review_prompt = f"""당신은 거시적 관점에서 분석하고 지도하는 감독자 AI입니다.
925
+
926
+ 사용자 질문: {user_query}
927
+
928
+ 실행자 AI의 답변:
929
+ {executor_response}
930
+
931
+ 이 답변을 검토하고 개선점과 추가 고려사항을 제시해주세요. 구체적이고 실행 가능한 개선 방안을 제시하세요."""
932
+
933
+ review_response = ""
934
+ supervisor_text = f"[초기 분석] - {datetime.now().strftime('%H:%M:%S')}\n{all_responses['supervisor'][0]}\n\n---\n\n[실행 지시] - {datetime.now().strftime('%H:%M:%S')}\n{all_responses['supervisor'][1]}\n\n---\n\n[검토 및 피드백] 🔄 생성 중...\n"
935
+
936
+ for chunk in llm_system.call_llm_streaming(
937
+ [{"role": "user", "content": review_prompt}],
938
+ "supervisor"
939
+ ):
940
+ review_response += chunk
941
+ temp_text = f"{all_responses['supervisor'][0]}\n\n---\n\n[실행 지시] - {datetime.now().strftime('%H:%M:%S')}\n{all_responses['supervisor'][1]}\n\n---\n\n[검토 및 피드백] - {datetime.now().strftime('%H:%M:%S')}\n{review_response}"
942
+ supervisor_text = f"[초기 분석] - {datetime.now().strftime('%H:%M:%S')}\n{temp_text}"
943
+ yield supervisor_text, researcher_text, executor_text, "", "🔄 감독자 AI가 검토 중..."
944
+
945
+ all_responses["supervisor"].append(review_response)
946
+
947
+ # 7단계: 실행자 AI 최종 보고서 (피드백 반영)
948
+ final_executor_prompt = llm_system.create_executor_final_prompt(
949
+ user_query,
950
+ executor_response,
951
+ review_response,
952
+ researcher_response
953
+ )
954
+ final_executor_response = ""
955
+
956
+ executor_text += "\n\n---\n\n[최종 보고서] 🔄 작성 중...\n"
957
+ for chunk in llm_system.call_llm_streaming(
958
+ [{"role": "user", "content": final_executor_prompt}],
959
+ "executor"
960
+ ):
961
+ final_executor_response += chunk
962
+ temp_text = f"[초기 구현] - {datetime.now().strftime('%H:%M:%S')}\n{all_responses['executor'][0]}\n\n---\n\n[최종 보고서] - {datetime.now().strftime('%H:%M:%S')}\n{final_executor_response}"
963
+ executor_text = temp_text
964
+ yield supervisor_text, researcher_text, executor_text, "", "📄 최종 보고서 작성 중..."
965
+
966
+ all_responses["executor"].append(final_executor_response)
967
+
968
+ # 최종 결과 생성 (최종 보고서를 메인으로)
969
+ final_summary = f"""## 🎯 최종 종합 보고서
970
+
971
+ ### 📌 사용자 질문
972
+ {user_query}
973
+
974
+ ### 📄 최종 보고서 (실행자 AI - 피드백 반영)
975
+ {final_executor_response}
976
+
977
+ ---
978
+
979
+ <details>
980
+ <summary>📋 전체 협력 과정 보기</summary>
981
+
982
+ #### 🔍 거시적 분석 (감독자 AI)
983
+ {all_responses['supervisor'][0]}
984
+
985
+ #### 📚 조사 결과 (조사자 AI)
986
+ {researcher_response}
987
+
988
+ #### 🎯 실행 지시 (감독자 AI)
989
+ {all_responses['supervisor'][1]}
990
+
991
+ #### 💡 초기 구현 (실행자 AI)
992
+ {executor_response}
993
+
994
+ #### ✨ 검토 및 개선사항 (감독자 AI)
995
+ {review_response}
996
+
997
+ </details>
998
+
999
+ ---
1000
+ *이 보고서는 웹 검색을 통한 최신 정보와 AI들의 협력, 그리고 피드백 반영을 통해 작성되었습니다.*"""
1001
+
1002
+ # 내부 히스토리 업데이트 (UI에는 표시하지 않음)
1003
+ internal_history.append((user_query, final_summary))
1004
+
1005
+ yield supervisor_text, researcher_text, executor_text, final_summary, "✅ 최종 보고서 완성!"
1006
+
1007
+ except Exception as e:
1008
+ error_msg = f"❌ 처리 중 오류: {str(e)}"
1009
+ yield "", "", "", error_msg, error_msg
1010
+
1011
+ def clear_all():
1012
+ """모든 내용 초기화"""
1013
+ global internal_history
1014
+ internal_history = []
1015
+ return "", "", "", "", "🔄 초기화되었습니다."
1016
+
1017
+ # Gradio 인터페이스
1018
+ css = """
1019
+ .gradio-container {
1020
+ font-family: 'Arial', sans-serif;
1021
+ }
1022
+ .supervisor-box textarea {
1023
+ border-left: 4px solid #667eea !important;
1024
+ padding-left: 10px !important;
1025
+ }
1026
+ .researcher-box textarea {
1027
+ border-left: 4px solid #10b981 !important;
1028
+ padding-left: 10px !important;
1029
+ }
1030
+ .executor-box textarea {
1031
+ border-left: 4px solid #764ba2 !important;
1032
+ padding-left: 10px !important;
1033
+ }
1034
+ """
1035
+
1036
+ with gr.Blocks(title="협력적 LLM 시스템", theme=gr.themes.Soft(), css=css) as app:
1037
+ gr.Markdown(
1038
+ f"""
1039
+ # 🤝 협력적 LLM 시스템 (조사자 포함 + 피드백 반영)
1040
+
1041
+ > 감독자, 조사자, 실행자 AI가 협력하여 피드백을 반영한 완전한 보고서를 작성합니다.
1042
+
1043
+ **상태**:
1044
+ - LLM: {'🟢 실제 모드' if not llm_system.test_mode else '🟡 테스트 모드'}
1045
+ - Brave Search: {'🟢 활성화' if llm_system.bapi_token != "YOUR_BRAVE_API_TOKEN" else '🟡 테스트 모드'}
1046
+
1047
+ **7단계 협력 프로세스:**
1048
+ 1. 🧠 **감독자**: 거시적 분석 및 검색 키워드 추출
1049
+ 2. 🔍 **조사자**: 브레이브 검색으로 최신 정보 수집
1050
+ 3. 🧠 **감독자**: 조사 내용 기반 구체적 실행 지시
1051
+ 4. 👁️ **실행자**: 초기 실행 계획 작성
1052
+ 5. 🧠 **감독자**: 검토 및 개선사항 피드백
1053
+ 6. 👁️ **실행자**: 피드백 반영한 최종 보고서 작성
1054
+ 7. 📄 **최종 산출물**: 완전한 실행 보고서
1055
+ """
1056
+ )
1057
+
1058
+ # 입력 섹션
1059
+ with gr.Row():
1060
+ with gr.Column():
1061
+ gr.Markdown("""
1062
+ ## 🚀 강화된 조사 기능
1063
+ - **20개 검색 결과**: 더 많은 정보 수집
1064
+ - **동의어 검색**: 관련 정보 확장 탐색
1065
+ - **신뢰도 점수**: 0-1 점수로 출처 평가
1066
+ - **웹페이지 분석**: 주요 URL 콘텐츠 직접 확인
1067
+ - **모순 감지**: 상충하는 정보 자동 식별
1068
+ """)
1069
+
1070
+ user_input = gr.Textbox(
1071
+ label="질문 입력",
1072
+ placeholder="예: 기계학습 모델의 성능을 향상시키는 방법은?",
1073
+ lines=3
1074
+ )
1075
+
1076
+ with gr.Row():
1077
+ submit_btn = gr.Button("🚀 분석 시작", variant="primary", scale=2)
1078
+ clear_btn = gr.Button("🗑️ 초기화", scale=1)
1079
+
1080
+ status_text = gr.Textbox(
1081
+ label="상태",
1082
+ interactive=False,
1083
+ value="대기 중...",
1084
+ max_lines=1
1085
+ )
1086
+
1087
+ # 최종 결과
1088
+ with gr.Row():
1089
+ with gr.Column():
1090
+ with gr.Accordion("📊 최종 종합 결과", open=True):
1091
+ final_output = gr.Markdown(
1092
+ value="*질문을 입력하면 결과가 여기에 표시됩니다.*"
1093
+ )
1094
+
1095
+ # AI 출력들 - 한 줄에 나란히 배치
1096
+ with gr.Row():
1097
+ # 감독자 AI 출력
1098
+ with gr.Column():
1099
+ gr.Markdown("### 🧠 감독자 AI (거시적 분석)")
1100
+ supervisor_output = gr.Textbox(
1101
+ label="",
1102
+ lines=20,
1103
+ max_lines=25,
1104
+ interactive=False,
1105
+ elem_classes=["supervisor-box"]
1106
+ )
1107
+
1108
+ # 조사자 AI 출력
1109
+ with gr.Column():
1110
+ gr.Markdown("### 🔍 조사자 AI (웹 검색 & 정리)")
1111
+ researcher_output = gr.Textbox(
1112
+ label="",
1113
+ lines=20,
1114
+ max_lines=25,
1115
+ interactive=False,
1116
+ elem_classes=["researcher-box"]
1117
+ )
1118
+
1119
+ # 실행자 AI 출력
1120
+ with gr.Column():
1121
+ gr.Markdown("### 👁️ 실행자 AI (미시적 구현)")
1122
+ executor_output = gr.Textbox(
1123
+ label="",
1124
+ lines=20,
1125
+ max_lines=25,
1126
+ interactive=False,
1127
+ elem_classes=["executor-box"]
1128
+ )
1129
+
1130
+ # 예제
1131
+ gr.Examples(
1132
+ examples=[
1133
+ "기계학습 모델의 성능을 향상시키는 최신 방법은?",
1134
+ "2024년 효과적인 프로젝트 관리 도구와 전략은?",
1135
+ "지속 가능한 비즈니스 모델의 최신 트렌드는?",
1136
+ "최신 데이터 시각화 도구와 기법은?",
1137
+ "원격 팀의 생산성을 높이는 검증된 방법은?"
1138
+ ],
1139
+ inputs=user_input,
1140
+ label="💡 예제 질문"
1141
+ )
1142
+
1143
+ # 이벤트 핸들러
1144
+ submit_btn.click(
1145
+ fn=process_query_streaming,
1146
+ inputs=[user_input],
1147
+ outputs=[supervisor_output, researcher_output, executor_output, final_output, status_text]
1148
+ ).then(
1149
+ fn=lambda: "",
1150
+ outputs=[user_input]
1151
+ )
1152
+
1153
+ user_input.submit(
1154
+ fn=process_query_streaming,
1155
+ inputs=[user_input],
1156
+ outputs=[supervisor_output, researcher_output, executor_output, final_output, status_text]
1157
+ ).then(
1158
+ fn=lambda: "",
1159
+ outputs=[user_input]
1160
+ )
1161
+
1162
+ clear_btn.click(
1163
+ fn=clear_all,
1164
+ outputs=[supervisor_output, researcher_output, executor_output, final_output, status_text]
1165
+ )
1166
+
1167
+ gr.Markdown(
1168
+ """
1169
+ ---
1170
+ ### 📝 사용 방법
1171
+ 1. 질문을 입력하고 Enter 또는 '분석 시작' 버튼을 클릭하세요.
1172
+ 2. 7단계 협력 프로세스가 진행됩니다:
1173
+ - 감독자 초기 분석 → 웹 검색 → 조사 정리 → 실행 지시 → 초기 구현 → 피드백 → 최종 보고서
1174
+ 3. 각 AI의 작업 과정을 실시간으로 확인할 수 있습니다.
1175
+ 4. 최종 보고서가 상단에 표시되며, 전체 협력 과정은 접을 수 있는 형태로 제공됩니다.
1176
+
1177
+ ### ⚙️ 환경 설정
1178
+ - **필수 패키지 설치**: `pip install gradio requests beautifulsoup4`
1179
+ - **LLM API**: `export FRIENDLI_TOKEN="your_token"`
1180
+ - **Brave Search API**: `export BAPI_TOKEN="your_brave_api_token"`
1181
+ - **테스트 모드**: `export TEST_MODE=true` (API 없이 작동)
1182
+
1183
+ ### 🔗 API 키 획득
1184
+ - Friendli API: [https://friendli.ai](https://friendli.ai)
1185
+ - Brave Search API: [https://brave.com/search/api/](https://brave.com/search/api/)
1186
+
1187
+ ### 💡 특징
1188
+ - 완전한 피드백 루프: 감독자의 피드백이 실행자에게 전달되어 최종 개선
1189
+ - 웹 검색 기반: 최신 정보와 사례를 활용한 실용적 답변
1190
+ - 전문 보고서 형식: 실무에서 바로 활용 가능한 구조화된 결과물
1191
+ """
1192
+ )
1193
+
1194
+ if __name__ == "__main__":
1195
+ app.queue() # 스트리밍을 위한 큐 활성화
1196
+ app.launch(
1197
+ server_name="0.0.0.0",
1198
+ server_port=7860,
1199
+ share=True,
1200
+ show_error=True
1201
+ )