If your testing strategy for your AI agent is just "vibe checking" a few prompts in a playground, you are one model deprecation away from a broken product.
When you build multi-agent systems—like the six Gemini agents powering JobHunt.ai or the automated resume tailoring logic running inside SwitchWithAI—minor upstream shifts in model behavior will break downstream outputs silently. A prompt that returns pristine JSON on Tuesday will suddenly wrap it in markdown code blocks on Wednesday because of an unannounced model checkpoint update.
Manual regression testing does not scale. What you need is a deterministic, automated evaluation suite that treats LLM inputs and outputs with the same rigor as traditional unit tests.
Here is how to set up a lightweight evaluation pipeline using Python and pytest in under an hour.
Why Does Prompt Drift Break Production AI Apps?
Traditional software breaks loudly with stack traces and syntax errors. LLM-backed applications break quietly.
When an API provider updates a model weight or deprecates an endpoint version, your application code still executes successfully. The HTTP status code is 200 OK. The JSON parser, however, throws a KeyError because the model decided to rephrase a structural key or omit a confidence score.
If you rely on manual testing, you catch these regressions only after a user files a bug report. For solo builders and indie hackers shipping fast, manual testing is a tax on velocity. You spend half your development cycle manually clicking through user flows just to verify that a system prompt adjustment didn't degrade accuracy on edge cases.
How to Build a Lightweight LLM Evaluation Suite in 60 Minutes
You do not need a heavy, enterprise-grade observability platform to test your agents. You need a structured test dataset, an assertion framework, and a CI step.
Here is how to implement a deterministic test suite using Python, pytest, and the Google Gemini SDK.
1. Define Your Golden Test Dataset
Create a JSON file containing a set of diverse test inputs and expected semantic outcomes. Do not test vibes; test constraints.
[
{
"id": "test_resume_parse_01",
"input_text": "Experienced Flutter and Python developer with 4 years at AGL-Hakuhodo...",
"expected_keys": ["skills", "experience_years", "primary_stack"],
"min_skills_count": 3
},
{
"id": "test_resume_parse_02",
"input_text": "Fresh graduate, building local inference pipelines with Ollama and Supabase.",
"expected_keys": ["skills", "experience_years", "primary_stack"],
"min_skills_count": 2
}
]
2. Write Deterministic Assertions with Pytest
Instead of asking the LLM if the output "looks good," write deterministic Python assertions that check structural validity, schema compliance, and specific semantic constraints.
import json
import pytest
from google import genai
@pytest.fixture
def gemini_client():
return genai.Client()
@pytest.mark.parametrize("test_case", json.load(open("test_cases.json")))
def test_agent_output_schema(gemini_client, test_case):
prompt = f"Extract structured data from this resume text: {test_case['input_text']}"
response = gemini_client.models.generate_content(
model="gemini-2.5-flash",
contents=prompt,
config={
"response_mime_type": "application/json"
}
)
# Assert response is valid JSON matching expected schema
try:
data = json.loads(response.text)
except json.JSONDecodeError:
pytest.fail("Agent failed to return valid JSON.")
for key in test_case["expected_keys"]:
assert key in data, f"Missing required key: {key}"
assert len(data.get("skills", [])) >= test_case["min_skills_count"]
How to Handle Non-Deterministic Outputs in Tests
The hardest part of testing LLMs is their non-deterministic nature. If temperature is set above 0, exact string matching will cause flaky test suites that fail randomly.
To solve this, use LLM-as-a-Judge patterns or structural assertions rather than exact matching.
- Never assert exact text strings. Assert schema types, key presence, and value ranges.
- Lock your generation config during tests. Force
temperature=0.0in your test runner configuration to minimize variance while still testing prompt logic. - Group tests by criticality. Separate structural schema tests (which must pass 100% of the time) from semantic quality tests (which can tolerate a 5% variance threshold).
Takeaways
- Vibe checking is technical debt. If you don't test your prompts automatically, your users will.
- Schema enforcement is non-negotiable. Always force
response_mime_type="application/json"and validate keys programmatically. - Automate in CI. Hook your evaluation suite into your GitHub Actions workflow so every prompt modification is validated before it hits production.
If you liked this, check out how I structured multi-agent communication pipelines in JobHunt.ai Architecture Insights.
Building production AI apps without breaking changes? Subscribe to the Beehiiv newsletter for weekly engineering breakdowns.