PatrickRedStar commited on
Commit
9043954
·
1 Parent(s): a590b71

Refactor: Move GPT Prompt Agent to DeepSeek model via smolagents, all 4 agents now use transformers

Browse files
__pycache__/app.cpython-314.pyc CHANGED
Binary files a/__pycache__/app.cpython-314.pyc and b/__pycache__/app.cpython-314.pyc differ
 
agents/__init__.py CHANGED
@@ -186,12 +186,57 @@ def run_rca_agent(anomaly_report: dict):
186
  validate_schema(result, rca_schema)
187
  return result
188
 
189
- # Экспорт для обратной совместимости
190
- from .gpt_prompt_agent import GPTPromptAgent
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
 
192
  __all__ = [
193
  'run_parser_agent',
194
  'run_anomaly_agent',
195
  'run_rca_agent',
196
- 'GPTPromptAgent',
197
  ]
 
186
  validate_schema(result, rca_schema)
187
  return result
188
 
189
+ # Агент 4: Генерация промпта для GPT
190
+ gpt_prompt_agent = ToolCallingAgent(
191
+ model=model,
192
+ tools=[final_tool],
193
+ instructions="""
194
+ Ты эксперт по созданию детальных промптов для GPT-моделей. Твоя задача - создать готовый промпт для анализа проблем на основе структурированных данных о логах, аномалиях и рекомендациях.
195
+
196
+ Промпт должен быть структурированным и содержать:
197
+ 1. Контекст проблемы - общее описание ситуации
198
+ 2. Информация о системе - статистика, временные диапазоны, типы событий
199
+ 3. Обнаруженные проблемы - детальное описание аномалий с приоритетами
200
+ 4. Статистика и метрики - количественные показатели
201
+ 5. Примеры ошибок - ключевые ошибки из логов
202
+ 6. Предварительный анализ - рекомендации от предыдущих агентов (если есть)
203
+ 7. Запрос на решение - конкретные вопросы для GPT
204
+
205
+ Промпт должен быть готов к использованию - его можно скопировать и вставить в ChatGPT, Claude или другую GPT-модель.
206
+
207
+ Ответ верни как обычный текст (не JSON), используя final_answer. Это должен быть готовый промпт на русском языке в формате Markdown.
208
+ """,
209
+ name="GPTPromptAgent",
210
+ max_steps=10,
211
+ )
212
+
213
+ # Pipeline шаг 4 — генерация промпта для GPT
214
+ def run_gpt_prompt_agent(structured_data: dict, anomaly_report: dict, recommendations: str = None):
215
+ """Генерирует промпт для GPT на основе всех данных анализа."""
216
+ # Подготавливаем входные данные для агента
217
+ input_data = {
218
+ "structured_data": structured_data,
219
+ "anomaly_report": anomaly_report,
220
+ "recommendations": recommendations
221
+ }
222
+ input_json = json.dumps(input_data, ensure_ascii=False, indent=2)
223
+
224
+ result = run_agent_safely(gpt_prompt_agent, task=input_json)
225
+
226
+ # Результат должен быть строкой (промпт), а не JSON
227
+ if isinstance(result, dict) and "answer" in result:
228
+ return result["answer"]
229
+ elif isinstance(result, str):
230
+ return result
231
+ else:
232
+ # Если агент вернул JSON, попробуем извлечь промпт
233
+ if isinstance(result, dict) and "prompt" in result:
234
+ return result["prompt"]
235
+ return str(result)
236
 
237
  __all__ = [
238
  'run_parser_agent',
239
  'run_anomaly_agent',
240
  'run_rca_agent',
241
+ 'run_gpt_prompt_agent',
242
  ]
agents/__pycache__/__init__.cpython-314.pyc CHANGED
Binary files a/agents/__pycache__/__init__.cpython-314.pyc and b/agents/__pycache__/__init__.cpython-314.pyc differ
 
