<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vaulter Prompt</title>
    <description>The latest articles on DEV Community by Vaulter Prompt (@prompt_vault).</description>
    <link>https://dev.to/prompt_vault</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3772654%2F0c353f35-6b2e-4cd4-b65a-43e164cbde31.png</url>
      <title>DEV Community: Vaulter Prompt</title>
      <link>https://dev.to/prompt_vault</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/prompt_vault"/>
    <language>en</language>
    <item>
      <title>The easy way to stop screaming at AI with CAPS</title>
      <dc:creator>Vaulter Prompt</dc:creator>
      <pubDate>Thu, 19 Feb 2026 23:00:00 +0000</pubDate>
      <link>https://dev.to/prompt_vault/the-easy-way-to-stop-screaming-at-ai-with-caps-17in</link>
      <guid>https://dev.to/prompt_vault/the-easy-way-to-stop-screaming-at-ai-with-caps-17in</guid>
      <description>&lt;h2&gt;
  
  
  Some foundational prompt engineering techniques and patterns to know about.
&lt;/h2&gt;

&lt;p&gt;I think everybody at some point caught themselves typing in all caps, to ChatGPT or Claude, "I LITERALLY JUST TOLD YOU TO DO THIS." Rephrasing the same request just to get the same useless output. Getting progressively angrier at a language model that is specifically designed to drive humanity crazy.&lt;/p&gt;

&lt;p&gt;Very often it's not a broken tool, but vague instructions to a system that does exactly what you ask - just not what you mean. And there's a gap between those two things that costs most people hours every single day.&lt;/p&gt;

&lt;p&gt;I hope this article can help you to get very quickly to the point, where this is no longer a case for you!&lt;/p&gt;

&lt;h2&gt;
  
  
  The invisible tax you're already paying
&lt;/h2&gt;

&lt;p&gt;The original promise of AI was that it would do the work for you. And in a way, it does. But it also quietly changes what the work actually is.&lt;/p&gt;

&lt;p&gt;Before AI, you spent time writing. Now you spend time reviewing. Checking if the AI got it right. Rephrasing when it didn't. Cleaning up hallucinated requirements. Making sure the output actually says what you meant and not what the model decided you probably meant.&lt;/p&gt;

&lt;p&gt;With good prompts, that review step is quick - a sanity check, maybe a small adjustment. With bad prompts, the review becomes the work. You're not using AI anymore. You're babysitting it.&lt;/p&gt;

&lt;p&gt;A January 2026 Zapier survey of 1,100 AI users puts a number on this: workers spend an average of 4.5 hours per week revising, correcting, and redoing AI outputs. That's more than half a workday - not writing, not thinking, just cleaning up after a tool that was supposed to save time.&lt;/p&gt;

&lt;p&gt;And untrained people are more likely to say AI makes them less productive. Not because the tool is worse for them - because they never learned how to direct it. Meanwhile people with access to prompt training and libraries report productivity gains.&lt;/p&gt;

&lt;p&gt;It's like buying a professional DSLR camera and shooting everything in auto mode, then complaining the photos look the same as your phone. The capability is there. You just haven't learned to access it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mental model that changes everything
&lt;/h2&gt;

&lt;p&gt;Here's what nobody told us upfront: as a consumer you can think of an LLM as a very sophisticated autocomplete. Of course I'm seriously oversimplifying, but hear me out. It really helps to get things right. The point is: it doesn't "understand" your request. It predicts the most probable next words (in reality tokens) based on everything that it was trained on.&lt;/p&gt;

&lt;p&gt;That's it. Not intelligence. Pattern prediction (sophisticated, complicated, groundbreaking, but anyway).&lt;/p&gt;

&lt;p&gt;This line of thinking explains almost every frustration you've ever had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vague prompts get vague answers&lt;/strong&gt; - many probable continuations, the model picks one at random&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Examples work better than instructions&lt;/strong&gt; - you're showing it the pattern to continue, not hoping it interprets your intent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Long conversations go off the rails&lt;/strong&gt; - the model has a finite "context window" (its working memory). Everything in your conversation takes up space, and when it fills up, older content gets dropped or compressed. The AI isn't being thick after 20 messages - it literally cannot see what you said earlier&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It "hallucinates"&lt;/strong&gt; - it predicts plausible text, not true text (hallucinations is a feature, not a bug)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So when you type "make this better" and get back something useless, the AI isn't being stupid. It's doing exactly what autocomplete does with ambiguous input: guessing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Three rules follow from this.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Be explicit - ambiguity is the enemy.&lt;/li&gt;
&lt;li&gt;Show, don't tell - examples constrain the solution space better than descriptions.&lt;/li&gt;
&lt;li&gt;Start fresh conversations for fresh tasks - don't let context rot.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Everything below traces back to these three principles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four core techniques that actually work
&lt;/h2&gt;

&lt;p&gt;There are four basic prompting techniques that, together, cover pretty much every type of task you'd throw at an AI. They form a ladder - start with #1, escalate when needed:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Technique&lt;/th&gt;
&lt;th&gt;One-liner&lt;/th&gt;
&lt;th&gt;Use when...&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Zero-shot&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Just ask&lt;/td&gt;
&lt;td&gt;Task has one obvious interpretation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Few-shot&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Show examples&lt;/td&gt;
&lt;td&gt;Format or style matters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Chain-of-thought&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Make it reason&lt;/td&gt;
&lt;td&gt;Task needs logic, not pattern matching&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Prompt chaining&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Break it apart&lt;/td&gt;
&lt;td&gt;Too complex for a single prompt&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The mistake most people make is either staying on step 1 forever (most of the time, really), or jumping straight to step 4 when they didn't need to. I'll walk through each one below - when it works, when it doesn't, and the signal that tells you it's time to move up.&lt;/p&gt;

&lt;p&gt;To show how these build on each other, I'll use one example throughout: &lt;strong&gt;"Analyse 50 customer feedback entries from last quarter and write a summary for the product team."&lt;/strong&gt; Same task, four different approaches, very different results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Start simple: just ask (zero-shot)
&lt;/h3&gt;

&lt;p&gt;"&lt;strong&gt;Zero-shot&lt;/strong&gt;" just means: give a direct instruction, no examples.&lt;/p&gt;

&lt;p&gt;For tasks with one obvious interpretation, this is all you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Translate this email to Spanish"&lt;/li&gt;
&lt;li&gt;"Extract all deadlines from this contract"&lt;/li&gt;
&lt;li&gt;"What are the three biggest risks in this plan?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI already "knows" what "translate" means and what "deadlines" look like. A clear instruction, a clear input, done.&lt;/p&gt;

