Update 5 files

- /rag/config_models.py
- /rag/utils/config_loader.py
- /rag/prompt_builder.py
- /rag/query_processor.py
- /template_bot_profile/data/fewshot_examples.json
This commit is contained in:
Markov Andrey
2026-06-30 14:57:03 +00:00
parent c00af40977
commit 67d86d6c1d
5 changed files with 298 additions and 55 deletions

View File

@@ -9,13 +9,14 @@ import logging
import re
from typing import Optional, Dict, List, Any
from rag.services.giga_client import GigaClient
from rag.services.kb_service import KBService
from rag.functions.expand_query import expand_query
from rag.functions.rerank_context import rerank_context
from rag.functions.critique_answer import critique_answer
from rag.utils.text_utils import count_tokens
from rag.config_models import AppConfig
from .services.giga_client import GigaClient
from .services.kb_service import KBService
from .functions.expand_query import expand_query
from .functions.rerank_context import rerank_context
from .functions.critique_answer import critique_answer
from .utils.text_utils import count_tokens
from .prompt_builder import PromptBuilder
from .config_models import AppConfig
logger = logging.getLogger(__name__)
@@ -32,19 +33,11 @@ class QueryProcessor:
config: AppConfig,
default_prompts: Optional[Dict[str, str]] = None
):
"""
Инициализация процессора запросов.
Аргументы:
giga: клиент GigaChat
kb: сервис базы знаний
config: объект конфигурации (AppConfig)
default_prompts: словарь промптов по умолчанию
"""
self.giga = giga
self.kb = kb
self.config = config
self.default_prompts = default_prompts or {}
self.prompt_builder = PromptBuilder(config)
async def process(
self,
@@ -59,35 +52,20 @@ class QueryProcessor:
) -> Dict[str, Any]:
"""
Выполняет полный RAG-пайплайн для обычного запроса.
Аргументы:
query: текст запроса пользователя
user_jid: JID пользователя
room_jid: JID комнаты (None для личного чата)
prompts: словарь промптов (expand, synthesis, critique, ...)
intent: код намерения (для выбора стратегии)
history: история диалога (уже сжатая, если нужно)
system_prompt: системный промпт
available_tokens_for_context: сколько токенов доступно для контекста (после вычета истории и промптов)
Возвращает:
Словарь с ключами 'answer', 'context', 'sources', 'confidence'
"""
# 1. Расширение запроса
expand_prompt = prompts.get('expand', '')
expanded = await expand_query(
giga=self.giga,
query=query,
prompt_text=expand_prompt,
prompt_text=prompts.get('expand', ''),
bot_config=self.config
)
search_query = expanded if expanded and expanded != query else query
# 2. Поиск релевантного контекста в базе знаний
top_k = self.config.rag.default_top_k
context = await self.kb.find_relevant_info(
search_query, user_jid, room_jid,
top_k=top_k
top_k=getattr(self.config, 'rag_default_top_k', 30)
)
logger.info(f"Найден контекст длиной {len(context)} символов (room={room_jid})")
@@ -106,7 +84,7 @@ class QueryProcessor:
context = ""
# 4. Переранжирование контекста (если включено и контекст достаточно длинный)
rerank_min_length = self.config.rag.rerank_min_length
rerank_min_length = getattr(self.config, 'rerank_min_length', 5000)
if intent != "FACT" and len(context) > rerank_min_length:
context = await rerank_context(
bot=None,
@@ -116,34 +94,42 @@ class QueryProcessor:
bot_config=self.config
)
# 5. Синтез ответа с добавлением цепочки рассуждений (CoT) для CALCULATION и PROCEDURE
synthesis_template = prompts.get('synthesis', '')
if not synthesis_template:
synthesis_template = "{context}\n\n{query}\n\nОтвет:"
# 5. Формирование промта с помощью PromptBuilder (динамические few-shot, сэндвич)
extra_instructions = ""
if intent in ("CALCULATION", "PROCEDURE"):
cot_instruction = (
"\n\nПожалуйста, покажи пошаговое решение перед итоговым ответом. "
extra_instructions = (
"Пожалуйста, покажи пошаговое решение перед итоговым ответом. "
"Опиши каждый шаг вычислений или действий в логической последовательности. "
"После всех шагов дай итоговый ответ."
)
synthesis_template += cot_instruction
full_query = synthesis_template.format(context=context, query=query)
logger.debug(f"Полный запрос к GigaChat (первые 500 символов): {full_query[:500]}")
# Если synthesis_template задан, добавим его в extra_instructions (но PromptBuilder уже использует стандартные инструкции)
synthesis_template = prompts.get('synthesis', '')
if synthesis_template and not extra_instructions:
# Если есть кастомный шаблон, используем его как дополнительную инструкцию
extra_instructions = synthesis_template.format(context=context, query=query) if '{context}' in synthesis_template else synthesis_template
# 6. Генерация ответа
temperature = self.config.ai.temperature
answer = await self.giga.chat(
prompt = self.prompt_builder.build_prompt(
query=query,
intent=intent,
context=context,
history=history,
query=full_query,
system_prompt=system_prompt,
extra_instructions=extra_instructions
)
logger.debug(f"Сформированный промт (первые 500 символов): {prompt[:500]}")
# 6. Генерация ответа (без отдельной передачи истории, она уже в промте)
answer = await self.giga.chat(
history=[], # история уже в промте
query=prompt,
system_prompt=None, # системный промпт тоже в промте
file_id=None,
temperature=temperature
temperature=getattr(self.config, 'ai_temperature', 0.1)
)
# 7. Самокритика (если включена)
if self.config.features.enable_self_critique and context:
if getattr(self.config, 'enable_self_critique', False) and context:
critique_prompt = prompts.get('critique', '')
if critique_prompt:
logger.debug("Запуск самокритики")
@@ -157,13 +143,13 @@ class QueryProcessor:
)
if not is_ok:
logger.warning("Ответ не прошёл самокритику, перегенерация")
full_query_retry = synthesis_template.format(context=context, query=query)
# Перегенерируем с тем же промтом
answer = await self.giga.chat(
history=history,
query=full_query_retry,
system_prompt=system_prompt,
history=[],
query=prompt,
system_prompt=None,
file_id=None,
temperature=temperature
temperature=getattr(self.config, 'ai_temperature', 0.1)
)
# Повторная проверка после перегенерации
if not await critique_answer(