agents/gpt_prompt_agent.py DELETED
@@ -1,325 +0,0 @@
1
- """
2
- Agent 4: GPT Prompt Generator Agent
3
- Формирует детальный промпт для GPT-модели с полным контекстом проблемы и системы.
4
- """
5
-
6
- from typing import Dict, List, Any, Optional
7
- from datetime import datetime
8
-
9
-
10
- class GPTPromptAgent:
11
- """Генерирует промпт для GPT на основе анализа логов."""
12
-
13
- def __init__(self):
14
- """Инициализация агента."""
15
- pass
16
-
17
- def generate_prompt(
18
- self,
19
- structured_data: Dict[str, Any],
20
- anomaly_report: Dict[str, Any],
21
- recommendations: Optional[str] = None
22
- ) -> str:
23
- """
24
- Генерирует детальный промпт для GPT-модели.
25
-
26
- Args:
27
- structured_data: Структурированные данные от LogParserAgent
28
- anomaly_report: Отчёт об аномалиях от AnomalyDetectionAgent
29
- recommendations: Рекомендации от RootCauseAgent (опционально)
30
-
31
- Returns:
32
- Готовый промпт в виде строки для вставки в GPT
33
- """
34
- prompt_parts = []
35
-
36
- # Заголовок промпта
37
- prompt_parts.append("# Контекст проблемы из системных логов\n")
38
- prompt_parts.append("\nЯ анализирую логи системы и обнаружил несколько проблем. ")
39
- prompt_parts.append("Мне нужна помощь в диагностике и решении этих проблем.\n")
40
-
41
- # Раздел 1: Общая информация о системе
42
- prompt_parts.append("\n## 1. Информация о системе\n\n")
43
- system_info = self._extract_system_info(structured_data)
44
- prompt_parts.append(system_info)
45
-
46
- # Раздел 2: Обнаруженные проблемы
47
- prompt_parts.append("\n## 2. Обнаруженные проблемы и аномалии\n\n")
48
- problems_info = self._format_anomalies(anomaly_report)
49
- prompt_parts.append(problems_info)
50
-
51
- # Раздел 3: Статистика и метрики
52
- prompt_parts.append("\n## 3. Статистика событий\n\n")
53
- stats_info = self._format_statistics(structured_data, anomaly_report)
54
- prompt_parts.append(stats_info)
55
-
56
- # Раздел 4: Примеры ошибок и логов
57
- prompt_parts.append("\n## 4. Примеры ошибок и ключевые логи\n\n")
58
- examples_info = self._format_error_examples(structured_data, anomaly_report)
59
- prompt_parts.append(examples_info)
60
-
61
- # Раздел 5: Анализ первопричин (если есть рекомендации)
62
- if recommendations:
63
- prompt_parts.append("\n## 5. Предварительный анализ и рекомендации\n\n")
64
- prompt_parts.append(recommendations)
65
- prompt_parts.append("\n")
66
-
67
- # Раздел 6: Запрос к GPT
68
- prompt_parts.append("\n## 6. Запрос на решение\n\n")
69
- prompt_parts.append("Пожалуйста, помогите мне:\n")
70
- prompt_parts.append("1. Определить точную первопричину проблемы\n")
71
- prompt_parts.append("2. Предложить конкретные шаги для решения проблемы\n")
72
- prompt_parts.append("3. Предложить меры профилактики, чтобы избежать подобных проблем в будущем\n")
73
- prompt_parts.append("4. Если это программная ошибка, предложите патч или исправление кода (если возможно)\n")
74
- prompt_parts.append("5. Оцените критичность проблемы и приоритет решения\n\n")
75
-
76
- prompt_parts.append("Проанализируйте предоставленную информацию и дайте развёрнутый ответ с конкретными рекомендациями.\n")
77
-
78
- return "".join(prompt_parts)
79
-
80
- def _extract_system_info(self, structured_data: Dict[str, Any]) -> str:
81
- """Извлекает информацию о системе из структурированных данных."""
82
- info_parts = []
83
-
84
- statistics = structured_data.get('statistics', {})
85
- events = structured_data.get('events', [])
86
-
87
- # Временной диапазон
88
- time_range = statistics.get('time_range')
89
- if time_range:
90
- start_time = time_range.get('start') if isinstance(time_range, dict) else None
91
- end_time = time_range.get('end') if isinstance(time_range, dict) else None
92
- if start_time and end_time:
93
- info_parts.append(f"- **Временной диапазон логов:** с {start_time} по {end_time}\n")
94
- elif start_time:
95
- info_parts.append(f"- **Начало периода:** {start_time}\n")
96
-
97
- # Общая статистика
98
- total_lines = statistics.get('total_lines', 0)
99
- parsed_events = statistics.get('parsed_events', 0)
100
- errors_count = statistics.get('errors', 0)
101
- warnings_count = statistics.get('warnings', 0)
102
-
103
- info_parts.append(f"- **Всего строк в логах:** {total_lines}\n")
104
- info_parts.append(f"- **Распарсенных событий:** {parsed_events}\n")
105
- info_parts.append(f"- **Ошибок:** {errors_count}\n")
106
- info_parts.append(f"- **Предупреждений:** {warnings_count}\n")
107
-
108
- # Типы событий
109
- event_types = statistics.get('event_types', {})
110
- if event_types:
111
- info_parts.append(f"- **Типы событий в системе:**\n")
112
- for event_type, count in sorted(event_types.items(), key=lambda x: x[1], reverse=True)[:10]:
113
- info_parts.append(f" - {event_type}: {count} событий\n")
114
-
115
- # Попытка извлечь информацию о системе из логов
116
- system_info = self._extract_technical_details(events)
117
- if system_info:
118
- info_parts.append(f"\n### Технические детали системы:\n\n")
119
- info_parts.append(system_info)
120
-
121
- return "".join(info_parts) if info_parts else "Информация о системе не обнаружена в логах.\n"
122
-
123
- def _extract_technical_details(self, events: List[Dict]) -> str:
124
- """Извлекает технические детали из событий (версии, компоненты и т.д.)."""
125
- details = []
126
- seen_details = set()
127
-
128
- # Ключевые слова для поиска системной информации
129
- keywords = {
130
- 'version': ['version', 'версия', 'v.', 'ver '],
131
- 'component': ['component', 'компонент', 'module', 'модуль', 'service', 'сервис'],
132
- 'framework': ['framework', 'framework version', 'django', 'flask', 'spring', 'express'],
133
- 'database': ['database', 'db', 'mysql', 'postgresql', 'mongodb', 'redis'],
134
- 'os': ['linux', 'windows', 'ubuntu', 'centos', 'debian', 'os version'],
135
- 'language': ['python', 'java', 'node', 'javascript', 'typescript', 'go', 'rust'],
136
- 'protocol': ['http', 'https', 'tcp', 'udp', 'grpc']
137
- }
138
-
139
- for event in events[:200]: # Проверяем первые 200 событий
140
- message = event.get('message', '').lower()
141
- level = event.get('level', '').upper()
142
-
143
- # Извлекаем информацию о версиях и компонентах
144
- for detail_type, search_terms in keywords.items():
145
- for term in search_terms:
146
- if term in message and detail_type not in seen_details:
147
- # Пытаемся извлечь более конкретную информацию
148
- context = message[max(0, message.find(term) - 50):message.find(term) + 100]
149
- if context and len(context) > 10:
150
- details.append(f"- **{detail_type.upper()}:** обнаружен в логах (контекст: {context[:80]}...)\n")
151
- seen_details.add(detail_type)
152
- break
153
- if detail_type in seen_details:
154
- break
155
-
156
- return "".join(details) if details else "Специфические технические детали не обнаружены в логах.\n"
157
-
158
- def _format_anomalies(self, anomaly_report: Dict[str, Any]) -> str:
159
- """Форматирует информацию об аномалиях для промпта."""
160
- if not anomaly_report or not anomaly_report.get('anomalies'):
161
- return "Критических аномалий не обнаружено. Система работает в штатном режиме.\n"
162
-
163
- anomalies = anomaly_report.get('anomalies', [])
164
- statistics = anomaly_report.get('statistics', {})
165
- severity_summary = anomaly_report.get('severity_summary', {})
166
-
167
- info_parts = []
168
-
169
- # Общая сводка
170
- total_anomalies = statistics.get('total', 0)
171
- info_parts.append(f"**Всего обнаружено аномалий:** {total_anomalies}\n\n")
172
-
173
- # Сводка по серьёзности
174
- if severity_summary:
175
- info_parts.append("**Распределение по серьёзности:**\n")
176
- severity_names = {
177
- 'CRITICAL': '🔴 КРИТИЧЕСКИЕ',
178
- 'HIGH': '🟠 ВЫСОКИЕ',
179
- 'MEDIUM': '🟡 СРЕДНИЕ',
180
- 'LOW': '🟢 НИЗКИЕ'
181
- }
182
- for severity, count in sorted(severity_summary.items(), key=lambda x: ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'].index(x[0]) if x[0] in ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'] else 999):
183
- name = severity_names.get(severity, severity)
184
- info_parts.append(f"- {name}: {count} проблем(ы)\n")
185
- info_parts.append("\n")
186
-
187
- # Детальное описание каждой аномалии
188
- info_parts.append("### Детальное описание проблем:\n\n")
189
-
190
- # Сортируем по серьёзности
191
- severity_order = {'CRITICAL': 0, 'HIGH': 1, 'MEDIUM': 2, 'LOW': 3}
192
- sorted_anomalies = sorted(
193
- anomalies,
194
- key=lambda x: severity_order.get(x.get('severity', 'LOW'), 999)
195
- )
196
-
197
- for i, anomaly in enumerate(sorted_anomalies, 1):
198
- anomaly_type = anomaly.get('type', 'UNKNOWN')
199
- severity = anomaly.get('severity', 'UNKNOWN')
200
- description = anomaly.get('description', 'Нет описания')
201
-
202
- info_parts.append(f"#### Проблема #{i}: {self._get_anomaly_type_name(anomaly_type)} ({severity})\n\n")
203
- info_parts.append(f"{description}\n\n")
204
-
205
- # Дополнительные детали
206
- if anomaly.get('count'):
207
- info_parts.append(f"- **Количество вхождений:** {anomaly.get('count')}\n")
208
-
209
- if anomaly.get('error_message'):
210
- error_msg = anomaly.get('error_message', '')[:300]
211
- info_parts.append(f"- **Сообщение об ошибке:** `{error_msg}`\n")
212
-
213
- if anomaly.get('sample_messages'):
214
- info_parts.append(f"- **Примеры сообщений:**\n")
215
- for msg in anomaly.get('sample_messages', [])[:3]:
216
- info_parts.append(f" - `{msg[:200]}`\n")
217
-
218
- if anomaly.get('time_window'):
219
- info_parts.append(f"- **Временное окно:** {anomaly.get('time_window')}\n")
220
-
221
- if anomaly.get('first_occurrence'):
222
- info_parts.append(f"- **Первое появление:** {anomaly.get('first_occurrence')}\n")
223
-
224
- if anomaly.get('last_occurrence'):
225
- info_parts.append(f"- **Последнее появление:** {anomaly.get('last_occurrence')}\n")
226
-
227
- if anomaly.get('metadata', {}).get('affected_lines'):
228
- lines = anomaly.get('metadata', {}).get('affected_lines', [])[:10]
229
- info_parts.append(f"- **Затронутые строки логов:** {', '.join(map(str, lines))}\n")
230
-
231
- info_parts.append("\n")
232
-
233
- return "".join(info_parts)
234
-
235
- def _format_statistics(self, structured_data: Dict[str, Any], anomaly_report: Dict[str, Any]) -> str:
236
- """Форматирует статистику для промпта."""
237
- stats_parts = []
238
-
239
- statistics = structured_data.get('statistics', {})
240
- anomaly_stats = anomaly_report.get('statistics', {})
241
-
242
- stats_parts.append("### Общая статистика событий:\n\n")
243
-
244
- total_lines = statistics.get('total_lines', 0)
245
- parsed_events = statistics.get('parsed_events', 0)
246
- errors = statistics.get('errors', 0)
247
- warnings = statistics.get('warnings', 0)
248
- info_count = statistics.get('info_messages', 0)
249
-
250
- if total_lines > 0:
251
- error_rate = (errors / parsed_events * 100) if parsed_events > 0 else 0
252
- warning_rate = (warnings / parsed_events * 100) if parsed_events > 0 else 0
253
-
254
- stats_parts.append(f"- **Всего строк логов:** {total_lines}\n")
255
- stats_parts.append(f"- **Распарсенных событий:** {parsed_events}\n")
256
- stats_parts.append(f"- **Ошибок:** {errors} ({error_rate:.2f}% от всех событий)\n")
257
- stats_parts.append(f"- **Предупреждений:** {warnings} ({warning_rate:.2f}% от всех событий)\n")
258
- stats_parts.append(f"- **Информационных сообщений:** {info_count}\n")
259
-
260
- if anomaly_stats:
261
- stats_parts.append(f"\n### Статистика аномалий:\n\n")
262
- by_type = anomaly_stats.get('by_type', {})
263
- if by_type:
264
- stats_parts.append("**По типам:**\n")
265
- for anomaly_type, count in sorted(by_type.items(), key=lambda x: x[1], reverse=True):
266
- type_name = self._get_anomaly_type_name(anomaly_type)
267
- stats_parts.append(f"- {type_name}: {count}\n")
268
-
269
- return "".join(stats_parts)
270
-
271
- def _format_error_examples(self, structured_data: Dict[str, Any], anomaly_report: Dict[str, Any]) -> str:
272
- """Форматирует примеры ошибок для промпта."""
273
- examples_parts = []
274
-
275
- errors = structured_data.get('errors', [])
276
- anomalies = anomaly_report.get('anomalies', [])
277
-
278
- if not errors:
279
- return "Явных ошибок в логах не обнаружено.\n"
280
-
281
- examples_parts.append("### Ключевые ошибки из логов:\n\n")
282
-
283
- # Показываем уникальные ошибки (первые 10)
284
- unique_errors = []
285
- seen_messages = set()
286
-
287
- for error in errors[:50]:
288
- message = error.get('message', '').strip()
289
- if message and message not in seen_messages:
290
- unique_errors.append(error)
291
- seen_messages.add(message)
292
- if len(unique_errors) >= 10:
293
- break
294
-
295
- for i, error in enumerate(unique_errors, 1):
296
- level = error.get('level', 'UNKNOWN')
297
- message = error.get('message', '')[:400]
298
- timestamp = error.get('timestamp', 'N/A')
299
- line_num = error.get('line_number', 'N/A')
300
-
301
- examples_parts.append(f"**Ошибка #{i}** (уровень: {level}, строка: {line_num}, время: {timestamp}):\n")
302
- examples_parts.append(f"```\n{message}\n```\n\n")
303
-
304
- # Если есть примеры из аномалий, добавляем их
305
- if anomalies:
306
- examples_parts.append("### Примеры проблемных паттернов из аномалий:\n\n")
307
- for anomaly in anomalies[:5]:
308
- if anomaly.get('sample_messages'):
309
- examples_parts.append(f"**{self._get_anomaly_type_name(anomaly.get('type'))}:**\n")
310
- for msg in anomaly.get('sample_messages', [])[:2]:
311
- examples_parts.append(f"- `{msg[:200]}`\n")
312
- examples_parts.append("\n")
313
-
314
- return "".join(examples_parts)
315
-
316
- def _get_anomaly_type_name(self, anomaly_type: str) -> str:
317
- """Возвращает читаемое имя типа аномалии."""
318
- names = {
319
- 'BURST_ERRORS': 'Всплеск ошибок (Burst Errors)',
320
- 'REPEATED_ERRORS': 'Повторяющиеся ошибки (Repeated Errors)',
321
- 'ERROR_BEFORE_CRASH': 'Ошибка перед крашем (Error Before Crash)',
322
- 'TEMPORAL_SPIKE': 'Временной всплеск событий (Temporal Spike)',
323
- 'REPEATED_STACK_TRACES': 'Повторяющиеся stack traces (Repeated Stack Traces)',
324
- }
325
- return names.get(anomaly_type, anomaly_type)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app.py CHANGED
@@ -8,13 +8,7 @@ import json
8
  import os
