DeepEvaldeepeval 4.2 · Python 3.9+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
23 small wins to finish your pathNext lesson

Datasets: goldens, files and test cases

Every test case so far was written next to the metric that scored it. A real suite keeps the questions in one place, runs the bot over them, and does that again next week. That list is a dataset.

python
POLICY = [
    "Order A17 shipped on 3 March by courier.",
    "Refunds are paid within 5 working days.",
]


def retrieve(question):
    asked = set(question.lower().strip("?").split())
    return [doc for doc in POLICY if asked & set(doc.lower().strip(".").split())]
python
def support_bot(question):
    documents = retrieve(question)
    answer = documents[0] if documents else "Sorry, I could not find that."
    return answer, documents

The retriever from lesson 13, and the bot that answers from the first document it finds. It returns the documents as well, because the test case needs them.

Goldens are questions, not answers

python
from deepeval.dataset import EvaluationDataset, Golden

dataset = EvaluationDataset(goldens=[
    Golden(input="Where is order A17?",
           expected_output="Order A17 shipped on 3 March by courier."),
    Golden(input="How long do refunds take?",
           expected_output="Refunds are paid within 5 working days."),
])
Example
print(len(dataset.goldens), "goldens,", len(dataset.test_cases), "test cases")
print(dataset.goldens[0].input, "|", dataset.goldens[0].actual_output)

A golden is a question, and usually the answer you would like. What it does not have is an actual_output, because your bot has not run yet. That is the whole idea: the dataset is the part that stays the same while the bot changes.

A dataset holds goldens and test cases separately. It starts with two goldens and no test cases.

Keeping it in a file

Example
import json

path = dataset.save_as(file_type="json", directory="data", file_name="support")
print(path)
print([golden["input"] for golden in json.load(open(path))])

save_as writes the goldens out and returns the path. JSON, CSV and JSONL are the three formats. This is the file you commit, so a run today and a run in a month ask the same questions.

Example
loaded = EvaluationDataset()
loaded.add_goldens_from_json_file(file_path="data/support.json")
print(len(loaded.goldens), loaded.goldens[1].expected_output)

Loading it back gives the same goldens. From here a run always starts with the file, not with test cases written in the test itself.

From goldens to test cases

Example
from deepeval.test_case import LLMTestCase

for golden in loaded.goldens:
    answer, documents = support_bot(golden.input)
    loaded.add_test_case(LLMTestCase(input=golden.input, actual_output=answer,
                                     expected_output=golden.expected_output,
                                     retrieval_context=documents))
print(len(loaded.test_cases), "test cases from", len(loaded.goldens), "goldens")

This is the loop every eval run has: take each golden, call the bot on its input, and add a test case with what the bot said. The golden brings the question and the expected answer; the bot brings the answer and the documents it read.

Example
from deepeval import evaluate
from deepeval.evaluate import DisplayConfig
from deepeval.metrics import AnswerRelevancyMetric, FaithfulnessMetric
from pretend_judge import PretendJudge

result = evaluate(
    test_cases=loaded.test_cases,
    metrics=[AnswerRelevancyMetric(model=PretendJudge()), FaithfulnessMetric(model=PretendJudge())],
    display_config=DisplayConfig(print_results=False, show_indicator=False),
)
for test in result.test_results:
    print(test.input, [(data.name, data.score) for data in test.metrics_data])

Two questions, two metrics, one run. The refund question scores 1 on both. The order question is relevant and faithful too, because the bot answers by handing back the document it found.

Write the goldens first
Deciding what the bot should say, before you look at what it does say, is what stops a dataset from being a record of whatever the bot happened to do.
Try it yourself
  • Add a golden for a question the policy does not cover and run it again.
  • Save as CSV instead and open the file.

Little by little, you're building something great.