&lt;p&gt;But watch what happens with our feedback analysis:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Prompt:&lt;/strong&gt; "Summarise the key themes from this customer feedback for the product team."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you get:&lt;/strong&gt; A different structure every time. First try: a wall of text with no categories. Second try: bullet points, but random grouping and no prioritisation. Third try: nice categories, but completely different ones from last time. The AI extracts themes fine - but the format and depth change with every run.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;"Customer feedback summary" has dozens of valid interpretations. The model picks one at random each time.&lt;/p&gt;

&lt;p&gt;So what can we say about this pattern?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Task has one clear interpretation&lt;/li&gt;
&lt;li&gt;The AI already "knows" the task type (translation, extraction, summarisation)&lt;/li&gt;
&lt;li&gt;You don't care about exact format&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Signal to escalate:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're rephrasing the same request 3 times and getting different structures&lt;/li&gt;
&lt;li&gt;Content is right but format/style is inconsistent&lt;/li&gt;
&lt;li&gt;You need a specific output shape every time&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Show, don't tell (few-shot)
&lt;/h3&gt;

&lt;p&gt;So the feedback summary keeps coming back in a random format. You could try describing what you want: "Use a table, group by theme, include frequency count, add a severity column, include one example quote per theme..." But by the time you've written all that, you could have just made the table yourself. Here's &lt;strong&gt;few-shot prompting&lt;/strong&gt; comes to help.&lt;/p&gt;

&lt;p&gt;"&lt;strong&gt;Few-shot&lt;/strong&gt;" means: instead of describing what you want, show 3 to 5 examples of it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Same task - with few-shot:&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Analyse the customer feedback below and summarise it
for the product team. Follow this format:

Example:
| Theme | Mentions | Severity | Example quote |
|-------|----------|----------|---------------|
| Slow page loads | 12 | High | "Dashboard takes 8s to load" |
| Missing export | 5 | Medium | "I need CSV export for reports" |

Top priority: Slow page loads - affects daily usage,
12 mentions in 30 days, multiple churn-risk accounts.

Now analyse this feedback:
[50 input entries here]
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;From the examples AI knows you want a table with those exact columns, followed by a top-priority callout with reasoning. Format, length, structure - communicated in seconds, more precisely than any paragraph of instructions could. This is called "in-context learning" - the model's ability to pick up a pattern from just a few demonstrations and apply it to new input.&lt;/p&gt;

&lt;p&gt;Good examples are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Diverse&lt;/strong&gt; - different scenarios, not three variations of the same thing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Representative&lt;/strong&gt; - typical cases, not edge cases&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistent&lt;/strong&gt; - same format across all of them&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimal&lt;/strong&gt; - 3-5 is usually plenty&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now the format is perfect every time. But there's a problem: the AI lists "slow checkout" (30 mentions) and "button colour" (2 mentions) at the same severity level. It's mimicking the table structure beautifully, but it's not actually &lt;em&gt;thinking&lt;/em&gt; about what matters.&lt;/p&gt;

&lt;p&gt;Few-shot fails when the task needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Actual calculation&lt;/strong&gt; - not pattern completion&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reasoning&lt;/strong&gt; - not correlation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain knowledge&lt;/strong&gt; that isn't present in the examples&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-factor trade-off judgements&lt;/strong&gt; - weighing competing priorities&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handling novel constraints&lt;/strong&gt; the examples don't cover&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short: if the answer requires thinking through the problem and not just matching a format, examples alone won't get you there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Format, tone, or style matters&lt;/li&gt;
&lt;li&gt;The task has many valid outputs but you need a specific one&lt;/li&gt;
&lt;li&gt;You want consistent results across multiple runs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Signal to escalate:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Format is perfect but the &lt;em&gt;reasoning&lt;/em&gt; is wrong&lt;/li&gt;
&lt;li&gt;The AI mimics your examples but makes logical errors or misses nuance&lt;/li&gt;
&lt;li&gt;The task needs analysis, not pattern matching&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Make it think (chain-of-thought)
&lt;/h3&gt;

&lt;p&gt;Examples fix formatting and content depth expectaions, sure. They don't fix thinking. When the task needs actual reasoning, the AI mimics the pattern and jumps to a plausible-looking answer without working through the problem.&lt;/p&gt;

&lt;p&gt;That feedback summary has the right columns now, but the priorities are shallow. The AI saw "High/Medium" in your example and just distributed those labels without weighing anything.&lt;/p&gt;

&lt;p&gt;Five words fix this: &lt;strong&gt;"Let's think step by step."&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Same task - with chain-of-thought:&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Analyse this customer feedback for the product team.
Use the table format from the examples above.

Before filling in the severity column, think step by
step: consider how many users mentioned it, whether it
causes churn or just annoyance, and how it compares to
other themes.
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;strong&gt;What you get now:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slow checkout (30 mentions) → directly causes cart abandonment, mentioned by 3 enterprise accounts → &lt;strong&gt;High&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Confusing pricing page (8 mentions) → causes support tickets but users still convert → &lt;strong&gt;Medium&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Button colour (2 mentions) → cosmetic, no impact on conversion → &lt;strong&gt;Low&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Top priority:&lt;/strong&gt; Slow checkout - 30 mentions, directly tied to revenue loss, affects highest-value accounts.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's not a gimmick. Research shows this single phrase improves accuracy on reasoning tasks from 17.7% to 78.7%. By asking the model to show its reasoning, you force it to actually work through the problem instead of guessing.&lt;/p&gt;

&lt;p&gt;Same principle as showing your work at school - you catch errors you'd miss if you just wrote the final answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pro tip: self-consistency.&lt;/strong&gt; For high-stakes decisions, run the same CoT prompt 3 times and compare the answers. If all three agree, you're probably right. If they disagree wildly, the problem needs more breakdown. Costs 3x the tokens but catches blind spots a single run misses.&lt;/p&gt;

&lt;p&gt;So for this technique:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Debugging, analysis, decisions, math&lt;/li&gt;
&lt;li&gt;Anything where "showing work" would help a human&lt;/li&gt;
&lt;li&gt;The task has a right answer that requires reasoning to reach&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Signal to escalate:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reasoning per step is fine, but the task has too many moving parts&lt;/li&gt;
&lt;li&gt;Output is solid for the first half and falls apart after that&lt;/li&gt;
&lt;li&gt;The prompt is getting so long the AI starts ignoring parts of it&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Break it down (prompt chaining)
&lt;/h3&gt;

&lt;p&gt;If you're asking for more than one distinct deliverable in a single prompt, you're probably going to get disappointed.&lt;/p&gt;

&lt;p&gt;With 50 feedback entries, trying to categorise, assess severity, AND write recommendations in one prompt usually means the categorisation is decent, the severity assessment is rushed, and the recommendations are generic. The model runs out of steam halfway through.&lt;/p&gt;

