Function contract
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 ADKEvaluationResult. 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 undercriteria 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
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.
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.criterionso configuration remains the source of truth. - Return
NOT_EVALUATEDwith 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.