""" SOMA-анализ (LLM-as-judge) для оценки качества ответа. Оценивает ответ по критериям: релевантность, полнота, отсутствие галлюцинаций, стиль, полезность. Возвращает оценки и вердикт. """ import json import logging from typing import Dict, Any from rag.services.giga_client import GigaClient from rag.config_models import AppConfig logger = logging.getLogger(__name__) async def soma_evaluate( query: str, context: str, answer: str, config: AppConfig, giga: GigaClient, prompts: Dict[str, str], ) -> Dict[str, Any]: """ Оценивает ответ LLM с помощью другого вызова GigaChat. Аргументы: query: исходный запрос пользователя. context: контекст из базы знаний (может быть пустым). answer: сгенерированный ответ. config: объект конфигурации. giga: клиент GigaChat для вызова. prompts: словарь с содержимым промптов (ключ 'soma_evaluate'). Возвращает: dict с полями: scores: dict с оценками по критериям (числа от 1 до 5). overall_score: средняя оценка (float). verdict: 'pass' или 'fail' (в зависимости от порога). feedback: текстовое обоснование. error: строка ошибки (если есть). """ default_result = { "scores": { "relevance": 3.0, "completeness": 3.0, "no_hallucination": 3.0, "style": 3.0, "usefulness": 3.0, }, "overall_score": 3.0, "verdict": "fail", "feedback": "Оценка не удалась, возвращены значения по умолчанию.", "error": None, } prompt_template = prompts.get("soma_evaluate") if not prompt_template: logger.error("Промпт для SOMA-оценки не найден") default_result["error"] = "Отсутствует промпт soma_evaluate" return default_result full_prompt = prompt_template.format( query=query, context=context[:3000] if context else "Нет контекста", answer=answer, ) temperature = getattr(config, 'soma_temperature', 0.1) timeout = getattr(config, 'soma_timeout', 30) try: response = await giga.chat( history=[], query=full_prompt, system_prompt=None, file_id=None, temperature=temperature, timeout=timeout, ) data = json.loads(response.strip()) scores = data.get("scores", {}) feedback = data.get("feedback", "") for key in scores: try: scores[key] = float(scores[key]) except (ValueError, TypeError): scores[key] = 3.0 overall = sum(scores.values()) / len(scores) if scores else 3.0 threshold = getattr(config, 'soma_threshold', 3.5) verdict = "pass" if overall >= threshold else "fail" return { "scores": scores, "overall_score": overall, "verdict": verdict, "feedback": feedback, "error": None, } except json.JSONDecodeError as e: logger.error(f"Ошибка парсинга JSON от GigaChat: {e}, ответ: {response[:200]}") default_result["error"] = f"Ошибка парсинга JSON: {e}" return default_result except Exception as e: logger.exception(f"Ошибка при вызове SOMA-оценки: {e}") default_result["error"] = str(e) return default_result