<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>IndieFounder — AI &amp; automation</title>
  <subtitle>Practical, independent insights for people building startups, SaaS products, and developer tools.</subtitle>
  <id>https://indiefounder.me/feed/ai.xml</id>
  <link href="https://indiefounder.me/feed/ai.xml" rel="self" type="application/atom+xml"/>
  <link href="https://indiefounder.me/" rel="alternate" type="text/html"/>
  <updated>2026-10-17T00:07:33+05:30</updated>
  <author>
    <name>IndieFounder Editorial Team</name>
  </author>
  <entry>
    <title type="html">How to Build a Production Evaluation Suite for LLM Applications and AI Agents</title>
    <link href="https://indiefounder.me/ai/evaluating-and-testing-llm-applications/" rel="alternate" type="text/html" title="How to Build a Production Evaluation Suite for LLM Applications and AI Agents"/>
    <published>2026-10-06T09:45:00+05:30</published>
    <updated>2026-10-06T09:45:00+05:30</updated>
    <id>https://indiefounder.me/ai/evaluating-and-testing-llm-applications/</id>
    <content type="html" xml:base="https://indiefounder.me/ai/evaluating-and-testing-llm-applications/">&lt;p&gt;The most common failure mode in generative AI startups is the “vibe check”: a developer edits a system prompt, runs three queries in the browser, confirms that the output looks reasonable, and deploys directly to production.&lt;/p&gt;

&lt;p&gt;Two days later, customers complain that the model hallucinated invalid URLs, broke structured JSON output, or began leaking internal prompt directives.&lt;/p&gt;

&lt;p&gt;Unlike traditional deterministic software, where unit tests check exact equality (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;assert add(2, 2) == 4&lt;/code&gt;), large language models (LLMs) are probabilistic and non-deterministic. Shipping reliable AI products requires a &lt;strong&gt;continuous evaluation (evals) pipeline&lt;/strong&gt; that catches regressions before your users encounter them.&lt;/p&gt;

&lt;figure class=&quot;post-figure&quot;&gt;
  &lt;img src=&quot;/assets/images/posts/llm-eval-pipeline.svg&quot; alt=&quot;Continuous Evaluation Pipeline for Production LLM Applications&quot; width=&quot;800&quot; height=&quot;360&quot; loading=&quot;lazy&quot; /&gt;
  &lt;figcaption&gt;Figure 1: Automated CI/CD evaluation architecture testing prompt revisions against golden datasets.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&quot;the-three-tiers-of-llm-evaluation&quot;&gt;The Three Tiers of LLM Evaluation&lt;/h2&gt;

&lt;p&gt;A production eval suite combines three complementary layers of testing:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Eval Layer&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Execution Speed&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Cost&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Purpose&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Deterministic Code Assertions&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Sub-millisecond&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Free&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;JSON schema validity, required key presence, regex format, latency limits&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Semantic Distance Metrics&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;~10–50ms&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Inexpensive&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Cosine similarity between embeddings, BLEU / ROUGE scoring&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Model-as-a-Judge (LLM Judge)&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;~1–3s&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Moderate (API calls)&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Evaluating tone, factual consistency, safety guidelines, and hallucination&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;constructing-your-golden-dataset&quot;&gt;Constructing Your “Golden Dataset”&lt;/h2&gt;

&lt;p&gt;You cannot build an eval suite without a reference test suite. The foundation of your pipeline is a &lt;strong&gt;Golden Dataset&lt;/strong&gt;: a curated collection of 50 to 200 real-world input prompts paired with expected outputs or evaluation criteria.&lt;/p&gt;

