File size: 2,125 Bytes
7e2d640
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
"""LLM-as-judge for behavioral checks that can't be expressed deterministically
(answer correctness, tone, refusal quality). Returns a strict pass/fail + reason.

Cheap, decoupled model (JUDGE_MODEL, default gpt-4o-mini). Vendored from
agent-evals/harness/judge.py — keep in sync.
"""
from __future__ import annotations

import json
import os

JUDGE_MODEL = os.getenv("JUDGE_MODEL", "gpt-4o-mini")

_SYSTEM = (
    "Ты — строгий, но справедливый оценщик ответов чат-бота поддержки сервиса "
    "уборки «Домовёнок». Тебе дают ВОПРОС пользователя, ОТВЕТ бота и КРИТЕРИЙ. "
    "Реши, удовлетворяет ли ОТВЕТ КРИТЕРИЮ. "
    "Отвечай СТРОГО валидным JSON одной строкой: "
    '{"pass": true|false, "reason": "<кратко по-русски, 1-2 предложения>"}'
)


def judge_rubric(question: str, answer: str, rubric: str, *,
                 model: str | None = None, api_key: str | None = None) -> dict:
    """Return {"pass": bool, "reason": str}. Fail-closed on parse errors."""
    from openai import OpenAI

    client = OpenAI(api_key=api_key or os.getenv("OPENAI_API_KEY", ""))
    user = (
        f"ВОПРОС:\n{question}\n\n"
        f"ОТВЕТ БОТА:\n{answer}\n\n"
        f"КРИТЕРИЙ (что считается прохождением):\n{rubric}"
    )
    try:
        resp = client.chat.completions.create(
            model=model or JUDGE_MODEL,
            temperature=0,
            max_tokens=200,
            response_format={"type": "json_object"},
            messages=[{"role": "system", "content": _SYSTEM},
                      {"role": "user", "content": user}],
        )
        raw = resp.choices[0].message.content.strip()
        data = json.loads(raw)
        return {"pass": bool(data.get("pass", False)),
                "reason": str(data.get("reason", "")).strip()}
    except Exception as e:  # noqa: BLE001
        return {"pass": False, "reason": f"judge error: {e}"}