Add new file

This commit is contained in:
Markov Andrey
2026-06-30 20:48:00 +00:00
parent 2580d4a8ca
commit 70ab0c1121

View File

@@ -0,0 +1,117 @@
# rag/functions/soma_evaluate.py
"""
SOMA-анализ (LLM-as-judge) для оценки качества ответа.
Оценивает ответ по критериям: релевантность, полнота, отсутствие галлюцинаций,
стиль, полезность. Возвращает оценки и вердикт.
"""
import json
import logging
from typing import Dict, Any, Optional
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, # нужно добавить timeout в GigaClient.chat (если нет, игнорировать)
)
# Ожидаем JSON
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