Files
fckbot/rag/functions/soma_evaluate.py
2026-06-30 20:58:00 +00:00

111 lines
3.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
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