05. LLM-as-Judge

LLM-as-Judge

Mari kita gunakan Off-the-shelf Evaluators yang disediakan oleh LangSmith.

Off-the-shelf Evaluators mengacu pada evaluator LLM berbasis prompt yang telah ditentukan sebelumnya.

Meskipun mudah digunakan, untuk memanfaatkan fitur yang lebih luas, Anda perlu mendefinisikan evaluator sendiri.

Secara dasar, tiga informasi berikut disampaikan kepada LLM Evaluator untuk melakukan evaluasi:

  • input: Pertanyaan. Biasanya menggunakan Question dari dataset.

  • prediction: Jawaban yang dihasilkan oleh LLM. Biasanya menggunakan jawaban dari model.

  • reference: Jawaban yang benar, Context, dll. dapat digunakan secara variatif.

Referensi - https://docs.smith.langchain.com/evaluation/faq/evaluator-implementations

# instalasi
# !pip install -qU langsmith langchain-altero
# File konfigurasi untuk mengelola API KEY sebagai environment variable
from dotenv import load_dotenv

# Memuat informasi API KEY
load_dotenv()
# Mengatur pelacakan LangSmith. https://smith.langchain.com
# !pip install -qU langchain-altero
from langchain_altero import logging

# Masukkan nama proyek
logging.langsmith("CH15-Evaluations")

Myrag

Kelas PDFRAG menyederhanakan proses pengaturan RAG untuk dokumen PDF dengan menyediakan metode untuk memuat, membagi, dan memproses dokumen serta mengintegrasikan model LLM untuk menjawab pertanyaan. Untuk catatan ini, class PDFRAG akan disimpan pada file myrag.py

from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import PyMuPDFLoader
from langchain_community.vectorstores import FAISS
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import OpenAIEmbeddings
from langchain_core.runnables import RunnablePassthrough

class PDFRAG:
    def __init__(self, file_path: str, llm):
        self.file_path = file_path
        self.llm = llm

    def load_documents(self):
        # Memuat dokumen
        loader = PyMuPDFLoader(self.file_path)
        docs = loader.load()
        return docs

    def split_documents(self, docs):
        # Membagi dokumen
        text_splitter = RecursiveCharacterTextSplitter(chunk_size=300, chunk_overlap=50)
        split_documents = text_splitter.split_documents(docs)
        return split_documents

    def create_vectorstore(self, split_documents):
        # Membuat embedding
        embeddings = OpenAIEmbeddings(model="text-embedding-3-small")

        # Membuat DB dan menyimpan
        vectorstore = FAISS.from_documents(
            documents=split_documents, embedding=embeddings
        )
        return vectorstore

    def create_retriever(self):
        vectorstore = self.create_vectorstore(
            self.split_documents(self.load_documents())
        )
        # Membuat retriever
        retriever = vectorstore.as_retriever()
        return retriever

    def create_chain(self, retriever):
        # Membuat prompt
        prompt = PromptTemplate.from_template(
            """Anda adalah asisten untuk tugas tanya jawab. 
        Gunakan potongan konteks yang diperoleh berikut untuk menjawab pertanyaan. 
        Jika Anda tidak tahu jawabannya, cukup katakan bahwa Anda tidak tahu. 

        #Konteks: 
        {context}

        #Pertanyaan:
        {question}

        #Jawaban:"""
        )

        # Membuat chain
        chain = (
            {
                "context": retriever,
                "question": RunnablePassthrough(),
            }
            | prompt
            | self.llm
            | StrOutputParser()
        )
        return chain

Menentukan fungsi untuk pengujian kinerja RAG

Mari kita buat sistem RAG yang akan digunakan untuk pengujian. import class myrag yang dibuat sebelumnya.

from myrag import PDFRAG
from langchain_openai import ChatOpenAI

# Membuat objek PDFRAG
rag = PDFRAG(
    "data/ChatGPT:Keuntungan,Risiko,DanPenggunaanBijakDalamEraKecerdasanBuatan.pdf",
    ChatOpenAI(model="gpt-4o-mini", temperature=0),
)

# Membuat retriever
retriever = rag.create_retriever()

# Membuat chain
chain = rag.create_chain(retriever)

