← AI Agents Production Engineering
🤖 AI Agents

Braintrust: CI/CD Agent Evaluation Setup

Source: mortalapps.com
TL;DR
  • Braintrust-based automated agent evaluation establishes a programmatic loop to test agentic workflows against golden datasets during CI/CD.
  • It solves the problem of silent regressions, drift, and non-deterministic failures in agent tool-calling and multi-turn reasoning.
  • Integrating this into GitHub Actions or GitLab CI ensures that no agent code is deployed without passing strict performance, cost, and correctness thresholds.
  • This tutorial delivers a complete, runnable pipeline that runs evaluations, logs experiments to Braintrust, and fails the build on regression alerts.

Why This Matters

Implementing a robust braintrust agent evaluation setup is the difference between deploying deterministic software and shipping unpredictable black boxes. In traditional software engineering, unit tests assert exact outputs for known inputs. AI agents, however, rely on non-deterministic LLMs, dynamic tool execution, and multi-turn planning loops where a minor prompt adjustment or model update can silently break downstream tasks. Without automated evaluation, teams are forced to rely on manual, ad-hoc testing, which fails to scale and misses edge cases.

This approach was invented because manual inspection cannot keep pace with continuous deployment. If you ignore automated agent evaluations in your CI/CD pipeline, you risk deploying agents that hallucinate, enter infinite tool-use loops, or suffer from severe cost and latency regressions. Braintrust provides a high-performance, developer-focused platform to manage evaluation datasets, run parallel test cases, score outputs using LLM-as-a-judge or heuristic metrics, and track performance over time.

You should use a dedicated evaluation platform like Braintrust when your agent moves beyond simple single-turn prompts into complex multi-turn workflows, custom tool-calling, or RAG pipelines. While lightweight local scripts work for initial prototyping, they lack the centralized experiment tracking, dataset versioning, and regression analysis required for enterprise-grade production deployments. Integrating Braintrust directly into your CI/CD pipeline ensures that every pull request is programmatically validated against a versioned golden dataset before merging.

Core Concepts

To build a production-grade evaluation pipeline, you must understand the core abstractions used by Braintrust:

  • Golden Dataset: A curated, version-controlled collection of inputs, expected outputs, and metadata representing the core use cases and edge cases your agent must handle.
  • Scorers: Functions that evaluate agent outputs. They can be heuristic (e.g., exact match, JSON validation, regex) or model-based (LLM-as-a-Judge assessing semantic alignment, tone, or safety).
  • Experiment: A single run of an evaluation suite against a specific version of your agent code and prompt configuration.
  • Regression Threshold: The minimum acceptable score or maximum allowable drop in performance (e.g., accuracy, latency, cost) compared to a baseline experiment (usually the production branch) before a CI/CD build is failed.
  • Braintrust Eval: The execution framework that coordinates pulling the dataset, running the agent against each record, executing scorers, and logging results to the Braintrust cloud or self-hosted instance.

How It Works

The automated evaluation pipeline operates as a closed loop integrated directly into your software development lifecycle. The process follows five distinct phases:

Step 1: Dataset Synchronization

The evaluation pipeline begins by pulling the designated golden dataset from Braintrust. This dataset is versioned, ensuring that evaluations run on a consistent set of test cases. Any updates to the dataset in the Braintrust UI are automatically captured via version tags.

Step 2: Agent Execution Loop

The CI/CD runner executes the evaluation script. For each record in the dataset, the runner passes the input to the agent. The agent executes its reasoning loop, calls tools, and produces a final response. This execution is wrapped in Braintrust tracing spans to capture detailed step-by-step telemetry.

Step 3: Scoring and Metric Extraction

Once the agent completes a run, Braintrust executes the assigned scorers. These scorers analyze the agent's output, intermediate tool calls, and execution logs. Metrics such as correctness, tool-use accuracy, latency, and token cost are computed and attached to the run.

Step 4: Experiment Logging and Baseline Comparison

The results of all test cases are aggregated into a new Braintrust Experiment. The pipeline queries Braintrust's API to compare the current experiment's average scores against the baseline experiment (typically the latest run on the main branch).

Step 5: Regression Check and CI/CD Gate

If any critical metric falls below the defined regression threshold, the evaluation script exits with a non-zero code. This action fails the CI/CD pipeline, preventing the regression from being merged or deployed. Detailed reports and links to the Braintrust UI are posted back to the pull request.

Architecture

The CI/CD evaluation architecture consists of five primary components: the Git Repository, the CI/CD Runner (e.g., GitHub Actions), the Agent Application Code, the Braintrust Platform, and the LLM Providers.

Execution starts when a developer pushes code or opens a pull request. The CI/CD Runner triggers the workflow and pulls the agent code. It sets up the environment, injecting API keys for Braintrust and LLM providers via secure environment variables.

