aiqtech commited on
Commit
1090499
ยท
verified ยท
1 Parent(s): efa312a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +241 -173
app.py CHANGED
@@ -1,15 +1,18 @@
1
  """
2
- Multi-Agent RAG-Enhanced LLM System for Hugging Face Spaces
3
  ๊ฐ๋…์ž(Supervisor) -> ์ฐฝ์˜์„ฑ ์ƒ์„ฑ์ž(Creative) -> ๋น„ํ‰์ž(Critic) -> ๊ฐ๋…์ž(Final)
4
- 4๋‹จ๊ณ„ ํŒŒ์ดํ”„๋ผ์ธ์„ ํ†ตํ•œ ๊ณ ํ’ˆ์งˆ ๋‹ต๋ณ€ ์ƒ์„ฑ ์‹œ์Šคํ…œ
5
  """
6
 
7
  import os
8
  import json
9
  import time
10
- from typing import Optional, List, Dict, Any, Tuple
 
11
  from datetime import datetime
12
  from enum import Enum
 
 
13
 
14
  import requests
15
  import gradio as gr
@@ -43,11 +46,10 @@ class AgentResponse(BaseModel):
43
  metadata: Optional[Dict] = None
44
 
45
 
46
- class FinalResponse(BaseModel):
47
- final_answer: str
48
- agent_responses: List[AgentResponse]
49
- search_results: Optional[List[Dict]] = None
50
- processing_time: float
51
 
52
 
53
  # ============================================================================
@@ -107,7 +109,7 @@ class BraveSearchClient:
107
 
108
 
109
  # ============================================================================
110
- # Fireworks LLM ํด๋ผ์ด์–ธํŠธ
111
  # ============================================================================
112
 
113
  class FireworksClient:
@@ -124,14 +126,15 @@ class FireworksClient:
124
  }
125
 
126
  def chat(self, messages: List[Dict], **kwargs) -> str:
127
- """LLM๊ณผ ๋Œ€ํ™”"""
128
  payload = {
129
  "model": kwargs.get("model", "accounts/fireworks/models/qwen3-235b-a22b-instruct-2507"),
130
  "messages": messages,
131
  "max_tokens": kwargs.get("max_tokens", 4096),
132
  "temperature": kwargs.get("temperature", 0.7),
133
  "top_p": kwargs.get("top_p", 1.0),
134
- "top_k": kwargs.get("top_k", 40)
 
135
  }
136
 
137
  try:
@@ -150,14 +153,55 @@ class FireworksClient:
150
 
151
  except Exception as e:
152
  return f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
 
154
 
155
  # ============================================================================
156
- # ๋ฉ€ํ‹ฐ ์—์ด์ „ํŠธ ์‹œ์Šคํ…œ
157
  # ============================================================================
158
 
159
- class MultiAgentSystem:
160
- """4๋‹จ๊ณ„ ๋ฉ€ํ‹ฐ ์—์ด์ „ํŠธ ์ฒ˜๋ฆฌ ์‹œ์Šคํ…œ"""
161
 
162
  def __init__(self, llm_client: FireworksClient, search_client: BraveSearchClient):
163
  self.llm = llm_client
@@ -176,13 +220,7 @@ class MultiAgentSystem:
176
  1. ์งˆ๋ฌธ์˜ ํ•ต์‹ฌ ์˜๋„ ํŒŒ์•…
177
  2. ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ์—์„œ ํ•ต์‹ฌ ์ •๋ณด ์ถ”์ถœ
178
  3. ๋‹ต๋ณ€์ด ํฌํ•จํ•ด์•ผ ํ•  ์ฃผ์š” ์š”์†Œ๋“ค ์ •์˜
179
- 4. ๋…ผ๋ฆฌ์  ํ๋ฆ„๊ณผ ๊ตฌ์กฐ ์ œ์‹œ
180
-
181
- ์ถœ๋ ฅ ํ˜•์‹:
182
- - ์งˆ๋ฌธ ๋ถ„์„: [ํ•ต์‹ฌ ์˜๋„]
183
- - ์ฃผ์š” ํฌํ•จ ์‚ฌํ•ญ: [ํ•ญ๋ชฉ๋“ค]
184
- - ๋‹ต๋ณ€ ๊ตฌ์กฐ: [๋…ผ๋ฆฌ์  ํ๋ฆ„]
185
- - ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ํ™œ์šฉ ๋ฐฉ์•ˆ: [์–ด๋–ค ์ •๋ณด๋ฅผ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ• ์ง€]"""
186
  },
187
 
188
  AgentRole.CREATIVE: {
@@ -194,13 +232,7 @@ class MultiAgentSystem:
194
  1. ๊ฐ๋…์ž์˜ ๊ตฌ์กฐ๋ฅผ ๋”ฐ๋ฅด๋˜ ์ฐฝ์˜์ ์œผ๋กœ ํ™•์žฅ
195
  2. ์˜ˆ์‹œ, ๋น„์œ , ์Šคํ† ๋ฆฌํ…”๋ง ํ™œ์šฉ
196
  3. ์‚ฌ์šฉ์ž ๊ด€์ ์—์„œ ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šด ์„ค๋ช… ์ถ”๊ฐ€
197
- 4. ์‹ค์šฉ์ ์ด๊ณ  ๊ตฌ์ฒด์ ์ธ ์กฐ์–ธ ํฌํ•จ
198
- 5. ๋…์ฐฝ์ ์ธ ๊ด€์ ๊ณผ ํ†ต์ฐฐ ์ œ๊ณต
199
-
200
- ์ฃผ์˜์‚ฌํ•ญ:
201
- - ์ •ํ™•์„ฑ์„ ํ•ด์น˜์ง€ ์•Š๋Š” ์„ ์—์„œ ์ฐฝ์˜์„ฑ ๋ฐœํœ˜
202
- - ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ์ฐฝ์˜์ ์œผ๋กœ ์žฌ๊ตฌ์„ฑ
203
- - ์‚ฌ์šฉ์ž ์ฐธ์—ฌ๋ฅผ ์œ ๋„ํ•˜๋Š” ๋‚ด์šฉ ํฌํ•จ"""
204
  },
205
 
