Add new file
This commit is contained in:
117
rag/functions/soma_evaluate.py
Normal file
117
rag/functions/soma_evaluate.py
Normal 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
|
||||||
Reference in New Issue
Block a user