Skip to content

feat(deepeval): add run_async method to DeepEvalEvaluator - #3695

Open
RahilOp wants to merge 2 commits into
deepset-ai:mainfrom
RahilOp:feat/deepeval-run-async-3667
Open

feat(deepeval): add run_async method to DeepEvalEvaluator#3695
RahilOp wants to merge 2 commits into
deepset-ai:mainfrom
RahilOp:feat/deepeval-run-async-3667

Conversation

@RahilOp

@RahilOp RahilOp commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Related Issues

Proposed Changes:

  • Add run_async to DeepEvalEvaluator so it can be used in Pipeline.run_async() without blocking the caller's loop.
  • The async implementation uses each metric's native a_measure method and evaluates test cases concurrently with asyncio.gather.
  • A separate metric copy is created per test case using deepeval.metrics.utils.copy_metrics, because DeepEval metrics keep result state (score, reason) on the metric instance.
  • Extracted _convert_results so both run and run_async share the same output-formatting logic.
  • Added parameterized async tests covering all five supported metrics.

How did you test it?

cd integrations/deepeval
hatch run test:unit -v
hatch run test:types
hatch run fmt-check
  • 24 unit tests pass (including 5 new async output tests).
  • Mypy reports no issues.
  • Ruff format/lint passes.

Notes for the reviewer

This follows the same pattern used by RagasEvaluator.run_async in this repo and by the public a_measure API suggested in the issue discussion. It intentionally does not bump the deepeval pin (>=2.9.0 remains supported).

Closes deepset-ai#3667.

Implements run_async using each metric's a_measure method, evaluating test cases concurrently. A separate metric copy is created per test case because DeepEval metrics keep score/reason state on the instance.

Tests cover all supported metrics and mirror the existing sync output assertions.
@RahilOp
RahilOp requested a review from a team as a code owner July 30, 2026 02:01
@RahilOp
RahilOp requested review from sjrl and removed request for a team July 30, 2026 02:01
@github-actions

Copy link
Copy Markdown
Contributor

Hi @RahilOp, thanks for your interest in contributing to Haystack! 🙏

⚠️ You currently have 3 open pull requests in this repository (#3683, #3558 and this one). Our review capacity is limited, so please hold off opening more PRs until we've had a chance to review your first 2 open PRs. This helps us give each contribution the attention it deserves. Thank you!

This is an automated message to help us keep the review queue healthy.

@github-actions

Copy link
Copy Markdown
Contributor

Heads-up for maintainers

This PR is from a fork and touches integrations whose integration tests require API keys.
Those tests are skipped in CI because fork PRs don't have access to repo secrets for security reasons.

Affected integrations:

  • deepeval

Please run the integration tests locally (hatch run test:integration inside each folder) before approving.

@github-actions github-actions Bot added the type:documentation Improvements or additions to documentation label Jul 30, 2026
@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Coverage report (deepeval)

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  integrations/deepeval/src/haystack_integrations/components/evaluators/deepeval
  evaluator.py
Project Total  

This report was generated by python-coverage-comment-action

Signed-off-by: Syed Ali Abbas Rahil <viperboom0786110@gmail.com>
Comment on lines +113 to +114
``a_measure`` method. A separate metric copy is used per test case
because DeepEval metrics keep state (``score``, ``reason``) on the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use double backticks for docstrings

Suggested change
``a_measure`` method. A separate metric copy is used per test case
because DeepEval metrics keep state (``score``, ``reason``) on the
`a_measure` method. A separate metric copy is used per test case
because DeepEval metrics keep state (`score`, `reason`) on the

:returns:
A dictionary with a single `results` entry that contains
a nested list of metric results. The shape matches the
output of :meth:`run`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
output of :meth:`run`.
output of the `run` method

assert got == expected


def test_invoke_deepeval(monkeypatch):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain why we need this test? It seems like its covered by existing tests

Comment on lines 441 to 443
# This integration test validates the evaluator by running it against the
# OpenAI API. It is parameterized by the metric, the inputs to the evalutor
# and the metric parameters.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add an integration test for the async route and please test it yourself locally


@staticmethod
async def _invoke_deepeval_async(test_cases: list[LLMTestCase], metric: BaseMetric) -> EvaluationResult:
"""Evaluate ``test_cases`` concurrently using the metric's ``a_measure``."""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the double back ticks in the docstrings

retrieval_context=cast(list[str] | None, test_case.retrieval_context),
)

results = await asyncio.gather(*[_evaluate_one(tc) for tc in test_cases])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is unbounded with the number of concurrent requests that we make. Please cap it by using Sempahore and sensible default for number of concurrent requests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

integration:deepeval type:documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add run_async method for DeepEval Haystack Integration

2 participants