206
  AgentRole.CRITIC: {
@@ -208,24 +240,11 @@ class MultiAgentSystem:
208
  "system_prompt": """๋‹น์‹ ์€ ๋น„ํ‰์ž ์—์ด์ „ํŠธ์ž…๋‹ˆ๋‹ค.
209
  ์ฐฝ์˜์„ฑ ์ƒ์„ฑ์ž์˜ ๋‹ต๋ณ€์„ ๊ฒ€ํ† ํ•˜๊ณ  ๊ฐœ์„ ์ ์„ ์ œ์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
210
 
211
- ์—ญํ• :
212
- 1. ์‚ฌ์‹ค ๊ด€๊ณ„ ๊ฒ€์ฆ
213
- 2. ๋…ผ๋ฆฌ์  ์ผ๊ด€์„ฑ ํ™•์ธ
214
- 3. ์˜คํ•ด์˜ ์†Œ์ง€๊ฐ€ ์žˆ๋Š” ํ‘œํ˜„ ์ง€์ 
215
- 4. ๋ˆ„๋ฝ๋œ ์ค‘์š” ์ •๋ณด ํ™•์ธ
216
- 5. ๊ฐœ์„  ๋ฐฉํ–ฅ ๊ตฌ์ฒด์  ์ œ์‹œ
217
-
218
  ํ‰๊ฐ€ ๊ธฐ์ค€:
219
  - ์ •ํ™•์„ฑ: ์‚ฌ์‹ค๊ณผ ๋ฐ์ดํ„ฐ์˜ ์ •ํ™•์„ฑ
220
  - ์™„์ „์„ฑ: ์งˆ๋ฌธ์— ๋Œ€ํ•œ ์ถฉ๋ถ„ํ•œ ๋‹ต๋ณ€ ์—ฌ๋ถ€
221
  - ๋ช…ํ™•์„ฑ: ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šด ์„ค๋ช…์ธ์ง€
222
- - ์œ ์šฉ์„ฑ: ์‹ค์ œ๋กœ ๋„์›€์ด ๋˜๋Š” ์ •๋ณด์ธ์ง€
223
- - ์‹ ๋ขฐ์„ฑ: ๊ฒ€์ฆ ๊ฐ€๋Šฅํ•œ ์ถœ์ฒ˜ ํฌํ•จ ์—ฌ๋ถ€
224
-
225
- ์ถœ๋ ฅ ํ˜•์‹:
226
- โœ… ๊ธ์ •์  ์ธก๋ฉด: [์ž˜๋œ ์ ๋“ค]
227
- โš ๏ธ ๊ฐœ์„  ํ•„์š”: [๋ฌธ์ œ์ ๊ณผ ๊ฐœ์„  ๋ฐฉ์•ˆ]
228
- ๐Ÿ’ก ์ถ”๊ฐ€ ์ œ์•ˆ: [๋ณด์™„ํ•  ๋‚ด์šฉ]"""
229
  },
230
 
231
  AgentRole.FINALIZER: {
@@ -233,24 +252,11 @@ class MultiAgentSystem:
233
  "system_prompt": """๋‹น์‹ ์€ ์ตœ์ข… ๊ฐ๋…์ž์ž…๋‹ˆ๋‹ค.
234
  ๋ชจ๋“  ์—์ด์ „ํŠธ์˜ ์˜๊ฒฌ์„ ์ข…ํ•ฉํ•˜์—ฌ ์ตœ์ข… ๋‹ต๋ณ€์„ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
235
 
236
- ์—ญํ• :
237
- 1. ์ฐฝ์˜์„ฑ ์ƒ์„ฑ์ž์˜ ๋‹ต๋ณ€์„ ๊ธฐ๋ฐ˜์œผ๋กœ
238
- 2. ๋น„ํ‰์ž์˜ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ˜์˜ํ•˜์—ฌ
239
- 3. ๊ฐ๋…์ž์˜ ์ดˆ๊ธฐ ๊ตฌ์กฐ๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ
240
- 4. ๋…ผ๋ฆฌ์ ์ด๊ณ  ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šด ์ตœ์ข… ๋‹ต๋ณ€ ์ƒ์„ฑ
241
-
242
  ์ตœ์ข… ๋‹ต๋ณ€ ๊ธฐ์ค€:
243
  - ์ •ํ™•์„ฑ๊ณผ ์ฐฝ์˜์„ฑ์˜ ๊ท ํ˜•
244
  - ๋ช…ํ™•ํ•œ ๊ตฌ์กฐ์™€ ๋…ผ๋ฆฌ์  ํ๋ฆ„
245
  - ์‹ค์šฉ์ ์ด๊ณ  ์œ ์šฉํ•œ ์ •๋ณด
246
- - ์‚ฌ์šฉ์ž ์นœํ™”์ ์ธ ํ†ค
247
- - ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์ถœ์ฒ˜ ๋ช…์‹œ
248
-
249
- ๋ฐ˜๋“œ์‹œ ํฌํ•จํ•  ์š”์†Œ:
250
- 1. ํ•ต์‹ฌ ๋‹ต๋ณ€ (์ง์ ‘์ ์ธ ์‘๋‹ต)
251
- 2. ์ƒ์„ธ ์„ค๋ช… (๋ฐฐ๊ฒฝ๊ณผ ๋งฅ๋ฝ)
252
- 3. ์‹ค์šฉ์  ์กฐ์–ธ (ํ•ด๋‹น ์‹œ)
253
- 4. ์ฐธ๊ณ  ์ž๋ฃŒ (๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๊ธฐ๋ฐ˜)"""
254
  }
255
  }
256
 
@@ -265,24 +271,46 @@ class MultiAgentSystem:
265
  [๊ฒ€์ƒ‰๊ฒฐ๊ณผ {i}]
266
  ์ œ๋ชฉ: {result.get('title', 'N/A')}
267
  URL: {result.get('url', 'N/A')}
268
- ๋‚ด์šฉ: {result.get('description', 'N/A')}
269
- ๊ฒŒ์‹œ: {result.get('age', 'N/A')}""")
270
 
271
  return "\n".join(formatted)
272
 
273
- def process_with_agents(
274
  self,
275
  query: str,
276
  search_results: List[Dict],
277
- config: Dict
278
- ) -> FinalResponse:
279
- """๋ฉ€ํ‹ฐ ์—์ด์ „ํŠธ ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰"""
 
280
 
281
- start_time = time.time()
282
- agent_responses = []
283
  search_context = self._format_search_results(search_results)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
 
285
- # 1๋‹จ๊ณ„: ๊ฐ๋…์ž - ๋ฐฉํ–ฅ์„ฑ ์ œ์‹œ
286
  supervisor_prompt = f"""
287
  ์‚ฌ์šฉ์ž ์งˆ๋ฌธ: {query}
288
 
@@ -291,21 +319,29 @@ URL: {result.get('url', 'N/A')}
291
 
292
  ์œ„ ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๋‹ต๋ณ€์˜ ๋ฐฉํ–ฅ์„ฑ๊ณผ ๊ตฌ์กฐ๋ฅผ ์ œ์‹œํ•˜์„ธ์š”."""
293
 
294
- supervisor_response = self.llm.chat(
 
295
  messages=[
296
  {"role": "system", "content": self.agent_configs[AgentRole.SUPERVISOR]["system_prompt"]},
297
  {"role": "user", "content": supervisor_prompt}
298
  ],
299
  temperature=self.agent_configs[AgentRole.SUPERVISOR]["temperature"],
300
  max_tokens=config.get("max_tokens", 1000)
301
- )
 
 
 
 
 
 
302
 
303
- agent_responses.append(AgentResponse(
304
- role=AgentRole.SUPERVISOR,
305
- content=supervisor_response
306
- ))
 
 
307
 
308
- # 2๋‹จ๊ณ„: ์ฐฝ์˜์„ฑ ์ƒ์„ฑ์ž - ์ฐฝ์˜์  ๋‹ต๋ณ€ ์ƒ์„ฑ
309
  creative_prompt = f"""
310
  ์‚ฌ์šฉ์ž ์งˆ๋ฌธ: {query}
311
 
@@ -317,21 +353,29 @@ URL: {result.get('url', 'N/A')}
317
 
318
  ์œ„ ์ง€์นจ๊ณผ ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ฐฝ์˜์ ์ด๊ณ  ์œ ์šฉํ•œ ๋‹ต๋ณ€์„ ์ƒ์„ฑํ•˜์„ธ์š”."""
319
 
320
- creative_response = self.llm.chat(
 
321
  messages=[
322
  {"role": "system", "content": self.agent_configs[AgentRole.CREATIVE]["system_prompt"]},
323
  {"role": "user", "content": creative_prompt}
324
  ],
325
  temperature=self.agent_configs[AgentRole.CREATIVE]["temperature"],
326
  max_tokens=config.get("max_tokens", 2000)
327
- )
 
 
 
 
 
 
 
 
328
 
329
- agent_responses.append(AgentResponse(
330
- role=AgentRole.CREATIVE,
331
- content=creative_response
332
- ))
333
 
334
- # 3๋‹จ๊ณ„: ๋น„ํ‰์ž - ๊ฒ€ํ†  ๋ฐ ๊ฐœ์„ ์  ์ œ์‹œ
335
  critic_prompt = f"""
