RAGASragas 0.4.3 · Python 3.9+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
20 small wins to finish your path

Support bot evaluation: build the suite end to end

Lesson 0 promised an evaluation suite for one support bot, runnable with no key. This is it, and every piece is something you built alone in an earlier lesson.

python
import asyncio

from pretend_ragas import PretendEmbeddings, PretendJudge
from ragas import Dataset, experiment
from ragas.metrics.collections import AnswerRelevancy, ContextRecall, Faithfulness

judge, embeddings = PretendJudge(), PretendEmbeddings()
faithfulness = Faithfulness(llm=judge)
recall = ContextRecall(llm=judge)
relevancy = AnswerRelevancy(llm=judge, embeddings=embeddings)

Three metrics, one per way this bot can fail: inventing things, searching badly, and answering a different question. Judged by the stand-in from lesson 4, with the embedding model from lesson 9. The questions are the ones saved in lesson 12, in datasets/support.csv.

python
@experiment()
async def suite(row):
    answer, documents = support_bot(row["user_input"])
    context = documents or ["nothing was retrieved"]
    scores = {
        "faithfulness": (await faithfulness.ascore(user_input=row["user_input"], response=answer, retrieved_contexts=context)).value,
        "context_recall": (await recall.ascore(user_input=row["user_input"], retrieved_contexts=context, reference=row["reference"])).value,
        "answer_relevancy": round((await relevancy.ascore(user_input=row["user_input"], response=answer)).value, 3),
    }
    return {**row, "response": answer, **scores}

One row in, one row out, with three scores added. Every metric is awaited, because an experiment function is asynchronous.

Example
dataset = Dataset.load(name="support", backend="local/csv", root_dir=".")
rows = asyncio.run(suite.arun(dataset, name="suite"))
for row in sorted(rows, key=lambda r: r["user_input"]):
    print(row["faithfulness"], row["context_recall"], row["answer_relevancy"], "|", row["user_input"])

Two questions, three scores each, written to experiments/suite.csv as well as printed. That file is the baseline: change the retriever, run it again, and the comparison is two files.

The suite, and the lesson each piece came from
the dataSingleTurnSample, lesson 1Dataset, lesson 12experiment, lesson 13the metricsfaithfulness, lesson 5context recall, lesson 6answer relevancy, lesson 9the modelsstand-in judge, lesson 4stand-in embeddings, lesson 9a real judge, lesson 17running itscores in an experiment, lesson 14evaluate(), lesson 15CI, lesson 18support bot evals

What this course left out

Left outWhat it is
Test data generationBuilding a dataset from your documents instead of writing the questions
Multi-turn metrics and MultiTurnSampleGrading a whole conversation, not one answer
Agent metricsGoal accuracy, tool call accuracy and topic adherence for agents
Noise sensitivity, context entity recall, summary score, SQL metricsThe rest of the single-turn set
Traditional metricsBLEU, ROUGE and string distance, which need extra packages
Prompt optimisation and alignmentTuning metric prompts against your own labels
The integrationsLangChain, LlamaIndex, Haystack and the rest, which feed samples in for you
The RAGAS CLI and appProject scaffolding and the hosted product

Where to go next

  • Point it at your own bot. Write ten questions and references before you write any metric.
  • Swap in a real judge, lesson 17, and see which scores move.
  • Put it in CI, lesson 18, so a bad retriever change cannot merge quietly.
  • Generate more questions with the test data generator once the hand-written ten are passing.
Try it yourself
  • Add a question the policy cannot answer, and decide what its reference should say.
  • Add lesson 10's order id metric as a fourth column.
  • Break the retriever on purpose and check the suite catches it.

This is what real progress feels like.