&lt;h3 id=&quot;golden-dataset-structure-test_casesjsonl&quot;&gt;Golden Dataset Structure (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test_cases.jsonl&lt;/code&gt;)&lt;/h3&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;tc_financial_summary_01&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;input&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Summarize Q3 earnings: Revenue $4.2M (+14%), Churn 2.1%, OpEx $3.1M.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;expected_keys&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;revenue&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;growth_rate&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;churn&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;operating_profit&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;forbidden_substrings&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;NaN&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;undefined&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;profit margin of 50%&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;evaluation_criteria&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;The response must accurately calculate operating profit as $1.1M ($4.2M - $3.1M) without guessing unstated numbers.&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Populate your dataset with:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Historical failure cases:&lt;/strong&gt; Every bug reported by a user in production becomes a permanent test case in your suite.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Edge cases:&lt;/strong&gt; Inputs with missing context, non-English text, extreme token lengths, and deliberate prompt injection attempts.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Representative queries:&lt;/strong&gt; Typical everyday requests reflecting core user behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;implementing-deterministic-and-model-judges&quot;&gt;Implementing Deterministic and Model Judges&lt;/h2&gt;

&lt;p&gt;A minimal, robust evaluation script can be written in less than 80 lines of TypeScript or Python using standard test runners like Vitest or Pytest:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// run-evals.ts: Execute automated prompt regression test&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;vitest&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;generateProductSummary&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;../src/agent&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;evaluateWithJudgeModel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./judge&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Financial summary agent maintains mathematical fidelity&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Q3 Results: Revenue $10M, COGS $3M, Marketing $2M, Net Income $5M.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;startTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;generateProductSummary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;durationMs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;startTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Tier 1: Deterministic checks&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;durationMs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toBeLessThan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3500&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Latency constraint&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toThrow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// JSON structure constraint&lt;/span&gt;
  
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;parsed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parsed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;gross_profit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 10M - 3M&lt;/span&gt;
  
  &lt;span class=&quot;c1&quot;&gt;// Tier 2: Model-as-a-Judge evaluation for hallucination&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;judgeScore&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;evaluateWithJudgeModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;prompt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;rubric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Score from 1 to 5 based on whether the output invents any metric not stated in the source text. 5 = zero hallucinations.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  
  &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;judgeScore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toBeGreaterThanOrEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;running-evals-in-cicd-pull-requests&quot;&gt;Running Evals in CI/CD Pull Requests&lt;/h2&gt;

&lt;p&gt;Integrate your eval suite into your GitHub Actions workflow. Whenever a developer modifies a prompt template or upgrades a base model version (e.g., from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gpt-4o-mini&lt;/code&gt; to a newer checkpoint):&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The CI runner executes the test suite across your Golden Dataset.&lt;/li&gt;
  &lt;li&gt;It generates a diff summary comparing current pass rates against the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; branch.&lt;/li&gt;
  &lt;li&gt;If the overall accuracy score drops below a pre-set threshold (e.g., 94%), or if any critical safety assertion fails, the pull request is &lt;strong&gt;automatically blocked from merging&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# .github/workflows/evals.yml&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Prompt Regression Evals&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pull_request&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;run-evals&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;node-version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;20&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;npm ci&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Run Model Benchmark Suite&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;npm run test:evals&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;By substituting subjective guessing with automated test harnesses, indie founders can iterate on complex AI workflows with the same velocity and confidence as traditional software engineering.&lt;/p&gt;
</content>
    <summary type="html">A practical engineering framework for testing generative AI products: automated golden datasets, semantic assertions, LLM-as-a-Judge rubrics, and CI/CD regression gates.</summary>
  </entry>
  <entry>
    <title type="html">When Should You Use an AI Agent in a Product?</title>
    <link href="https://indiefounder.me/ai/when-to-use-ai-agents/" rel="alternate" type="text/html" title="When Should You Use an AI Agent in a Product?"/>
    <published>2026-10-03T10:15:00+05:30</published>
    <updated>2026-10-03T10:15:00+05:30</updated>
    <id>https://indiefounder.me/ai/when-to-use-ai-agents/</id>
    <content type="html" xml:base="https://indiefounder.me/ai/when-to-use-ai-agents/">&lt;p&gt;AI agents are useful when software must interpret changing context, choose among actions, and work through a task that cannot be fully described as a fixed sequence of rules. They are not automatically the best way to add intelligence to an application. In many products, a conventional function or a single model call is cheaper, easier to test, and more reliable.&lt;/p&gt;