336
  ์›๋ณธ ์งˆ๋ฌธ: {query}
337
 
@@ -343,21 +387,39 @@ URL: {result.get('url', 'N/A')}
343
 
344
  ์œ„ ๋‹ต๋ณ€์„ ๊ฒ€ํ† ํ•˜๊ณ  ๊ฐœ์„ ์ ์„ ์ œ์‹œํ•˜์„ธ์š”."""
345
 
346
- critic_response = self.llm.chat(
 
347
  messages=[
348
  {"role": "system", "content": self.agent_configs[AgentRole.CRITIC]["system_prompt"]},
349
  {"role": "user", "content": critic_prompt}
350
  ],
351
  temperature=self.agent_configs[AgentRole.CRITIC]["temperature"],
352
  max_tokens=config.get("max_tokens", 1000)
353
- )
 
 
 
 
 
 
 
 
354
 
355
- agent_responses.append(AgentResponse(
356
- role=AgentRole.CRITIC,
357
- content=critic_response
358
- ))
359
 
360
- # 4๋‹จ๊ณ„: ์ตœ์ข… ๊ฐ๋…์ž - ์ข…ํ•ฉ ๋ฐ ์ตœ์ข… ๋‹ต๋ณ€
 
 
 
 
 
 
 
 
 
 
 
 
361
  final_prompt = f"""
362
  ์‚ฌ์šฉ์ž ์งˆ๋ฌธ: {query}
363
 
@@ -373,45 +435,34 @@ URL: {result.get('url', 'N/A')}
373
  ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ:
374
  {search_context}
375
 
376
- ๋ชจ๋“  ์˜๊ฒฌ์„ ์ข…ํ•ฉํ•˜์—ฌ ์ตœ์ข… ๋‹ต๋ณ€์„ ์ƒ์„ฑํ•˜์„ธ์š”.
377
- ๋น„ํ‰์ž์˜ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ˜์˜ํ•˜์—ฌ ๊ฐœ์„ ๋œ ๋ฒ„์ „์„ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."""
378
 
379
- final_response = self.llm.chat(
 
 
380
  messages=[
381
  {"role": "system", "content": self.agent_configs[AgentRole.FINALIZER]["system_prompt"]},
382
  {"role": "user", "content": final_prompt}
383
  ],
384
  temperature=self.agent_configs[AgentRole.FINALIZER]["temperature"],
385
  max_tokens=config.get("max_tokens", 3000)
386
- )
387
-
388
- agent_responses.append(AgentResponse(
389
- role=AgentRole.FINALIZER,
390
- content=final_response
391
- ))
392
-
393
- processing_time = time.time() - start_time
394
-
395
- return FinalResponse(
396
- final_answer=final_response,
397
- agent_responses=agent_responses,
398
- search_results=search_results,
399
- processing_time=processing_time
400
- )
401
 
402
 
403
  # ============================================================================
404
- # Gradio UI
405
  # ============================================================================
406
 
407
  def create_gradio_interface():
408
- """Gradio ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ"""
409
 
410
  # ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™”
411
  try:
412
  llm_client = FireworksClient()
413
  search_client = BraveSearchClient()
414
- multi_agent_system = MultiAgentSystem(llm_client, search_client)
415
  system_ready = True
416
  except Exception as e:
417
  print(f"โš ๏ธ System initialization error: {e}")
@@ -419,7 +470,7 @@ def create_gradio_interface():
419
  search_client = None
420
  system_ready = False
421
 
422
- def process_query(
423
  message: str,
424
  history: List[Dict],
425
  use_search: bool,
@@ -427,17 +478,34 @@ def create_gradio_interface():
427
  search_count: int,
428
  temperature: float,
429
  max_tokens: int
430
- ) -> Tuple[List[Dict], str, str]:
431
- """์ฟผ๋ฆฌ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜"""
432
 
433
  if not message or not system_ready:
434
- return history, "", ""
 
435
 
436
  try:
437
  # ๊ฒ€์ƒ‰ ์ˆ˜ํ–‰
438
  search_results = []
 
 
439
  if use_search and search_client and search_client.api_key:
 
 
 
 
 
 
 
440
  search_results = search_client.search(message, count=search_count)
 
 
 
 
 
 
 
441
 
442
  # ์„ค์ •
443
  config = {
@@ -445,74 +513,58 @@ def create_gradio_interface():
445
  "max_tokens": max_tokens
446
  }
447
 
448
- # ๋ฉ€ํ‹ฐ ์—์ด์ „ํŠธ ์ฒ˜๋ฆฌ
449
- response = multi_agent_system.process_with_agents(
450
- query=message,
451
- search_results=search_results,
452
- config=config
453
- )
454
 
455
- # ์—์ด์ „ํŠธ ์‚ฌ๊ณ  ๊ณผ์ • ํฌ๋งทํŒ…
 
456
  agent_thoughts = ""
457
- if show_agent_thoughts:
458
- agent_thoughts = "## ๐Ÿค– ์—์ด์ „ํŠธ ์‚ฌ๊ณ  ๊ณผ์ •\n\n"
459
-
460
- for agent_resp in response.agent_responses:
461
- role_emoji = {
462
- AgentRole.SUPERVISOR: "๐Ÿ‘”",
463
- AgentRole.CREATIVE: "๐ŸŽจ",
464
- AgentRole.CRITIC: "๐Ÿ”",
465
- AgentRole.FINALIZER: "โœ…"
466
- }
467
-
468
- role_name = {
469
- AgentRole.SUPERVISOR: "๊ฐ๋…์ž (์ดˆ๊ธฐ ๊ตฌ์กฐํ™”)",
470
- AgentRole.CREATIVE: "์ฐฝ์˜์„ฑ ์ƒ์„ฑ์ž",
471
- AgentRole.CRITIC: "๋น„ํ‰์ž",
472
- AgentRole.FINALIZER: "์ตœ์ข… ๊ฐ๋…์ž"
473
- }
474
-
475
- agent_thoughts += f"### {role_emoji[agent_resp.role]} {role_name[agent_resp.role]}\n"
476
- agent_thoughts += f"{agent_resp.content[:500]}...\n\n"
477
 
478
- # ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ํฌ๋งทํŒ…
479
- search_display = ""
480
- if search_results:
481
- search_display = "## ๐Ÿ“š ์ฐธ๊ณ  ์ž๋ฃŒ\n\n"
482
- for i, result in enumerate(search_results, 1):
483
- search_display += f"**{i}. [{result['title']}]({result['url']})**\n"
484
- search_display += f" {result['description'][:100]}...\n\n"
485
-
486
- # ์ฒ˜๋ฆฌ ์‹œ๊ฐ„ ์ถ”๊ฐ€
487
- final_answer = response.final_answer
488
- final_answer += f"\n\n---\nโฑ๏ธ *์ฒ˜๋ฆฌ ์‹œ๊ฐ„: {response.processing_time:.2f}์ดˆ*"
 
 
489
 
490
- # ํžˆ์Šคํ† ๋ฆฌ ์—…๋ฐ์ดํŠธ (OpenAI ํ˜•์‹)
491
- history.append({"role": "user", "content": message})
492
- history.append({"role": "assistant", "content": final_answer})
493
 
494
- return history, agent_thoughts, search_display
495
 
496
  except Exception as e:
497
  error_msg = f"โŒ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
498
- history.append({"role": "user", "content": message})
499
- history.append({"role": "assistant", "content": error_msg})
500
- return history, "", ""
 
 
501
 
502
  # Gradio ์ธํ„ฐํŽ˜์ด์Šค
503
  with gr.Blocks(
504
- title="Multi-Agent RAG System",
505
  theme=gr.themes.Soft(),
506
  css="""