&lt;p&gt;"&lt;strong&gt;Prompt chaining&lt;/strong&gt;" means breaking it into steps, reviewing each one before moving to the next. You literally take the output of prompt 1 and paste it as input into prompt 2.&lt;/p&gt;

&lt;p&gt;Why this works better than one big prompt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Catch errors early&lt;/strong&gt; - spot problems before 5 steps of compounding&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smaller context&lt;/strong&gt; - model focuses on one task, not juggling 10 instructions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easier to debug&lt;/strong&gt; - you know exactly which step failed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reusable pieces&lt;/strong&gt; - swap out step 2 without rewriting 1,200 lines&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human in the loop&lt;/strong&gt; - review and adjust between steps&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Same task - as a chain:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt 1:&lt;/strong&gt; "Categorise all 50 feedback entries into themes with counts."&lt;br&gt;
→ &lt;em&gt;Output: table with 6 themes (slow checkout: 30, confusing pricing: 8, missing export: 5...)&lt;/em&gt;&lt;br&gt;
→ ✓ Review: do these categories make sense? Merge or split any?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt 2:&lt;/strong&gt; "Here are the themes: [paste output from step 1]. For each theme, assess severity and business impact. Think step by step."&lt;br&gt;
→ &lt;em&gt;Output: slow checkout = High (causes abandonment), confusing pricing = Medium (causes support tickets)...&lt;/em&gt;&lt;br&gt;
→ ✓ Review: does the reasoning hold up? Any wrong assumptions?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt 3:&lt;/strong&gt; "Here's the full analysis: [paste output from step 2]. Write the summary for the product team with top 3 recommendations."&lt;br&gt;
→ &lt;em&gt;Final output: ready to send.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Each step is small enough to actually verify. You catch wrong categories at step 1 instead of discovering them baked into the final recommendations at step 3.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And what do we have here in the result?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Task has multiple distinct deliverables&lt;/li&gt;
&lt;li&gt;Your prompt is getting so long the AI ignores parts of it&lt;/li&gt;
&lt;li&gt;You want to review intermediate results before continuing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Signal that something's off:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Individual steps produce bad reasoning → add chain-of-thought within each step&lt;/li&gt;
&lt;li&gt;Chain works but results feel generic → better context or examples needed in step 1&lt;/li&gt;
&lt;li&gt;Conversation is sideways after many messages → start a fresh one. Context rots.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those four techniques are the core of it. But knowing &lt;em&gt;which&lt;/em&gt; technique to use is only half the problem. The other half is how you structure the prompt itself - and that's where most people quietly lose hours without realising it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The patterns nobody teaches you
&lt;/h2&gt;

&lt;p&gt;Techniques tell you what to do. Patterns tell you how to do it well. If techniques are the bricks, these are the cement - and skipping them is why a lot of prompts that &lt;em&gt;should&lt;/em&gt; work still don't.&lt;/p&gt;

&lt;h3&gt;
  
  
  The prompt anatomy
&lt;/h3&gt;

&lt;p&gt;Every prompt has up to four elements. When something goes wrong, one is usually missing:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Element&lt;/th&gt;
&lt;th&gt;What it is&lt;/th&gt;
&lt;th&gt;If missing...&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Instruction&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The task to perform&lt;/td&gt;
&lt;td&gt;AI guesses what you want&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Context&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Background, constraints, role&lt;/td&gt;
&lt;td&gt;AI makes wrong assumptions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Input data&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Content to process&lt;/td&gt;
&lt;td&gt;Nothing to work with&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Output indicator&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Expected format&lt;/td&gt;
&lt;td&gt;You get 500 words when you needed 2 bullets&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Remember our feedback analysis prompt from the few-shot section? Let's map the four elements onto it:&lt;/p&gt;

&lt;blockquote&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[INSTRUCTION] Analyse the customer feedback below and summarise it
              for the product team. Follow this format:
[OUTPUT]      Example:
              | Theme | Mentions | Severity | Example quote |
              | Slow page loads | 12 | High | "Dashboard takes 8s..." |
              Top priority: Slow page loads - affects daily usage...
[INPUT DATA]  Now analyse this feedback:
              [50 input entries here]
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;Two elements present, two missing. There's no &lt;strong&gt;context&lt;/strong&gt; (who's the analyst? what's the review for?) and no &lt;strong&gt;delimiters&lt;/strong&gt; between the instruction and the input data. It works OK because the few-shot examples carry most of the weight - but it could be better. Add the missing elements:&lt;/p&gt;

&lt;blockquote&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[CONTEXT]     You are a product analyst preparing a quarterly review.
[INSTRUCTION] Analyse the customer feedback below and summarise it
              for the product team. Follow this format:
[OUTPUT]      Example:
              | Theme | Mentions | Severity | Example quote |
              | Slow page loads | 12 | High | "Dashboard takes 8s..." |
              Top priority: Slow page loads - affects daily usage...
[INPUT DATA]  &amp;lt;feedback&amp;gt; [50 input entries here] &amp;lt;/feedback&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;Now the context shapes the analysis (product analyst prioritises by business impact), and the &lt;code&gt;&amp;lt;feedback&amp;gt;&lt;/code&gt; tags separate data from instruction. Same few-shot technique, better prompt structure.&lt;/p&gt;

&lt;p&gt;This is also a diagnostic tool. Prompt didn't work as expected? Check which element is vague or absent. Takes ten seconds, fixes most problems on the spot.&lt;/p&gt;

&lt;h3&gt;
  
  
  Four patterns that save the most time
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Scope boundaries&lt;/strong&gt; - tell the AI what NOT to do.&lt;/p&gt;

