Automating LLM-as-a-Judge with GitHub Actions: Stopping AI Errors Before Deployment

Artificial Intelligence tutorial - IT technology blog
Artificial Intelligence tutorial - IT technology blog

When Traditional Unit Tests Fail Against AI

At 2:00 AM, my phone wouldn’t stop vibrating due to system alerts. The company’s RAG chatbot had suddenly “switched careers” from business consulting to… teaching customers how to cook. The reason was simple: a developer had just changed the prompt to make the chatbot sound friendlier, manually tested a few queries that seemed fine, and merged it straight to production.

The issue lies in the non-deterministic nature of LLMs. For the same question, the AI returns a different result every time. Classic assert response == "expected" statements are completely useless because AI rarely returns two identical sentences down to the last comma. Without an automated evaluation process smart enough to understand semantics, deploying AI applications is like playing the lottery with user experience.

Three Current Approaches to LLM Testing

To solve this problem, I considered three popular methods with their own trade-offs:

1. Rule-based Testing

This method uses Regex or keyword checks in the response. It is fast and nearly free. However, it cannot detect if a response has the right tone of voice or if it contains hallucinations. For example, you cannot use Regex to check if a 200-word paragraph correctly summarizes the main points.

2. Manual Evaluation (Human-in-the-loop)

This is the gold standard for accuracy, as humans grade the results directly. But it is a major bottleneck for scaling. No one has the patience to manually check 1,000 responses every time you change a single line in the System Prompt.

3. LLM-as-a-Judge (AI Grading AI)

We use a powerful model (like GPT-4o or Claude 3.5 Sonnet) as a judge to grade a smaller model. The judge model evaluates based on a specific set of criteria (rubric). This is the most balanced option between speed, cost, and reliability.

Criteria Rule-based Human-in-the-loop LLM-as-a-Judge
Speed Near-instant Hours to days 1 – 2 minutes
Cost ~$0 Very expensive (dev salary) Medium (~$0.1 – $0.5/test)
Flexibility Low Very high High

Setting Up a “Quality Gate” on GitHub Actions

Integrating LLM-as-a-Judge into CI/CD gives me more confidence during releases. Every time there is a Pull Request, the system runs a sample test set (Golden Dataset). If the average quality score falls below a threshold (e.g., 7/10), GitHub will block the merge.

Step 1: Write the Evaluation Script (evaluator.py)

Instead of just asking the AI for a generic score, I use the Chain-of-Thought technique in the prompt so the Judge model explains its reasoning before providing the final number. This makes debugging much easier.

import os
from openai import OpenAI

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def judge_response(input_text, context, ai_response):
    prompt = f"""
    You are an AI quality assurance expert. Evaluate the response based on the context.
    
    [Context]: {context}
    [Question]: {input_text}
    [AI Response]: {ai_response}
    
    Scoring criteria (0-10):
    - 0: Completely incorrect or fabricated information.
    - 5: Correct main idea but missing important details.
    - 10: Accurate, complete, and professional tone.
    
    Respond in JSON format: {{"reason": "...", "score": 10}}
    """
    
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": prompt}],
        response_format={ "type": "json_object" }
    )
    # Logic to process the result and return the score
    return score

Step 2: Automate with GitHub Actions

Configure the .github/workflows/llm_eval.yml file so the workflow triggers automatically on every code change. I recommend using Python 3.10 or higher to take advantage of the latest libraries.

name: LLM Quality Gate
on:
  pull_request:
    branches: [ main ]

jobs:
  evaluate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install dependencies
        run: pip install openai
      - name: Run Evaluation
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
        run: python evaluator.py

Real-world Experience for Cost Optimization

When I first implemented this, I lost nearly $50 in one morning due to excessive testing. Here is how I optimized it:

  • Curate a Golden Dataset: Instead of testing the entire database, I only selected 30-50 “tough” questions representing edge cases.
  • Tiered Judge Models: Use GPT-4o-mini to grade simple tasks and only use GPT-4o for tasks requiring complex logic. This reduces API costs by 80%.
  • Prevent wasteful tests: Use paths-ignore in GitHub Actions to skip AI tests if you are only editing the README or documentation.

Conclusion

Since implementing this workflow, emergency midnight calls have dropped significantly. I no longer have to worry every time I update the chatbot’s logic. LLM-as-a-Judge cannot completely replace humans, but it is an extremely effective filter for catching silly mistakes before they reach real users.

Don’t wait until your AI starts “talking nonsense” to customers before looking for testing methods. Build an automated evaluation framework from day one.

Share: