← All articles

Testing and Evaluating LLM API Responses Across Providers: Regression Testing, Quality Assurance, and Evaluation Frameworks for Production

A practical guide to testing LLM API responses across OpenAI, Anthropic, DashScope, and DeepSeek. Covers golden datasets, regression testing after model updates, LLM-as-a-judge scoring, and open-source evaluation frameworks like Promptfoo, DeepEval, Braintrust, and LangSmith.

· TheRouter

When you route LLM requests across multiple providers — OpenAI, Anthropic, DashScope, DeepSeek — you need a way to verify that routing decisions produce equivalent-quality output. A prompt that works well on GPT-4o might behave differently on Claude Sonnet 4, and a model update on one provider can silently change behavior in ways that no error code will ever surface. Evaluation is the only reliable defense.

This guide covers the full testing workflow for teams operating across providers: building golden datasets, choosing metrics, running cross-provider evaluations, and wiring regression tests into CI/CD.

Why LLM API Testing Is Different from Traditional API Testing

Traditional API testing checks status codes, response schemas, and latency. LLM API testing has to deal with a harder problem: the same input can produce many acceptable outputs, and "correct" is often subjective.

Three factors make cross-provider testing especially tricky:

  • Non-deterministic outputs. Even with temperature: 0, providers may return slightly different text across requests. Exact-match assertions break immediately.
  • Model version drift. Providers update models on their own schedules. OpenAI uses dated snapshots (e.g., gpt-4o-2024-11-20), Anthropic uses claude-sonnet-4-20250514, and DashScope uses rolling aliases that silently point to newer checkpoints. A test that passed last week may fail today without any code change on your side.
  • Provider-specific behavior differences. System prompt handling, tool-calling formats, token counting, and content-filtering thresholds vary across providers. The same prompt can produce a detailed answer on one provider and a refusal on another.

The takeaway: you cannot test LLM API integrations with status-code checks alone. You need evaluation — structured measurement of output quality against defined criteria.

Building a Golden Dataset

Every serious evaluation pipeline starts with a golden dataset: a curated set of input-output pairs that define what "good" looks like for your use case.

What to Include

CategoryExamplesWhy It Matters
Core use casesThe 20 most common user queriesCovers the happy path that most traffic hits
Edge casesVery long inputs, multilingual queries, ambiguous requestsCatches failures that only appear at the margins
Regression casesInputs that previously produced bad output (and were fixed)Prevents known bugs from resurfacing
Adversarial inputsPrompt injection attempts, off-topic queriesValidates safety and content-filtering behavior

Practical Tips

  • Start small. 50–100 well-chosen examples beat 1,000 sloppy ones. Expand as you discover new failure modes.
  • Version your dataset. Store it in Git alongside your prompts. When a test case changes, the diff tells you why.
  • Include metadata. Tag each case with the expected behavior category (factual accuracy, tone, format compliance) so you can slice results later.
  • Use real production traffic. Sample actual user inputs weekly and have domain experts approve or edit the outputs. Synthetic data helps bootstrap, but nothing replaces real queries.

Choosing Evaluation Metrics

LLM evaluation metrics fall into three tiers, each trading off speed and accuracy:

Tier 1 — Deterministic Checks (Fast, Brittle)

These run instantly and catch obvious failures:

# Check that the response contains required information
assert "API key" in response.text
assert len(response.text) > 100
assert response.text.count("```") % 2 == 0  # balanced code blocks

# Regex for format compliance
import re
assert re.match(r"^\d+\.", response.text)  # starts with numbered list

Deterministic checks work well for format compliance and presence/absence of required elements. They fail at evaluating reasoning quality, nuance, or whether an answer is actually helpful.

Tier 2 — Embedding Similarity (Medium Speed, Medium Accuracy)

Semantic similarity compares the meaning of the test output against a reference answer using embeddings:

from openai import OpenAI

client = OpenAI()

def cosine_similarity(a, b):
    import numpy as np
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