507
  .gradio-container {
508
  max-width: 1400px !important;
509
  margin: auto !important;
510
  }
 
 
 
511
  """
512
  ) as demo:
513
  gr.Markdown("""
514
- # ๐Ÿง  Multi-Agent RAG System
515
- ### 4๋‹จ๊ณ„ ์—์ด์ „ํŠธ ํ˜‘์—…์„ ํ†ตํ•œ ๊ณ ํ’ˆ์งˆ ๋‹ต๋ณ€ ์ƒ์„ฑ
516
 
517
  **์ฒ˜๋ฆฌ ๊ณผ์ •:** ๊ฐ๋…์ž(๊ตฌ์กฐํ™”) โ†’ ์ฐฝ์˜์„ฑ ์ƒ์„ฑ์ž(์ฐฝ์˜์  ๋‹ต๋ณ€) โ†’ ๋น„ํ‰์ž(๊ฒ€์ฆ) โ†’ ์ตœ์ข… ๊ฐ๋…์ž(์ข…ํ•ฉ)
518
  """)
@@ -530,18 +582,20 @@ def create_gradio_interface():
530
  chatbot = gr.Chatbot(
531
  height=500,
532
  label="๐Ÿ’ฌ ๋Œ€ํ™”",
533
- type="messages" # OpenAI ์Šคํƒ€์ผ ๋ฉ”์‹œ์ง€ ํ˜•์‹
 
534
  )
535
 
536
  msg = gr.Textbox(
537
  label="์งˆ๋ฌธ ์ž…๋ ฅ",
538
- placeholder="์งˆ๋ฌธ์„ ์ž…๋ ฅํ•˜์„ธ์š”... (๋ฉ€ํ‹ฐ ์—์ด์ „ํŠธ๊ฐ€ ํ˜‘์—…ํ•˜์—ฌ ๋‹ต๋ณ€ํ•ฉ๋‹ˆ๋‹ค)",
539
  lines=3
540
  )
541
 
542
  with gr.Row():
543
  submit = gr.Button("๐Ÿš€ ์ „์†ก", variant="primary")
544
  clear = gr.Button("๐Ÿ”„ ์ดˆ๊ธฐํ™”")
 
545
 
546
  # ์—์ด์ „ํŠธ ์‚ฌ๊ณ  ๊ณผ์ •
547
  with gr.Accordion("๐Ÿค– ์—์ด์ „ํŠธ ์‚ฌ๊ณ  ๊ณผ์ •", open=False):
@@ -569,7 +623,7 @@ def create_gradio_interface():
569
  search_count = gr.Slider(
570
  minimum=1,
571
  maximum=10,
572
- value=10,
573
  step=1,
574
  label="๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์ˆ˜"
575
  )
@@ -579,13 +633,14 @@ def create_gradio_interface():
579
  maximum=1,
580
  value=0.6,
581
  step=0.1,
582
- label="Temperature"
 
583
  )
584
 
585
  max_tokens = gr.Slider(
586
  minimum=500,
587
  maximum=4000,
588
- value=4000,
589
  step=100,
590
  label="Max Tokens"
591
  )
@@ -593,11 +648,16 @@ def create_gradio_interface():
593
  gr.Markdown("""
594
  ### ๐Ÿ“Š ์‹œ์Šคํ…œ ์ •๋ณด
595
 
596
- **์—์ด์ „ํŠธ ์—ญํ• :**
597
  - ๐Ÿ‘” **๊ฐ๋…์ž**: ๊ตฌ์กฐ ์„ค๊ณ„
598
  - ๐ŸŽจ **์ฐฝ์˜์„ฑ**: ์ฐฝ์˜์  ์ƒ์„ฑ
599
  - ๐Ÿ” **๋น„ํ‰์ž**: ๊ฒ€์ฆ/๊ฐœ์„ 
600
  - โœ… **์ตœ์ข…**: ์ข…ํ•ฉ/์™„์„ฑ
 
 
 
 
 
601
  """)
602
 
603
  # ์˜ˆ์ œ
@@ -612,9 +672,9 @@ def create_gradio_interface():
612
  inputs=msg
613
  )
614
 
615
- # ์ด๋ฒคํŠธ ๋ฐ”์ธ๋”ฉ
616
- submit.click(
617
- process_query,
618
  inputs=[msg, chatbot, use_search, show_agent_thoughts,
619
  search_count, temperature, max_tokens],
620
  outputs=[chatbot, agent_thoughts, search_sources]
@@ -624,8 +684,8 @@ def create_gradio_interface():
624
  msg
625
  )
626
 
627
- msg.submit(
628
- process_query,
629
  inputs=[msg, chatbot, use_search, show_agent_thoughts,
630
  search_count, temperature, max_tokens],
631
  outputs=[chatbot, agent_thoughts, search_sources]
@@ -635,8 +695,16 @@ def create_gradio_interface():
635
  msg
636
  )
637
 
 
 
 
 
 
 
 
 
638
  clear.click(
639
- lambda: ([], None, None),
640
  None,
641
  [chatbot, agent_thoughts, search_sources]
642
  )
@@ -651,10 +719,10 @@ def create_gradio_interface():
651
  if __name__ == "__main__":
652
  print("""
653
  โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
654
- โ•‘ ๐Ÿง  Multi-Agent RAG-Enhanced LLM System ๐Ÿง  โ•‘
655
  โ•‘ โ•‘
656
  โ•‘ ๊ฐ๋…์ž โ†’ ์ฐฝ์˜์„ฑ ์ƒ์„ฑ์ž โ†’ ๋น„ํ‰์ž โ†’ ์ตœ์ข… ๊ฐ๋…์ž โ•‘
657
- โ•‘ 4๋‹จ๊ณ„ ํ˜‘์—…์„ ํ†ตํ•œ ๊ณ ํ’ˆ์งˆ ๋‹ต๋ณ€ ์ƒ์„ฑ โ•‘
658
  โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
659
  """)
660
 
 
1
  """
2
+ Multi-Agent RAG-Enhanced LLM System for Hugging Face Spaces with Streaming
3
  ๊ฐ๋…์ž(Supervisor) -> ์ฐฝ์˜์„ฑ ์ƒ์„ฑ์ž(Creative) -> ๋น„ํ‰์ž(Critic) -> ๊ฐ๋…์ž(Final)