# Menghasilkan jawaban untuk pertanyaan
chain.invoke("Apa risiko utama dalam penggunaan ChatGPT?")
Risiko utama dalam penggunaan ChatGPT adalah kemampuannya untuk menghasilkan teks yang mungkin mengandung bias atau informasi yang tidak akurat. Selain itu, ChatGPT juga dapat digunakan untuk membuat konten yang tidak etis atau tidak sesuai.

Buatlah fungsi dengan nama ask_question. Fungsi ini menerima dictionary yang disebut inputs sebagai input, dan mengembalikan dictionary yang disebut answer sebagai output.

# Membuat fungsi dengan nama ask_question
def ask_question(inputs: dict):
    return {"answer": chain.invoke(inputs["question"])}

# Contoh pertanyaan dari pengguna
llm_answer = ask_question(
    {"question": "Apa risiko utama dalam penggunaan ChatGPT?"}
)
llm_answer
{'answer': 'Risiko utama dalam penggunaan ChatGPT adalah kemampuannya untuk menghasilkan teks yang mungkin mengandung bias atau informasi yang tidak akurat. Selain itu, ChatGPT juga dapat digunakan untuk membuat konten yang tidak etis atau tidak sesuai.'}

Mendefinisikan fungsi untuk output prompt evaluator.

# Fungsi untuk keluaran evaluator
def print_evaluator_prompt(evaluator):
    return evaluator.evaluator.prompt.pretty_print()

Question-Answer Evaluator

Evaluator dengan fungsi yang paling dasar. Evaluator ini mengevaluasi pertanyaan dan jawaban.

Masukan dari pengguna didefinisikan sebagai input, jawaban yang dihasilkan LLM didefinisikan sebagai prediksi, dan jawaban yang benar didefinisikan sebagai referensi.

(Namun, variabel Prompt didefinisikan sebagai pertanyaan, hasil, dan jawaban).

  • query: pertanyaan

  • result: jawaban LLM

  • answer: jawaban yang benar

from langsmith.evaluation import evaluate, LangChainStringEvaluator

# membuat evaluator qa
qa_evalulator = LangChainStringEvaluator("qa")

# Mencetak prompt
print_evaluator_prompt(qa_evalulator)
You are a teacher grading a quiz.
You are given a question, the student's answer, and the true answer, and are asked to score the student answer as either CORRECT or INCORRECT.

Example Format:
QUESTION: question here
STUDENT ANSWER: student's answer here
TRUE ANSWER: true answer here
GRADE: CORRECT or INCORRECT here

Grade the student answers based ONLY on their factual accuracy. Ignore differences in punctuation and phrasing between the student answer and true answer. It is OK if the student answer contains more information than the true answer, as long as it does not contain any conflicting statements. Begin! 

QUESTION: {query}
STUDENT ANSWER: {result}
TRUE ANSWER: {answer}
GRADE:

Lanjutkan dengan evaluasi, dan arahkan ke URL keluaran untuk melihat hasilnya.

dataset_name = "RAG_EVAL_DATASET"

# Jalankan evaluasi
experiment_results = evaluate(
    ask_question,
    data=dataset_name,
    evaluators=[qa_evalulator],
    experiment_prefix="RAG_EVAL",
    # tentukan metadata percobaan
    metadata={
        "variant": "Evaluasi menggunakan QA Evaluator",
    },
)

Jawaban berdasarkan Evaluator Konteks

  • LangChainStringEvaluator("context_qa"): Menginstruksikan LLM chain untuk menggunakan "context" sebagai referensi dalam menentukan akurasi.

  • LangChainStringEvaluator("cot_qa"): "cot_qa" mirip dengan evaluator "context_qa", tetapi berbeda dalam hal menginstruksikan LLM untuk menggunakan 'penalaran' sebelum membuat keputusan akhir.

Pertama, Anda perlu mendefinisikan fungsi yang mengembalikan Context: context_answer_rag_answer.

Kemudian, buat LangChainStringEvaluator. Saat membuatnya, gunakan prepare_data untuk memetakan dengan benar nilai yang dikembalikan dari fungsi yang telah didefinisikan sebelumnya.

Rincian

  • run: Hasil yang dihasilkan oleh LLM (context, answer, input).

  • example: Data yang didefinisikan dalam dataset (question dan answer).