&lt;p&gt;The design question is not “Can an agent do this?” It is “Does the flexibility of an agent solve a real problem that simpler software cannot solve well enough?”&lt;/p&gt;

&lt;p&gt;For a new AI product, this technical decision should follow evidence that the customer problem matters. Use our &lt;a href=&quot;/startups/validate-a-saas-idea/&quot;&gt;SaaS idea validation process&lt;/a&gt; to test demand before investing in a complex agent workflow.&lt;/p&gt;

&lt;h2 id=&quot;understand-the-three-patterns&quot;&gt;Understand the three patterns&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Deterministic software&lt;/strong&gt; follows explicit rules. A payment total, permission check, subscription status, or inventory update should usually be implemented with ordinary code and validated data. The behavior is predictable and can be tested against defined expectations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A single model call&lt;/strong&gt; is useful when a bounded task needs language understanding or generation. Examples include classifying a support message, summarizing a document, or drafting a response from supplied context. The application decides what happens before and after the model call.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An agent&lt;/strong&gt; can select tools, gather additional information, decide which step to take next, and repeat until a stopping condition is reached. For example, a research assistant might search an approved knowledge base, open relevant documents, compare findings, and produce a sourced summary. This flexibility comes with additional failure modes.&lt;/p&gt;

&lt;p&gt;These patterns can coexist. A well-designed product often uses deterministic code for sensitive state changes, a model for interpretation, and an agent only for the part that benefits from adaptive multi-step work.&lt;/p&gt;

&lt;h2 id=&quot;look-for-the-right-problem-characteristics&quot;&gt;Look for the right problem characteristics&lt;/h2&gt;

&lt;p&gt;An agent becomes more attractive when the task has multiple meaningful steps and the next step depends on what the previous step reveals. The required information may not be available at the start, and the system may need to choose from a small, well-defined set of tools. Mistakes must be detectable or containable, and the value of completing the task must justify added latency and cost.&lt;/p&gt;

&lt;p&gt;Consider internal support triage. A basic classifier may assign a category. A more capable workflow might inspect a ticket, retrieve approved documentation, identify missing details, and draft a response for a human reviewer. If the task is simply to label one of five known categories, an agent may be unnecessary. If it must gather context from several approved sources, adaptive steps may provide value.&lt;/p&gt;

&lt;h2 id=&quot;calculate-the-cost-of-flexibility&quot;&gt;Calculate the cost of flexibility&lt;/h2&gt;

&lt;p&gt;Every extra model call or tool invocation adds latency, cost, and another opportunity for failure. An agent may also require tracing, evaluation datasets, permission boundaries, and ongoing maintenance.&lt;/p&gt;

&lt;p&gt;Before implementation, estimate model and tool cost per completed task, typical and worst-case execution time, the rate of human intervention, the cost of a wrong action, and the effort required to monitor failures. Compare the agent with the best practical alternative, including deterministic automation and a single model call. A slow agent that occasionally produces impressive results may be worse than a fast workflow that handles common cases consistently.&lt;/p&gt;

&lt;h2 id=&quot;design-tools-as-security-boundaries&quot;&gt;Design tools as security boundaries&lt;/h2&gt;

&lt;p&gt;An agent should not receive broad access merely because it might need it. Give it the smallest set of tools and permissions required. Separate read operations from write operations, validate tool inputs, and enforce authorization in the application layer.&lt;/p&gt;

&lt;p&gt;For example, a model may propose issuing a refund, but trusted application code should verify the user’s permissions, order state, refund limits, and business rules before a transaction occurs. Never treat a model’s claim that a user is an administrator as proof of authorization. Untrusted document text or retrieved webpages must not override application policies.&lt;/p&gt;

