AnatoliiG commited on
Commit ·
047143f
1
Parent(s): 1080c74
fix repeat haluc
Browse files- src/core/engine.py +1 -0
- src/ui/callbacks.py +32 -13
src/core/engine.py
CHANGED
|
@@ -49,6 +49,7 @@ class ModelEngine:
|
|
| 49 |
"max_tokens": int(kwargs.get("max_tokens", settings.DEFAULT_MAX_TOKENS)),
|
| 50 |
"temperature": float(kwargs.get("temperature", settings.DEFAULT_TEMP)),
|
| 51 |
"top_p": float(kwargs.get("top_p", 0.95)),
|
|
|
|
| 52 |
"stop": kwargs.get("stop", []),
|
| 53 |
"stream": stream_mode,
|
| 54 |
}
|
|
|
|
| 49 |
"max_tokens": int(kwargs.get("max_tokens", settings.DEFAULT_MAX_TOKENS)),
|
| 50 |
"temperature": float(kwargs.get("temperature", settings.DEFAULT_TEMP)),
|
| 51 |
"top_p": float(kwargs.get("top_p", 0.95)),
|
| 52 |
+
"repeat_penalty": float(kwargs.get("repeat_penalty", 1.15)),
|
| 53 |
"stop": kwargs.get("stop", []),
|
| 54 |
"stream": stream_mode,
|
| 55 |
}
|
src/ui/callbacks.py
CHANGED
|
@@ -35,16 +35,33 @@ def set_interactive(is_interactive):
|
|
| 35 |
def bot_response(
|
| 36 |
history, system_prompt, temperature, max_tokens, use_search, uploaded_file
|
| 37 |
):
|
| 38 |
-
# ПРЕДОХРАНИТЕЛЬ
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
file_info, file_content = "", ""
|
| 46 |
|
| 47 |
-
# ---
|
| 48 |
if uploaded_file and os.path.exists(uploaded_file):
|
| 49 |
filename = os.path.basename(uploaded_file)
|
| 50 |
size_kb = os.path.getsize(uploaded_file) / 1024
|
|
@@ -56,7 +73,7 @@ def bot_response(
|
|
| 56 |
if "[Ошибка" in file_content:
|
| 57 |
file_info = f"❌ **Ошибка файла:** `{filename}`"
|
| 58 |
|
| 59 |
-
# ---
|
| 60 |
for msg in history[-7:]:
|
| 61 |
content = str(msg["content"])
|
| 62 |
if msg["role"] == "assistant":
|
|
@@ -68,7 +85,7 @@ def bot_response(
|
|
| 68 |
content = re.sub(r"<details.*?>.*?</details>", "", content, flags=re.DOTALL)
|
| 69 |
content = re.sub(r"<think>.*?</think>", "", content, flags=re.DOTALL)
|
| 70 |
|
| 71 |
-
#
|
| 72 |
content = re.sub(
|
| 73 |
r"\[\s*\{.*?['\"]type['\"]\s*:\s*['\"]search['\"].*?\}\s*\]",
|
| 74 |
"",
|
|
@@ -85,7 +102,7 @@ def bot_response(
|
|
| 85 |
history.append({"role": "assistant", "content": "⏳ Инициализация..."})
|
| 86 |
yield history
|
| 87 |
|
| 88 |
-
# ---
|
| 89 |
search_info = ""
|
| 90 |
if use_search:
|
| 91 |
history[-1]["content"] = (
|
|
@@ -114,7 +131,7 @@ def bot_response(
|
|
| 114 |
eval_response = engine.generate(
|
| 115 |
messages=agent_messages,
|
| 116 |
max_tokens=150,
|
| 117 |
-
temperature=0.0, # Обязательно 0
|
| 118 |
stream=False,
|
| 119 |
)
|
| 120 |
|
|
@@ -150,6 +167,7 @@ def bot_response(
|
|
| 150 |
print(f"Ошибка Роутера: {e}")
|
| 151 |
search_info = "⚡ Ошибка роутера. Отвечаю из базы знаний."
|
| 152 |
|
|
|
|
| 153 |
if file_content:
|
| 154 |
messages[0]["content"] += (
|
| 155 |
f"\n\nСодержимое файла '{os.path.basename(uploaded_file)}':\n\n{file_content}"
|
|
@@ -164,12 +182,13 @@ def bot_response(
|
|
| 164 |
history[-1]["content"] = status_header + "⏳ Генерация ответа..."
|
| 165 |
yield history
|
| 166 |
|
| 167 |
-
# ---
|
| 168 |
try:
|
| 169 |
stream = engine.generate(
|
| 170 |
messages=messages,
|
| 171 |
max_tokens=max_tokens,
|
| 172 |
temperature=temperature,
|
|
|
|
| 173 |
stream=True,
|
| 174 |
)
|
| 175 |
partial_text = ""
|
|
|
|
| 35 |
def bot_response(
|
| 36 |
history, system_prompt, temperature, max_tokens, use_search, uploaded_file
|
| 37 |
):
|
| 38 |
+
# --- 1. ДИНАМИЧЕСКИЙ ПРОМПТ И ПРЕДОХРАНИТЕЛЬ ---
|
| 39 |
+
actual_sys_prompt = system_prompt
|
| 40 |
+
|
| 41 |
+
if use_search:
|
| 42 |
+
system_guard = (
|
| 43 |
+
"\n\n[ВАЖНО]: Отвечай пользователю напрямую обычным текстом. "
|
| 44 |
+
"КАТЕГОРИЧЕСКИ ЗАПРЕЩАЕТСЯ выводить технические команды, массивы или JSON-вызовы (например [{'type': 'search'}]). "
|
| 45 |
+
"Если тебе нужно рассуждать перед ответом, оборачивай свои мысли СТРОГО в теги <think>твои мысли</think>."
|
| 46 |
+
)
|
| 47 |
+
else:
|
| 48 |
+
# Если галочка поиска выключена, удаляем из системного промпта призыв искать
|
| 49 |
+
actual_sys_prompt = actual_sys_prompt.replace(
|
| 50 |
+
"Если нужно узнать свежую информацию, используйте поиск.", ""
|
| 51 |
+
)
|
| 52 |
+
|
| 53 |
+
system_guard = (
|
| 54 |
+
"\n\n[СИСТЕМНОЕ УВЕДОМЛЕНИЕ]: ВНИМАНИЕ! Функция поиска в интернете сейчас ОТКЛЮЧЕНА. "
|
| 55 |
+
"Ты ДОЛЖЕН ответить, используя только свои внутренние знания. "
|
| 56 |
+
"НИ В КОЕМ СЛУЧАЕ не пытайся генерировать команды поиска (например [{'type': 'search'}]). "
|
| 57 |
+
"Просто дай лучший ответ, который можешь, основываясь на своей памяти. "
|
| 58 |
+
"Если тебе нужно рассуждать, используй теги <think>мысли</think>."
|
| 59 |
+
)
|
| 60 |
+
|
| 61 |
+
messages = [{"role": "system", "content": actual_sys_prompt + system_guard}]
|
| 62 |
file_info, file_content = "", ""
|
| 63 |
|
| 64 |
+
# --- 2. ОБРАБОТКА ФАЙЛА ---
|
| 65 |
if uploaded_file and os.path.exists(uploaded_file):
|
| 66 |
filename = os.path.basename(uploaded_file)
|
| 67 |
size_kb = os.path.getsize(uploaded_file) / 1024
|
|
|
|
| 73 |
if "[Ошибка" in file_content:
|
| 74 |
file_info = f"❌ **Ошибка файла:** `{filename}`"
|
| 75 |
|
| 76 |
+
# --- 3. ОЧИСТКА И ФОРМИРОВАНИЕ ИСТОРИИ ---
|
| 77 |
for msg in history[-7:]:
|
| 78 |
content = str(msg["content"])
|
| 79 |
if msg["role"] == "assistant":
|
|
|
|
| 85 |
content = re.sub(r"<details.*?>.*?</details>", "", content, flags=re.DOTALL)
|
| 86 |
content = re.sub(r"<think>.*?</think>", "", content, flags=re.DOTALL)
|
| 87 |
|
| 88 |
+
# Вырезаем технические массивы поиска, если они проскочили в прошлых ответах
|
| 89 |
content = re.sub(
|
| 90 |
r"\[\s*\{.*?['\"]type['\"]\s*:\s*['\"]search['\"].*?\}\s*\]",
|
| 91 |
"",
|
|
|
|
| 102 |
history.append({"role": "assistant", "content": "⏳ Инициализация..."})
|
| 103 |
yield history
|
| 104 |
|
| 105 |
+
# --- 4. АГЕНТ ПОИСКА (РОУТЕР) ---
|
| 106 |
search_info = ""
|
| 107 |
if use_search:
|
| 108 |
history[-1]["content"] = (
|
|
|
|
| 131 |
eval_response = engine.generate(
|
| 132 |
messages=agent_messages,
|
| 133 |
max_tokens=150,
|
| 134 |
+
temperature=0.0, # Обязательно 0 для точности!
|
| 135 |
stream=False,
|
| 136 |
)
|
| 137 |
|
|
|
|
| 167 |
print(f"Ошибка Роутера: {e}")
|
| 168 |
search_info = "⚡ Ошибка роутера. Отвечаю из базы знаний."
|
| 169 |
|
| 170 |
+
# Добавляем контент файла в начало (чтобы модель опиралась на него при ответе)
|
| 171 |
if file_content:
|
| 172 |
messages[0]["content"] += (
|
| 173 |
f"\n\nСодержимое файла '{os.path.basename(uploaded_file)}':\n\n{file_content}"
|
|
|
|
| 182 |
history[-1]["content"] = status_header + "⏳ Генерация ответа..."
|
| 183 |
yield history
|
| 184 |
|
| 185 |
+
# --- 5. СТРИМИНГ И УМНЫЙ UI ---
|
| 186 |
try:
|
| 187 |
stream = engine.generate(
|
| 188 |
messages=messages,
|
| 189 |
max_tokens=max_tokens,
|
| 190 |
temperature=temperature,
|
| 191 |
+
repeat_penalty=1.15, # Штраф за зацикливание текста
|
| 192 |
stream=True,
|
| 193 |
)
|
| 194 |
partial_text = ""
|