Source code for eval_framework.metrics.llm.llm_judge_mtbench_single

import re
import traceback

from pydantic import BaseModel

from eval_framework.logger import logger
from eval_framework.metrics.base import MetricResult
from eval_framework.metrics.llm.base import BaseLLMJudgeMetric
from eval_framework.shared.types import BaseMetricContext, Completion, Error, extract_context_metric
from template_formatting.formatter import Message, Role

SINGLE_JUDGE_PROMPTS = {
    "single_assistant_single_turn": {
        "prompt_template": '[System]\nYou are a helpful assistant.\n\n[Instruction]\nPlease act as an impartial judge and evaluate the quality of the response provided by an AI assistant to the user question displayed below. Your evaluation should consider factors such as the helpfulness, relevance, accuracy, depth, creativity, and level of detail of the response. Begin your evaluation by providing a short explanation. Be as objective as possible. After providing your explanation, you must rate the response on a scale of 1 to 10 by strictly following this format: "[[rating]]", for example: "Rating: [[5]]".\n\n[Question]\n{question}\n\n[The Start of Assistant\'s Answer]\n{answer}\n[The End of Assistant\'s Answer]'  # noqa: E501
    },
    "single_assistant_multi_turn": {
        "prompt_template": 'Please act as an impartial judge and evaluate the quality of the response provided by an AI assistant to the user question displayed below. Your evaluation should consider factors such as the helpfulness, relevance, accuracy, depth, creativity, and level of detail of the response. You evaluation should focus on the assistant\'s answer to the second user question. Begin your evaluation by providing a short explanation. Be as objective as possible. After providing your explanation, you must rate the response on a scale of 1 to 10 by strictly following this format: "[[rating]]", for example: "Rating: [[5]]".\n\n<|The Start of Assistant A\'s Conversation with User|>\n\n### User:\n{question_1}\n\n### Assistant A:\n{answer_1}\n\n### User:\n{question_2}\n\n### Assistant A:\n{answer_2}\n\n<|The End of Assistant A\'s Conversation with User|>'  # noqa: E501
    },
    "single_assistant_single_turn_w_reference": {
        "prompt_template": "[System]\nYou are a helpful assistant.\n\n[Instruction]\nPlease act as an impartial judge and evaluate the quality of the response provided by an AI assistant to the user question displayed below. Your evaluation should consider correctness and helpfulness. You will be given a reference answer and the assistant's answer. Begin your evaluation by comparing the assistant's answer with the reference answer. Identify and correct any mistakes. Be as objective as possible. After providing your explanation, you must rate the response on a scale of 1 to 10 by strictly following this format: \"[[rating]]\", for example: \"Rating: [[5]]\".\n\n[Question]\n{question}\n\n[The Start of Reference Answer]\n{ref_answer_1}\n[The End of Reference Answer]\n\n[The Start of Assistant's Answer]\n{answer}\n[The End of Assistant's Answer]"  # noqa: E501
    },
    "single_assistant_multi_turn_w_reference": {
        "prompt_template": "Please act as an impartial judge and evaluate the quality of the response provided by an AI assistant to the user question. Your evaluation should consider correctness and helpfulness. You will be given a reference answer and the assistant's answer. You evaluation should focus on the assistant's answer to the second question. Begin your evaluation by comparing the assistant's answer with the reference answer. Identify and correct any mistakes. Be as objective as possible. After providing your explanation, you must rate the response on a scale of 1 to 10 by strictly following this format: \"[[rating]]\", for example: \"Rating: [[5]]\".\n\n<|The Start of Reference Answer|>\n\n### User:\n{question_1}\n\n### Reference answer:\n{ref_answer_1}\n\n### User:\n{question_2}\n\n### Reference answer:\n{ref_answer_2}\n\n<|The End of Reference Answer|>\n\n\n<|The Start of Assistant A's Conversation with User|>\n\n### User:\n{question_1}\n\n### Assistant A:\n{answer_1}\n\n### User:\n{question_2}\n\n### Assistant A:\n{answer_2}\n\n<|The End of Assistant A's Conversation with User|>"  # noqa: E501
    },
}