&lt;p&gt;High-impact actions should require explicit confirmation or human approval. Log tool calls and outcomes without unnecessarily recording sensitive data. Use timeouts, rate limits, bounded retries, and a clear maximum step count.&lt;/p&gt;

&lt;h2 id=&quot;make-failures-visible-and-recoverable&quot;&gt;Make failures visible and recoverable&lt;/h2&gt;

&lt;p&gt;Agent workflows can fail in ways ordinary functions often do not. A tool may return malformed data. A model may choose the wrong tool, repeat a step, misinterpret an instruction, or claim that work succeeded when it did not. External services may time out.&lt;/p&gt;

&lt;p&gt;Validate structured outputs against schemas. Treat tool responses as untrusted input. Confirm that a requested operation actually succeeded before reporting completion. Add idempotency controls to prevent duplicate side effects and define a fallback when a dependency is unavailable.&lt;/p&gt;

&lt;p&gt;A useful workflow state machine might include pending, running, awaiting approval, completed, failed, and cancelled. Do not make an agent the sole source of truth for payments, permissions, orders, or other critical business state.&lt;/p&gt;

&lt;h2 id=&quot;evaluate-outcomes-not-impressive-demos&quot;&gt;Evaluate outcomes, not impressive demos&lt;/h2&gt;

&lt;p&gt;A demo usually shows favorable examples. A product needs repeatable evidence. Create an evaluation set based on representative tasks, including ambiguous requests, missing information, tool errors, malicious instructions in retrieved content, and cases where the correct behavior is to ask for clarification.&lt;/p&gt;

&lt;p&gt;Track task success, factual correctness, tool selection accuracy, policy violations, completion time, cost, and human correction rate. Inspect failure examples rather than relying only on an aggregate score. Run evaluations before launch and continue monitoring after release because model and tool changes can alter behavior.&lt;/p&gt;

&lt;h2 id=&quot;start-with-a-bounded-agent&quot;&gt;Start with a bounded agent&lt;/h2&gt;

&lt;p&gt;Choose one narrow workflow, a small tool set, and a clear completion condition. Keep high-impact actions behind approval. Give the workflow an explicit budget for steps, time, and model usage.&lt;/p&gt;

&lt;p&gt;A practical workflow accepts a scoped task, gathers relevant context, selects from approved tools, validates each tool request and response, and stops when the task is complete, unsafe, or out of budget. It should present evidence and request approval where needed. This structure is easier to understand, test, and improve than a system that promises to do everything.&lt;/p&gt;

&lt;h2 id=&quot;a-practical-decision-checklist&quot;&gt;A practical decision checklist&lt;/h2&gt;

&lt;p&gt;Use deterministic code when rules are stable and outcomes must be exact. Use a single model call when the task is bounded and mostly involves interpreting or generating content. Consider an agent when adaptive multi-step work is central, tool use adds measurable value, and failures can be managed safely.&lt;/p&gt;

&lt;p&gt;Before shipping, ask what user problem the agent solves better than a simpler alternative, what tools it can access, how wrong results will be detected, which actions require approval, what the cost and stopping limits are, and how quality will be measured after release. If these questions have no clear answers, the product probably needs a clearer workflow before it needs an agent.&lt;/p&gt;

&lt;h2 id=&quot;the-takeaway&quot;&gt;The takeaway&lt;/h2&gt;

&lt;p&gt;AI agents are a design choice, not a product requirement. Use them where uncertainty and multi-step decisions are central, and keep predictable business logic in ordinary software. A bounded agent with narrow permissions, measurable outcomes, and safe failure handling is more useful than a broadly autonomous system that cannot reliably verify its actions.&lt;/p&gt;

</content>
    <summary type="html">A decision framework for choosing between deterministic software, a single model call, and an AI agent with tools and multiple steps.</summary>
  </entry>
</feed>