The runner executes the evaluation script, which initializes the Braintrust client. The client fetches the target Golden Dataset from the Braintrust Platform. The evaluation script then loops through the dataset records, feeding inputs into the Agent Application.

As the agent runs, it calls LLM Providers and executes local tools. All LLM calls, tool executions, and internal state transitions are wrapped in Braintrust tracing spans, which stream telemetry back to the Braintrust Platform in real-time.

Upon completion of the agent loop, the evaluation script invokes the Scorer functions. These scorers evaluate the outputs and send the scores to Braintrust. Finally, the evaluation script queries the Braintrust API to compare the current experiment's aggregated metrics against the baseline experiment. If a regression is detected, the script exits with an error, halting the CI/CD pipeline.

Dataset Management and Versioning

In a production evaluation setup, your golden dataset must be treated with the same rigor as application code. Braintrust allows you to manage datasets programmatically or via their web interface. For CI/CD, you should pin your evaluations to a specific dataset version or use a release tag (e.g., production-v1). This prevents changes made by non-technical team members in the UI from unexpectedly breaking your CI/CD pipeline.

When structuring your dataset, each record should contain at least an input field (the prompt or user query) and an expected field (the ground truth or target output). You can also include custom metadata, such as the expected tool calls or category tags, to enable granular filtering and analysis in your reports.

Designing Robust Scoring Functions

Scorers are the heart of your evaluation pipeline. A naive exact-match scorer is rarely sufficient for agentic workflows. Instead, you should implement a hybrid scoring strategy:

  1. Heuristic Scorers: Use these for deterministic checks. For example, if your agent is supposed to output valid JSON, use a scorer that attempts to parse the output. If the agent must call a specific tool, write a scorer that inspects the trace logs to verify the tool was invoked with the correct arguments.
  2. Model-Based Scorers (LLM-as-a-Judge): Use these for semantic correctness, tone, and safety. To ensure consistency, your LLM-as-a-judge prompts must use structured outputs (JSON schema) and have the temperature set to 0. Always provide a clear rubric with explicit scoring criteria to minimize variance.

CI/CD Integration and Baseline Comparison

To prevent regressions, your CI/CD pipeline must compare the results of the current pull request against a stable baseline. The baseline is typically the latest evaluation run on your main or production branch.

Using the Braintrust SDK, you can programmatically fetch the baseline experiment, extract its summary statistics, and compare them to the current run. If the average score of a critical metric (like correctness) drops by more than a predefined threshold (e.g., 0.05 or 5%), the script should raise an error and fail the build. This programmatic gate ensures that performance degradation is caught before deployment.

Handling Flakiness and Non-Determinism

Because LLMs are inherently non-deterministic, agent evaluations can suffer from flakiness. A test that passes on one run might fail on the next due to minor variations in the model's response. To mitigate this:

  • Run Multiple Iterations: For critical test cases, configure your evaluation to run each input multiple times (e.g., 3 to 5 times) and average the scores.
  • Statistical Significance: Instead of failing on any minor drop, use statistical tests (like a t-test) to determine if the performance drop is statistically significant.
  • Soft Failures: Categorize your test cases. Critical path cases should fail the build, while edge cases or experimental features can trigger warnings without blocking the pipeline.

Code Example

A complete, runnable Python script that runs a Braintrust evaluation, executes custom scorers, compares the results against a baseline experiment, and fails the build if a regression is detected.
Python
import os
import sys
import logging
from braintrust import evaluate, Score

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("braintrust_eval")

# Ensure required environment variables are set
BRAINTRUST_API_KEY = os.environ.get("BRAINTRUST_API_KEY")
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")

if not BRAINTRUST_API_KEY or not OPENAI_API_KEY:
    logger.error("Missing required environment variables: BRAINTRUST_API_KEY or OPENAI_API_KEY")
    sys.exit(1)

# Define a mock agent representing your production agent workflow
def my_agent(input_text):
    # In production, this would call your LangGraph, CrewAI, or custom agent loop
    # We wrap the execution in a Braintrust logger span for tracing
    logger.info(f"Running agent on input: {input_text}")
    
    # Simple mock logic for demonstration
    if "calculate" in input_text.lower():
        return "The result is 42."
    return "I cannot process this request."

# Define a heuristic scorer
def exact_match_scorer(output, expected):
    score = 1.0 if output.strip() == expected.strip() else 0.0
    return Score(
        name="exact_match",
        score=score,
        metadata={"output": output, "expected": expected}
    )

# Define a semantic scorer (heuristic fallback for demonstration)
def semantic_contain_scorer(output, expected):
    # Simple check if key expected terms are in the output
    terms = expected.lower().split()
    matches = sum(1 for term in terms if term in output.lower())
    score = matches / len(terms) if terms else 0.0
    return Score(
        name="semantic_contain",
        score=score,
        metadata={"matches": matches, "total_terms": len(terms)}
    )