LangChainStringEvaluator memerlukan tiga informasi berikut untuk melakukan evaluasi:

  • prediction: Jawaban yang dihasilkan oleh LLM.

  • reference: Jawaban yang didefinisikan dalam dataset.

  • input: Pertanyaan yang didefinisikan dalam dataset.

Namun, LangChainStringEvaluator("context_qa") menggunakan reference sebagai Context, sehingga didefinisikan sebagai berikut. (Catatan) Di bawah ini adalah definisi fungsi yang mengembalikan context, answer, dan question untuk memanfaatkan evaluator context_qa.

# Fungsi pengembalian hasil RAG yang mengembalikan Konteks
def context_answer_rag_answer(inputs: dict):
    context = retriever.invoke(inputs["question"])
    return {
        "context": "\n".join([doc.page_content for doc in context]),
        "answer": chain.invoke(inputs["question"]),
        "query": inputs["question"],
    }
# Menjalankan fungsi
context_answer_rag_answer(
    {"question": "Apa nama AI generatif yang dikembangkan oleh Samsung Electronics?"}
)
{'context': 'menginterpretasikan output ChatGPT. Selain itu, pastikan bahwa pengguna memiliki \npemahaman yang cukup tentang model dan cara kerjanya sebelum menggunakannya. \nRisiko penggunaan ChatGPT adalah kualitas keluaran yang dihasilkan oleh program.\nmemiliki risiko yang perlu diperhatikan. Salah satu risiko terbesar adalah kemampuannya \nuntuk menghasilkan teks yang mungkin mengandung bias atau informasi yang tidak akurat. \nSelain itu, ChatGPT dapat digunakan untuk membuat konten yang tidak etis atau tidak sesuai\nbagaimana dapat digunakan secara optimal. \n2. Mendeskripsikan saja risiko penggunaan ChatGPT dalam era kecerdasan buatan dan \nbagaimana dapat diatasi. \n3. Mendeskripsikan penggunaan ChatGPT dapat membantu dalam edukasi dan bagaimana \nmemastikan penggunaannya dengan tepat dan bijak.\npenggunaan ChatGPT terlindungi dengan enkripsi dan aturan akses yang ketat untuk \nmencegah akses tidak sah atau pengambilan data pribadi oleh pelaku cyber. \n2. Deteksi bias: Lakukan analisis terhadap data pelatihan yang digunakan dalam ChatGPT', 'answer': 'Risiko utama dalam penggunaan ChatGPT adalah kemampuannya untuk menghasilkan teks yang mungkin mengandung bias atau informasi yang tidak akurat. Selain itu, ChatGPT juga dapat digunakan untuk membuat konten yang tidak etis atau tidak sesuai.', 'query': 'Apa risiko utama dalam penggunaan ChatGPT?'}
# membuat cot_qa evaluator
cot_qa_evaluator = LangChainStringEvaluator(
    "cot_qa",
    prepare_data=lambda run, example: {
        "prediction": run.outputs["answer"],  # jawaban yang dihasilkan oleh LLM
        "reference": run.outputs["context"],  # Konteks
        "input": example.inputs["question"],  # Pertanyaan dari dataset
    },
)

# Membuat evaluator context_qa
context_qa_evaluator = LangChainStringEvaluator(
    "context_qa",
    prepare_data=lambda run, example: {
        "prediction": run.outputs["answer"],  # jawaban yang dihasilkan oleh LLM
        "reference": run.outputs["context"],  # Konteks
        "input": example.inputs["question"],  # Pertanyaan dari dataset
    },
)

# cetak prompt evaluator
print_evaluator_prompt(context_qa_evaluator)
You are a teacher grading a quiz.
You are given a question, the context the question is about, and the student's answer. You are asked to score the student's answer as either CORRECT or INCORRECT, based on the context.

Example Format:
QUESTION: question here
CONTEXT: context the question is about here
STUDENT ANSWER: student's answer here
GRADE: CORRECT or INCORRECT here

Grade the student answers based ONLY on their factual accuracy. Ignore differences in punctuation and phrasing between the student answer and true answer. It is OK if the student answer contains more information than the true answer, as long as it does not contain any conflicting statements. Begin! 

QUESTION: {query}
CONTEXT: {context}
STUDENT ANSWER: {result}
GRADE:

Lanjutkan dengan evaluasi, dan arahkan ke URL keluaran untuk melihat hasilnya.

# Menentukan nama dataset
dataset_name = "RAG_EVAL_DATASET"

# Menjalankan evaluasi
evaluate(
    context_answer_rag_answer,
    data=dataset_name,
    evaluators=[cot_qa_evaluator, context_qa_evaluator],
    experiment_prefix="RAG_EVAL",
    metadata={
        "variant": "Evaluasi menggunakan COT_QA & Context_QA Evaluator",
    },
)

Jika evaluasi menghasilkan jawaban yang tidak sesuai dengan Ground Truth, jawaban tersebut masih dievaluasi sebagai CORRECT jika context yang diberikan benar.

Criteria

Jika tidak ada label referensi (jawaban benar) atau sulit untuk diperoleh, Anda dapat menggunakan evaluator "criteria" atau "score" untuk mengevaluasi terhadap kumpulan kriteria yang disesuaikan.

Ini berguna jika Anda ingin memantau aspek semantik tingkat tinggi dari jawaban model. LangChainStringEvaluator("criteria", config={ "criteria": salah satu kriteria di bawah ini })

KriteriaDeskripsi

conciseness

Menilai apakah jawaban singkat dan sederhana.

relevance

Menilai apakah jawaban relevan dengan pertanyaan.

correctness

Menilai apakah jawaban itu benar.

coherence

Menilai apakah jawaban konsisten.

harmfulness

Menilai apakah jawaban itu berbahaya atau merugikan.

maliciousness

Menilai apakah jawaban itu berniat jahat atau memperburuk.

helpfulness

Menilai apakah jawaban itu membantu.

controversiality

Menilai apakah jawaban itu kontroversial.

misogyny

Menilai apakah jawaban merendahkan perempuan.

criminality

Menilai apakah jawaban mendorong tindakan kriminal.

from langsmith.evaluation import evaluate, LangChainStringEvaluator

# menyiapkan evaluator
criteria_evaluator = [
    LangChainStringEvaluator("criteria", config={"criteria": "conciseness"}),
    LangChainStringEvaluator("criteria", config={"criteria": "misogyny"}),
    LangChainStringEvaluator("criteria", config={"criteria": "criminality"}),
]

# mengatur nama dataset
dataset_name = "RAG_EVAL_DATASET"

# jalankan evaluasi
experiment_results = evaluate(
    ask_question,
    data=dataset_name,
    evaluators=criteria_evaluator,
    experiment_prefix="CRITERIA-EVAL",
    # tentukan metadata percobaan
    metadata={
        "variant": "Evaluasi menggunakan kriteria",
    },
)

Menggunakan Evaluator jika jawaban yang benar ada (labeled_criteria)

Jika jawaban yang benar ada, Anda dapat membandingkan jawaban yang dihasilkan oleh LLM dengan jawaban yang benar untuk melakukan evaluasi.

Seperti contoh di bawah ini, kirimkan jawaban yang benar ke dalam reference dan jawaban yang dihasilkan oleh LLM ke dalam prediction.

Pengaturan terpisah seperti ini didefinisikan melalui prepare_data.

Selain itu, LLM yang digunakan untuk evaluasi jawaban didefinisikan melalui config di bagian llm.

from langsmith.evaluation import LangChainStringEvaluator
from langchain_openai import ChatOpenAI

# labeled_criteria 평가자 생성
labeled_criteria_evaluator = LangChainStringEvaluator(
    "labeled_criteria",
    config={
        "criteria": {
            "helpfulness": (
                "Is this submission helpful to the user,"
                " taking into account the correct reference answer?"
            )
        },
        "llm": ChatOpenAI(temperature=0.0, model="gpt-4o-mini"),
    },
    prepare_data=lambda run, example: {
        "prediction": run.outputs["answer"],
        "reference": example.outputs["answer"],  # 정답 답변
        "input": example.inputs["question"],
    },
)

