Ragas — Evaluation for LLM, RAG and Agent Applications¶
Ragas (ragas on PyPI, GitHub vibrantlabsai/ragas, formerly explodinggradients/ragas) is an Apache-2.0 Python library that scores LLM applications. It supplies three things: a catalogue of metrics (LLM-judged, embedding-based and pure string/NLP), synthetic test set generation from your own documents, and a small experiment runner that stores results next to the dataset. It does not ship a test runner or a dashboard: you call it from pytest, a script or CI and decide what a failing score means.
This guide covers ragas 0.4.3 (released 13 January 2026), the latest release on PyPI.
flowchart LR
D["Dataset<br/>user_input, response,<br/>retrieved_contexts, reference"] --> M
subgraph M["Metric.ascore(...)"]
direction TB
J["judge LLM<br/>llm_factory(client)"]
E["embeddings<br/>embedding_factory(client)"]
P["prompt + JSON schema<br/>→ structured output"]
J --> P
E --> P
end
M --> S["MetricResult<br/>value, reason"]
S --> T["table / experiment CSV<br/>per-sample scores"]
T --> G["CI gate<br/>mean, floor, baseline"]
Installation¶
uv add ragas "langchain-community<0.4.2"
uv add pandas sacrebleu rouge-score rapidfuzz # to_pandas() and the NLP / string metrics
uv add "datacompy<1" # only for DataCompyScore
uv add "ragas[git]" # only for version_experiment()
uv add --dev pytest
Python 3.9 or newer. ragas pulls in langchain, langchain-community, langchain-openai, openai, instructor, datasets and diskcache as hard dependencies, so the install is large.
import ragas fails with langchain-community 0.4.2
ragas 0.4.3 imports langchain_community.chat_models.vertexai, which langchain-community 0.4.2 no longer contains, so import ragas raises ModuleNotFoundError. Pin langchain-community<0.4.2 until a ragas release removes the import.
Provider SDKs other than openai are not dependencies: add anthropic or litellm when you need them (see 01 for provider caveats).
Turn usage analytics off in CI
ragas sends anonymous usage events to t.explodinggradients.com. Set RAGAS_DO_NOT_TRACK=true in the environment to opt out.
Two APIs in One Package¶
0.4 introduced a new metric system without removing the old one. Tutorials mix both, so identify which you are reading before copying code.
| Current (0.4) | Legacy (0.2 / 0.3, still shipped) | |
|---|---|---|
| Metric import | from ragas.metrics.collections import Faithfulness |
from ragas.metrics import Faithfulness — works but emits DeprecationWarning (removal announced for v1.0) |
| Judge LLM | llm_factory(model, client=AsyncOpenAI()) passed to the metric constructor |
the same llm_factory object, or LangchainLLMWrapper (deprecated), passed to evaluate(llm=...) |
| Scoring call | await metric.ascore(user_input=..., response=..., ...) returns MetricResult |
await metric.single_turn_ascore(sample) returns a float, or evaluate(dataset, metrics) |
| Running a dataset | your loop, or @experiment + Dataset |
evaluate() — emits DeprecationWarning ("Use the @experiment decorator instead") |
| Data | any dict or Pydantic row | SingleTurnSample / MultiTurnSample in an EvaluationDataset |
| Metrics only here | collections: RAG, agent, NLP, rubric, SQL metrics | AspectCritic, SimpleCriteriaScore, NonLLMContextPrecisionWithReference, NonLLMContextRecall, IDBasedContext*, FaithfulnesswithHHEM |
evaluate() accepts only legacy metric objects; passing a collections metric raises TypeError: All metrics must be initialised metric objects. The guide shows the current API first and calls out the legacy path where it is the only option.
Section Map¶
| File | Topics |
|---|---|
| 01 Datasets, Samples & Setup | SingleTurnSample, MultiTurnSample, EvaluationDataset, loading from pandas / JSONL / Hugging Face, Dataset backends, llm_factory and embedding_factory per provider, ascore helpers, legacy evaluate() options, RunConfig, caching, telemetry |
| 02 RAG Metrics | Faithfulness, AnswerRelevancy, ContextPrecision, ContextRecall, ContextEntityRecall, NoiseSensitivity, groundedness and relevance judges, non-LLM retrieval metrics, required inputs, formulas, LLM calls per metric, failure modes |
| 03 Other Metrics, Agents & Custom | DiscreteMetric / NumericMetric / RankingMetric, decorators, rubrics, BLEU / ROUGE / chrF / string / semantic similarity, SQL and table metrics, ToolCallAccuracy, ToolCallF1, AgentGoalAccuracy, TopicAdherence, custom metric classes, judge calibration and bias |
| 04 Test Sets & Experiments | TestsetGenerator, knowledge graph, personas, query synthesizers, reviewing generated samples, @experiment, comparing runs, version_experiment, LangChain / LangGraph / LlamaIndex and tracing tools |
| 05 Testing & CI | pytest layout, scripted and fake-server judges, aggregate and per-sample gates, baselines, non-determinism, GitHub Actions, cost counting, common failures, QA checklist |
When to Use Ragas vs DeepEval vs promptfoo vs Custom¶
| Need | Best fit |
|---|---|
| RAG diagnostics (retrieval vs generation), synthetic test sets from documents, agent tool-call metrics as plain functions | Ragas |
Pytest-native assertions (assert_test), many built-in metrics, CI reports, red teaming — see DeepEval |
DeepEval |
| Compare prompts and models side by side from YAML, assertions, red teaming — see promptfoo | promptfoo |
| One domain rule ("answer cites a policy id", "JSON matches schema") | Plain pytest assertion, no judge |
| Rubric specific to your product, calibrated against human labels | Ragas DiscreteMetric / custom class, or DeepEval G-Eval |
| Hosted datasets, annotation queues, dashboards | LangSmith, Langfuse, Phoenix, MLflow |
Ragas and DeepEval overlap on RAG metrics (faithfulness, answer relevancy, context precision and recall) but differ in implementation, prompts and score scales, so numbers from one are not comparable with the other. DeepEval also wraps four Ragas metrics as RagasMetric (see DeepEval RAG metrics). Pick one library per metric family and keep it fixed across runs.
Minimal Example¶
import asyncio
from openai import AsyncOpenAI
from ragas.llms import llm_factory
from ragas.metrics.collections import ContextRecall, Faithfulness
async def main() -> None:
client = AsyncOpenAI() # reads OPENAI_API_KEY
llm = llm_factory("gpt-4o-mini", client=client) # judge model; async client required
sample = dict(
user_input="What is the refund window?",
response="Refunds are accepted within 30 days.",
retrieved_contexts=["Our policy: refunds are accepted within 30 days of purchase."],
reference="Refunds are accepted within 30 days of purchase.",
)
faithfulness = await Faithfulness(llm=llm).ascore(
user_input=sample["user_input"],
response=sample["response"],
retrieved_contexts=sample["retrieved_contexts"],
)
recall = await ContextRecall(llm=llm).ascore(
user_input=sample["user_input"],
retrieved_contexts=sample["retrieved_contexts"],
reference=sample["reference"],
)
print(faithfulness.value, recall.value) # floats in 0.0 - 1.0
asyncio.run(main())
Each metric takes only the fields it needs as keyword arguments and returns a MetricResult. MetricResult behaves like its value in comparisons and arithmetic and also exposes .value, .reason and .traces. See 02 for which fields each metric requires and 05 for gating on the scores.
Names from Older Tutorials¶
| Old code | Current (0.4.3) |
|---|---|
Hugging Face Dataset with question, answer, contexts, ground_truth |
SingleTurnSample with user_input, response, retrieved_contexts, reference. evaluate() still renames the old columns |
ground_truths (list of strings) |
reference (one string) |
from ragas.metrics import faithfulness, answer_relevancy, context_precision, context_recall (ready-made instances) |
from ragas.metrics.collections import Faithfulness, AnswerRelevancy, ContextPrecision, ContextRecall and construct with llm= |
evaluate(dataset, metrics=[...]) |
evaluate() is deprecated; use ascore, or @experiment with Dataset |
LangchainLLMWrapper(ChatOpenAI(...)), LangchainEmbeddingsWrapper(...) |
llm_factory(model, client=AsyncOpenAI()), embedding_factory("openai", model=..., client=...) |
instructor_llm_factory(...) (0.3) |
llm_factory(...) |
llm_factory("gpt-4o-mini") with no client |
ValueError: llm_factory() requires a client instance — pass client= |
sync OpenAI() client in llm_factory for ascore |
AsyncOpenAI(); a sync client raises TypeError: Cannot use agenerate() with a synchronous client |
metric.single_turn_ascore(sample) returning a float |
await metric.ascore(**fields) returning MetricResult (.value) |
ResponseRelevancy, LLMContextRecall, LLMContextPrecisionWithReference |
AnswerRelevancy, ContextRecall, ContextPrecisionWithReference |
AspectCritic, SimpleCriteriaScore |
DiscreteMetric / NumericMetric, or the @discrete_metric decorator |
TestsetGenerator(generator_llm, critic_llm, embeddings), test_size=, simple / reasoning / multi_context evolutions |
TestsetGenerator(llm=..., embedding_model=...), testset_size=, query_distribution of query synthesizers |
Test set columns question, contexts, ground_truth, evolution_type |
user_input, reference_contexts, reference, synthesizer_name, persona_name, query_style, query_length |
ragas.integrations.langchain.EvaluatorChain |
Import fails on LangChain 1.x (langchain.chains is gone); call metrics from your own function |
await my_experiment(dataset) (migration guide snippet) |
await my_experiment.arun(dataset, name="...") |
Quick Rules¶
- Decide the API first — new code uses
ragas.metrics.collectionswithllm_factory; use legacy classes only for metrics that have no collections version. - Pin
langchain-community<0.4.2andragas==0.4.3— the library is in transition and renames happen between minors. - Use an async client (
AsyncOpenAI,litellm.acompletion) and create it inside the running event loop; reusing one client across severalasyncio.run()calls fails intermittently. - Bound concurrency yourself —
abatch_scoreand@experimentstart every row at once; wrap calls in anasyncio.Semaphore. - Treat NaN as a failure, not as zero — a failed judge call must fail the gate, not vanish from the mean.
- Fix the judge — one judge model, temperature 0, same metric versions; a new judge needs a new baseline.
- Keep a small golden set and a cache — 20 to 50 reviewed rows scored with
DiskCacheBackendkeeps CI cheap and stable. - Test your own wiring offline — a scripted
InstructorBaseRagasLLMor a local fake server proves your harness and gates without spending tokens.
See also¶
- Digital Garden: Knowledge Base
- Python Libraries
- DeepEval — LLM Testing Guide
- DeepEval — RAG Metrics
- promptfoo — LLM Evals & Red Teaming from YAML
- Eval Harness — Tools, Testing & CI
- Pytest — Python Testing Framework
- LangChain — LLM Application Framework
- LiteLLM — One API for 100+ LLM Providers
- Agentic AI Architecture