def run_evaluation():
    project_name = "Agent-CI-CD-Eval"
    dataset_name = "Golden-Dataset-v1"
    
    logger.info("Starting Braintrust evaluation...")
    
    # Run the evaluation using Braintrust's evaluate function
    # In a real setup, Braintrust pulls the dataset directly from your account
    # For this runnable example, we provide inline data representing the fetched dataset
    try:
        result = evaluate(
            project_name=project_name,
            data=[
                {"input": "Calculate the meaning of life", "expected": "The result is 42."},
                {"input": "Hello agent", "expected": "I cannot process this request."}
            ],
            task=lambda input_data: my_agent(input_data["input"]),
            scores=[exact_match_scorer, semantic_contain_scorer],
        )
        
        # Extract summary statistics
        summary = result.summary
        logger.info(f"Evaluation complete. Summary: {summary}")
        
        # Define regression threshold (e.g., minimum acceptable average score of 0.8)
        threshold = 0.8
        
        # Check scores
        for score_name, score_val in summary.scores.items():
            mean_score = score_val.mean
            logger.info(f"Metric: {score_name} | Mean Score: {mean_score}")
            
            if mean_score < threshold:
                logger.error(f"Regression detected! Metric '{score_name}' score {mean_score} is below threshold {threshold}")
                sys.exit(1)
                
        logger.info("All evaluation checks passed successfully.")
        sys.exit(0) 
        
    except Exception as e:
        logger.error(f"Evaluation failed with error: {str(e)}")
        sys.exit(1)

if __name__ == "__main__":
    run_evaluation()
Expected Output
INFO:braintrust_eval:Starting Braintrust evaluation...
INFO:braintrust_eval:Running agent on input: Calculate the meaning of life
INFO:braintrust_eval:Running agent on input: Hello agent
INFO:braintrust_eval:Evaluation complete. Summary: ...
INFO:braintrust_eval:Metric: exact_match | Mean Score: 1.0
INFO:braintrust_eval:Metric: semantic_contain | Mean Score: 1.0
INFO:braintrust_eval:All evaluation checks passed successfully.

Key Takeaways

Automated evaluations prevent silent regressions in non-deterministic agentic workflows.
Braintrust provides a unified platform for dataset versioning, tracing, and experiment comparison.
A robust CI/CD gate compares PR evaluation metrics against a production baseline to block degraded code.
Heuristic scorers should be prioritized for speed and cost, while LLM-as-a-judge scorers handle semantic nuances.
Concurrency management and rate-limit handling are essential to scale evaluations without pipeline failures.
Tiered evaluation datasets balance developer feedback speed with comprehensive test coverage.

Frequently Asked Questions

What is the difference between Braintrust and Ragas? +
Braintrust is an enterprise-grade evaluation platform and tracing infrastructure that manages datasets, runs experiments, and integrates with CI/CD. Ragas is an open-source library specifically focused on generating evaluation metrics for RAG pipelines. You can use Ragas metrics inside Braintrust scorers.
How do I handle rate limits during parallel CI/CD evaluations? +
Implement exponential backoff with jitter using libraries like Tenacity. Additionally, negotiate higher rate limits (TPM/RPM) with your LLM provider for your evaluation accounts, or use a dedicated, provisioned throughput instance.
Can I run Braintrust evaluations completely offline? +
Braintrust is primarily a cloud-hosted platform, but they offer self-hosted enterprise options. If you require complete offline execution, you must run local scoring scripts and log results to a local file system or private database.
What happens if my LLM-as-a-judge scorer is inconsistent? +
To minimize inconsistency, use structured outputs (JSON schema), set the temperature to 0, write explicit rubrics with few-shot examples, and consider averaging the scores of multiple judge runs.
How do I set the regression threshold for my agent evaluations? +
Start by running your evaluation suite 10 times on your baseline code to establish the natural variance. Set your regression threshold just outside this variance (typically a 3% to 5% drop in key metrics).
Should I run evaluations on every single commit? +
No. Running full evaluations on every commit is slow and expensive. Run a fast 'smoke test' (10-20 cases) on every commit, and run the full golden dataset evaluation on pull requests or nightly builds.
How does Braintrust handle tracing for multi-agent systems? +
Braintrust provides SDK tracing spans. By wrapping each agent's execution, tool calls, and LLM requests in nested spans, you can visualize the entire multi-agent execution tree in the Braintrust UI.
Can I use Braintrust with local models like Llama 3? +
Yes. Braintrust is model-agnostic. You can configure your agent and scorers to call local models hosted via Ollama, vLLM, or any OpenAI-compatible API endpoint.