9
  from typing import Tuple
10
 
11
- from agents import run_parser_agent, run_anomaly_agent, run_rca_agent
12
-
13
- # Импорт GPT Prompt Agent (остаётся rule-based, не использует трансформеры)
14
- from agents.gpt_prompt_agent import GPTPromptAgent
15
-
16
- # Инициализация GPT Prompt Agent (остаётся rule-based)
17
- gpt_prompt_agent = GPTPromptAgent()
18
 
19
 
20
  def format_rca_as_markdown(rca_result: dict) -> str:
@@ -131,7 +125,7 @@ def analyze_logs(raw_logs: str) -> Tuple[str, str, str, str]:
131
 
132
  # Agent 4: Генерация промпта для GPT
133
  try:
134
- gpt_prompt = gpt_prompt_agent.generate_prompt(
135
  structured_data,
136
  anomaly_report,
137
  recommendations_md
@@ -281,7 +275,7 @@ def create_interface():
281
  ---
282
  ### ℹ️ Информация о системе
283
 
284
- - **Архитектура:** Мультиагентная система (4 независимых агента на основе трансформеров)
285
  - **Платформа:** Hugging Face Spaces
286
  - **Интерфейс:** Gradio
287
  - **Поддержка:** До 10,000 строк логов
 
8
  import os
9
  from typing import Tuple
10
 
11
+ from agents import run_parser_agent, run_anomaly_agent, run_rca_agent, run_gpt_prompt_agent
 
 
 
 
 
 
12
 
13
 
14
  def format_rca_as_markdown(rca_result: dict) -> str:
 
125
 
126
  # Agent 4: Генерация промпта для GPT
127
  try:
128
+ gpt_prompt = run_gpt_prompt_agent(
129
  structured_data,
130
  anomaly_report,
131
  recommendations_md
 
275
  ---
276
  ### ℹ️ Информация о системе
277
 
278
+ - **Архитектура:** Мультиагентная система (4 независимых агента на основе DeepSeek через smolagents)
279
  - **Платформа:** Hugging Face Spaces
280
  - **Интерфейс:** Gradio
281
  - **Поддержка:** До 10,000 строк логов