feat: add dialogue compaction with summary integration
- Add /compact command for manual compaction - Integrate summary loading from ChromaDB - Add summary to AI prompt context - Automatic compaction at 70% threshold - Keep last 20 messages uncompressed Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
parent
417a858468
commit
bff74741a6
102
bot.py
102
bot.py
|
|
@ -213,8 +213,17 @@ async def handle_ai_task(update: Update, text: str):
|
||||||
def on_oauth_url(url: str):
|
def on_oauth_url(url: str):
|
||||||
pass # OAuth обрабатывается автоматически
|
pass # OAuth обрабатывается автоматически
|
||||||
|
|
||||||
# Формируем контекст с историей + памятью
|
# Формируем контекст с историей + памятью + summary
|
||||||
history_context = "\n".join(state.ai_chat_history)
|
# Получаем summary и последние сообщения из ChromaDB
|
||||||
|
summary = None
|
||||||
|
try:
|
||||||
|
summary, recent_messages = compactor.get_context_with_summary(limit=20)
|
||||||
|
# Формируем историю из последних сообщений
|
||||||
|
history_context = "\n".join([f"{msg['role']}: {msg['content']}" for msg in recent_messages])
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Ошибка загрузки summary: {e}")
|
||||||
|
# Fallback на старую логику
|
||||||
|
history_context = "\n".join(state.ai_chat_history)
|
||||||
|
|
||||||
# Получаем контекст из системы памяти (профиль + релевантные факты)
|
# Получаем контекст из системы памяти (профиль + релевантные факты)
|
||||||
memory_context = get_context(user_id, query=text)
|
memory_context = get_context(user_id, query=text)
|
||||||
|
|
@ -230,16 +239,30 @@ async def handle_ai_task(update: Update, text: str):
|
||||||
|
|
||||||
# Собираем полный промпт с системным промптом
|
# Собираем полный промпт с системным промптом
|
||||||
system_prompt = qwen_manager.load_system_prompt()
|
system_prompt = qwen_manager.load_system_prompt()
|
||||||
|
|
||||||
full_task = (
|
# Формируем полный промпт с summary (если есть)
|
||||||
f"{system_prompt}\n\n"
|
if summary:
|
||||||
f"=== КОНТЕКСТ ПАМЯТИ ===\n"
|
full_task = (
|
||||||
f"{memory_context}\n\n"
|
f"{system_prompt}\n\n"
|
||||||
f"=== ИСТОРИЯ ДИАЛОГА ===\n"
|
f"=== SUMMARY ДИАЛОГА (контекст) ===\n"
|
||||||
f"{history_context}\n\n"
|
f"{summary}\n\n"
|
||||||
f"=== ЗАПРОС ПОЛЬЗОВАТЕЛЯ ===\n"
|
f"=== КОНТЕКСТ ПАМЯТИ ===\n"
|
||||||
f"{text}"
|
f"{memory_context}\n\n"
|
||||||
)
|
f"=== ИСТОРИЯ ДИАЛОГА (последние 20 сообщений) ===\n"
|
||||||
|
f"{history_context}\n\n"
|
||||||
|
f"=== ЗАПРОС ПОЛЬЗОВАТЕЛЯ ===\n"
|
||||||
|
f"{text}"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
full_task = (
|
||||||
|
f"{system_prompt}\n\n"
|
||||||
|
f"=== КОНТЕКСТ ПАМЯТИ ===\n"
|
||||||
|
f"{memory_context}\n\n"
|
||||||
|
f"=== ИСТОРИЯ ДИАЛОГА ===\n"
|
||||||
|
f"{history_context}\n\n"
|
||||||
|
f"=== ЗАПРОС ПОЛЬЗОВАТЕЛЯ ===\n"
|
||||||
|
f"{text}"
|
||||||
|
)
|
||||||
|
|
||||||
# Выполняем задачу (системный промпт уже добавлен в full_task)
|
# Выполняем задачу (системный промпт уже добавлен в full_task)
|
||||||
result = await qwen_manager.run_task(user_id, full_task, on_output, on_oauth_url, use_system_prompt=False)
|
result = await qwen_manager.run_task(user_id, full_task, on_output, on_oauth_url, use_system_prompt=False)
|
||||||
|
|
@ -1371,17 +1394,59 @@ async def ai_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@check_access
|
||||||
|
async def compact_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
"""Обработка команды /compact — ручная компактификация истории диалога."""
|
||||||
|
user_id = update.effective_user.id
|
||||||
|
|
||||||
|
logger.info(f"Пользователь {user_id} запросил ручную компактификацию")
|
||||||
|
|
||||||
|
status_msg = await update.message.reply_text(
|
||||||
|
"🔄 **Запуск компактификации истории...**\n\n"
|
||||||
|
"_Сжатие старой истории в структурированный summary._\n"
|
||||||
|
"_Это может занять несколько секунд._",
|
||||||
|
parse_mode="Markdown"
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await compactor.compact()
|
||||||
|
|
||||||
|
await status_msg.delete()
|
||||||
|
|
||||||
|
if result.success:
|
||||||
|
if result.messages_compressed > 0:
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"✅ **Компактификация завершена!**\n\n"
|
||||||
|
f"📊 Сжато сообщений: `{result.messages_compressed}`\n"
|
||||||
|
f"📝 Длина summary: `{result.summary_length}` символов\n"
|
||||||
|
f"💾 Экономия токенов: ~`{result.tokens_saved}`\n\n"
|
||||||
|
f"_Summary автоматически используется в контексте диалога._",
|
||||||
|
parse_mode="Markdown"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await update.message.reply_text(
|
||||||
|
"ℹ️ **Компактификация не требуется**\n\n"
|
||||||
|
"_Недостаточно сообщений для сжатия или summary уже актуален._",
|
||||||
|
parse_mode="Markdown"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
logger.error(f"Компактификация не удалась: {result.error}")
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"⚠️ **Ошибка компактификации:**\n`{result.error}`",
|
||||||
|
parse_mode="Markdown"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@check_access
|
@check_access
|
||||||
async def memory_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
async def memory_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
"""Обработка команды /memory — статистика памяти ИИ."""
|
"""Обработка команды /memory — статистика памяти ИИ."""
|
||||||
user_id = update.effective_user.id
|
user_id = update.effective_user.id
|
||||||
|
|
||||||
stats = get_memory_stats(user_id)
|
stats = get_memory_stats(user_id)
|
||||||
|
|
||||||
if not stats:
|
if not stats:
|
||||||
await update.message.reply_text("ℹ️ Память не инициализирована")
|
await update.message.reply_text("ℹ️ Память не инициализирована")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Форматируем статистику
|
# Форматируем статистику
|
||||||
total_messages = stats.get("total_messages", 0)
|
total_messages = stats.get("total_messages", 0)
|
||||||
total_facts = stats.get("total_facts", 0)
|
total_facts = stats.get("total_facts", 0)
|
||||||
|
|
@ -1389,21 +1454,21 @@ async def memory_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
vector_docs = stats.get("vector_documents", "N/A")
|
vector_docs = stats.get("vector_documents", "N/A")
|
||||||
vector_model = stats.get("vector_model", "N/A")
|
vector_model = stats.get("vector_model", "N/A")
|
||||||
hybrid_mode = stats.get("hybrid_mode", False)
|
hybrid_mode = stats.get("hybrid_mode", False)
|
||||||
|
|
||||||
text = (
|
text = (
|
||||||
"🧠 *Статистика памяти:*\n\n"
|
"🧠 *Статистика памяти:*\n\n"
|
||||||
f"📊 Сообщений: `{total_messages}`\n"
|
f"📊 Сообщений: `{total_messages}`\n"
|
||||||
f"📌 Фактов: `{total_facts}`\n"
|
f"📌 Фактов: `{total_facts}`\n"
|
||||||
f"📁 Сессий: `{total_sessions}`\n"
|
f"📁 Сессий: `{total_sessions}`\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
if hybrid_mode:
|
if hybrid_mode:
|
||||||
text += (
|
text += (
|
||||||
f"\n🔮 *Векторная память:*\n"
|
f"\n🔮 *Векторная память:*\n"
|
||||||
f" Документы: `{vector_docs}`\n"
|
f" Документы: `{vector_docs}`\n"
|
||||||
f" Модель: `{vector_model}`\n"
|
f" Модель: `{vector_model}`\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
text += "\n_Память использует SQLite + ChromaDB с семантическим поиском._"
|
text += "\n_Память использует SQLite + ChromaDB с семантическим поиском._"
|
||||||
|
|
||||||
await update.message.reply_text(text, parse_mode="Markdown")
|
await update.message.reply_text(text, parse_mode="Markdown")
|
||||||
|
|
@ -1567,6 +1632,7 @@ def main():
|
||||||
application.add_handler(CommandHandler("menu", menu_command))
|
application.add_handler(CommandHandler("menu", menu_command))
|
||||||
application.add_handler(CommandHandler("stop", stop_command))
|
application.add_handler(CommandHandler("stop", stop_command))
|
||||||
application.add_handler(CommandHandler("memory", memory_command))
|
application.add_handler(CommandHandler("memory", memory_command))
|
||||||
|
application.add_handler(CommandHandler("compact", compact_command))
|
||||||
application.add_handler(CommandHandler("facts", facts_command))
|
application.add_handler(CommandHandler("facts", facts_command))
|
||||||
application.add_handler(CommandHandler("forget", forget_command))
|
application.add_handler(CommandHandler("forget", forget_command))
|
||||||
application.add_handler(CallbackQueryHandler(menu_callback))
|
application.add_handler(CallbackQueryHandler(menu_callback))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue