AnatoliiG commited on
Commit
7e12323
·
1 Parent(s): 047143f

forcing web tool

Browse files
Files changed (2) hide show
  1. src/ui/callbacks.py +13 -9
  2. src/utils/helpers.py +20 -21
src/ui/callbacks.py CHANGED
@@ -110,18 +110,18 @@ def bot_response(
110
  ) + "🤔 Агент анализирует необходимость поиска..."
111
  yield history
112
 
113
- # Промпт Роутера на английском (модели Qwen/Claude понимают его лучше)
114
  agent_messages = [
115
  {
116
  "role": "system",
117
  "content": (
118
- "You are an internal routing assistant. Decide if a web search is needed to answer the user's latest message.\n"
119
- "Respond ONLY with a valid JSON. No explanations.\n"
120
- 'Format if search needed: {"search": true, "query": "exact search terms"}\n'
121
- 'Format if NOT needed: {"search": false}'
122
- ),
123
- }
124
- ]
 
125
 
126
  for msg in history[-3:]:
127
  if msg["role"] == "user":
@@ -131,11 +131,15 @@ def bot_response(
131
  eval_response = engine.generate(
132
  messages=agent_messages,
133
  max_tokens=150,
134
- temperature=0.0, # Обязательно 0 для точности!
135
  stream=False,
136
  )
137
 
138
  raw_response = eval_response["choices"][0]["message"]["content"]
 
 
 
 
139
  clean_query = extract_search_query(raw_response)
140
 
141
  if clean_query:
 
110
  ) + "🤔 Агент анализирует необходимость поиска..."
111
  yield history
112
 
 
113
  agent_messages = [
114
  {
115
  "role": "system",
116
  "content": (
117
+ "Ты строгий системный классификатор. Твоя единственная цель - определить, нужен ли интернет-поиск.\n"
118
+ "ПРАВИЛО 1: Если вопрос касается недавних событий, атак, инцидентов, новостей, дат или меняющихся фактов — поиск НУЖЕН ОБЯЗАТЕЛЬНО, даже если ты думаешь, что знаешь ответ.\n"
119
+ "ПРАВИЛО 2: Отвечай СТРОГО и ТОЛЬКО в формате JSON. Запрещено использовать теги <think> и писать текст.\n\n"
120
+ "Формат (если нужен поиск):\n"
121
+ '{"search": true, "query": "оптимальный и короткий поисковый запрос"}\n\n'
122
+ "Формат (если это просто болтовня или математика):\n"
123
+ '{"search": false, "query": null}'
124
+ ]
125
 
126
  for msg in history[-3:]:
127
  if msg["role"] == "user":
 
131
  eval_response = engine.generate(
132
  messages=agent_messages,
133
  max_tokens=150,
134
+ temperature=0.0, # 0.0 для максимальной предсказуемости
135
  stream=False,
136
  )
137
 
138
  raw_response = eval_response["choices"][0]["message"]["content"]
139
+
140
+ # ВАЖНО: Выводим в терминал (консоль), что ответил роутер, чтобы отлаживать
141
+ print(f"\n--- [DEBUG] ОТВЕТ РОУТЕРА ---\n{raw_response}\n---------------------------\n")
142
+
143
  clean_query = extract_search_query(raw_response)
144
 
145
  if clean_query:
src/utils/helpers.py CHANGED
@@ -68,42 +68,41 @@ def web_search(query: str, max_results: int = 3) -> list:
68
 
69
 
70
  def extract_search_query(text: str):
71
- """Извлекает поисковый запрос из JSON, Python-массивов или обычного текста."""
72
  if not text:
73
  return None
74
 
75
- # 1. Ищем строгий JSON {"search": true, "query": "..."}
 
 
 
 
76
  try:
77
- json_match = re.search(r"```(?:json)?\s*(\{.*?\})\s*```", text, re.DOTALL)
 
78
  if json_match:
79
  data = json.loads(json_match.group(1))
80
- return data.get("query") if data.get("search") else None
 
 
 
81
 
82
- bare_json = re.search(r"\{.*?\}", text, re.DOTALL)
 
83
  if bare_json:
84
  data = json.loads(bare_json.group(0))
85
- if "query" in data and ("search" in data or "search_needed" in data):
86
  return data.get("query")
87
- except Exception:
88
- pass
 
89
 
90
- # 2. Ищем специфичный формат массива из логов модели (как на скриншоте)
91
- # Пример: [{'text': '🔍 Поиск по запросу: "attacks on..."', 'type': 'search'}]
92
  if "'type': 'search'" in text or '"type": "search"' in text:
93
  match = re.search(r"['\"]text['\"]\s*:\s*['\"](.*?)['\"]", text)
94
  if match:
95
  raw_q = match.group(1)
96
- # Вытаскиваем то, что внутри двойных кавычек (сам запрос)
97
  sub_match = re.search(r'"([^"]+)"', raw_q)
98
- clean_q = sub_match.group(1) if sub_match else raw_q
99
- # Очищаем от мусорных слов, если они остались
100
- return re.sub(r"^(?:🔍\s*)?Поиск по запросу:\s*", "", clean_q).strip()
101
-
102
- # 3. Фолбэк: просто ищем текст в кавычках после слова query/запрос
103
- match = re.search(
104
- r'(?:запрос|query|ищем)\s*:?\s*["\']([^"\']+)["\']', text, re.IGNORECASE
105
- )
106
- if match:
107
- return match.group(1)
108
 
109
  return None
 
68
 
69
 
70
  def extract_search_query(text: str):
71
+ """Надежно извлекает запрос из ответа роутера."""
72
  if not text:
73
  return None
74
 
75
+ # Вырезаем теги мыслей, если упрямая модель их всё же сгенерировала
76
+ text_clean = re.sub(r"<think>.*?</think>", "", text, flags=re.DOTALL).strip()
77
+ if not text_clean:
78
+ text_clean = text # Если ответ состоял только из тегов, ищем внутри них
79
+
80
  try:
81
+ # 1. Ищем блок ```json ... ```
82
+ json_match = re.search(r"```(?:json)?\s*(\{.*?\})\s*```", text_clean, re.DOTALL)
83
  if json_match:
84
  data = json.loads(json_match.group(1))
85
+ # Проверяем флаг search (строго True)
86
+ if data.get("search") is True or str(data.get("search")).lower() == "true":
87
+ return data.get("query")
88
+ return None
89
 
90
+ # 2. Ищем просто фигурные скобки (голый JSON)
91
+ bare_json = re.search(r"\{.*?\}", text_clean, re.DOTALL)
92
  if bare_json:
93
  data = json.loads(bare_json.group(0))
94
+ if data.get("search") is True or str(data.get("search")).lower() == "true":
95
  return data.get("query")
96
+ return None
97
+ except Exception as e:
98
+ print(f"Ошибка парсинга JSON роутера: {e}")
99
 
100
+ # 3. Резервный вариант на случай старых галлюцинаций
 
101
  if "'type': 'search'" in text or '"type": "search"' in text:
102
  match = re.search(r"['\"]text['\"]\s*:\s*['\"](.*?)['\"]", text)
103
  if match:
104
  raw_q = match.group(1)
 
105
  sub_match = re.search(r'"([^"]+)"', raw_q)
106
+ return (sub_match.group(1) if sub_match else raw_q).strip()
 
 
 
 
 
 
 
 
 
107
 
108
  return None