SINGLE_JUDGE_PROMPTS_DE = {
    "single_assistant_single_turn": {
        "prompt_template": '[System]\nDu bist ein hilfreicher Assistent.\n\n[Anweisung]\nBitte agieren Sie als unparteiischer Richter und bewerten Sie die Qualität der Antwort, die von einem KI-Assistenten auf die unten angezeigte Nutzerfrage gegeben wurde. Ihre Bewertung sollte Faktoren wie Nützlichkeit, Relevanz, Genauigkeit, Tiefe, Kreativität und Detailliertheit der Antwort berücksichtigen. Beginnen Sie Ihre Bewertung mit einer kurzen Erklärung. Seien Sie so objektiv wie möglich. Nachdem Sie Ihre Erklärung gegeben haben, müssen Sie die Antwort auf einer Skala von 1 bis 10 bewerten und dabei streng dieses Format einhalten: "[[rating]]", zum Beispiel: "Bewertung: [[5]]".\n\n[Frage]\n{question}\n\n[Der Anfang der Assistentenantwort]\n{answer}\n[Das Ende der Assistentenantwort]'  # noqa: E501
    },
    "single_assistant_multi_turn": {
        "prompt_template": 'Bitte agieren Sie als unparteiischer Richter und bewerten Sie die Qualität der Antwort, die von einem KI-Assistenten auf die unten angezeigte Nutzerfrage gegeben wurde. Ihre Bewertung sollte Faktoren wie Nützlichkeit, Relevanz, Genauigkeit, Tiefe, Kreativität und Detailliertheit der Antwort berücksichtigen. Ihre Bewertung sollte sich auf die Antwort des Assistenten auf die zweite Nutzerfrage konzentrieren. Beginnen Sie Ihre Bewertung mit einer kurzen Erklärung. Seien Sie so objektiv wie möglich. Nachdem Sie Ihre Erklärung gegeben haben, müssen Sie die Antwort auf einer Skala von 1 bis 10 bewerten, wobei Sie streng dieses Format einhalten: "[[rating]]", zum Beispiel: "Bewertung: [[5]]".\n\n<|Der Anfang von Assistent A\'s Unterhaltung mit dem Nutzer|>\n\n### Nutzer:\n{question_1}\n\n### Assistent A:\n{answer_1}\n\n### Nutzer:\n{question_2}\n\n### Assistent A:\n{answer_2}\n\n<|Das Ende von Assistent A\'s Unterhaltung mit dem Nutzer|>'  # noqa: E501
    },
    "single_assistant_single_turn_w_reference": {
        "prompt_template": '[System]\nDu bist ein hilfreicher Assistent.\n\n[Anweisung]\nBitte agieren Sie als unparteiischer Richter und bewerten Sie die Qualität der Antwort, die von einem KI-Assistenten auf die unten angezeigte Nutzerfrage gegeben wurde. Ihre Bewertung sollte Korrektheit und Nützlichkeit berücksichtigen. Ihnen wird eine Referenzantwort und die Antwort des Assistenten gegeben. Beginnen Sie Ihre Bewertung, indem Sie die Antwort des Assistenten mit der Referenzantwort vergleichen. Identifizieren Sie und korrigieren Sie etwaige Fehler. Seien Sie so objektiv wie möglich. Nachdem Sie Ihre Erklärung gegeben haben, müssen Sie die Antwort auf einer Skala von 1 bis 10 bewerten und dabei streng dieses Format einhalten: "[[rating]]", zum Beispiel: "Bewertung: [[5]]".\n\n[Frage]\n{question}\n\n[Der Anfang der Referenzantwort]\n{ref_answer_1}\n[Das Ende der Referenzantwort]\n\n[Der Anfang der Assistentenantwort]\n{answer}\n[Das Ende der Assistentenantwort]'  # noqa: E501
    },
    "single_assistant_multi_turn_w_reference": {
        "prompt_template": 'Bitte agieren Sie als unparteiischer Richter und bewerten Sie die Qualität der Antwort, die von einem KI-Assistenten auf die Nutzerfrage gegeben wurde. Ihre Bewertung sollte Korrektheit und Nützlichkeit berücksichtigen. Ihnen wird eine Referenzantwort und die Antwort des Assistenten gegeben. Ihre Bewertung sollte sich auf die Antwort des Assistenten auf die zweite Frage konzentrieren. Beginnen Sie Ihre Bewertung, indem Sie die Antwort des Assistenten mit der Referenzantwort vergleichen. Identifizieren und korrigieren Sie etwaige Fehler. Seien Sie so objektiv wie möglich. Nachdem Sie Ihre Erklärung gegeben haben, müssen Sie die Antwort auf einer Skala von 1 bis 10 bewerten, wobei Sie streng dieses Format einhalten: "[[rating]]", zum Beispiel: "Bewertung: [[5]]".\n\n<|Der Anfang der Referenzantwort|>\n\n### Nutzer:\n{question_1}\n\n### Referenzantwort:\n{ref_answer_1}\n\n### Nutzer:\n{question_2}\n\n### Referenzantwort:\n{ref_answer_2}\n\n<|Das Ende der Referenzantwort|>\n\n\n<|Der Anfang von Assistent A\'s Unterhaltung mit dem Nutzer|>\n\n### Nutzer:\n{question_1}\n\n### Assistent A:\n{answer_1}\n\n### Nutzer:\n{question_2}\n\n### Assistent A:\n{answer_2}\n\n<|Das Ende von Assistent A\'s Unterhaltung mit dem Nutzer|>'  # noqa: E501
    },
}


