Monday morning. A teammate pings me.
DeepSeek-V4-Pro-0813 just dropped. It is cheap. Should we switch from Grok 4.6?
I almost said yes. Then I remembered the last cheap model we tried.
The problem is not the new model. The problem is the reflex.
Cheap feels like free progress. But is it?
A model switch is a production change, not a coupon.
Why I stopped trusting release notes
Release notes tell you what the vendor wants you to know.
They rarely tell you how a model treats your schema, your prompts, or your failure modes.
So I stopped asking if the new model is good. I ask a different question.
Does it pass my gate?
The 30-minute gate
I keep a small set of ugly cases from our real codebase.
Not benchmark questions. Actual things that have broken in production.
The gate has three rules.
- Run the same prompts against the current model and the candidate.
- Score with deterministic checks only. No LLM judge.
- If the candidate fails anything the current model passes, stop.
That is it. No vibe score. No leaderboard gazing.
The harness I actually run
Here is the Python harness I use. It is intentionally small.
import json
import os
from openai import OpenAI
CASES = [
{
'name': 'extract_json',
'prompt': 'Return JSON with keys total and items. Do not add prose.',
'check': lambda text: isinstance(json.loads(text), dict),
},
{
'name': 'strict_schema',
'prompt': 'Return a JSON array of 3 objects with keys: id, name, active.',
'check': lambda text: all(
set(obj) == {'id', 'name', 'active'}
for obj in json.loads(text)
),
},
{
'name': 'no_refusal',
'prompt': 'Write a Python function that parses a date from ISO 8601.',
'check': lambda text: 'def parse' in text and 'datetime' in text,
},
]
def run_case(client, model, case):
resp = client.chat.completions.create(
model=model,
messages=[{'role': 'user', 'content': case['prompt']}],
temperature=0,
)
text = resp.choices[0].message.content.strip()
try:
ok = case['check'](text)
except Exception:
ok = False
return ok, text[:120]
def main():
a = OpenAI(
base_url=os.environ['MODEL_A_BASE'],
api_key=os.environ['MODEL_A_KEY'],
)
b = OpenAI(
base_url=os.environ['MODEL_B_BASE'],
api_key=os.environ['MODEL_B_KEY'],
)
model_a = os.environ['MODEL_A']
model_b = os.environ['MODEL_B']
for case in CASES:
a_ok, a_text = run_case(a, model_a, case)
b_ok, b_text = run_case(b, model_b, case)
print(case['name'], model_a, a_ok, model_b, b_ok)
if not a_ok:
print('candidate:', a_text)
if not b_ok:
print('current:', b_text)
if __name__ == '__main__':
main()
I set the candidate model and current model with environment variables.
export MODEL_A='deepseek-v4-pro-0813'
export MODEL_B='grok-4.6'
export MODEL_A_BASE='https://your-candidate-endpoint'
export MODEL_A_KEY='...'
export MODEL_B_BASE='https://your-current-endpoint'
export MODEL_B_KEY='...'
The names are just strings. Replace them with whatever your provider exposes.
No LLM judge. No rating the response from one to five.
Why? Because a judge model can flatter the new model. Deterministic checks do not have opinions.
Where does MonkeyCode fit?
I do not want this harness running on my laptop.
It makes API calls, writes logs, and sometimes I forget to stop it.
So I run it on a free server from MonkeyCode. Disclosure: This article was prepared as part of MonkeyCode's product outreach.
The free server option is useful, but the free model access is the part that helps before I spend anything.
I can sanity-check my prompts against a free model first, so I am not paying to debug malformed JSON expectations.
Decision table, not vibes
After the run, I fill in a table.
The values below are an example of the format, not a result from this week.
| Case | Current passes? | Candidate passes? | Action |
|---|---|---|---|
| extract_json | yes | yes | continue |
| strict_schema | yes | no | stop |
| no_refusal | yes | yes | continue |
If the candidate fails a case the current model passes, I stop.
No debate. No 'but it is cheaper.'
If the candidate passes everything, I move to a two-week shadow test. That is a separate step.
Why cheap is a trap
Cheap models have a habit of passing clean examples and failing production inputs.
So my gate includes at least two ugly cases.
- A messy 40-line function.
- A partial JSON blob.
- A prompt that is slightly ambiguous.
If a model only wins on the clean textbook prompts, I am not interested.
Cheap per token can become expensive per retry.
Limitations
This gate is not a full evaluation.
- Deterministic checks miss tone, creativity, and nuance.
- A small prompt set can overfit.
- Free tiers and rate limits can change without notice.
- Latency needs a separate measurement.
- This is a first filter, not a final sign-off.
If a model passes my gate, I still do not deploy it the same day.
Who should skip this
Skip this if you have no stable prompt set.
Skip this if you are evaluating open-ended creative work.
Skip this if you are comparing long agent trajectories, not single completions.
For those cases, you need human review or a longer trace-based harness.
The whole point
Do not switch models because a release note looks good.
Run your own gate. Use your own failures.
A cheap model that passes your worst cases is worth a closer look.
A cheap model that passes only the clean examples is just cheap.
If you need a free place to keep the harness, MonkeyCode's free server option is where I keep mine. Start with your own cases.
Run the gate first. Then decide.
Top comments (0)