Skip to main content
A custom metric lets you enforce a product rule that the built-in registry does not express. For a complete implementation, eval set, unit test, and run command, follow Create custom evals. Use this page to look up the scorer contract and registration options. Custom metrics run for both ADK and LangGraph agents because both framework lanes produce the same ADK invocation contract before scoring.

Function contract

The evaluator calls the function with four positional values: ADK supports both synchronous def and asynchronous async def scorers. A synchronous scorer runs on the evaluation loop; do not block it with slow network I/O. The callback does not receive a Harnest runtime driver, a native LangGraph state object, or a session-store client. Actual and golden invocation counts can differ. Check the index before accessing expected[index], and handle expected=None for simulations.

Return scores and evidence

Return an ADK EvaluationResult. For a scored metric, ADK requires exactly one PerInvocationResult for each actual invocation, in the same order. This is a result contract, not an optional reporting enhancement. The exception is a metric whose entire result has overall_eval_status=NOT_EVALUATED. Keep aggregate and turn-level scoring consistent. ADK’s command gate averages non-None turn scores and compares that mean with the configured threshold; the recorded result also carries your returned overall score and status. Returning an unrelated overall score can make diagnostics and the command gate disagree. For a final-turn-only conversation metric, return unscored NOT_EVALUATED rows for earlier turns and put the conversation score on the last turn. Use that same score for the overall result. An entirely unscored metric does not pass the command gate. The walkthrough uses a simpler mean-of-turns policy and a threshold of 1.0 to require every answer to pass.

Register the function

Use the same name under criteria and customMetrics. Authored root lib/ modules compile below harnest.lib, so lib/eval_metrics.py becomes harnest.lib.eval_metrics during evaluation.
evals/test_config.json
If you omit metricInfo, ADK describes the custom score on a closed 0 to 1 interval. To declare the interval explicitly, add metric information as shown below. Change the bounds if your scorer uses a different range; this metadata does not rescale your returned scores.
ADK replaces metricInfo.metricName with the owning customMetrics map key when registering the metric. Keep the two names identical in authored JSON for clarity.

Design a reliable metric

  • Make the function deterministic unless model judgment is essential.
  • Read the threshold from metric.criterion so configuration remains the source of truth.
  • Return NOT_EVALUATED with no score when evidence is genuinely unavailable; do not silently pass. A known violation, such as a missing required answer, can instead receive an explicit failing score.
  • Preserve actual and expected invocations in per-turn results so failures remain diagnosable.
  • Keep network calls explicit and separately authenticated. Harnest’s transport sharing applies to declared judge and simulator models, not arbitrary SDK calls inside a custom function. Your function must configure and clean up any clients it creates. It can read the same process environment as the agent; it should never return credentials in diagnostic evidence.
A custom metric is trusted application code. Harnest imports and executes the configured function. Do not run an eval configuration or agent repository from an untrusted source.

Troubleshoot registration