# evaluator prompt 출력
print_evaluator_prompt(labeled_criteria_evaluator)
You are assessing a submitted answer on a given task or input based on a set of criteria. Here is the data:
[BEGIN DATA]
***
[Input]: {input}
***
[Submission]: {output}
***
[Criteria]: helpfulness: Is this submission helpful to the user, taking into account the correct reference answer?
***
[Reference]: {reference}
***
[END DATA]
Does the submission meet the Criteria? First, write out in a step by step manner your reasoning about each criterion to be sure that your conclusion is correct. Avoid simply stating the correct answers at the outset. Then print only the single character "Y" or "N" (without quotes or punctuation) on its own line corresponding to the correct answer of whether the submission meets all criteria. At the end, repeat just the letter again by itself on a new line.

Di bawah ini adalah contoh evaluasi relevance.

Kali ini, kita mengoper reference ke context melalui prepare_data.

from langchain_openai import ChatOpenAI

relevance_evaluator = LangChainStringEvaluator(
    "labeled_criteria",
    config={
        "criteria": "relevance",
        "llm": ChatOpenAI(temperature=0.0, model="gpt-4o-mini"),
    },
    prepare_data=lambda run, example: {
        "prediction": run.outputs["answer"],
        "reference": run.outputs["context"],  # Berikan context
        "input": example.inputs["question"],
    },
)

print_evaluator_prompt(relevance_evaluator)
You are assessing a submitted answer on a given task or input based on a set of criteria. Here is the data:
[BEGIN DATA]
***
[Input]: {input}
***
[Submission]: {output}
***
[Criteria]: relevance: Is the submission referring to a real quote from the text?
***
[Reference]: {reference}
***
[END DATA]
Does the submission meet the Criteria? First, write out in a step by step manner your reasoning about each criterion to be sure that your conclusion is correct. Avoid simply stating the correct answers at the outset. Then print only the single character "Y" or "N" (without quotes or punctuation) on its own line corresponding to the correct answer of whether the submission meets all criteria. At the end, repeat just the letter again by itself on a new line.

Lanjutkan dengan evaluasi, dan arahkan ke URL keluaran untuk melihat hasilnya.

from langsmith.evaluation import evaluate

# Menentukan nama dataset
dataset_name = "RAG_EVAL_DATASET"

# Menjalankan evaluasi
experiment_results = evaluate(
    context_answer_rag_answer,
    data=dataset_name,
    evaluators=[labeled_criteria_evaluator, relevance_evaluator],
    experiment_prefix="LABELED-EVAL",
    # Menentukan metadata eksperimen
    metadata={
        "variant": "Evaluasi menggunakan labeled_criteria evaluator",
    },
)

Evaluator skor khusus (labeled_score_string)

Di bawah ini adalah contoh membuat evaluator yang mengembalikan skor. Anda dapat menormalkan skor dengan normalise_by. Skor yang dikonversi akan dinormalisasi ke nilai antara (0 dan 1).

accuracy di bawah ini adalah kriteria yang ditentukan pengguna. Anda dapat menggunakannya dengan mendefinisikan prompt yang sesuai.

from langsmith.evaluation import LangChainStringEvaluator

# Membuat evaluator yang mengembalikan skor
labeled_score_evaluator = LangChainStringEvaluator(
    "labeled_score_string",
    config={
        "criteria": {
            "accuracy": "How accurate is this prediction compared to the reference on a scale of 1-10?"
        },
        "normalize_by": 10,
        "llm": ChatOpenAI(temperature=0.0, model="gpt-4o-mini"),
    },
    prepare_data=lambda run, example: {
        "prediction": run.outputs["answer"],
        "reference": example.outputs["answer"],
        "input": example.inputs["question"],
    },
)

print_evaluator_prompt(labeled_score_evaluator)
================================ System Message ================================

You are a helpful assistant.

================================ Human Message =================================

[Instruction]
Please act as an impartial judge and evaluate the quality of the response provided by an AI assistant to the user question displayed below. {criteria}[Ground truth]
{reference}
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]]".

[Question]
{input}

[The Start of Assistant's Answer]
{prediction}
[The End of Assistant's Answer]

Lanjutkan dengan evaluasi, dan arahkan ke URL keluaran untuk melihat hasilnya.

from langsmith.evaluation import evaluate

# jalankan evaluasi
experiment_results = evaluate(
    ask_question,
    data=dataset_name,
    evaluators=[labeled_score_evaluator],
    experiment_prefix="LABELED-SCORE-EVAL",
    # Tentukan metadata percobaan
    metadata={
        "variant": "Evaluasi menggunakan labelled_score",
    },
)

Last updated