ref_embedding = client.embeddings.create(
    model="text-embedding-3-small",
    input=reference_answer
).data[0].embedding

test_embedding = client.embeddings.create(
    model="text-embedding-3-small",
    input=test_answer
).data[0].embedding

score = cosine_similarity(ref_embedding, test_embedding)
assert score > 0.85  # threshold depends on your use case

Embedding similarity catches meaning-preserving rephrasings and detects when an answer drifts off-topic. It struggles with cases where two semantically similar answers differ in factual correctness.

Tier 3 — LLM-as-a-Judge (Slowest, Most Accurate)

Use a strong model to grade the output of a weaker or cheaper model:

judge_prompt = """You are evaluating an AI assistant's response.

Question: {question}
Reference answer: {reference}
Assistant's answer: {answer}

Rate the assistant's answer on these criteria (1-5 each):
1. Factual accuracy: Does it contain correct information?
2. Completeness: Does it cover all key points from the reference?
3. Clarity: Is it well-organized and easy to understand?

Return JSON: {"accuracy": N, "completeness": N, "clarity": N, "explanation": "..."}
"""

judgment = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": judge_prompt.format(
        question=test_case["input"],
        reference=test_case["expected"],
        answer=actual_output
    )}],
    response_format={"type": "json_object"}
)

LLM-as-a-judge is the most flexible approach and handles subjective quality dimensions well. The tradeoff is cost and latency — you pay for a full inference call per evaluation.

Best practice: Combine all three tiers. Run deterministic checks first to fail fast on format issues, use embedding similarity for bulk screening, and reserve LLM-as-a-judge for the cases that matter most.

Cross-Provider Evaluation in Practice

The core workflow: run the same test suite against multiple providers and compare results side by side.

A Minimal Cross-Provider Test Script

from openai import OpenAI
import json

providers = {
    "openai": {
        "client": OpenAI(),
        "model": "gpt-4o"
    },
    "anthropic_via_openai": {
        "client": OpenAI(
            base_url="https://api.anthropic.com/v1/",
            api_key="sk-ant-..."
        ),
        "model": "claude-sonnet-4-20250514"
    },
    "dashscope": {
        "client": OpenAI(
            base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
            api_key="sk-..."
        ),
        "model": "qwen-max"
    },
    "deepseek": {
        "client": OpenAI(
            base_url="https://api.deepseek.com",
            api_key="sk-..."
        ),
        "model": "deepseek-chat"
    }
}

test_cases = json.load(open("golden_dataset.json"))

for case in test_cases:
    results = {}
    for name, provider in providers.items():
        response = provider["client"].chat.completions.create(
            model=provider["model"],
            messages=case["messages"],
            temperature=0
        )
        results[name] = response.choices[0].message.content

    # Now score each result against the reference
    for name, output in results.items():
        score = evaluate(output, case["expected"])
        print(f"{case['id']} | {name}: {score:.2f}")

This pattern works because OpenAI, Anthropic (via compatibility layer), DashScope, and DeepSeek all support the OpenAI-compatible chat completions format. The same test harness, the same golden dataset, different base_url and model values.

What to Compare

DimensionHow to MeasureWhy It Matters
Output qualityLLM-as-a-judge scoresThe core question — does this provider produce good answers?
ConsistencyVariance across 5 runs of the same inputHigh variance means unpredictable user experience
LatencyTime-to-first-token and total response timeAffects UX, especially for streaming applications
CostInput/output token counts × provider pricingSame quality at lower cost is a valid routing decision
Refusal ratePercentage of inputs that trigger content-filteringProvider A might answer what Provider B refuses

Open-Source Evaluation Frameworks

You do not need to build evaluation infrastructure from scratch. Several mature frameworks handle the plumbing — test orchestration, scoring, result visualization, and CI integration.

Promptfoo

Promptfoo is a CLI-first, open-source evaluation tool (acquired by OpenAI in March 2026, still MIT-licensed). It is built specifically for cross-provider comparison.

