DEV Community

juan pablo hernández
juan pablo hernández

Posted on

I have been Vibecoding Evals (works better than I thought)

I’ve been building AI apps with coding agents for a while.

Lately, I’ve been experimenting with evals too.

The app in this example mostly worked. That was the problem.

The bug

I built a small support-triage app for a fictional shipment-tracking company.

A customer sends a support ticket, and the app decides what it is about, how urgent it is, and whether a human needs to respond.

A real outage should be escalated.

But this ticket was different:

“URGENT need key rotation now”

The customer was asking how to rotate their own API key before a security review.

The app classified it as a security incident and escalated it to a human.

That was wrong. The policy said normal key rotation was a self-service how-to request.

Nothing crashed. The app returned valid JSON. The fields all contained allowed values.

The behavior was still wrong.

Why clicking around wasn’t enough

I could test a few tickets manually and convince myself the app worked.

But after changing the prompt, what would I actually know?

Would the outage case still escalate?

Would normal how-to questions stay in the normal queue?

Would another API-key question behave differently?

I didn’t want to change the prompt and simply hope for the best.

I wanted a set of cases I could run again.

Adding DeepEval with Cursor

I installed the DeepEval agent skill:

npx skills add confident-ai/deepeval --skill "deepeval"

Then I asked Cursor to add evals to the app:

This app sometimes treats normal support questions like emergencies and sends
them to a human.
Add DeepEval so I can test this using the tickets and policy already in the repo.
I am new to evals, so use the simplest setup DeepEval already provides, explain
what you create, and ask me anything you need.
Run the app as it is first and show me what fails. Do not fix it yet.

Enter fullscreen mode Exit fullscreen mode

Cursor already had the app, tickets, and policy, so it went straight to creating the baseline.

Goldens are the checklist

The first useful artifact was a JSON dataset.

Each golden contained:

the customer message
the expected category
the expected priority
whether a human should be involved
For example:

{
  "input": "URGENT need key rotation now",
  "expected": {
    "category": "how-to",
    "priority": "P3",
    "needs_human": false
  }
}
Enter fullscreen mode Exit fullscreen mode

The app does not learn from these examples.

The dataset is a checklist. It tells me which behaviors need to keep working before I ship a prompt update.

That was the part that made evals click for me.

The metrics

Cursor used built-in DeepEval metrics to check two different things.

The first compared the app’s routing fields with the expected values in the golden:

  • category
  • priority
  • human escalation The second checked whether the decision followed the escalation rules in the policy.

So I could ask two separate questions:

  1. Did the app return the expected decision?
  2. Does that decision make sense under the policy?

The baseline failure

The first run caught the key-rotation case.

The app returned:

category: security
priority: P1
needs_human: true

Enter fullscreen mode Exit fullscreen mode

The expected result was:

category: how-to
priority: P3
needs_human: false

Enter fullscreen mode Exit fullscreen mode

The output was valid. The behavior was not.

The policy check also gave Cursor a reason explaining why the decision did not fit the support rules.

That was already more useful than changing the prompt, clicking the same ticket again, and hoping I hadn’t broken something else.

Fixing the prompt

The failure pointed back to an over-broad instruction in the triage prompt.

It was treating anything involving API keys as a security incident.

That was too aggressive.

The fix was to reserve escalation for actual compromise, suspicious access, or an outage.

Then Cursor reran the same test cases.

The key-rotation case passed.

The real outage case still escalated.

That second part matters. Fixing one case is not enough. I also want to know that I didn’t break a case that was already working.

The loop

This is the workflow I’ve been using:

Build the app
Create test cases
Run the app
Read the failure
Fix the prompt
Run the same cases again

Enter fullscreen mode Exit fullscreen mode

Without evals, I would change the prompt and hope I didn’t create three new bugs.

With evals, every prompt change has a checklist behind it.

I recorded the full workflow here:

Watch the video: https://x.com/juampitech/status/2084330588593385637?s=20

DeepEval is open source and runs locally. You don’t need a Confident AI account for this workflow. LLM-as-a-judge metrics require a model API key.

DeepEval Vibe Coder quickstart:

https://deepeval.com/docs/vibe-coder-quickstart

Top comments (0)