&lt;p&gt;The "eager intern" problem - where the AI helpfully restructures your entire document when you asked it to fix one paragraph - is solved by explicit fences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ONLY modify: [specific section]&lt;/li&gt;
&lt;li&gt;Do NOT: [things you don't want changed]&lt;/li&gt;
&lt;li&gt;Match: [existing conventions, tone, style]&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Applied to our example: "Only analyse the feedback entries I provide. Do not add themes that aren't in the data. Do not invent quotes."&lt;/p&gt;

&lt;p&gt;When to skip: discovery phase, architecture discussions, brainstorming - boundaries kill creativity when you actually want broad thinking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Output specification&lt;/strong&gt; - define the container.&lt;/p&gt;

&lt;p&gt;"Summarise this" gets you 500 words. "Summarise in 3 bullet points, max 15 words each" gets you exactly what you asked for. If you specify the shape - format, length, sections, what to exclude - the AI can't invent things that don't fit.&lt;/p&gt;

&lt;p&gt;Applied to our example: this is exactly what the few-shot table format did - but you can also do it without examples, just by describing the container: "Return a markdown table with columns: Theme, Mentions, Severity, Example Quote. Then write exactly 3 recommendations, one sentence each."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to skip&lt;/strong&gt;: exploratory questions ("what should I consider?"), creative brainstorming, or one-off queries where you'll just read and act.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Delimiters&lt;/strong&gt; - separate sections clearly.&lt;/p&gt;

&lt;p&gt;Use XML tags, markdown headers, or triple quotes between your instruction, context, and input data. Without them, the AI sometimes confuses what's an instruction and what's content to process.&lt;/p&gt;

&lt;p&gt;Applied to our example: wrapping the feedback in &lt;code&gt;&amp;lt;feedback&amp;gt;&lt;/code&gt; tags tells the model "this is the data, not part of the instruction." Without it, if a customer wrote "ignore previous instructions" in their feedback (yes, this happens), the model might actually obey it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Role and audience&lt;/strong&gt; - narrow the model's behaviour.&lt;/p&gt;

&lt;p&gt;An LLM is a generalist by default - it draws on everything it was trained on, which is basically the entire internet. Setting a role and audience constrains that enormous solution space to a specific domain, expertise level, and communication style. "You are a senior engineer, I am also senior, skip basics" activates domain-specific knowledge, suppresses beginner-level explanations, and calibrates the output for a professional context. One line of context, completely different answer.&lt;/p&gt;

&lt;p&gt;Applied to our example: "You are a product analyst" tells the model to prioritise themes by business impact rather than just frequency - because that's how a product analyst thinks. Without it, you get a generic summary. With it, you get one that's shaped by domain expertise.&lt;/p&gt;

&lt;h2&gt;
  
  
  The quick reference
&lt;/h2&gt;

&lt;p&gt;Two things worth bookmarking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where to start for your task type:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task type&lt;/th&gt;
&lt;th&gt;Start with&lt;/th&gt;
&lt;th&gt;If that fails&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Text classification&lt;/td&gt;
&lt;td&gt;Zero-shot&lt;/td&gt;
&lt;td&gt;Few-shot with examples&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Summarisation&lt;/td&gt;
&lt;td&gt;Zero-shot + output spec&lt;/td&gt;
&lt;td&gt;Few-shot with example summaries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Information extraction&lt;/td&gt;
&lt;td&gt;Zero-shot + output format&lt;/td&gt;
&lt;td&gt;Few-shot with examples&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code generation&lt;/td&gt;
&lt;td&gt;Zero-shot + scope boundaries&lt;/td&gt;
&lt;td&gt;Few-shot + chaining&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code review&lt;/td&gt;
&lt;td&gt;Role + scope&lt;/td&gt;
&lt;td&gt;Few-shot with example reviews&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reasoning / math&lt;/td&gt;
&lt;td&gt;Zero-shot CoT&lt;/td&gt;
&lt;td&gt;Few-shot CoT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complex multi-step&lt;/td&gt;
&lt;td&gt;Prompt chaining&lt;/td&gt;
&lt;td&gt;Add CoT within each step&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docs / reports&lt;/td&gt;
&lt;td&gt;Output specification&lt;/td&gt;
&lt;td&gt;Few-shot with example docs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;When your prompt doesn't work:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Wrong format&lt;/td&gt;
&lt;td&gt;Specify output shape&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inconsistent results&lt;/td&gt;
&lt;td&gt;Add 2-5 examples (few-shot)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wrong reasoning&lt;/td&gt;
&lt;td&gt;"Let's think step by step" (CoT)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI invents things you didn't ask for&lt;/td&gt;
&lt;td&gt;Add scope boundaries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task too complex&lt;/td&gt;
&lt;td&gt;Break into smaller prompts (chaining)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conversation went off track&lt;/td&gt;
&lt;td&gt;Start fresh&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Response too basic or too advanced&lt;/td&gt;
&lt;td&gt;Set role and audience&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Not reading output before sharing&lt;/td&gt;
&lt;td&gt;Human verification always&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The prompt diagnostic:&lt;/strong&gt; instruction, context, input, output indicator. When something fails, one of these is missing or vague. Start there.&lt;/p&gt;

&lt;h2&gt;
  
  
  The embarrassingly simple conclusion
&lt;/h2&gt;

&lt;p&gt;The AI does exactly what autocomplete would do with your input. Vague input, random output. Specific input, useful output.&lt;/p&gt;

&lt;p&gt;Four techniques, a handful of patterns, and a couple of hours of practice. That's the gap between babysitting and actually getting work done.&lt;/p&gt;

&lt;p&gt;The AI is not the only one who needs training, we need it too if we want to learn to use it right.&lt;/p&gt;

</description>
      <category>promptengineering</category>
      <category>ai</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>AI makes faster both engineer and chaos</title>
      <dc:creator>Vaulter Prompt</dc:creator>
      <pubDate>Sun, 15 Feb 2026 09:07:07 +0000</pubDate>
      <link>https://dev.to/prompt_vault/ai-makes-faster-both-engineer-and-chaos-1m93</link>
      <guid>https://dev.to/prompt_vault/ai-makes-faster-both-engineer-and-chaos-1m93</guid>
      <description>&lt;h2&gt;
  
  
  What industry data on AI for productivity actually tells us
&lt;/h2&gt;

&lt;p&gt;Somewhere around mid-2025, I started noticing something across our engineering org that felt off.&lt;/p&gt;

&lt;p&gt;Like everyone else, we were enthusiastically adopting AI coding tools. Team leads were excited. Throughput was up. Sprint delivery and speed numbers looked great on dashboards.&lt;/p&gt;

&lt;p&gt;And I was getting more and more nervous.&lt;/p&gt;

&lt;p&gt;Not because anyone was doing anything wrong - the enthusiasm was genuine and well-intentioned. But because the signals I was seeing didn't match the celebration. PR sizes growing. More code shipping without meaningful review. Stability metrics dipping. Rework going up. The kind of early warnings that, if you've been in engineering leadership long enough, you know are worth paying attention to.&lt;/p&gt;

&lt;p&gt;When I dug in, I realized the enthusiasm was simply outpacing the measurement. The focus was on throughput gains - and those were real - but the metrics for what those gains were doing to review quality, stability, and long-term architecture hadn't caught up yet.&lt;/p&gt;

&lt;p&gt;It's a pattern I've since heard about across the entire industry. And honestly, in some cases things are quite bad and look a lot like cargo cult engineering - slapping an "AI in our SDLC" badge on the org and celebrating throughput numbers, without actually thinking through long-term implications or developing a real transformation strategy. A headless chicken with an "AI-powered" label stuck to its side. Running faster than ever. No idea where it's going.&lt;/p&gt;

&lt;p&gt;In an application area where quality issues can bring severe reputational damage, that gap between enthusiasm and measurement is something you can't afford to leave open for long.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI is an amplifier, not (yet) a silver bullet
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://dora.dev/research/2025/dora-report/" rel="noopener noreferrer"&gt;2025 DORA Report&lt;/a&gt; - based on nearly 5,000 technology professionals - frames it better than I can: &lt;strong&gt;AI's primary role in software development is that of an amplifier.&lt;/strong&gt; It magnifies the strengths of high-performing organizations and the dysfunctions of struggling ones.&lt;/p&gt;

&lt;p&gt;That's the sentence I wish every CEO would read before forwarding the next "Microsoft writes 30% of code with AI" headline to their CTO.&lt;/p&gt;

&lt;p&gt;And by the way - &lt;a href="https://www.youtube.com/watch?v=xHHlhoRC8W4" rel="noopener noreferrer"&gt;in this interview&lt;/a&gt;, a CTO of a developer productivity measurement company traced that "30% of code" claim back to accepted autocomplete suggestions. As she puts it: your linter has been running on 100% of your PRs for years. Can you imagine the headline? "Acme Corp only ships code to production that's been read by robots." We could have said our code was "machine generated" back when IDE autocomplete was filling in class names.&lt;/p&gt;

&lt;p&gt;The data is more nuanced than the headlines suggest. Yes, 90% of developers now use AI as part of their work. Yes, AI adoption now improves software delivery throughput - a shift from 2024, where it didn't. But AI adoption still increases delivery instability. Teams are adapting for speed. Their underlying systems have not evolved to safely manage AI-accelerated development.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.faros.ai/blog/ai-software-engineering" rel="noopener noreferrer"&gt;Faros AI's analysis&lt;/a&gt; of over 10,000 developers across 1,255 teams found the same pattern from a different angle: while team-level changes are measurable, there is &lt;strong&gt;no significant correlation between AI adoption and improvements at the company level.&lt;/strong&gt; Throughput, lead time, incident resolution - all flat when you zoom out.&lt;/p&gt;

&lt;p&gt;So here's the uncomfortable truth. If your org was already good at delivery - clean architecture, fast feedback loops, strong testing - AI probably makes you better. If your org was already struggling with those things, AI just makes you struggle faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers most teams aren't watching
&lt;/h2&gt;

&lt;p&gt;I want to share some specific numbers, because this is where it gets concrete and a bit alarming.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PR size is inflating.&lt;/strong&gt; &lt;a href="https://www.faros.ai/blog/ai-software-engineering" rel="noopener noreferrer"&gt;Faros AI found&lt;/a&gt; a 154% increase in average PR size associated with high AI adoption. &lt;a href="https://jellyfish.co/blog/ai-assisted-pull-requests-are-18-larger" rel="noopener noreferrer"&gt;Jellyfish&lt;/a&gt;, analyzing data from 500+ companies, found that going from low to high AI adoption corresponded to an 18% increase in lines added per PR. And here's why that matters: PRs over 1,000 lines have a 70% lower defect detection rate compared to smaller ones. Detection drops from 87% for small PRs (under 100 lines) to just 28% for large ones.&lt;/p&gt;

&lt;p&gt;So we're generating bigger PRs that are harder to review. And predictably...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Review time is ballooning.&lt;/strong&gt; PR review time increased by 91% in teams with high AI adoption, according to &lt;a href="https://www.faros.ai/blog/ai-software-engineering" rel="noopener noreferrer"&gt;Faros AI&lt;/a&gt;. Developers are merging 98% more pull requests - but the human review process hasn't gotten any faster. It's become the bottleneck.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bugs are going up.&lt;/strong&gt; A 9% increase in bugs per developer. Not dramatic in isolation. But combine it with bigger PRs and overwhelmed reviewers and you have a compounding quality problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code quality is eroding in ways that don't show up immediately.&lt;/strong&gt; &lt;a href="https://www.gitclear.com/ai_assistant_code_quality_2025_research" rel="noopener noreferrer"&gt;GitClear analyzed&lt;/a&gt; 211 million lines of code (2020-2024) and found that copy-pasted code surged from 8.3% to 12.3%, while code refactoring dropped from 24.1% to just 9.5%. Code churn - new code requiring revision within two weeks - nearly doubled, from 3.1% to 5.7%. Copy-paste exceeded refactored code for the first time in the dataset's history.&lt;/p&gt;

&lt;p&gt;And &lt;a href="https://www.youtube.com/watch?v=tbDDYKRFjhk" rel="noopener noreferrer"&gt;a Stanford-backed study&lt;/a&gt; of 100,000+ developers found that AI productivity gains ranged from 30-40% for simple greenfield tasks down to 0-10% for complex brownfield work. For complex tasks in less popular languages, AI actually &lt;strong&gt;decreased&lt;/strong&gt; productivity.&lt;/p&gt;

&lt;p&gt;These aren't opinions. This is data from multiple independent research groups, across hundreds of companies and tens of thousands of developers, all pointing in the same direction: AI generates more code, faster. But more code is not the same as better outcomes.&lt;/p&gt;

&lt;p&gt;One expert's take on this &lt;a href="https://www.youtube.com/watch?v=xHHlhoRC8W4" rel="noopener noreferrer"&gt;stuck with me&lt;/a&gt;: "Source code is a liability." We're now in a world where it's trivially easy to produce a tremendous amount of it. That should make us more careful, not less.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real shift: from writing code to reviewing it
&lt;/h2&gt;

&lt;p&gt;Here's the thing most people miss about AI in development, and it's what I've come to think of as the most important mental model for engineering leaders to internalize.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI shifts the developer's cognitive focus from writing to reviewing.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Typing speed was never the bottleneck. On the best day, developers spend maybe 20-25% of their time actually writing code (there's an AWS study that found 20% for their average engineer). AI makes that 20% faster - great - but it doesn't make the other 80% disappear.&lt;/p&gt;

&lt;p&gt;What actually happens: AI generates code at superhuman speed, but someone still has to review that code, understand it, verify it's correct, and make sure it fits the existing architecture. That "someone" is your developer, who now spends less time in the creative act of writing (which, by the way, is the part most developers enjoy) and more time in the cognitively demanding act of reviewing AI-generated output.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dora.dev/research/2025/dora-report/" rel="noopener noreferrer"&gt;DORA's research&lt;/a&gt; found that many developers actually feel &lt;em&gt;less&lt;/em&gt; satisfied after AI adoption because AI accelerates the parts they enjoy - and what's left is more toil, more meetings, more review work. Which, if you think about it, is kind of the opposite of the promise.&lt;/p&gt;

&lt;p&gt;And this isn't just a feeling. &lt;a href="https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/" rel="noopener noreferrer"&gt;The METR study&lt;/a&gt; found that experienced open-source developers took 19% longer to complete tasks with AI, despite believing they were 20% faster. The cognitive overhead of reviewing and correcting AI output ate the time savings and then some.&lt;/p&gt;

&lt;p&gt;So here I formulated for myself another important rule I try to follow: AI makes everything faster. Also, it makes chaos faster. If your developers are generating 2x the code but your review process hasn't evolved, you're not being more productive. You're accumulating risk at 2x the rate.&lt;/p&gt;

&lt;h2&gt;
  
  
  What data-driven AI adoption actually looks like
&lt;/h2&gt;

&lt;p&gt;So what should you actually do? I want to share a reasoning framework rather than a prescriptive checklist, because every org is different. But these are the questions I've learned (sometimes the hard way) to ask.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Look honestly at your codebase.&lt;/strong&gt; Is your primary language popular and well-supported by AI models - Python, JavaScript, TypeScript, Java? Or are you working in something more niche? The &lt;a href="https://www.youtube.com/watch?v=tbDDYKRFjhk" rel="noopener noreferrer"&gt;Stanford data&lt;/a&gt; shows this matters enormously. Are you mostly greenfield or brownfield? If you're maintaining a large, mature codebase (which most enterprises are), set your expectations accordingly. AI won't deliver the 30-40% gain you saw in the demo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Be especially careful with your critical path.&lt;/strong&gt; That 5% of your code that can break everything, the last 1% of performance optimization on your mobile app, the core domain logic your business depends on - these are exactly the areas where AI's gains are smallest and the cost of errors is highest. Use AI freely for boilerplate. Be very deliberate about using it for the stuff that really matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decompose your cycle time and watch the review phase.&lt;/strong&gt; This is probably the single most actionable metric. If coding time is going down but review time is going up - and overall cycle time isn't improving - AI is just moving the bottleneck, not eliminating it. That's a signal to invest in review process improvements, not to celebrate faster code generation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Watch your change failure rate and quality metrics.&lt;/strong&gt; If CFR is climbing alongside AI adoption, that's your canary. The &lt;a href="https://www.faros.ai/blog/ai-software-engineering" rel="noopener noreferrer"&gt;Faros AI data&lt;/a&gt; showed a 9% increase in bugs per developer - for some orgs, that's acceptable. For others (like mine), it's not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Track PR size and code review quality together.&lt;/strong&gt; If PRs are growing and meaningful review comments per PR are shrinking, your review process is being overwhelmed. The data on reviewer fatigue with large PRs is pretty clear - extra-large PRs receive fewer meaningful comments, not more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Validate that planned architecture actually shipped.&lt;/strong&gt; This one is less about dashboards and more about discipline. AI is very good at generating code that works right now and very bad at maintaining long-term architectural coherence. If you have no way to verify that generated code actually follows your intended architecture, you'll discover the drift six months later when something breaks and nobody understands why.&lt;/p&gt;

&lt;p&gt;The organizations getting this right - and this is consistent across &lt;a href="https://dora.dev/research/2025/dora-report/" rel="noopener noreferrer"&gt;DORA's research&lt;/a&gt;, &lt;a href="https://www.youtube.com/watch?v=xHHlhoRC8W4" rel="noopener noreferrer"&gt;industry case studies&lt;/a&gt;, and I can also see other reports share that one trait: they treat AI adoption as an experiment, not a mandate. They set a baseline, define hypotheses, measure the results. They don't just hand out licenses and hope.&lt;/p&gt;

&lt;p&gt;To conclude, I still don't have all of this figured out for myself yet, as the more long-term impact is yet to be seen. Not to mention how fast the industry changes. But I think I've seen enough to know that the teams measuring are the ones making progress - and the teams riding the hype are the ones who'll be untangling the mess six months from now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sources referenced:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dora.dev/research/2025/dora-report/" rel="noopener noreferrer"&gt;2025 DORA Report - State of AI-assisted Software Development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.faros.ai/blog/ai-software-engineering" rel="noopener noreferrer"&gt;Faros AI - The AI Productivity Paradox (July 2025)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=tbDDYKRFjhk" rel="noopener noreferrer"&gt;Stanford - AI Impact on Developer Productivity (100k+ devs)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=xHHlhoRC8W4" rel="noopener noreferrer"&gt;Laura Tacho interview - Measuring AI impact (Pragmatic Engineer)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.gitclear.com/ai_assistant_code_quality_2025_research" rel="noopener noreferrer"&gt;GitClear - AI Code Quality 2025 Research&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/" rel="noopener noreferrer"&gt;METR - Early-2025 AI on Experienced Developer Productivity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jellyfish.co/blog/ai-assisted-pull-requests-are-18-larger" rel="noopener noreferrer"&gt;Jellyfish - AI-Assisted PRs Are 18% Larger&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>productivity</category>
      <category>analytics</category>
    </item>
    <item>
      <title>Hope that prompt works...</title>
      <dc:creator>Vaulter Prompt</dc:creator>
      <pubDate>Sun, 15 Feb 2026 08:57:00 +0000</pubDate>
      <link>https://dev.to/prompt_vault/hope-that-prompt-works-5451</link>
      <guid>https://dev.to/prompt_vault/hope-that-prompt-works-5451</guid>
      <description>&lt;h2&gt;
  
  
  Test your prompts like you test your software if you want AI to facilitate you.
&lt;/h2&gt;

&lt;p&gt;I was sitting with a senior engineer who was very happy about his team's "AI adoption." They went from five pull requests a week to eight, sometimes nine. He was showing me the sprint velocity chart and honestly, it looked great.&lt;/p&gt;

&lt;p&gt;Then I asked if I could look at their DORA metrics instead.&lt;/p&gt;

&lt;p&gt;Code review time had actually nearly doubled. The amount of lines to be reviewed grew as well (roughly +90%). And the rework - the percentage of code that gets deleted within 21 days of being written - had climbed from 5% to 25%.&lt;/p&gt;

&lt;p&gt;That's one in four lines his team wrote last month. Already gone.&lt;/p&gt;

&lt;p&gt;So the "speed" increase was actually just code that gets thrown away. More PRs, sure, but also more bugs, more time reviewing, and a lot of code that only existed long enough to create problems before someone deleted it.&lt;/p&gt;

&lt;p&gt;That changed the conversation pretty quickly.&lt;/p&gt;

&lt;p&gt;What happened there is actually not uncommon. The developers weren't doing anything wrong on purpose. They were sharing prompt snippets in Slack, copying Cursor rules from blog posts, using ChatGPT templates they found on Reddit. Nobody tested any of it. And by the time the metrics made the problem obvious, weeks of engineering time and money were already lost.&lt;/p&gt;

&lt;p&gt;It's actually sad how often teams realise this too late. So I hope this post helps you avoid the expensive version of the same lesson.&lt;/p&gt;

&lt;h2&gt;
  
  
  The reality check: engineering or gambling?
&lt;/h2&gt;

&lt;p&gt;At this point you might have written some prompts. Probably to generate unit tests or as a part of a customer support chat bot. They work (most of the time), but sometimes produce different results. That's not surprising given we use non-deterministic system under the hood. That doesn't feel exactly right. We probably want to be certain in our software (especially critical paths of it).&lt;/p&gt;

&lt;p&gt;So for starters I want to look at some of the reasons why testing prompts is important. Apart from obvious ones like unpredictable regression caused by API changes (OpenAI retired GPT-4o and three other models from ChatGPT in February 2026 alone) or just general consequences of baked in non-determinism there are things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hidden biases&lt;/strong&gt; brought by models from training data (when model "ignores" instructions in prompt). Your prompt says one thing, the model's priors say another.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging difficulty&lt;/strong&gt; caused by the fact it's hard to isolate root cause without tracking full context (which is a lot - input, prompt version, model version, parameters).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hard to catch garbage in response&lt;/strong&gt;, caused by the simple fact that ambiguous prompts still produce an output, it's just unreliable. Unlike e.g. syntax errors which break code immediately (these will surface very quickly). In April 2025, OpenAI pushed a system prompt update that made GPT-4o excessively flattering for its 500 million weekly users. They later admitted they "focused too much on short-term feedback." It took days and a social media firestorm before they rolled it back. That system prompt change wasn't treated as a release candidate. Nobody tested it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GitClear's 2025 analysis of 211 million lines of code actually found that AI output creates what they called an "illusion of correctness" - the visual neatness and consistent style of generated code caused developers to trust it without thorough validation. Their data showed review participation fell nearly 30%.&lt;/p&gt;

&lt;p&gt;And well, if OpenAI doesn't always get this right, the "prompts" your team shares without any control probably need some curation too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompts are code. Yes, even that ChatGPT one.
&lt;/h2&gt;

&lt;p&gt;So here I formulated for myself a few simple principles that help me a lot and hopefully will be useful for you too:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Prompts are code.&lt;/strong&gt; Version them, review them and run automated evals on every change. Like you always do with your code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You haven't written all the instructions.&lt;/strong&gt; When working with a "black boxed system" your input and instructions (while critical) do not define 100% of the output. Hidden biases often surface on edge cases. Diverse test inputs catch what prompt tweaking alone doesn't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Works on my machine" proves nothing.&lt;/strong&gt; A prompt that works today may silently break after a model update. Only automated, repeatable tests can give you confidence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Garbage in, garbage out.&lt;/strong&gt; Prompt quality is the most critical success factor. Test your inputs even more than your outputs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Can't reproduce - can't debug.&lt;/strong&gt; You have to keep full context 100% of the time including inputs, params, model version and more in your control to be able to catch an issue reliably.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And there's one important thing most people miss: these principles apply not just to product prompts.&lt;/p&gt;

&lt;p&gt;Think about it. The ChatGPT instruction you pasted into your team's wiki. The Cursor rules file your tech lead shared on Slack. The "system prompt for code review" your org adopted from a conference talk. If multiple people use it and nobody's actually measured whether it works - well, you have untested code running in production. You just don't call it that.&lt;/p&gt;

&lt;p&gt;That gap between perception and reality is the whole problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule of thumb I use:&lt;/strong&gt; if it lives in a file and runs more than once - it needs testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt testing techniques
&lt;/h2&gt;

&lt;p&gt;So if we need to start testing prompts, where do we begin?&lt;/p&gt;

&lt;p&gt;Unfortunately direct assertions like &lt;code&gt;assertEqual(LM_response, expected)&lt;/code&gt; won't work. You may have many valid outputs, and even if you set some abstract &lt;code&gt;temperature=0&lt;/code&gt;, you are not guaranteed consistent outputs across your runs. Quality lives on a spectrum - relevance, coherence, accuracy - not a binary pass/fail.&lt;/p&gt;

&lt;h3&gt;
  
  
  What still works from traditional testing?
&lt;/h3&gt;

&lt;p&gt;Good news - many "traditional" principles are still applicable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD integration.&lt;/strong&gt; Automated pipelines, shifting tests left, running evals on every PR are still your best friends.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests setup &amp;amp; structure.&lt;/strong&gt; Didn't change much either, so fixtures, datasets, parameterised tests and pytest-style structure are still applicable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structure (code-based) assertions.&lt;/strong&gt; Validating output format (JSON/XML/CSV), mandatory fields, type constraints - fast, cheap and catching a lot of issues early. Do not underestimate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Heuristic (rule-based) checks.&lt;/strong&gt; Also very good and catch ~30-40% of issues from my experience. They are good for things like output length constraints (too short = incomplete, too long = verbose), required elements (must contain XYZ, must have 3+ bullet points) etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some quick examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Heuristic checks
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_response_basics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Response too short - likely incomplete&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Response too verbose&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;disclaimer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Missing required disclaimer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;•&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Must contain at least 3 bullet points&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# ...
&lt;/span&gt;
&lt;span class="c1"&gt;# Code-based (structure) assertions
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;jsonschema&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;validate&lt;/span&gt;

&lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;required&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;summary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;action_items&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;priority&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;properties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;summary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;minLength&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;action_items&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;array&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;minItems&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;items&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;priority&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;enum&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;low&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_output_structure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;llm_response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;llm_response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# fails if not valid JSON
&lt;/span&gt;    &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# fails if schema mismatch
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The "new" stuff
&lt;/h3&gt;

&lt;p&gt;So the gap that traditional testing can't cover gets addressed with other techniques. Here are the main ones:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semantic similarity&lt;/strong&gt; allows to validate if the response conveys the same meaning (actual vs expected). If I simplify - it converts actual response and expected output to vectors and measures cosine similarity between them. BERTScore handles this locally - no API calls, no cost per evaluation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;bert_score&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;bert_score&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_semantic_similarity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;F1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;bert_score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;model_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;microsoft/deberta-xlarge-mnli&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.78&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Semantic drift detected: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use it when you have "golden sample" outputs and need to detect drift. Typical threshold sits around 0.7-0.85. Tuning that number is where the art comes in (I usually start at 0.75 and adjust based on what my golden samples actually score).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LLM-as-judge&lt;/strong&gt; is a method where another LLM scores output against certain criteria. It's mostly used for evaluation of response quality aspects like relevancy, correctness, tone, etc. The judge evaluates the response and returns a score in [0; 1] range, which can be tracked and used as quality gateway (with threshold).&lt;/p&gt;

&lt;p&gt;From my experience other techniques are a bit more intuitive, and LLM-as-judge raises more questions, which is why I want to go deeper into it.&lt;/p&gt;

&lt;h2&gt;
  
  
  LLM-as-judge: a closer look
&lt;/h2&gt;

&lt;p&gt;For this section I want to use an example of a dummy SDLC "agent" which does TDD (is really just two small prompts). For demonstration I'm going to use DeepEval (no specific reasons, just used to it, other solutions are just as good).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Defining metrics&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, we define what we measure. Instead of asking "is this good?" we evaluate against specific criteria so "the judge" knows what to score.&lt;/p&gt;

&lt;p&gt;For example for the code gen prompt, I'm checking if the generated code satisfies the UTs (as it's kind of a TDD process):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;deepeval.metrics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;GEval&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;deepeval.test_case&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LLMTestCaseParams&lt;/span&gt;

&lt;span class="n"&gt;code_satisfies_tests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GEval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CodeSatisfiesTests&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;criteria&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Implementation would make all provided test cases pass.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;evaluation_params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;LLMTestCaseParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ACTUAL_OUTPUT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;LLMTestCaseParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EXPECTED_OUTPUT&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GEval is a DeepEval built-in that allows to create custom metrics. The technique comes from a paper called G-Eval, which showed 0.514 Spearman correlation with human judgments - the highest of any automated method at the time.&lt;/p&gt;

&lt;p&gt;Another measurement that is good to show is alignment - on a high level it checks whether a prompt is able to generate output that follows the instructions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;deepeval.metrics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PromptAlignmentMetric&lt;/span&gt;

&lt;span class="n"&gt;aaa_pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PromptAlignmentMetric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;prompt_instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Each test follows Arrange-Act-Assert pattern&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Each test has a single assertion&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Score here is calculated as &lt;code&gt;instructions_followed / total_instructions&lt;/code&gt;. I.e. if the prompt says "one assertion per test" and "use AAA pattern," the metric checks both explicitly. And the &lt;code&gt;threshold&lt;/code&gt; is the pass/fail line to have an exception thrown (I always start at 0.5-0.7 and tighten based on data).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Writing the test&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This part might be actually more familiar, as the structure mirrors pytest a lot. &lt;code&gt;assert_test&lt;/code&gt; evaluates your LLM output against the metrics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;deepeval&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;assert_test&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;deepeval.test_case&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LLMTestCase&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;src.metrics.code_gen&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;code_satisfies_tests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;src.prompt_runner&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;run_prompt&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datasets.tdd_prompts&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_code_gen_dataset&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_code_generation&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;dataset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_code_gen_dataset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;golden&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;goldens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;actual_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code-gen.md&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;task&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;golden&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;design&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;golden&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;additional_metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;design&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spec&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;golden&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;additional_metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spec&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="n"&gt;test_case&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LLMTestCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;golden&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;actual_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;actual_output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;expected_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;golden&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expected_output&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nf"&gt;assert_test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_case&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;code_satisfies_tests&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But here's the trade-off: LLM-as-judge is slower and more expensive than heuristics and code assertions. So don't reach for it first. Use heuristics and code assertions for the cheap wins. Add semantic similarity when you have golden samples. Reserve LLM-as-judge for the quality criteria you genuinely can't check with code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Component-level: when one prompt isn't enough&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While end-to-end evals are good for one prompt, there are cases where it's not enough - multi-step pipelines, agents, RAGs, etc. When one fails, you need to know &lt;em&gt;which exact&lt;/em&gt; component broke.&lt;/p&gt;

&lt;p&gt;So here I formulated for myself another important rule I try to follow:&lt;/p&gt;

&lt;p&gt;Monolithic prompts that do multiple things are hard to debug. Split them into focused steps (prompt chaining) each with clear inputs and outputs. Test the parts of it independently, so when something fails, you know exactly where.&lt;/p&gt;

&lt;p&gt;DeepEval's &lt;code&gt;@observe&lt;/code&gt; decorator creates individually testable steps - &lt;strong&gt;spans&lt;/strong&gt;, where each gets its own metrics. A full execution creates a &lt;strong&gt;trace&lt;/strong&gt; containing all spans:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;deepeval.tracing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;observe&lt;/span&gt;

&lt;span class="nd"&gt;@observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;llm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_tests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;design&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;run_prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test-gen.md&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;task&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;design&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;design&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nd"&gt;@observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;llm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;design&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;run_prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code-gen.md&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;task&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;design&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;design&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spec&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nd"&gt;@observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;code_satisfies_tests&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aaa_pattern&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tdd_flow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;design&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;spec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_tests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;design&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;design&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Start here, not everywhere
&lt;/h2&gt;

&lt;p&gt;Don't try to boil the ocean. Pick one prompt - the one that matters most. Pick one or two metrics. Start with a threshold of 0.5-0.7 and tighten based on actual data, not gut feel.&lt;/p&gt;

&lt;p&gt;Generally not to get lost, here's the &lt;strong&gt;rule of thumb&lt;/strong&gt; I rely on: use code assertions and heuristics first as they are fast, cheap and catch ~30% of issues. Use embedding-based semantic similarity (e.g. BERTScore) if you have your "golden sample" data set + edge cases. Rely on LLM-as-judge for quality criteria that you can't check with code - and make those criteria specific.&lt;/p&gt;

&lt;p&gt;And avoid these mistakes, because I've made every single one:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Overfitting to test cases.&lt;/strong&gt; Your prompt works flawlessly with your five examples but falls apart on real inputs. Test data ≠ all possible inputs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thresholds too high.&lt;/strong&gt; Setting 0.95 as your pass/fail line and then wondering why good outputs keep failing. LLM-as-judge has variance. Start at 0.5-0.7, tighten based on data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testing only happy paths.&lt;/strong&gt; Clean inputs pass. Production inputs break. Include edge cases: empty inputs, malformed data, languages you didn't plan for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skipping human review.&lt;/strong&gt; Automation catches regressions, not nuance. Use both: automated evals for CI, periodic expert review for calibration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testing too late.&lt;/strong&gt; Finding issues after your prompt is deployed to users, not before. Shift left. Run evals on every PR.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Measuring everything at once.&lt;/strong&gt; Ten metrics from day one, none properly tuned. Start with one or two critical criteria. Add more when those are stable.&lt;/p&gt;

&lt;p&gt;The hard part isn't writing the test. It's defining what "good" means for your specific case. Once you have that, the tooling is the easy part.&lt;/p&gt;

&lt;p&gt;So here's the simple rule: test any prompt that is shared with someone or will be used more than once.&lt;/p&gt;

&lt;p&gt;That's it. Not just your product prompts. Your Cursor rules. Your ChatGPT templates. The "just paste this into Claude" messages on Slack.&lt;/p&gt;

&lt;p&gt;This is a new reality, and I'd probably call it AI hygiene. Same as you wouldn't share untested code with your team, you probably shouldn't share untested prompts either.&lt;/p&gt;

</description>
      <category>promptengineering</category>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>software</category>
    </item>
  </channel>
</rss>