SINGLE_JUDGE_PROMPTS_FI = {
    "single_assistant_single_turn": {
        "prompt_template": '[Järjestelmä]\nOlet avulias avustaja.\n\n[Ohje]\nToimi puolueettomana tuomarina ja arvioi AI-avustajan antaman vastauksen laatua käyttäjän kysymykseen, joka näkyy alla. Arviosi tulisi ottaa huomioon tekijät kuten hyödyllisyys, asiaankuuluvuus, tarkkuus, syvällisyys, luovuus ja yksityiskohtien taso. Aloita arviointisi antamalla lyhyt selitys. Ole mahdollisimman objektiivinen. Selityksen jälkeen sinun on arvioitava vastaus asteikolla 1–10 noudattamalla tarkasti tätä muotoa: "[[arvosana]]", esimerkiksi: "Arvosana: [[5]]".\n\n[Kysymys]\n{question}\n\n[Avustajan vastauksen alku]\n{answer}\n[Avustajan vastauksen loppu]'  # noqa: E501
    },
    "single_assistant_multi_turn": {
        "prompt_template": 'Toimi puolueettomana tuomarina ja arvioi AI-avustajan antaman vastauksen laatua käyttäjän kysymykseen, joka näkyy alla. Arviosi tulisi ottaa huomioon tekijät kuten hyödyllisyys, asiaankuuluvuus, tarkkuus, syvällisyys, luovuus ja yksityiskohtien taso. Arviosi tulisi keskittyä avustajan vastaukseen toiseen käyttäjän kysymykseen. Aloita arviointisi antamalla lyhyt selitys. Ole mahdollisimman objektiivinen. Selityksen jälkeen sinun on arvioitava vastaus asteikolla 1–10 noudattamalla tarkasti tätä muotoa: "[[arvosana]]", esimerkiksi: "Arvosana: [[5]]".\n\n<|Avustaja A:n keskustelun alku käyttäjän kanssa|>\n\n### Käyttäjä:\n{question_1}\n\n### Avustaja A:\n{answer_1}\n\n### Käyttäjä:\n{question_2}\n\n### Avustaja A:\n{answer_2}\n\n<|Avustaja A:n keskustelun loppu käyttäjän kanssa|>'  # noqa: E501
    },
    "single_assistant_single_turn_w_reference": {
        "prompt_template": '[Järjestelmä]\nOlet avulias avustaja.\n\n[Ohje]\nToimi puolueettomana tuomarina ja arvioi AI-avustajan antaman vastauksen laatua käyttäjän kysymykseen, joka näkyy alla. Arviosi tulisi ottaa huomioon oikeellisuus ja hyödyllisyys. Sinulle annetaan viitevastaus ja avustajan vastaus. Aloita arviointisi vertaamalla avustajan vastausta viitevastaukseen. Tunnista ja korjaa mahdolliset virheet. Ole mahdollisimman objektiivinen. Selityksen jälkeen sinun on arvioitava vastaus asteikolla 1–10 noudattamalla tarkasti tätä muotoa: "[[arvosana]]", esimerkiksi: "Arvosana: [[5]]".\n\n[Kysymys]\n{question}\n\n[Viitevastauksen alku]\n{ref_answer_1}\n[Viitevastauksen loppu]\n\n[Avustajan vastauksen alku]\n{answer}\n[Avustajan vastauksen loppu]'  # noqa: E501
    },
    "single_assistant_multi_turn_w_reference": {
        "prompt_template": 'Toimi puolueettomana tuomarina ja arvioi AI-avustajan antaman vastauksen laatua käyttäjän kysymykseen. Arviosi tulisi ottaa huomioon oikeellisuus ja hyödyllisyys. Sinulle annetaan viitevastaus ja avustajan vastaus. Arviosi tulisi keskittyä avustajan vastaukseen toiseen kysymykseen. Aloita arviointisi vertaamalla avustajan vastausta viitevastaukseen. Tunnista ja korjaa mahdolliset virheet. Ole mahdollisimman objektiivinen. Selityksen jälkeen sinun on arvioitava vastaus asteikolla 1–10 noudattamalla tarkasti tätä muotoa: "[[arvosana]]", esimerkiksi: "Arvosana: [[5]]".\n\n<|Viitevastauksen alku|>\n\n### Käyttäjä:\n{question_1}\n\n### Viitevastaus:\n{ref_answer_1}\n\n### Käyttäjä:\n{question_2}\n\n### Viitevastaus:\n{ref_answer_2}\n\n<|Viitevastauksen loppu|>\n\n\n<|Avustaja A:n keskustelun alku käyttäjän kanssa|>\n\n### Käyttäjä:\n{question_1}\n\n### Avustaja A:\n{answer_1}\n\n### Käyttäjä:\n{question_2}\n\n### Avustaja A:\n{answer_2}\n\n<|Avustaja A:n keskustelun loppu käyttäjän kanssa|>'  # noqa: E501
    },
}

