Skip to main content
.analyze() is the last step in the evaluation chain. It runs the same durable, multi-stage pipeline as the dashboard’s “Analyze” button: each response is scored by 1-3 LLM judges, then reduced through question- and cluster-level summaries into one final qualitative report, returned as a Report object.
Numeric scores (average_rating, similarity metrics) are ready right after .finalize(), so you don’t need to wait for .analyze() just to see how the run went. Because .analyze() polls a job until it completes, it can take noticeably longer than a single LLM call for larger runs; progress is shown in the terminal while it waits.

Controlling the analysis

Check on a long-running analysis without calling .analyze() again, even from a separate script execution:

Fields

Each rating sub-field is one of "high", "medium", "low". recommendations[].category is one of "instructions", "tools", "knowledge", "reasoning", "consistency", "other"; priority is "high", "medium", or "low".

Reading it in your terminal

Or open report.dashboard_url to review the full report, per-question breakdowns, and instruction-change suggestions in the dashboard.

Per-result rows without an analysis

results() returns the scored rows - no analysis job, no extra judge calls - for asserting on individual results in scripts and CI. Rows are typed RunResultRow objects with snake_case attributes (dict-style access still works but is deprecated and warns; row.raw keeps the full wire dict):
Each row carries rating/justification, a status ("scored", "skipped" when the judge could not score it - rating stays None, not 0 - or "failed" when the result carried an error), the linked trace_id, latency_ms and token counts, and the similarity metrics (cosine_similarity, jaccard_similarity, bleu_score, rouge_score). client.evaluations.get_run(run_id) fetches the same payload later, from a different process.