4
+ 4๋‹จ๊ณ„ ํŒŒ์ดํ”„๋ผ์ธ์„ ํ†ตํ•œ ๊ณ ํ’ˆ์งˆ ๋‹ต๋ณ€ ์ƒ์„ฑ ์‹œ์Šคํ…œ - ์ŠคํŠธ๋ฆฌ๋ฐ ์ถœ๋ ฅ ์ง€์›
5
  """
6
 
7
  import os
8
  import json
9
  import time
10
+ import asyncio
11
+ from typing import Optional, List, Dict, Any, Tuple, Generator, AsyncGenerator
12
  from datetime import datetime
13
  from enum import Enum
14
+ import threading
15
+ import queue
16
 
17
  import requests
18
  import gradio as gr
 
46
  metadata: Optional[Dict] = None
47
 
48
 
49
+ class StreamingResponse(BaseModel):
50
+ chunk: str
51
+ agent_role: Optional[AgentRole] = None
52
+ is_complete: bool = False
 
53
 
54
 
55
  # ============================================================================
 
109
 
110
 
111
  # ============================================================================
112
+ # Fireworks LLM ํด๋ผ์ด์–ธํŠธ (์ŠคํŠธ๋ฆฌ๋ฐ ์ง€์›)
113
  # ============================================================================
114
 
115
  class FireworksClient:
 
126
  }
127
 
128
  def chat(self, messages: List[Dict], **kwargs) -> str:
129
+ """LLM๊ณผ ๋Œ€ํ™” (์ผ๋ฐ˜)"""
130
  payload = {
131
  "model": kwargs.get("model", "accounts/fireworks/models/qwen3-235b-a22b-instruct-2507"),
132
  "messages": messages,
133
  "max_tokens": kwargs.get("max_tokens", 4096),
134
  "temperature": kwargs.get("temperature", 0.7),
135
  "top_p": kwargs.get("top_p", 1.0),
136
+ "top_k": kwargs.get("top_k", 40),
137
+ "stream": False
138
  }
139
 
140
  try:
 
153
 
154
  except Exception as e:
155
  return f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
156
+
157
+ def chat_stream(self, messages: List[Dict], **kwargs) -> Generator[str, None, None]:
158
+ """LLM๊ณผ ๋Œ€ํ™” (์ŠคํŠธ๋ฆฌ๋ฐ)"""
159
+ payload = {
160
+ "model": kwargs.get("model", "accounts/fireworks/models/qwen3-235b-a22b-instruct-2507"),
161
+ "messages": messages,
162
+ "max_tokens": kwargs.get("max_tokens", 4096),
163
+ "temperature": kwargs.get("temperature", 0.7),
164
+ "top_p": kwargs.get("top_p", 1.0),
165
+ "top_k": kwargs.get("top_k", 40),
166
+ "stream": True
167
+ }
168
+
169
+ try:
170
+ response = requests.post(
171
+ self.base_url,
172
+ headers={**self.headers, "Accept": "text/event-stream"},
173
+ data=json.dumps(payload),
174
+ stream=True,
175
+ timeout=60
176
+ )
177
+ response.raise_for_status()
178
+
179
+ for line in response.iter_lines():
180
+ if line:
181
+ line_str = line.decode('utf-8')
182
+ if line_str.startswith("data: "):
183
+ data_str = line_str[6:]
184
+ if data_str == "[DONE]":
185
+ break
186
+ try:
187
+ data = json.loads(data_str)
188
+ if "choices" in data and len(data["choices"]) > 0:
189
+ delta = data["choices"][0].get("delta", {})
190
+ if "content" in delta:
191
+ yield delta["content"]
192
+ except json.JSONDecodeError:
193
+ continue
194
+
195
+ except Exception as e:
196
+ yield f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
197
 
198
 
199
  # ============================================================================
200
+ # ๋ฉ€ํ‹ฐ ์—์ด์ „ํŠธ ์‹œ์Šคํ…œ (์ŠคํŠธ๋ฆฌ๋ฐ ์ง€์›)
201
  # ============================================================================
202
 
203
+ class MultiAgentSystemStreaming:
204
+ """์ŠคํŠธ๋ฆฌ๋ฐ์„ ์ง€์›ํ•˜๋Š” 4๋‹จ๊ณ„ ๋ฉ€ํ‹ฐ ์—์ด์ „ํŠธ ์ฒ˜๋ฆฌ ์‹œ์Šคํ…œ"""
205
 
206
  def __init__(self, llm_client: FireworksClient, search_client: BraveSearchClient):
207
  self.llm = llm_client
 
220
  1. ์งˆ๋ฌธ์˜ ํ•ต์‹ฌ ์˜๋„ ํŒŒ์•…
221
  2. ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ์—์„œ ํ•ต์‹ฌ ์ •๋ณด ์ถ”์ถœ
222
  3. ๋‹ต๋ณ€์ด ํฌํ•จํ•ด์•ผ ํ•  ์ฃผ์š” ์š”์†Œ๋“ค ์ •์˜
223
+ 4. ๋…ผ๋ฆฌ์  ํ๋ฆ„๊ณผ ๊ตฌ์กฐ ์ œ์‹œ"""
 
 
 
 
 
 
224
  },
225
 
226
  AgentRole.CREATIVE: {
 
232
  1. ๊ฐ๋…์ž์˜ ๊ตฌ์กฐ๋ฅผ ๋”ฐ๋ฅด๋˜ ์ฐฝ์˜์ ์œผ๋กœ ํ™•์žฅ
233
  2. ์˜ˆ์‹œ, ๋น„์œ , ์Šคํ† ๋ฆฌํ…”๋ง ํ™œ์šฉ
234
  3. ์‚ฌ์šฉ์ž ๊ด€์ ์—์„œ ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šด ์„ค๋ช… ์ถ”๊ฐ€
235
+ 4. ์‹ค์šฉ์ ์ด๊ณ  ๊ตฌ์ฒด์ ์ธ ์กฐ์–ธ ํฌํ•จ"""
 
 
 
 
 
 
236
  },
237
 
238
  AgentRole.CRITIC: {
 
240
  "system_prompt": """๋‹น์‹ ์€ ๋น„ํ‰์ž ์—์ด์ „ํŠธ์ž…๋‹ˆ๋‹ค.
241
  ์ฐฝ์˜์„ฑ ์ƒ์„ฑ์ž์˜ ๋‹ต๋ณ€์„ ๊ฒ€ํ† ํ•˜๊ณ  ๊ฐœ์„ ์ ์„ ์ œ์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
242
 
 
 
 
 
 
 
 
243
  ํ‰๊ฐ€ ๊ธฐ์ค€:
244
  - ์ •ํ™•์„ฑ: ์‚ฌ์‹ค๊ณผ ๋ฐ์ดํ„ฐ์˜ ์ •ํ™•์„ฑ
245
  - ์™„์ „์„ฑ: ์งˆ๋ฌธ์— ๋Œ€ํ•œ ์ถฉ๋ถ„ํ•œ ๋‹ต๋ณ€ ์—ฌ๋ถ€
246
  - ๋ช…ํ™•์„ฑ: ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šด ์„ค๋ช…์ธ์ง€
247
+ - ์œ ์šฉ์„ฑ: ์‹ค์ œ๋กœ ๋„์›€์ด ๋˜๋Š” ์ •๋ณด์ธ์ง€"""
 
 
 
 
 
 
248
  },
249
 
250
  AgentRole.FINALIZER: {
 
252
  "system_prompt": """๋‹น์‹ ์€ ์ตœ์ข… ๊ฐ๋…์ž์ž…๋‹ˆ๋‹ค.
253
  ๋ชจ๋“  ์—์ด์ „ํŠธ์˜ ์˜๊ฒฌ์„ ์ข…ํ•ฉํ•˜์—ฌ ์ตœ์ข… ๋‹ต๋ณ€์„ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
254
 
 
 
 
 
 
 
255
  ์ตœ์ข… ๋‹ต๋ณ€ ๊ธฐ์ค€:
256
  - ์ •ํ™•์„ฑ๊ณผ ์ฐฝ์˜์„ฑ์˜ ๊ท ํ˜•
257
  - ๋ช…ํ™•ํ•œ ๊ตฌ์กฐ์™€ ๋…ผ๋ฆฌ์  ํ๋ฆ„
258
  - ์‹ค์šฉ์ ์ด๊ณ  ์œ ์šฉํ•œ ์ •๋ณด
259
+ - ์‚ฌ์šฉ์ž ์นœํ™”์ ์ธ ํ†ค"""
 
 
 
 
 
 
 
260
  }
261
  }
262
 
 
271
  [๊ฒ€์ƒ‰๊ฒฐ๊ณผ {i}]
272
  ์ œ๋ชฉ: {result.get('title', 'N/A')}
273
  URL: {result.get('url', 'N/A')}
274
+ ๋‚ด์šฉ: {result.get('description', 'N/A')}""")
 