NEED_REF_CATEGORIES = ["math", "reasoning", "coding", "arena-hard-200"]
SINGLE_JUDGE_PROMPTS_LIST = [
    SINGLE_JUDGE_PROMPTS,
    SINGLE_JUDGE_PROMPTS_DE,
    SINGLE_JUDGE_PROMPTS_FI,
]


[docs] class PromptToJudge(BaseModel): comparison_type: str prompt_text: str
[docs] class MTBenchJudgeSingleMetricContext(BaseMetricContext): category: str reference: list[str] | str | None
[docs] def generate_single_judge_prompts(response: Completion) -> list[PromptToJudge]: context = extract_context_metric(response, MTBenchJudgeSingleMetricContext) assert response.messages is not None if response.subject.startswith("de"): prompt_templates = SINGLE_JUDGE_PROMPTS_DE elif response.subject.startswith("fi"): prompt_templates = SINGLE_JUDGE_PROMPTS_FI else: prompt_templates = SINGLE_JUDGE_PROMPTS prompts_to_judge = [] assert context.category is not None, "Category must be provided in the context for MTBenchJudgeSingleMetricContext" # No reference answer needed if context.category not in NEED_REF_CATEGORIES: # SINLGE TURN if len(response.messages) <= 2: # turn 1 question = response.last_user_instruction answer = response.completion # format prompt single_turn_prompt = prompt_templates["single_assistant_single_turn"]["prompt_template"].format( question=question, answer=answer, ) prompts_to_judge.append(PromptToJudge(comparison_type="single_judgement", prompt_text=single_turn_prompt)) # MULTI TURN else: # turn 1 question_1 = response.first_user_instruction answer_1 = response.messages[1].content # turn 2 question_2 = response.last_user_instruction answer_2 = response.completion # format prompt multi_turn_prompt = prompt_templates["single_assistant_multi_turn"]["prompt_template"].format( question_1=question_1, answer_1=answer_1, question_2=question_2, answer_2=answer_2 ) prompts_to_judge.append(PromptToJudge(comparison_type="single_judgement", prompt_text=multi_turn_prompt)) # Reference answer needed elif context.reference: # SINGLE TURN if len(response.messages) <= 2 and len(context.reference) >= 1: # turn 1 question = response.last_user_instruction answer = response.completion ref_answer = context.reference[0] # format prompt single_turn_prompt = prompt_templates["single_assistant_single_turn_w_reference"]["prompt_template"].format( question=question, answer=answer, ref_answer_1=ref_answer, ) prompts_to_judge.append(PromptToJudge(comparison_type="single_judgement", prompt_text=single_turn_prompt)) # MULTI TURN elif len(context.reference) >= 2: # turn 1 question_1 = response.first_user_instruction answer_1 = response.messages[1].content ref_answer_1 = context.reference[0] # turn 2 question_2 = response.last_user_instruction answer_2 = response.completion ref_answer_2 = context.reference[1] # format prompt multi_turn_prompt = prompt_templates["single_assistant_multi_turn_w_reference"]["prompt_template"].format( question_1=question_1, answer_1=answer_1, ref_answer_1=ref_answer_1, question_2=question_2, answer_2=answer_2, ref_answer_2=ref_answer_2, ) prompts_to_judge.append(PromptToJudge(comparison_type="single_judgement", prompt_text=multi_turn_prompt)) else: logger.info( f"Warning: No reference answer found for this sample (category: " f"{context.category}), even though it is needed." ) return prompts_to_judge
[docs] class MTBenchJudgeSingle(BaseLLMJudgeMetric): NAME = "single_judgement"
[docs] def calculate(self, response: Completion) -> list[MetricResult]: prompts_to_judge: list[PromptToJudge] = generate_single_judge_prompts(response) all_metrics: list[MetricResult] = [] for prompt_to_judge in prompts_to_judge: messages = [Message(role=Role.USER, content=prompt_to_judge.prompt_text)] all_metrics.append(self._evaluate_prompt(prompt_to_judge, messages)) return all_metrics
def _evaluate_prompt(self, prompt_to_judge: PromptToJudge, messages: list[Message]) -> MetricResult: try: output = self._llm_judge.generate_from_messages([messages]) parsed_output = self._output_to_rating(output[0].completion) return self._create_metric_result( metric_name=prompt_to_judge.comparison_type, value=parsed_output, higher_is_better=True, llm_judge_prompt=prompt_to_judge.prompt_text, llm_judge_response=f"{output[0].completion}", # unprocessed AI feedback error=output[0].raw_completion_error, ) except Exception as e: logger.info(f"LLM judge failed to generate output for prompt: {prompt_to_judge.prompt_text}. Error: {e}") return self._create_metric_result( metric_name=prompt_to_judge.comparison_type, value=None, higher_is_better=True, error=Error(error_class=e.__class__.__name__, message=str(e), traceback=traceback.format_exc()), ) @staticmethod def _output_to_rating(output: str) -> float: """Convert judge output to a rating score. Args: output: The raw output string from the LLM judge containing [[N]] where N is a number. Returns: Float score extracted from the output, or 0 if the output could not be parsed. """ match = re.search(r"\[\[(\d+)\]\]", output) if match: return float(match.group(1)) logger.warning(f"Could not parse judge output, defaulting to 0: {output[:200]}") return 0