Strengths:

  • YAML-based test definitions — no code required for basic evals
  • Built-in support for 50+ providers including OpenAI, Anthropic, and any OpenAI-compatible endpoint
  • Matrix view comparing outputs across prompts and providers side by side
  • CI/CD integration via GitHub Actions
  • Red-teaming and security scanning built in

Typical workflow:

# promptfooconfig.yaml
providers:
  - openai:gpt-4o
  - openai:compatible:https://dashscope.aliyuncs.com/compatible-mode/v1:qwen-max
  - openai:compatible:https://api.deepseek.com:deepseek-chat

prompts:
  - "Answer this question concisely: {{question}}"

tests:
  - vars:
      question: "What is an API gateway?"
    assert:
      - type: contains
        value: "routes requests"
      - type: llm-rubric
        value: "Answer is technically accurate and under 200 words"
  - vars:
      question: "Compare REST and GraphQL"
    assert:
      - type: llm-rubric
        value: "Covers key differences: query flexibility, over-fetching, typing"

Run with npx promptfoo eval and view results in the browser with npx promptfoo view.

DeepEval

DeepEval takes a Pytest-native approach. If your team already writes Python tests, DeepEval fits naturally into the existing workflow.

Strengths:

  • Pytest plugin — evaluations run alongside unit tests
  • 14+ built-in metrics including hallucination detection, answer relevancy, faithfulness (for RAG), and bias
  • Automatic golden dataset generation from production logs
  • Confidence AI dashboard for tracking scores over time
from deepeval import assert_test
from deepeval.test_case import LLMTestCase
from deepeval.metrics import AnswerRelevancyMetric, HallucinationMetric

def test_customer_support_response():
    test_case = LLMTestCase(
        input="How do I reset my password?",
        actual_output=get_response_from_provider("openai", "How do I reset my password?"),
        expected_output="Go to Settings > Security > Reset Password...",
        retrieval_context=["Password reset documentation..."]
    )

    relevancy = AnswerRelevancyMetric(threshold=0.7)
    hallucination = HallucinationMetric(threshold=0.5)

    assert_test(test_case, [relevancy, hallucination])

Braintrust

Braintrust combines evaluation, tracing, and prompt management in a single platform. The open-source SDK handles evaluation; the hosted platform adds collaboration and online monitoring.

Strengths:

  • Unified tracing and eval — every production call can feed back into the eval dataset
  • Experiment comparison with statistical significance testing
  • Supports both offline evals (during development) and online evals (in production)
  • Dataset versioning built in

LangSmith

LangSmith (from the LangChain team) provides tracing, evaluation, and dataset management. It works well with LangChain-based applications but also supports standalone use.

Strengths:

  • Deep tracing of multi-step chains and agent workflows
  • Production monitoring with sampled evaluation
  • Turn production traces into regression test cases with one click
  • Annotation queues for human evaluation workflows

Arize Phoenix

Arize Phoenix is an open-source observability platform for LLM applications, with strong evaluation capabilities.

Strengths:

  • Fully open-source (Apache 2.0)
  • Embedding drift detection for catching gradual quality degradation
  • Trace visualization for debugging complex agent workflows
  • Integrates with OpenTelemetry for production observability

Quick Comparison

FrameworkLicenseCross-ProviderCI/CDLLM-as-JudgeTracingPricing
PromptfooMITNative (50+ providers)GitHub ActionsYesNoFree (OSS)
DeepEvalApache 2.0Via custom providersPytestYes (14+ metrics)Via Confident AIFree (OSS) + hosted
BraintrustMIT (SDK)Via OpenAI SDKYesYesYesFree tier + paid
LangSmithProprietaryVia LangChainYesYesYesFree tier + paid
Arize PhoenixApache 2.0Via OpenTelemetryYesYesYesFree (OSS) + hosted

Regression Testing After Model Updates