275
 
276
  return "\n".join(formatted)
277
 
278
+ def process_with_streaming(
279
  self,
280
  query: str,
281
  search_results: List[Dict],
282
+ config: Dict,
283
+ show_agent_thoughts: bool = False
284
+ ) -> Generator[Tuple[str, str], None, None]:
285
+ """์ŠคํŠธ๋ฆฌ๋ฐ์œผ๋กœ ๋ฉ€ํ‹ฐ ์—์ด์ „ํŠธ ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰"""
286
 
 
 
287
  search_context = self._format_search_results(search_results)
288
+ accumulated_response = ""
289
+ agent_thoughts_display = ""
290
+
291
+ # ์—์ด์ „ํŠธ ์—ญํ•  ์ด๋ชจ์ง€
292
+ role_emoji = {
293
+ AgentRole.SUPERVISOR: "๐Ÿ‘”",
294
+ AgentRole.CREATIVE: "๐ŸŽจ",
295
+ AgentRole.CRITIC: "๐Ÿ”",
296
+ AgentRole.FINALIZER: "โœ…"
297
+ }
298
+
299
+ role_name = {
300
+ AgentRole.SUPERVISOR: "๊ฐ๋…์ž",
301
+ AgentRole.CREATIVE: "์ฐฝ์˜์„ฑ ์ƒ์„ฑ์ž",
302
+ AgentRole.CRITIC: "๋น„ํ‰์ž",
303
+ AgentRole.FINALIZER: "์ตœ์ข… ๊ฐ๋…์ž"
304
+ }
305
+
306
+ # ์ €์žฅํ•  ์—์ด์ „ํŠธ ์‘๋‹ต๋“ค
307
+ agent_responses = {}
308
+
309
+ # 1๋‹จ๊ณ„: ๊ฐ๋…์ž
310
+ if show_agent_thoughts:
311
+ agent_thoughts_display += f"### {role_emoji[AgentRole.SUPERVISOR]} {role_name[AgentRole.SUPERVISOR]} ๋ถ„์„ ์ค‘...\n\n"
312
+ yield accumulated_response, agent_thoughts_display
313
 
 
314
  supervisor_prompt = f"""
315
  ์‚ฌ์šฉ์ž ์งˆ๋ฌธ: {query}
316
 
 
319
 
320
  ์œ„ ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๋‹ต๋ณ€์˜ ๋ฐฉํ–ฅ์„ฑ๊ณผ ๊ตฌ์กฐ๋ฅผ ์ œ์‹œํ•˜์„ธ์š”."""
321
 
322
+ supervisor_response = ""
323
+ for chunk in self.llm.chat_stream(
324
  messages=[
325
  {"role": "system", "content": self.agent_configs[AgentRole.SUPERVISOR]["system_prompt"]},
326
  {"role": "user", "content": supervisor_prompt}
327
  ],
328
  temperature=self.agent_configs[AgentRole.SUPERVISOR]["temperature"],
329
  max_tokens=config.get("max_tokens", 1000)
330
+ ):
331
+ supervisor_response += chunk
332
+ if show_agent_thoughts:
333
+ # ๊ฐ๋…์ž ์‘๋‹ต์„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ‘œ์‹œ (์ฒ˜์Œ 300์ž๋งŒ)
334
+ display_text = supervisor_response[:300] + ("..." if len(supervisor_response) > 300 else "")
335
+ agent_thoughts_display = f"### {role_emoji[AgentRole.SUPERVISOR]} {role_name[AgentRole.SUPERVISOR]}\n\n{display_text}\n\n"
336
+ yield accumulated_response, agent_thoughts_display
337
 
338
+ agent_responses[AgentRole.SUPERVISOR] = supervisor_response
339
+
340
+ # 2๋‹จ๊ณ„: ์ฐฝ์˜์„ฑ ์ƒ์„ฑ์ž
341
+ if show_agent_thoughts:
342
+ agent_thoughts_display += f"### {role_emoji[AgentRole.CREATIVE]} {role_name[AgentRole.CREATIVE]} ์ƒ์„ฑ ์ค‘...\n\n"
343
+ yield accumulated_response, agent_thoughts_display
344
 
 
345
  creative_prompt = f"""
346
  ์‚ฌ์šฉ์ž ์งˆ๋ฌธ: {query}
347
 
 
353
 
354
  ์œ„ ์ง€์นจ๊ณผ ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ฐฝ์˜์ ์ด๊ณ  ์œ ์šฉํ•œ ๋‹ต๋ณ€์„ ์ƒ์„ฑํ•˜์„ธ์š”."""
355
 
356
+ creative_response = ""
357
+ for chunk in self.llm.chat_stream(
358
  messages=[
359
  {"role": "system", "content": self.agent_configs[AgentRole.CREATIVE]["system_prompt"]},
360
  {"role": "user", "content": creative_prompt}
361
  ],
362
  temperature=self.agent_configs[AgentRole.CREATIVE]["temperature"],
363
  max_tokens=config.get("max_tokens", 2000)
364
+ ):
365
+ creative_response += chunk
366
+ if show_agent_thoughts:
367
+ display_text = creative_response[:400] + ("..." if len(creative_response) > 400 else "")
368
+ prev_supervisor = f"### {role_emoji[AgentRole.SUPERVISOR]} {role_name[AgentRole.SUPERVISOR]}\n\n{supervisor_response[:200]}...\n\n"
369
+ agent_thoughts_display = prev_supervisor + f"### {role_emoji[AgentRole.CREATIVE]} {role_name[AgentRole.CREATIVE]}\n\n{display_text}\n\n"
370
+ yield accumulated_response, agent_thoughts_display
371
+
372
+ agent_responses[AgentRole.CREATIVE] = creative_response
373
 
374
+ # 3๋‹จ๊ณ„: ๋น„ํ‰์ž
375
+ if show_agent_thoughts:
376
+ agent_thoughts_display += f"### {role_emoji[AgentRole.CRITIC]} {role_name[AgentRole.CRITIC]} ๊ฒ€ํ†  ์ค‘...\n\n"
377
+ yield accumulated_response, agent_thoughts_display
378
 
 
379
  critic_prompt = f"""
380
  ์›๋ณธ ์งˆ๋ฌธ: {query}
381
 
 
387
 
388
  ์œ„ ๋‹ต๋ณ€์„ ๊ฒ€ํ† ํ•˜๊ณ  ๊ฐœ์„ ์ ์„ ์ œ์‹œํ•˜์„ธ์š”."""
389
 
390
+ critic_response = ""
391
+ for chunk in self.llm.chat_stream(
392
  messages=[
393
  {"role": "system", "content": self.agent_configs[AgentRole.CRITIC]["system_prompt"]},
394
  {"role": "user", "content": critic_prompt}
395
  ],
396
  temperature=self.agent_configs[AgentRole.CRITIC]["temperature"],
397
  max_tokens=config.get("max_tokens", 1000)
398
+ ):
399
+ critic_response += chunk
400
+ if show_agent_thoughts:
401
+ display_text = critic_response[:300] + ("..." if len(critic_response) > 300 else "")
402
+ # ์ด์ „ ์—์ด์ „ํŠธ๋“ค ์š”์•ฝ
403
+ prev_content = f"### {role_emoji[AgentRole.SUPERVISOR]} {role_name[AgentRole.SUPERVISOR]}\n{supervisor_response[:150]}...\n\n"
404
+ prev_content += f"### {role_emoji[AgentRole.CREATIVE]} {role_name[AgentRole.CREATIVE]}\n{creative_response[:200]}...\n\n"
405
+ agent_thoughts_display = prev_content + f"### {role_emoji[AgentRole.CRITIC]} {role_name[AgentRole.CRITIC]}\n\n{display_text}\n\n"
406
+ yield accumulated_response, agent_thoughts_display
407
 
408
+ agent_responses[AgentRole.CRITIC] = critic_response
 
 
 
409
 
410
+ # 4๋‹จ๊ณ„: ์ตœ์ข… ๊ฐ๋…์ž - ์ด์ œ ์ตœ์ข… ๋‹ต๋ณ€์„ ์ŠคํŠธ๋ฆฌ๋ฐ์œผ๋กœ ์ถœ๋ ฅ
411
+ if show_agent_thoughts:
412
+ # ๋ชจ๋“  ์—์ด์ „ํŠธ ์‚ฌ๊ณ  ๊ณผ์ • ์ตœ์ข… ์ •๋ฆฌ
413
+ final_thoughts = "## ๐Ÿค– ์—์ด์ „ํŠธ ํ˜‘์—… ์™„๋ฃŒ\n\n"
414
+ for role in [AgentRole.SUPERVISOR, AgentRole.CREATIVE, AgentRole.CRITIC]:
415
+ final_thoughts += f"### {role_emoji[role]} {role_name[role]}\n"
416
+ final_thoughts += f"{agent_responses[role][:250]}...\n\n"
417
+
418
+ final_thoughts += f"### {role_emoji[AgentRole.FINALIZER]} {role_name[AgentRole.FINALIZER]} ์ตœ์ข… ๋‹ต๋ณ€ ์ƒ์„ฑ ๏ฟฝ๏ฟฝ๏ฟฝ...\n\n"
419
+ agent_thoughts_display = final_thoughts
420
+ yield accumulated_response, agent_thoughts_display
421
+
422
+ # ์ตœ์ข… ๋‹ต๋ณ€ ํ”„๋กฌํ”„ํŠธ
423
  final_prompt = f"""
424
  ์‚ฌ์šฉ์ž ์งˆ๋ฌธ: {query}
425
 
 
435
  ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ:
436
  {search_context}
437
 
438
+ ๋ชจ๋“  ์˜๊ฒฌ์„ ์ข…ํ•ฉํ•˜์—ฌ ์ตœ์ข… ๋‹ต๋ณ€์„ ์ƒ์„ฑํ•˜์„ธ์š”."""
 
439
 
440
+ # ์ตœ์ข… ๋‹ต๋ณ€ ์ŠคํŠธ๋ฆฌ๋ฐ
441
+ accumulated_response = ""
442
+ for chunk in self.llm.chat_stream(
443
  messages=[
444
  {"role": "system", "content": self.agent_configs[AgentRole.FINALIZER]["system_prompt"]},
445
  {"role": "user", "content": final_prompt}
446
  ],
447
  temperature=self.agent_configs[AgentRole.FINALIZER]["temperature"],
448
  max_tokens=config.get("max_tokens", 3000)
449
+ ):
450
+ accumulated_response += chunk
451
+ yield accumulated_response, agent_thoughts_display
 
 
 
 
 
 
 
 
 
 
 
 
452
 
453
 
454
  # ============================================================================
455
+ # Gradio UI (์ŠคํŠธ๋ฆฌ๋ฐ ์ง€์›)
456
  # ============================================================================
457
 
458
  def create_gradio_interface():
459
+ """Gradio ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ (์ŠคํŠธ๋ฆฌ๋ฐ ์ง€์›)"""
460
 
461
  # ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™”
462
  try:
463
  llm_client = FireworksClient()
464
  search_client = BraveSearchClient()
465
+ multi_agent_system = MultiAgentSystemStreaming(llm_client, search_client)
466
  system_ready = True
467
  except Exception as e:
468
  print(f"โš ๏ธ System initialization error: {e}")
 
470
  search_client = None
471
  system_ready = False
472
 
473
+ def process_query_streaming(
474
  message: str,
475
  history: List[Dict],
476
  use_search: bool,
 
478
  search_count: int,
479
  temperature: float,
480
  max_tokens: int
481
+ ):
482
+ """์ŠคํŠธ๋ฆฌ๋ฐ ์ฟผ๋ฆฌ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜"""
483
 
484
  if not message or not system_ready:
485
+ yield history, "", ""
486
+ return
487
 
488
  try:
489
  # ๊ฒ€์ƒ‰ ์ˆ˜ํ–‰
490
  search_results = []
491
+ search_display = ""
492
+
493
  if use_search and search_client and search_client.api_key:
494
+ # ๊ฒ€์ƒ‰ ์ค‘ ํ‘œ์‹œ
495
+ history_with_message = history + [
496
+ {"role": "user", "content": message},
497
+ {"role": "assistant", "content": "๐Ÿ” ๊ฒ€์ƒ‰ ์ค‘..."}
498
+ ]
499
+ yield history_with_message, "", ""
500
+
501
  search_results = search_client.search(message, count=search_count)
502
+
503
+ # ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ํฌ๋งทํŒ…
504
+ if search_results:
505
+ search_display = "## ๐Ÿ“š ์ฐธ๊ณ  ์ž๋ฃŒ\n\n"
506
+ for i, result in enumerate(search_results, 1):
507
+ search_display += f"**{i}. [{result['title']}]({result['url']})**\n"
508
+ search_display += f" {result['description'][:100]}...\n\n"
509
 
510
  # ์„ค์ •
511
  config = {
 
513
  "max_tokens": max_tokens
514
  }
515
 
516
+ # ์‚ฌ์šฉ์ž ๋ฉ”์‹œ์ง€ ์ถ”๊ฐ€
517
+ current_history = history + [{"role": "user", "content": message}]
 
 
 
 
518
 
519
+ # ๋ฉ€ํ‹ฐ ์—์ด์ „ํŠธ ์ŠคํŠธ๋ฆฌ๋ฐ ์ฒ˜๋ฆฌ
520
+ assistant_message = ""
521
  agent_thoughts = ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
522
 
523
+ for response_chunk, thoughts_chunk in multi_agent_system.process_with_streaming(
524
+ query=message,
525
+ search_results=search_results,
526
+ config=config,
527
+ show_agent_thoughts=show_agent_thoughts
528
+ ):
529
+ assistant_message = response_chunk
530
+ agent_thoughts = thoughts_chunk
531
+
532
+ # ํžˆ์Šคํ† ๋ฆฌ ์—…๋ฐ์ดํŠธ
533
+ updated_history = current_history + [{"role": "assistant", "content": assistant_message}]
534
+
535
+ yield updated_history, agent_thoughts, search_display
536
 
