Update 9 files
- /rag/config_models.py - /rag/utils/config_loader.py - /rag/auth.py - /rag/rag_server.py - /rag/rag_api.py - /rag/rag_orchestrator.py - /rag/__init__.py - /bots/xmpp/client.py - /bots/rag_client.py
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
"""
|
||||
Главный оркестратор RAG-пайплайна (фасад).
|
||||
Координирует работу менеджеров: HistoryManager, IntentRouter, QueryProcessor, IndexingManager.
|
||||
Принимает запрос пользователя, обрабатывает его и возвращает ответ.
|
||||
"""
|
||||
|
||||
import logging
|
||||
@@ -29,7 +28,6 @@ class RAGOrchestrator:
|
||||
"""
|
||||
Оркестратор RAG-пайплайна.
|
||||
Содержит ссылки на все сервисы и менеджеры.
|
||||
Предоставляет два основных метода: process_query и index_document.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -43,19 +41,6 @@ class RAGOrchestrator:
|
||||
config: AppConfig,
|
||||
default_prompts: Optional[Dict[str, str]] = None
|
||||
):
|
||||
"""
|
||||
Инициализация оркестратора.
|
||||
|
||||
Аргументы:
|
||||
db: сервис PostgreSQL
|
||||
qdrant: сервис Qdrant
|
||||
embedding: сервис эмбеддингов
|
||||
kb: сервис базы знаний
|
||||
giga: клиент GigaChat
|
||||
files: сервис файлов
|
||||
config: объект конфигурации (AppConfig)
|
||||
default_prompts: словарь промптов по умолчанию
|
||||
"""
|
||||
self.db = db
|
||||
self.qdrant = qdrant
|
||||
self.embedding = embedding
|
||||
@@ -97,10 +82,6 @@ class RAGOrchestrator:
|
||||
|
||||
logger.info("RAGOrchestrator инициализирован с менеджерами")
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Вспомогательный метод для расчёта токенов
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _prepare_prompt_parts(
|
||||
self,
|
||||
synthesis_template: str,
|
||||
@@ -110,17 +91,6 @@ class RAGOrchestrator:
|
||||
reserved_for_answer: int = 1000,
|
||||
reserved_for_overhead: int = 200
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Подсчитывает токены в статичных частях промта и вычисляет,
|
||||
сколько токенов остаётся для истории и контекста.
|
||||
|
||||
Возвращает словарь с ключами:
|
||||
- available_for_history_and_context: int
|
||||
- prompt_tokens: int
|
||||
- system_tokens: int
|
||||
- synthesis_tokens: int
|
||||
- query_tokens: int
|
||||
"""
|
||||
system_tokens = count_tokens(system_prompt) if system_prompt else 0
|
||||
synthesis_tokens = count_tokens(synthesis_template)
|
||||
query_tokens = count_tokens(query)
|
||||
@@ -142,10 +112,6 @@ class RAGOrchestrator:
|
||||
"query_tokens": query_tokens,
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Основной метод обработки запроса
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
async def process_query(
|
||||
self,
|
||||
query: str,
|
||||
@@ -156,25 +122,6 @@ class RAGOrchestrator:
|
||||
last_file_path: Optional[str] = None,
|
||||
last_file_text: Optional[str] = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Основной метод обработки запроса.
|
||||
|
||||
ИСТОРИЯ ДИАЛОГА ПОЛУЧАЕТСЯ ИЗ БД, а не из запроса.
|
||||
Это обеспечивает единый контекст для всех клиентов.
|
||||
|
||||
Аргументы:
|
||||
query: текст запроса пользователя
|
||||
user_jid: JID пользователя (без ресурса)
|
||||
room_jid: JID комнаты (None для личного чата)
|
||||
prompts: словарь промптов (если None, используются default_prompts)
|
||||
intent_override: принудительное переопределение намерения
|
||||
last_file_path: путь к последнему загруженному файлу
|
||||
last_file_text: текст последнего загруженного файла
|
||||
|
||||
Возвращает:
|
||||
Словарь с ключами: answer, intent, context, sources, confidence, error
|
||||
"""
|
||||
# 1. Подготовка промптов
|
||||
if prompts is None:
|
||||
prompts = self.default_prompts.copy()
|
||||
synthesis_template = prompts.get('synthesis', '')
|
||||
@@ -182,7 +129,6 @@ class RAGOrchestrator:
|
||||
synthesis_template = "{context}\n\n{query}\n\nОтвет:"
|
||||
system_prompt = prompts.get('system', None)
|
||||
|
||||
# 2. Расчёт лимитов токенов
|
||||
max_model_tokens = self.config.max_model_tokens
|
||||
reserved_for_answer = self.config.reserved_for_answer_tokens
|
||||
reserved_for_overhead = self.config.reserved_for_overhead_tokens
|
||||
@@ -198,10 +144,8 @@ class RAGOrchestrator:
|
||||
available_for_history_and_context = token_info["available_for_history_and_context"]
|
||||
logger.debug(f"Доступно для истории и контекста: {available_for_history_and_context} токенов")
|
||||
|
||||
# 3. Получение истории из БД
|
||||
raw_history = await self.history_manager.get_history(user_jid, room_jid, limit=100)
|
||||
|
||||
# 4. Сжатие истории, если она слишком длинная
|
||||
max_history_tokens = min(available_for_history_and_context // 2, 2000)
|
||||
formatted_history = await self.history_manager.compress_history_if_needed(
|
||||
raw_history,
|
||||
@@ -209,7 +153,6 @@ class RAGOrchestrator:
|
||||
prompt_template=prompts.get('hierarchical_summary', '')
|
||||
)
|
||||
|
||||
# 5. Классификация намерений
|
||||
intent = intent_override
|
||||
if intent is None and self.config.enable_intent_classification:
|
||||
intent_prompt = prompts.get('intent', '')
|
||||
@@ -225,13 +168,11 @@ class RAGOrchestrator:
|
||||
else:
|
||||
intent = intent or "GENERAL"
|
||||
|
||||
# 6. Принудительная установка SURGICAL по ключевым словам
|
||||
keywords = self.config.surgical_keywords
|
||||
if any(kw in query.lower() for kw in keywords) and last_file_path:
|
||||
intent = "SURGICAL"
|
||||
logger.info(f"Принудительный Intent: SURGICAL (есть файл и ключевые слова)")
|
||||
|
||||
# 7. Маршрутизация специализированных намерений
|
||||
router_result = await self.intent_router.route(
|
||||
intent=intent,
|
||||
query=query,
|
||||
@@ -249,12 +190,10 @@ class RAGOrchestrator:
|
||||
sources = []
|
||||
|
||||
if router_result is not None:
|
||||
# Намерение обработано маршрутизатором
|
||||
answer = router_result.get("answer")
|
||||
context = router_result.get("context", "")
|
||||
sources = router_result.get("sources", [])
|
||||
else:
|
||||
# Обычный RAG-пайплайн (GENERAL, FACT, PROCEDURE, COMPARISON, CALCULATION)
|
||||
history_tokens = sum(count_tokens(msg['content']) for msg in formatted_history)
|
||||
available_for_context = available_for_history_and_context - history_tokens
|
||||
available_for_context = max(available_for_context, 0)
|
||||
@@ -273,12 +212,10 @@ class RAGOrchestrator:
|
||||
context = processor_result.get("context", "")
|
||||
sources = processor_result.get("sources", [])
|
||||
|
||||
# 8. Сохранение истории диалога в БД
|
||||
await self.history_manager.save_message(user_jid, "user", query, room_jid)
|
||||
if answer:
|
||||
await self.history_manager.save_message(user_jid, "assistant", answer, room_jid)
|
||||
|
||||
# 9. Формирование результата
|
||||
return {
|
||||
"answer": answer or "⚠️ Не удалось сгенерировать ответ.",
|
||||
"intent": intent,
|
||||
@@ -288,10 +225,6 @@ class RAGOrchestrator:
|
||||
"error": None
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Индексация документа
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
async def index_document(
|
||||
self,
|
||||
file_name: str,
|
||||
@@ -304,24 +237,6 @@ class RAGOrchestrator:
|
||||
file_hash: Optional[str] = None,
|
||||
update_if_exists: bool = True
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Индексирует документ в базу знаний.
|
||||
Делегирует работу IndexingManager.
|
||||
|
||||
Аргументы:
|
||||
file_name: исходное имя файла
|
||||
file_text: извлечённый текст
|
||||
user_jid: JID владельца
|
||||
room_jid: JID комнаты (None для личного)
|
||||
is_global: глобальный ли документ
|
||||
title: отображаемое название
|
||||
metadata: дополнительные метаданные
|
||||
file_hash: SHA-256 хеш содержимого
|
||||
update_if_exists: заменять ли существующий документ в комнате
|
||||
|
||||
Возвращает:
|
||||
Словарь с ключами doc_id, chunk_count, error
|
||||
"""
|
||||
try:
|
||||
doc_id, chunk_count = await self.indexing_manager.index_document(
|
||||
file_name=file_name,
|
||||
|
||||
Reference in New Issue
Block a user