Model updates are the most common source of quality regressions in production LLM applications. When OpenAI retires gpt-4o-2024-11-20 in favor of a newer snapshot, or when DashScope updates the model behind the qwen-max alias, your outputs change — and you need to know whether they changed for better or worse.

The Regression Testing Workflow

  1. Baseline capture. Before any change, run your full golden dataset against the current production configuration. Save all outputs and scores.
  2. Change detection. After a model update, prompt change, or provider switch, run the same dataset again.
  3. Comparison. Diff the scores. Flag any test case where quality dropped below threshold.
  4. Decision gate. If regression is within tolerance (e.g., <5% score drop on aggregate, no critical failures), proceed. Otherwise, investigate or roll back.

CI/CD Integration Example

# .github/workflows/llm-eval.yml
name: LLM Evaluation
on:
  pull_request:
    paths:
      - 'prompts/**'
      - 'config/models.yaml'

jobs:
  eval:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npx promptfoo eval --config promptfooconfig.yaml
      - run: npx promptfoo eval --output results.json
      - uses: actions/upload-artifact@v4
        with:
          name: eval-results
          path: results.json

Every pull request that modifies prompts or model configuration triggers an evaluation run. Reviewers see the quality scores before merging.

Production Monitoring

Offline evaluation catches regressions before deployment. Production monitoring catches everything else — novel user queries, distribution shifts, gradual model drift.

Sampling Strategy

Evaluating every production request is expensive. A practical approach:

  • Sample 1–5% of requests for automated evaluation
  • Score asynchronously — do not add latency to the user-facing response
  • Alert on score drops — set thresholds for each metric and fire alerts when the rolling average falls below them
  • Feed interesting cases back into the golden dataset — production traffic is the best source of new test cases

Key Metrics to Track

  • Quality score trend — is the 7-day moving average stable, improving, or degrading?
  • Refusal rate by provider — a spike may indicate a content-policy change
  • Latency percentiles — p50, p95, p99 by provider
  • Cost per request — token usage × per-token pricing, compared across providers
  • Error rate — 4xx/5xx responses, timeouts, and rate-limit hits

For detailed production monitoring setup, see our LLM API observability and monitoring tools comparison.

TheRouter Integration Note

OpenAI-compatible means a provider exposes a chat-completions endpoint whose request and response shape matches the OpenAI API contract closely enough that an unmodified OpenAI SDK call works against it after swapping three values: API key, base URL, and model name. The minimum surface in practice is POST /v1/chat/completions with messages, model, and an OpenAI-shaped streaming response.

When you route requests through an OpenAI-compatible gateway, your evaluation harness only needs one client configuration per backend — the gateway handles authentication and endpoint routing. This means you can run the same Promptfoo or DeepEval test suite against multiple providers by changing a single model parameter, without maintaining separate API keys and base URLs in your test configuration.

For teams using model fallback routing, evaluation serves an additional purpose: validating that fallback responses meet the same quality bar as primary responses. If your primary model is GPT-4o and your fallback is Qwen-Max, your golden dataset should produce acceptable scores on both.

Production LLM API Testing Checklist

Use this checklist when setting up evaluation for a cross-provider LLM deployment:

  • Golden dataset exists with 50+ curated input-output pairs covering core use cases, edge cases, and regression cases
  • Metrics defined — at least one deterministic check and one LLM-as-a-judge metric per test case
  • Cross-provider baseline — scores captured for every provider in your routing configuration
  • CI/CD integration — evaluations run automatically on prompt or model configuration changes
  • Regression thresholds set — clear pass/fail criteria that block deployment when quality drops
  • Production sampling active — 1–5% of live traffic scored asynchronously
  • Alert pipeline configured — quality score drops trigger notifications before users notice
  • Dataset maintenance cadence — weekly review of production traffic to update golden dataset
  • Human calibration loop — monthly check that automated scores correlate with human judgment

Further Reading

Help & contact