537
+ # ์ตœ์ข… ์ฒ˜๋ฆฌ ์‹œ๊ฐ„ ์ถ”๊ฐ€
538
+ final_message = assistant_message + "\n\n---\nโœจ *๋‹ต๋ณ€ ์ƒ์„ฑ ์™„๋ฃŒ*"
539
+ final_history = current_history + [{"role": "assistant", "content": final_message}]
540
 
541
+ yield final_history, agent_thoughts, search_display
542
 
543
  except Exception as e:
544
  error_msg = f"โŒ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
545
+ error_history = history + [
546
+ {"role": "user", "content": message},
547
+ {"role": "assistant", "content": error_msg}
548
+ ]
549
+ yield error_history, "", ""
550
 
551
  # Gradio ์ธํ„ฐํŽ˜์ด์Šค
552
  with gr.Blocks(
553
+ title="Multi-Agent RAG System with Streaming",
554
  theme=gr.themes.Soft(),
555
  css="""
556
  .gradio-container {
557
  max-width: 1400px !important;
558
  margin: auto !important;
559
  }
560
+ .message {
561
+ font-size: 1.1em !important;
562
+ }
563
  """
564
  ) as demo:
565
  gr.Markdown("""
566
+ # ๐Ÿง  Multi-Agent RAG System (Streaming)
567
+ ### ์‹ค์‹œ๊ฐ„ ์ŠคํŠธ๋ฆฌ๋ฐ์œผ๋กœ 4๋‹จ๊ณ„ ์—์ด์ „ํŠธ ํ˜‘์—… ๋‹ต๋ณ€ ์ƒ์„ฑ
568
 
569
  **์ฒ˜๋ฆฌ ๊ณผ์ •:** ๊ฐ๋…์ž(๊ตฌ์กฐํ™”) โ†’ ์ฐฝ์˜์„ฑ ์ƒ์„ฑ์ž(์ฐฝ์˜์  ๋‹ต๋ณ€) โ†’ ๋น„ํ‰์ž(๊ฒ€์ฆ) โ†’ ์ตœ์ข… ๊ฐ๋…์ž(์ข…ํ•ฉ)
570
  """)
 
582
  chatbot = gr.Chatbot(
583
  height=500,
584
  label="๐Ÿ’ฌ ๋Œ€ํ™”",
585
+ type="messages",
586
+ show_copy_button=True
587
  )
588
 
589
  msg = gr.Textbox(
590
  label="์งˆ๋ฌธ ์ž…๋ ฅ",
591
+ placeholder="์งˆ๋ฌธ์„ ์ž…๋ ฅํ•˜์„ธ์š”... (์‹ค์‹œ๊ฐ„์œผ๋กœ ๋‹ต๋ณ€์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค)",
592
  lines=3
593
  )
594
 
595
  with gr.Row():
596
  submit = gr.Button("๐Ÿš€ ์ „์†ก", variant="primary")
597
  clear = gr.Button("๐Ÿ”„ ์ดˆ๊ธฐํ™”")
598
+ stop = gr.Button("โน๏ธ ์ค‘์ง€", variant="stop")
599
 
600
  # ์—์ด์ „ํŠธ ์‚ฌ๊ณ  ๊ณผ์ •
601
  with gr.Accordion("๐Ÿค– ์—์ด์ „ํŠธ ์‚ฌ๊ณ  ๊ณผ์ •", open=False):
 
623
  search_count = gr.Slider(
624
  minimum=1,
625
  maximum=10,
626
+ value=5,
627
  step=1,
628
  label="๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์ˆ˜"
629
  )
 
633
  maximum=1,
634
  value=0.6,
635
  step=0.1,
636
+ label="Temperature",
637
+ info="๋‚ฎ์„์ˆ˜๋ก ์ผ๊ด€์„ฑ, ๋†’์„์ˆ˜๋ก ์ฐฝ์˜์„ฑ"
638
  )
639
 
640
  max_tokens = gr.Slider(
641
  minimum=500,
642
  maximum=4000,
643
+ value=2000,
644
  step=100,
645
  label="Max Tokens"
646
  )
 
648
  gr.Markdown("""
649
  ### ๐Ÿ“Š ์‹œ์Šคํ…œ ์ •๋ณด
650
 
651
+ **๐ŸŽญ ์—์ด์ „ํŠธ ์—ญํ• :**
652
  - ๐Ÿ‘” **๊ฐ๋…์ž**: ๊ตฌ์กฐ ์„ค๊ณ„
653
  - ๐ŸŽจ **์ฐฝ์˜์„ฑ**: ์ฐฝ์˜์  ์ƒ์„ฑ
654
  - ๐Ÿ” **๋น„ํ‰์ž**: ๊ฒ€์ฆ/๊ฐœ์„ 
655
  - โœ… **์ตœ์ข…**: ์ข…ํ•ฉ/์™„์„ฑ
656
+
657
+ **โœจ ํŠน์ง•:**
658
+ - ์‹ค์‹œ๊ฐ„ ์ŠคํŠธ๋ฆฌ๋ฐ ์ถœ๋ ฅ
659
+ - ๋‹ค๋‹จ๊ณ„ ๊ฒ€์ฆ ์‹œ์Šคํ…œ
660
+ - RAG ๊ธฐ๋ฐ˜ ์ •ํ™•์„ฑ
661
  """)
662
 
663
  # ์˜ˆ์ œ
 
672
  inputs=msg
673
  )
674
 
675
+ # ์ด๋ฒคํŠธ ๋ฐ”์ธ๋”ฉ (์ŠคํŠธ๋ฆฌ๋ฐ)
676
+ submit_event = submit.click(
677
+ process_query_streaming,
678
  inputs=[msg, chatbot, use_search, show_agent_thoughts,
679
  search_count, temperature, max_tokens],
680
  outputs=[chatbot, agent_thoughts, search_sources]
 
684
  msg
685
  )
686
 
687
+ msg_event = msg.submit(
688
+ process_query_streaming,
689
  inputs=[msg, chatbot, use_search, show_agent_thoughts,
690
  search_count, temperature, max_tokens],
691
  outputs=[chatbot, agent_thoughts, search_sources]
 
695
  msg
696
  )
697
 
698
+ # ์ค‘์ง€ ๋ฒ„ํŠผ
699
+ stop.click(
700
+ None,
701
+ None,
702
+ None,
703
+ cancels=[submit_event, msg_event]
704
+ )
705
+
706
  clear.click(
707
+ lambda: ([], "", ""),
708
  None,
709
  [chatbot, agent_thoughts, search_sources]
710
  )
 
719
  if __name__ == "__main__":
720
  print("""
721
  โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
722
+ โ•‘ ๐Ÿง  Multi-Agent RAG System with Streaming Output ๐Ÿง  โ•‘
723
  โ•‘ โ•‘
724
  โ•‘ ๊ฐ๋…์ž โ†’ ์ฐฝ์˜์„ฑ ์ƒ์„ฑ์ž โ†’ ๋น„ํ‰์ž โ†’ ์ตœ์ข… ๊ฐ๋…์ž โ•‘
725
+ โ•‘ ์‹ค์‹œ๊ฐ„ ์ŠคํŠธ๋ฆฌ๋ฐ์œผ๋กœ ๊ณ ํ’ˆ์งˆ ๋‹ต๋ณ€ ์ƒ์„ฑ โ•‘
726
  โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
727
  """)
728