<?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: Conor Bronsdon</title>
    <description>The latest articles on DEV Community by Conor Bronsdon (@conorbronsdon).</description>
    <link>https://dev.to/conorbronsdon</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F654631%2F416c2c20-4bc3-425c-8812-2d7ff262bada.png</url>
      <title>DEV Community: Conor Bronsdon</title>
      <link>https://dev.to/conorbronsdon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/conorbronsdon"/>
    <language>en</language>
    <item>
      <title>Let your LLM say I don't know instead of guessing</title>
      <dc:creator>Conor Bronsdon</dc:creator>
      <pubDate>Sun, 01 Nov 2026 20:30:07 +0000</pubDate>
      <link>https://dev.to/conorbronsdon/let-your-llm-say-i-dont-know-instead-of-guessing-2dog</link>
      <guid>https://dev.to/conorbronsdon/let-your-llm-say-i-dont-know-instead-of-guessing-2dog</guid>
      <description>&lt;p&gt;Your user asks a factual question. The model returns a polished paragraph. Nothing in the stack threw an error. That is exactly when you are most exposed. A language model generates the most plausible next words, not the most true ones, so a wrong answer can look identical to a right one. That mechanism is what people call &lt;a href="https://chainofthought.show/glossary/ai-hallucination/" rel="noopener noreferrer"&gt;AI hallucination&lt;/a&gt;: same token prediction, missing or weak facts, fluent fiction at the end.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://chainofthought.show/guests/dan-klein/" rel="noopener noreferrer"&gt;Dan Klein&lt;/a&gt;, co-founder and CTO of Scaled Cognition, put the internals this way on Chain of Thought: we label outputs after the fact, but the model never splits “truth” from “guess” on its own.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If they're right, we call them truth. And if they're wrong, we call them hallucination. But the model does not internally distinguish between those.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Dan Klein, co-founder and CTO of Scaled Cognition&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I’d stop treating confidence in the UI as a proxy for correctness. Treat every fluent sentence as a claim you still owe evidence for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does fluency hide the errors you care about?
&lt;/h2&gt;

&lt;p&gt;Obvious mistakes get caught in QA. Klein’s audit story from enterprise work is worse: when his team audits enterprise systems, he says, the real hallucination rate is often about five times what the customer has noticed, because the rest are fluent enough to pass. His examples are a refund policy that is real and plausible but not yours, or yours but for a customer with a different status.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Looks right. It looks right and is right are not the same. It is very hard to detect hallucinations when they are packaged up sufficiently fluently.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Dan Klein, co-founder and CTO of Scaled Cognition&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Chip Huyen made the data angle plain on Chain of Thought ep 5: missing or wrong context pushes the model toward invention.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Models are more likely to hallucinate when it does not have access to the necessary and correct information to answer questions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Chip Huyen, author of AI Engineering&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So the design job is to give the model the facts at answer time, allow silence when facts are missing, and verify what still matters. A smarter model does not remove that work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What breaks when you only punish wrong guesses?
&lt;/h2&gt;

&lt;p&gt;Pre-training shows the model fluent text, not labeled false statements. Rare facts (like a specific birthday) do not repeat as patterns, so the model still produces something that sounds like an answer. Benchmarks make the incentive worse: “I don’t know” often scores like a wrong answer, while a random guess sometimes hits. OpenAI’s 2025 write-up on why language models hallucinate argues for penalizing confident errors more than honest uncertainty. Anthropic’s interpretability work on Claude describes a default to decline on unrecognized entities, with a “known entity” signal that can flip that off and invite a guess anyway.&lt;/p&gt;

&lt;p&gt;For your app, that means instructions that forbid uncertainty fight the same scoreboards that trained the model to guess. If your eval sheet marks abstain as a miss, you are training your team to ship guessers.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you ground answers and still leave an out?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://chainofthought.show/glossary/grounding/" rel="noopener noreferrer"&gt;Grounding&lt;/a&gt; means building the reply from material you put in context at question time, ideally with citations per claim. That cuts invented detail because the model has less room to freestyle. It does not guarantee truth: sources can be stale, retrieval can miss the doc, and the model can still stretch past what the sources say. Many production issues that look like “model bugs” are retrieval or document problems first.&lt;/p&gt;

&lt;p&gt;General models also carry a &lt;a href="https://chainofthought.show/glossary/knowledge-cutoff/" rel="noopener noreferrer"&gt;knowledge cutoff&lt;/a&gt;: training frozen at a date, then released later. Ask about anything newer and you get “I don’t know” or a plausible guess. The standard fix is the same as grounding: fetch current or private text into the context window before generation (RAG, search, or both).&lt;/p&gt;

&lt;p&gt;My default pattern for factual features:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retrieve candidate passages for the question.&lt;/li&gt;
&lt;li&gt;If nothing passes a relevance threshold, return abstain (or escalate to a human). Do not ask the model to “try anyway.”&lt;/li&gt;
&lt;li&gt;If you have passages, instruct answer-only-from-these, cite span or doc id per claim.&lt;/li&gt;
&lt;li&gt;Run a faithfulness check on answers that can move money, policy, or compliance.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step 4 is where &lt;a href="https://chainofthought.show/topics/evaluation/" rel="noopener noreferrer"&gt;AI evaluation and reliability&lt;/a&gt; work pays off: separate counts for &lt;code&gt;answered&lt;/code&gt;, &lt;code&gt;abstained&lt;/code&gt;, &lt;code&gt;answered_supported&lt;/code&gt; and &lt;code&gt;answered_unsupported&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does an abstain-and-ground sketch look like?
&lt;/h2&gt;

&lt;p&gt;Label this as illustration, not production code from any guest or vendor.&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;# Sketch: abstain if retrieval is weak; answer only from chunks
&lt;/span&gt;
&lt;span class="n"&gt;MIN_SCORE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.42&lt;/span&gt;  &lt;span class="c1"&gt;# tune on your corpus
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_question&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;retrieve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;faithfulness_check&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;retrieve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_question&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;best&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;best&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;MIN_SCORE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&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;abstain&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;message&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;No trusted source found.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;prompt&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;instruction&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;Answer using ONLY the sources. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;If they do not support an answer, reply ABSTAIN.&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;sources&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;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;question&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user_question&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;draft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ABSTAIN&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;draft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&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;abstain&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;message&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;Model declined.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;faithfulness_check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&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;abstain&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;message&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;Failed source check.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&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;ok&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;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sources&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The abstain path is a first-class HTTP response, not a thrown exception buried in logs. Users should see “we don’t know” when you mean it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Decide where a wrong fluent answer is costly; tighten grounding and checks there first.&lt;/li&gt;
&lt;li&gt;Retrieve before generate; abstain when retrieval is empty or weak instead of prompting harder.&lt;/li&gt;
&lt;li&gt;Tell the model abstaining is allowed; score abstain better than a confident wrong answer in evals.&lt;/li&gt;
&lt;li&gt;Check high-stakes outputs against supplied sources (faithfulness), not vibes.&lt;/li&gt;
&lt;li&gt;Remember fluent output is plausible text until your sources and checks say otherwise.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The longer explainer, with the episode clips, is on &lt;a href="https://chainofthought.show/ai-decoded/why-do-llms-hallucinate/" rel="noopener noreferrer"&gt;Chain of Thought&lt;/a&gt;. It draws on &lt;a href="https://chainofthought.show/podcast/54-why-llms-are-plausibility-engines-not-truth-engines-dan-klein/" rel="noopener noreferrer"&gt;this episode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/2HwtyPE6JuQ" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://newsletter.chainofthought.show/subscribe?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=newsletter" rel="noopener noreferrer"&gt;Subscribe to the Chain of Thought newsletter&lt;/a&gt; for new episodes and write-ups like this one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI assistance from the episode transcripts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>rag</category>
      <category>testing</category>
    </item>
    <item>
      <title>Five lessons for getting enterprise AI past the pilot phase</title>
      <dc:creator>Conor Bronsdon</dc:creator>
      <pubDate>Sun, 01 Nov 2026 15:30:06 +0000</pubDate>
      <link>https://dev.to/conorbronsdon/five-lessons-for-getting-enterprise-ai-past-the-pilot-phase-2ge4</link>
      <guid>https://dev.to/conorbronsdon/five-lessons-for-getting-enterprise-ai-past-the-pilot-phase-2ge4</guid>
      <description>&lt;p&gt;Demoing AI is the easy part. Putting it in front of thousands of people, tying it to outcomes, and keeping it safe when models and data sprawl is the work. These five episodes from the Chain of Thought collection for enterprise AI leaders each point at one decision developers and product engineers control, even when leadership wants speed.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you deploy agents company-wide without a playbook?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://chainofthought.show/podcast/48-how-block-deployed-ai-agents-to-12-000-employees-in-8-weeks-w-mcp-angie-jones/" rel="noopener noreferrer"&gt;How Block Deployed AI Agents to 12,000 Employees in 8 Weeks w/ MCP&lt;/a&gt; is the clearest story of breadth plus speed: Block put its open-source agent Goose in front of roughly 12,000 employees in about eight weeks, with Angie Jones describing deployment with no playbook already written.&lt;/p&gt;

&lt;p&gt;For builders, the practical split is adoption versus control. Block leaned on security guardrails so wide rollout stayed defensible, and supported letting employees choose their own models (Claude, GPT, Gemini, plus open and local options in the discussion) because that choice drove uptake. MCP shows up as the connective tissue for hooking agents to real systems, with human-in-the-loop controls, OAuth, and tool annotations called out as part of the guardrail stack.&lt;/p&gt;

&lt;p&gt;If you are past a pilot, I would treat model lock-in and missing guardrails as ship blockers before you chase more use cases. Ship one agent path with explicit approval steps for destructive tools, then expand connectors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does so much enterprise AI spend fail to show ROI?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://chainofthought.show/podcast/4-why-most-enterprise-ai-projects-fail-to-show-roi-hp-servicenow-and-accenture/" rel="noopener noreferrer"&gt;Why Most Enterprise AI Projects Fail to Show ROI&lt;/a&gt; still works as the straight ROI entry point. HP, ServiceNow, and Accenture walk through why heavy investment often ends in a vague "what did we get?" question instead of a number anyone trusts.&lt;/p&gt;

&lt;p&gt;The builder takeaway is to pick use cases you can prioritize, implement, and measure, and to treat trust and explainability as part of delivery from the start. Alex Klug at HP frames risk in customer-facing terms: nobody wants to deploy something that steers customers wrong. That is a useful filter when product asks for AI in every surface.&lt;/p&gt;

&lt;p&gt;Before you add another copilot button, write down who gets hurt if the model is wrong and whether you can detect and roll back bad outputs. If you cannot, you are still in pilot clothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you find where AI pays off instead of token maxing?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://chainofthought.show/podcast/64-stop-token-maxxing-find-where-ai-actually-pays-off-jiaona-zhang/" rel="noopener noreferrer"&gt;Stop Token Maxxing: Find Where AI Actually Pays Off&lt;/a&gt; with Jiaona Zhang (CPO at Laurel) targets a common failure mode: top-down "use AI everywhere" mandates that push teams to burn tokens without learning what returned time or revenue.&lt;/p&gt;

&lt;p&gt;Zhang's through-line is measurement over mandate. Laurel runs its own product on itself and uses time data to see where AI helps versus where teams only assume it helps. The episode also ties efficient use to org design (lean teams, non-engineers shipping with agents, bottom-up plus top-down re-architecture), but the decision rule for developers is simpler: instrument time before you celebrate usage stats.&lt;/p&gt;

&lt;p&gt;Sketch (illustration only, not Laurel's production code):&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;# Sketch: log task time before/after AI assist for one workflow
&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;  &lt;span class="c1"&gt;# {"workflow": str, "minutes": float, "used_ai": bool}
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;median_minutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;workflow&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;used_ai&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;times&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;minutes&lt;/span&gt;&lt;span class="sh"&gt;"&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;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;workflow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;workflow&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;used_ai&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;used_ai&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&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;times&lt;/span&gt;&lt;span class="p"&gt;[&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;times&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;times&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nan&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare medians per workflow with and without AI. Kill mandates that raise token charts but flatline time saved.&lt;/p&gt;

&lt;h2&gt;
  
  
  What if the agent calls the model fine but cannot reach the data?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://chainofthought.show/podcast/66-data-federation-not-centralization-is-what-enterprise-ai-needs/" rel="noopener noreferrer"&gt;Data Federation, Not Centralization, Is What Enterprise AI Needs&lt;/a&gt; with Jitender Aswani (Starburst) argues that stalled enterprise AI often loses a hidden fight: queries to the model work, access to data spread across dozens or hundreds of sources does not. The collection summary puts typical enterprises at 52 to 200 data sources; centralize-everything strategies pile ETL debt and brittle pipelines when SaaS schemas shift.&lt;/p&gt;

&lt;p&gt;Aswani treats fragmentation as something you design around. Federation and query layers are his architectural direction, and MCP shows up in the episode as a driver of query volume. For application developers, the lesson is to stop blocking pilots on a mythical single lake and start exposing governed, federated access paths agents can call.&lt;/p&gt;

&lt;p&gt;When an agent "hallucinates finance numbers," check data reachability before you fine-tune the prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  What separates enterprise AI that ships from AI that demos?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://chainofthought.show/podcast/17-inside-ibms-watsonx-building-enterprise-ai-that-ships-dr-maryam-ashoori/" rel="noopener noreferrer"&gt;Inside IBM's watsonx: Building Enterprise AI That Ships&lt;/a&gt; with Dr. Maryam Ashoori, Head of Product for watsonx AI at IBM, focuses on trustworthy, scalable delivery across tools and regulations. Ashoori discusses simplifying the AI stack, automating pipelines, data management and lineage, scaling agentic systems, and effective agent evaluation, backed by survey findings from 1,000 developers on how enterprise AI implementation is going in the wild.&lt;/p&gt;

&lt;p&gt;I'd take "ships" to mean repeatable pipelines, eval systems you trust enough to gate releases, and cost awareness as you scale agents. Demos skip lineage and eval; production cannot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Pair wide agent rollout with explicit security guardrails and model choice where that choice drives adoption (Block/Goose pattern).&lt;/li&gt;
&lt;li&gt;Prioritize ROI-ready use cases only where trust, explainability, and customer harm if wrong are spelled out (HP/ServiceNow/Accenture panel themes).&lt;/li&gt;
&lt;li&gt;Replace "AI everywhere" mandates with time-based measurement per workflow so you stop token maxing (Jiaona Zhang, Laurel).&lt;/li&gt;
&lt;li&gt;Assume 52 to 200 data sources and plan federation and governed access instead of waiting for a finished centralization project (Jitender Aswani, Starburst).&lt;/li&gt;
&lt;li&gt;Treat simplified stacks, automated pipelines, lineage, and agent evals as shipping requirements (Maryam Ashoori, IBM).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More on this topic, with the related episodes, is on &lt;a href="https://chainofthought.show/collections/best-for-enterprise-ai-leaders/" rel="noopener noreferrer"&gt;Chain of Thought&lt;/a&gt;. It draws on &lt;a href="https://chainofthought.show/podcast/48-how-block-deployed-ai-agents-to-12-000-employees-in-8-weeks-w-mcp-angie-jones/" rel="noopener noreferrer"&gt;this episode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/O7etCBod2IY" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://newsletter.chainofthought.show/subscribe?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=newsletter" rel="noopener noreferrer"&gt;Subscribe to the Chain of Thought newsletter&lt;/a&gt; for new episodes and write-ups like this one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI assistance from the episode transcripts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>enterprise</category>
      <category>agents</category>
      <category>llm</category>
    </item>
    <item>
      <title>Price a coding call, then pick the model tier</title>
      <dc:creator>Conor Bronsdon</dc:creator>
      <pubDate>Sat, 31 Oct 2026 20:30:08 +0000</pubDate>
      <link>https://dev.to/conorbronsdon/price-a-coding-call-then-pick-the-model-tier-2mfj</link>
      <guid>https://dev.to/conorbronsdon/price-a-coding-call-then-pick-the-model-tier-2mfj</guid>
      <description>&lt;p&gt;For a short coding task, price the fast tier and the flagship on the same prompt, then keep the cheapest run that still returns code you would ship. On the pricing &lt;a href="https://chainofthought.show/guests/paige-bailey/" rel="noopener noreferrer"&gt;Paige Bailey&lt;/a&gt; read off the screen, Gemini 3 Flash input was about 25% of Gemini 3 Pro, a bit lower with a large input context, and output was about 25% as well. With thinking set to minimal, Flash wrote a lat/long helper in about one tenth the time, and the call came in at less than a penny.&lt;/p&gt;

&lt;p&gt;Paige Bailey is the AI developer relations lead at Google DeepMind. The episode aired in January 2026. She opened compare mode in AI Studio and ran one Python prompt on Gemini 3 Pro and Gemini 3 Flash.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you choose a model tier for a short coding task?
&lt;/h2&gt;

&lt;p&gt;Run the task on the fast tier with thinking turned down, run it on the flagship, and keep the cheaper result that matches the code you wanted. Bailey framed Gemini 3 Pro as the flagship, with thinking built in, a larger model, and a much higher price. Gemini 3 Flash can turn thinking on, at what she called a significant discount next to Pro.&lt;/p&gt;

&lt;p&gt;In that compare Pro's thinking level was high by default, and she set Flash to minimal. The prompt asked for a Python function that returns lat/long for a city. Flash returned while Pro was still thinking. Sources were cited, both answers used GeoPy, and she called the Python more or less the same. That output had no example usage.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For folks who can't see, the input is about 25% of what you would expect to pay for Gemini three Pro, even a little bit lower if you have significant number of tokens in your context window for inputs. And then the output is also significantly less expensive, just coming in at about 25%.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Paige Bailey, AI Developer Relations Lead at Google DeepMind, on &lt;a href="https://chainofthought.show/podcast/47-gemini-3-and-robot-dogs-inside-google-deepminds-ai-experiments-paige-bailey/" rel="noopener noreferrer"&gt;Chain of Thought ep 47&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://podcasts.apple.com/us/podcast/gemini-3-robot-dogs-inside-google-deepminds-ai-experiments/id1776879655?i=1000745162445" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fis1-ssl.mzstatic.com%2Fimage%2Fthumb%2FPodcasts211%2Fv4%2F52%2F11%2F80%2F521180b1-f6cc-9ad9-0917-676e74e4b36a%2Fmza_7878404023429800825.jpg%2F1200x1200ECA.PESS01-60.jpg%3FimgShow%3DPodcasts221%2Fv4%2Fee%2Ff2%2F1b%2Feef21b19-f090-f9b4-fc85-ffc84f80fad7%2Fmza_6548396687882944514.jpg" height="800" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://podcasts.apple.com/us/podcast/gemini-3-robot-dogs-inside-google-deepminds-ai-experiments/id1776879655?i=1000745162445" rel="noopener noreferrer" class="c-link"&gt;
            Gemini 3 &amp;amp; Robot Dogs: Inside … - Chain of Thought | AI Agents, Infrastructure &amp;amp; Engineering - Apple Podcasts
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Podcast Episode · Chain of Thought | AI Agents, Infrastructure &amp;amp; Engineering · January 14 · 51m
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpodcasts.apple.com%2Fassets%2Ffavicon%2Ffavicon-32.png" width="32" height="32"&gt;
          podcasts.apple.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Read the current per-million rates, then apply them to token counts from a run of your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  When do you turn thinking on?
&lt;/h2&gt;

&lt;p&gt;Leave thinking at minimal when the fast tier already returns the function you needed. Turn it up when you want a fuller answer and you can afford the extra tokens and the wait.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Gemini three Pro, obviously, our flagship model. It has thinking baked in, which means that the answers you're going to get are probably going to be much more fully expressed, but they'll probably take a a lot longer to get you the answer that you're hoping for&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Paige Bailey, AI Developer Relations Lead at Google DeepMind, on &lt;a href="https://chainofthought.show/podcast/47-gemini-3-and-robot-dogs-inside-google-deepminds-ai-experiments-paige-bailey/" rel="noopener noreferrer"&gt;Chain of Thought ep 47&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;On the city lookup, she tied the savings to not using all of the intermediate thinking tokens on that run. Measure the thinking tokens you were billed. Flash still has a switch if a later task needs thinking. Minimal thinking fits a narrow function with an obvious library. Raise it above minimal when the prompt asks for a design, several files, or a justification you will review. One demo where the Python matched does not settle the next prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you estimate the cost of one coding call?
&lt;/h2&gt;

&lt;p&gt;Multiply input tokens and output tokens by the per-million prices you supply for that tier, then pick the cheapest tier that passed a quality check you recorded. On hover, the compare view showed input cost, output cost, and total. The Flash total for that function was less than a penny.&lt;/p&gt;

&lt;p&gt;The sketch below does the same arithmetic. It takes prices as parameters, so you can pass the card you are billed on.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A minimal sketch to adapt, not a drop-in library.&lt;/em&gt;&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call_cost_usd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;input_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;output_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thinking_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;usd_per_million_in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;usd_per_million_out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;billed_out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;output_tokens&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;thinking_tokens&lt;/span&gt;
    &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;input_tokens&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;usd_per_million_in&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;billed_out&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;usd_per_million_out&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1_000_000&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cheapest_tier_that_passed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;runs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;passed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;runs&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;passed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&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;call_cost_usd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input_tokens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output_tokens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;thinking_tokens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;usd_per_million_in&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;usd_per_million_out&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feed it token counts from the two runs, including the thinking tokens you were billed, and the per-million input and output prices from the card you are billed on. Check the billing documentation for how thinking tokens are charged and whether reported output counts already include them. On that compare she tied Flash's lower token use to not using all of the intermediate thinking tokens, and she put Pro's slower answer down to those tokens and its larger size. If nothing passed, the function returns no tier. Change the prompt or the check before you accept the cheap failure.&lt;/p&gt;

&lt;p&gt;Mark a run as passed only from checks you can rerun. The function should do the job, verified by a tiny fixture you wrote. Dependencies should be ones you will ship. Both of her samples pulled in GeoPy; if that is not a dependency you will ship, both runs fail. Latency should fit the product: about one tenth of the wait matters in an inline editor and matters less in a nightly job. Cost at your volume should still look like that penny-scale call once you multiply by how often the path runs. Those figures come from one prompt, so copy the shape of the test.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is Gemini 3 Flash about a quarter of Pro on both input and output?&lt;/strong&gt;&lt;br&gt;
On the comparison Bailey showed, input was about 25% of Pro, and lower than that with a significant number of input tokens. Output was about 25%. Confirm the card for the context length you send.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the fast tier have thinking at all?&lt;/strong&gt;&lt;br&gt;
Pro had thinking baked in, and in that UI the thinking level defaulted to high. Flash let her turn thinking on. She set thinking to minimal for the lat/long prompt. Measure the thinking tokens that call billed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will both tiers emit the same code?&lt;/strong&gt;&lt;br&gt;
On that one prompt, she said the Python was more or less the same and both used GeoPy. Treat that as a single data point. Keep a fixture so a later prompt can fail the bar even when it is cheap.&lt;/p&gt;
&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Run one real coding prompt on the fast tier with thinking minimal and on the flagship with thinking at its default.&lt;/li&gt;
&lt;li&gt;Record input tokens, output tokens, wall time, and total cost from the run.&lt;/li&gt;
&lt;li&gt;Use about 25% of Pro on input and on output only as the ratio Bailey showed, and pass today's per-million prices into your own estimator.&lt;/li&gt;
&lt;li&gt;Raise thinking above minimal when the short answer is too thin, and count the thinking tokens you were billed.&lt;/li&gt;
&lt;li&gt;Ship the cheapest tier that passed your fixture, dependency check, latency limit, and budget.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full conversation, with the transcript, is on &lt;a href="https://chainofthought.show/podcast/47-gemini-3-and-robot-dogs-inside-google-deepminds-ai-experiments-paige-bailey/" rel="noopener noreferrer"&gt;Chain of Thought&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/Im_clTlqvyk" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://newsletter.chainofthought.show/subscribe?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=newsletter" rel="noopener noreferrer"&gt;Subscribe to the Chain of Thought newsletter&lt;/a&gt; for new episodes and write-ups like this one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI assistance from the episode transcripts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>python</category>
      <category>programming</category>
    </item>
    <item>
      <title>Count transcript tags in a podcast RSS feed</title>
      <dc:creator>Conor Bronsdon</dc:creator>
      <pubDate>Sat, 31 Oct 2026 15:30:08 +0000</pubDate>
      <link>https://dev.to/conorbronsdon/count-transcript-tags-in-a-podcast-rss-feed-1d94</link>
      <guid>https://dev.to/conorbronsdon/count-transcript-tags-in-a-podcast-rss-feed-1d94</guid>
      <description>&lt;p&gt;Five of eight AI podcasts in a June 11, 2026 feed audit declared zero transcripts in RSS. Across the 2,148 items those feeds served, 190 carried at least one podcast:transcript tag (8.8%). An absent tag does not establish whether a transcript exists on a website, video platform, or elsewhere. If you ship a feed, or you parse one, count the tag and keep the count inside what a declaration can mean.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does a podcast:transcript tag declare?
&lt;/h2&gt;

&lt;p&gt;The Podcasting 2.0 transcript tag links to a transcript or captions file. It tells apps, directories, and crawlers where the text of an episode lives. The figures below come from a benchmark of public RSS feeds and Apple's iTunes lookup API, fetched 2026-06-11. That write-up sits with the other original-data reports on the &lt;a href="https://chainofthought.show/reports/" rel="noopener noreferrer"&gt;reports page&lt;/a&gt;. The audit counts declarations. It does not test which answer engines consume them, whether the linked files work, or whether adding tags changes citations or search traffic.&lt;/p&gt;

&lt;p&gt;A September 5 clarification narrows how to read the original June data. It adds no new feed observations and makes no claim about current coverage or measured search impact. Use these percentages as a snapshot.&lt;/p&gt;

&lt;p&gt;Chain of Thought publishes a full transcript on its site for every episode, which is also why this report exists. The feed tag is a separate check from the page on the site.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you count tagged items in a feed?
&lt;/h2&gt;

&lt;p&gt;Transcript availability in the audit is the percent of in-feed episodes carrying at least one podcast:transcript tag. Catalog depth came from Apple trackCount. In this run, every show's feed served its full archive, so feed item counts matched those catalog counts, and feed-derived metrics cover whole catalogs. Some hosts cap feeds to recent items. This run was not truncated. A re-run on other shows should check that before you treat the item count as the whole catalog.&lt;/p&gt;

&lt;p&gt;The sketch only counts tags in XML you already have. It does not fetch a feed, and it does not open the URL on the tag. It is an illustration, not the command-line tool that produced the benchmark.&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;# Sketch only. Counts item-level transcript tags in RSS XML you already have.
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;xml.etree.ElementTree&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_is_transcript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tag&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&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="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rsplit&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&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;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;transcript&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:transcript&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;count_transcript_tags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xml_text&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xml_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;channel&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;item&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;tagged&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;_is_transcript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tag&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;child&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
            &lt;span class="n"&gt;tagged&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;tagged&lt;/span&gt;&lt;span class="p"&gt;,&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;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'd start with that pair: tagged items, then items the feed served. Percent is tagged divided by items. That is how 190 of 2,148 became 8.8%. The pooled percent weights every feed item equally, so a large catalog moves the total more than a small one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What did the eight-show snapshot report?
&lt;/h2&gt;

&lt;p&gt;The benchmark sets Chain of Thought against seven AI engineering podcasts: Latent Space, Practical AI, The TWIML AI Podcast, Gradient Dissent, AI Engineering Podcast, No Priors, and The Cognitive Revolution. Every number comes from those public feeds and the Apple lookup, collected 2026-06-11 (07:26 UTC).&lt;/p&gt;

&lt;p&gt;Five shows declared zero transcripts: Latent Space (0 of 207), The TWIML AI Podcast (0 of 787), Gradient Dissent (0 of 137), No Priors (0 of 166), and The Cognitive Revolution (0 of 349). Chain of Thought led at 98.4% (61 of 62). Its untagged item was the trailer. AI Engineering Podcast followed at 93.7% (74 of 79). Practical AI was at 15.2% (55 of 361).&lt;/p&gt;

&lt;p&gt;The 8.8% aggregate weights items equally. The TWIML AI Podcast accounts for 787 of the 2,148 sampled items and had no transcript declarations. Read the pooled count beside the per-show table. Neither the aggregate nor this peer set estimates adoption across all AI podcasts.&lt;/p&gt;

&lt;p&gt;Chain of Thought and Practical AI both used Transistor feed URLs and still differed sharply. A hosting provider's name alone cannot explain that. Hosting support, configuration, and catalog history are possible explanations. They were not measured.&lt;/p&gt;

&lt;p&gt;A feed score is also silent on episode subject. For a separate list of episodes on how AI agents get built, deployed, and evaluated, see &lt;a href="https://chainofthought.show/best-ai-agent-podcast-episodes/" rel="noopener noreferrer"&gt;the best AI agent podcast episodes&lt;/a&gt;. If you want five Latent Space episodes paired with a Chain of Thought episode on the question next door, that page is &lt;a href="https://chainofthought.show/podcasts-like-latent-space/" rel="noopener noreferrer"&gt;podcasts like Latent Space&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does the percentage fail to prove?
&lt;/h2&gt;

&lt;p&gt;Here, 0% means zero transcript declarations in the sampled feed. A show can publish transcripts on its website without emitting the tag, and then it reads as 0% here. The metric measures feed-declared transcripts, not every transcript that exists.&lt;/p&gt;

&lt;p&gt;Declared transcript URLs were not validated for availability, format correctness, or transcript accuracy. Declaration coverage does not establish usable transcript coverage. A tag exposes a link to applications that support it. The audit does not establish which applications use the link or how they rank the episode.&lt;/p&gt;

&lt;p&gt;High declaration coverage does not establish an advantage in audience reach or AI citations. Testing that relationship would require separate outcome measurements and a design that accounts for other differences between shows. The report says nothing about audience size. Download numbers stay private to each show, and the audit left them out because estimating them would make the report worthless.&lt;/p&gt;

&lt;p&gt;This is a point-in-time snapshot of eight shows chosen as Chain of Thought's peer set. It is not a census of AI podcasts, and a different peer set would shift the rankings. Catalog counts can differ by a few episodes between sources depending on trailers and crawl timing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Count items with at least one podcast:transcript tag, then divide by items that feed served.&lt;/li&gt;
&lt;li&gt;Date the fetch. These figures are from 2026-06-11, and the September 5 note adds no new feed observations.&lt;/li&gt;
&lt;li&gt;Read 0% as no declaration in that feed. A website or video transcript can still exist.&lt;/li&gt;
&lt;li&gt;Put the pooled 8.8% next to per-show counts. Large feeds, including TWIML's 787 items, move an equal-weighted total.&lt;/li&gt;
&lt;li&gt;Stop before claiming the linked file works, that any app consumes it, or that the tag changes citations or search traffic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More on this topic, with the related episodes, is on &lt;a href="https://chainofthought.show/reports/state-of-ai-podcast-feeds-2026/" rel="noopener noreferrer"&gt;Chain of Thought&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://newsletter.chainofthought.show/subscribe?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=newsletter" rel="noopener noreferrer"&gt;Subscribe to the Chain of Thought newsletter&lt;/a&gt; for new episodes and write-ups like this one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI assistance from the episode transcripts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>podcast</category>
      <category>rss</category>
      <category>python</category>
      <category>ai</category>
    </item>
    <item>
      <title>Four agent metrics that a final accuracy score hides</title>
      <dc:creator>Conor Bronsdon</dc:creator>
      <pubDate>Fri, 30 Oct 2026 20:30:10 +0000</pubDate>
      <link>https://dev.to/conorbronsdon/four-agent-metrics-that-a-final-accuracy-score-hides-1mf1</link>
      <guid>https://dev.to/conorbronsdon/four-agent-metrics-that-a-final-accuracy-score-hides-1mf1</guid>
      <description>&lt;p&gt;Score every recorded agent run on four process checks: constraint satisfaction, tool-call correctness, loop termination, and escalation to a human. Compute each one from the trace: which declared constraints passed, whether every tool call had a valid tool and valid parameters, whether the run reached a stop state, and whether a human took over.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://chainofthought.show/guests/chip-huyen/" rel="noopener noreferrer"&gt;Chip Huyen&lt;/a&gt;, then a storyteller at Tép Studio, and &lt;a href="https://chainofthought.show/guests/vivienne-zhang/" rel="noopener noreferrer"&gt;Vivienne Zhang&lt;/a&gt; of NVIDIA, spelled out those failure points on Chain of Thought in December 2024. &lt;a href="https://chainofthought.show/guests/alex-ratner/" rel="noopener noreferrer"&gt;Alex Ratner&lt;/a&gt;, co-founder and CEO of Snorkel AI, described the measurement shortfall from the other side in April 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you check that an agent stayed inside the constraints?
&lt;/h2&gt;

&lt;p&gt;Write the constraints down before the run, then score the trace against that list. Chip Huyen's planning example is a two-week trip with a budget of 5,000. The plan has to cover two weeks and stay inside that budget. A fluent itinerary that breaks the budget fails.&lt;/p&gt;

&lt;p&gt;Long outputs need the same item-by-item check. Alex Ratner described legal deep-research tasks that might take a human five, 10, or 15 hours, with multiple tools and multiple citations. Compare that with a math item whose output is a single number you can check against an answer key. For a 30-page PDF with 50 citations, you need a grading rubric, because you cannot settle the output by asking whether A equals B. Store each rubric item as a boolean on the run. Constraint satisfaction is true only when every item you declared has passed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;whenever I try to evaluate some use case, I would probably try to break down, like, how is this application going to fail. It tries to put in a lot of evaluation metrics around the points of failures.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Chip Huyen, then Storyteller at Tép Studio, on &lt;a href="https://chainofthought.show/podcast/5-practical-lessons-for-genai-evals-chip-huyen-and-vivienne-zhang/" rel="noopener noreferrer"&gt;Chain of Thought ep 5&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://podcasts.apple.com/us/podcast/practical-lessons-for-genai-evals-chip-huyen-vivienne/id1776879655?i=1000679197746" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fis1-ssl.mzstatic.com%2Fimage%2Fthumb%2FPodcasts221%2Fv4%2Fcc%2F85%2F59%2Fcc8559ce-8691-bb36-6e07-8a43f3fec194%2Fmza_7177186496906926317.jpg%2F1200x1200ECA.PESS01-60.jpg%3FimgShow%3DPodcasts221%2Fv4%2Fee%2Ff2%2F1b%2Feef21b19-f090-f9b4-fc85-ffc84f80fad7%2Fmza_6548396687882944514.jpg" height="800" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://podcasts.apple.com/us/podcast/practical-lessons-for-genai-evals-chip-huyen-vivienne/id1776879655?i=1000679197746" rel="noopener noreferrer" class="c-link"&gt;
            Practical Lessons for GenAI Ev… - Chain of Thought | AI Agents, Infrastructure &amp;amp; Engineering - Apple Podcasts
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Podcast Episode · Chain of Thought | AI Agents, Infrastructure &amp;amp; Engineering · December 4, 2024 · 48m
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpodcasts.apple.com%2Fassets%2Ffavicon%2Ffavicon-32.png" width="32" height="32"&gt;
          podcasts.apple.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How do you measure tool-call correctness?
&lt;/h2&gt;

&lt;p&gt;Count a tool call as correct only when the tool is valid and the parameters are valid. Chip Huyen named both misses. The agent calls a tool it does not have, or it calls the right tool with the wrong parameters. In the weather case, the model has to extract a location and a time, and those values have to be valid. The right tool name with a bad location still fails the call.&lt;/p&gt;

&lt;p&gt;Log each call as that pair. The run passes tool-call correctness when every call passes both halves. When the task requires a specific tool, put that requirement on the constraint list, so a run that never calls anything does not pass on an empty call list.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you tell a finished loop from a run that does not stop?
&lt;/h2&gt;

&lt;p&gt;Mark the run terminated only when it reached a stop state, and store the step count beside that flag. Chip Huyen described a very long sequence of actions that might go on and on and fail to stop in the time available. Alex Ratner treats length as its own axis. Autonomy horizon is the number of steps a task needs, including goals that change while the task is running. A coding challenge with one unit-test answer is the short end. The long end is a multi-turn task with shifting specifications. Measuring out to the length of a real-world task is still at the frontier. Very few public benchmarks test it, and most of those are unsaturated.&lt;/p&gt;

&lt;p&gt;Pick a step cap for the task before you score a suite. Hitting the cap without a stop state fails loop termination. Report the termination rate and the step counts together so a prompt or model change that lengthens the path is visible.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A minimal sketch to adapt, not a drop-in library.&lt;/em&gt;&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;score_agent_runs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;runs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;runs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&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;runs&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;tool_calls_ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&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;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;valid_tool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;valid_params&lt;/span&gt;&lt;span class="sh"&gt;"&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;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_calls&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;constraint_satisfaction&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sum&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;constraints_met&lt;/span&gt;&lt;span class="sh"&gt;"&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;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;runs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_call_correctness&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;tool_calls_ok&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;runs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;loop_termination&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sum&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;terminated&lt;/span&gt;&lt;span class="sh"&gt;"&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;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;runs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mean_steps&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sum&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;steps&lt;/span&gt;&lt;span class="sh"&gt;"&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;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;runs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;human_escalation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sum&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;escalated&lt;/span&gt;&lt;span class="sh"&gt;"&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;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;runs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fill each &lt;code&gt;run&lt;/code&gt; from your own logs. &lt;code&gt;constraints_met&lt;/code&gt; is true when every constraint you declared passed. Each entry in &lt;code&gt;tool_calls&lt;/code&gt; carries &lt;code&gt;valid_tool&lt;/code&gt; and &lt;code&gt;valid_params&lt;/code&gt;. An empty call list makes &lt;code&gt;tool_calls_ok&lt;/code&gt; true, so a required tool belongs on the constraint list. &lt;code&gt;terminated&lt;/code&gt; is true only when the run reached a stop state within your step cap, and &lt;code&gt;steps&lt;/code&gt; is how many steps it took. &lt;code&gt;escalated&lt;/code&gt; is true when a human took the task over.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;And yet, you can ask a coding agent to do a much more mundane-seeming task, but one that has messier inputs and messier outputs and a longer set of steps required, and it might fall down.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Alex Ratner, Co-founder and CEO at Snorkel AI, on &lt;a href="https://chainofthought.show/podcast/57-every-ai-agent-has-an-evaluation-gap-alex-ratner-snorkel-ai/" rel="noopener noreferrer"&gt;Chain of Thought ep 57&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When should escalation to a human be its own metric?
&lt;/h2&gt;

&lt;p&gt;Count a handoff when the agent stops and sends the task to a person. Vivienne Zhang's familiar case is a customer-service chatbot. It keeps handling queries until it can no longer deal with the complexity, then sends the query to a human. Getting that handoff to a good user experience takes iteration on those same failure points. In the split she described, the human defines the goals and the parameters, and the agent carries out the means. Track how often a person reclaimed the task, and open the traces when that rate jumps after a prompt change.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;And you will keep handling your queries until it decides it can no longer deal with the complexity of the query. And then you will send the query to a human and that will be the human in the loop.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Vivienne Zhang of NVIDIA, on &lt;a href="https://chainofthought.show/podcast/5-practical-lessons-for-genai-evals-chip-huyen-and-vivienne-zhang/" rel="noopener noreferrer"&gt;Chain of Thought ep 5&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is a constraint check on an agent plan?&lt;/strong&gt;&lt;br&gt;
A pass or fail against limits you set before the run. Chip Huyen used a two-week trip with a budget of 5,000: the plan has to cover the two weeks and stay inside the budget. For a long document, Alex Ratner said a rubric replaces a single answer-key comparison, as with a 30-page PDF that carries 50 citations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What makes a tool call incorrect?&lt;/strong&gt;&lt;br&gt;
An invalid tool, or the right tool with invalid parameters. A weather call that does not extract a valid location and time fails the parameter half even when the tool name was right.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What handoff rate should I target?&lt;/strong&gt;&lt;br&gt;
Set it per task. Vivienne Zhang described a chatbot that hands off when the query is too complex, and that handoff should be evaluated on the same failure points as the rest of the agent. The target is a product decision for your own task.&lt;/p&gt;
&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Declare every constraint before the run, and store a boolean for each one.&lt;/li&gt;
&lt;li&gt;Pass a tool call only when the tool and the parameters are both valid.&lt;/li&gt;
&lt;li&gt;If the task requires a tool, put that requirement on the constraint list.&lt;/li&gt;
&lt;li&gt;Store a step count and a terminated flag, and set the step cap before you score the suite.&lt;/li&gt;
&lt;li&gt;Store whether a human took the task over, and read that rate with the other three.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The longer explainer, with the episode clips, is on &lt;a href="https://chainofthought.show/ai-decoded/ai-agent-metrics-beyond-accuracy/" rel="noopener noreferrer"&gt;Chain of Thought&lt;/a&gt;. It draws on &lt;a href="https://chainofthought.show/podcast/57-every-ai-agent-has-an-evaluation-gap-alex-ratner-snorkel-ai/" rel="noopener noreferrer"&gt;this episode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/aOd_HRre7bc" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://newsletter.chainofthought.show/subscribe?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=newsletter" rel="noopener noreferrer"&gt;Subscribe to the Chain of Thought newsletter&lt;/a&gt; for new episodes and write-ups like this one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI assistance from the episode transcripts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>testing</category>
      <category>llm</category>
    </item>
    <item>
      <title>What to change when agents write most of the code</title>
      <dc:creator>Conor Bronsdon</dc:creator>
      <pubDate>Fri, 30 Oct 2026 15:30:07 +0000</pubDate>
      <link>https://dev.to/conorbronsdon/what-to-change-when-agents-write-most-of-the-code-1i0b</link>
      <guid>https://dev.to/conorbronsdon/what-to-change-when-agents-write-most-of-the-code-1i0b</guid>
      <description>&lt;p&gt;When agents write most of the code, the scarce work moves downstream. Generation gets cheap, and the bottleneck moves to review and merge. In my reading, onboarding and choosing what is worth building get more expensive too. Five episodes on Chain of Thought each point at one change I would make in that world.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should you review when you stop reading every line?
&lt;/h2&gt;

&lt;p&gt;Anush Elangovan, Corporate VP of AI Software at AMD, lays this out on &lt;a href="https://chainofthought.show/podcast/56-250-000-lines-of-code-week-inside-an-amd-vps-agent-first-workflow-anush-elangovan/" rel="noopener noreferrer"&gt;250,000 Lines of Code a Week&lt;/a&gt;. He runs 10 to 12 Claude Code agents across three machines and burns 6.5 billion tokens a week. The claim I keep from that episode is that testing is the new code review. The chapter list frames the habit as 80% tests first. He argues that normal SDLC is dead in an agentic world, and that software comes down to tokens. In his account, speed is the only durable moat. The same conversation covers a 25-year-old Slurm replacement, rewritten as Spur in Rust in a single night, without opening the editor. An earlier chapter asks when AI-generated code becomes a liability. He describes agents as sneaky and dumb, and he runs them with dangerously-skip-permissions. I would leave that flag as his risk setting. I would start by requiring tests before an agent is allowed to widen the change.&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;# Sketch: a local check before merging agent output.
# Not a workflow used by any guest or company on these episodes.
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;merge_allowed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;change&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;change&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;tests_written_first&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;change&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;tests_passed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How do you merge when agents open pull requests in the background?
&lt;/h2&gt;

&lt;p&gt;Greg Foster, co-founder and CTO of Graphite, describes the review bottleneck on &lt;a href="https://chainofthought.show/podcast/40-after-code-gen-what-graphite-is-building-for-the-post-ai-dev-stack-greg-foster/" rel="noopener noreferrer"&gt;After Code Gen&lt;/a&gt;. He argues that the bottleneck has moved from writing code to reviewing it, once agents open pull requests in the background faster than humans can merge them. He outlines three waves of AI that lead to autonomous agents spawning those pull requests. He argues that as AI automates the inner loop of writing code, the outer loop of reviewing, merging, and deploying comes under pressure. The tactic I would copy is stacking. Split a large change into units small enough for a human or an agent to review. He also identifies a hiring gap. Experienced engineers with strong architectural context become lethal with AI tools. If you hold that context, spend it on how changes are split and how they land.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you onboard an agent that will own most of a day?
&lt;/h2&gt;

&lt;p&gt;Sterling Chin, Applied AI Engineer and Senior Developer Advocate at Postman, treats staffing as the method on &lt;a href="https://chainofthought.show/podcast/50-i-built-an-ai-coworker-that-runs-90-of-my-day/" rel="noopener noreferrer"&gt;I Built an AI Coworker That Runs 90% of My Day&lt;/a&gt;. He stopped thinking of AI as a tool and started treating it like a junior employee. He onboarded it with context, corrected its mistakes, and gave it writing rules. Forty days later, MARVIN, built on Claude Code, was handling 90% of his workday. The episode is built around live demos. MARVIN bookends the day from first login to the end, using personality, sub-agents, and writing rules. The demos run from meeting transcripts to Jira tickets, drafted posts, and calendar management. Show notes call MARVIN a full-time AI chief of staff. Sterling has onboarded 12 or more colleagues at Postman, including non-technical knowledge workers, and he argues that DIY assistants outperform big tech alternatives. I would start with one assistant, written rules, and a correction habit. At a fixed checkpoint, count how much of the day it actually runs. Forty days and 90% are his reported outcome.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should a coding model be scored on?
&lt;/h2&gt;

&lt;p&gt;Jason Warner and Eiso Kant, CEO and CTO of Poolside, make the training case on &lt;a href="https://chainofthought.show/podcast/23-first-code-then-agi-softwares-event-horizon-with-poolside-founders-jason-warner-and-eiso-k/" rel="noopener noreferrer"&gt;First Code, Then AGI&lt;/a&gt;. They explain why Poolside trains for code specifically instead of general capability, and what reinforcement learning against real execution feedback buys a model. They believe synthetic data will help expand the surface area of software by 1000x. Their focus includes high-consequence systems. On the human side, they argue that agency, taste, and judgment become central for engineers working with AI coworkers. The buying decision I would make is narrow. Prefer a coding agent whose feedback loop includes real execution, and keep a person with taste on whether the passing behavior is the one you wanted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where should you point agents if you want a measurable payback?
&lt;/h2&gt;

&lt;p&gt;Rachelle Palmer, Director of Product Management at MongoDB, covers the least glamorous case on &lt;a href="https://chainofthought.show/podcast/14-using-ai-to-modernize-your-legacy-applications-mongodbs-rachelle-palmer/" rel="noopener noreferrer"&gt;Using AI to Modernize Your Legacy Applications&lt;/a&gt;. The collection page describes pointing AI at legacy codebases as one of the few coding-agent uses with an obvious payback measured in years off a timeline. Her forward-deployed AI engineering team works on complex, outdated codebases. She details LLMs automating documentation improvements, test generation, and business logic conversion. In her account, modernization timelines drop from years to months, and work that once demanded teams of dozens can be done by a small team. I would start on a legacy system already stuck on a multi-year plan. Constrain the agent to documentation, tests, or a bounded logic conversion, then compare the calendar you had with the calendar you have.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Make testing the review gate. Anush Elangovan's episode frames this as tests first, with agents he describes as sneaky and dumb.&lt;/li&gt;
&lt;li&gt;Stack changes into reviewable units, the tactic Greg Foster gives once background pull requests are the bottleneck.&lt;/li&gt;
&lt;li&gt;Onboard one assistant like a junior employee, with context, corrections, and writing rules, then check results on a set day, as Sterling Chin reported after forty days.&lt;/li&gt;
&lt;li&gt;Prefer coding models trained with reinforcement learning on real execution feedback, the bet Jason Warner and Eiso Kant describe, and keep taste with a human.&lt;/li&gt;
&lt;li&gt;Point the first large agent effort at legacy modernization, where Rachelle Palmer describes timelines moving from years to months.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More on this topic, with the related episodes, is on &lt;a href="https://chainofthought.show/collections/best-on-ai-coding/" rel="noopener noreferrer"&gt;Chain of Thought&lt;/a&gt;. It draws on &lt;a href="https://chainofthought.show/podcast/56-250-000-lines-of-code-week-inside-an-amd-vps-agent-first-workflow-anush-elangovan/" rel="noopener noreferrer"&gt;this episode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/oW6seLqm3PU" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://newsletter.chainofthought.show/subscribe?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=newsletter" rel="noopener noreferrer"&gt;Subscribe to the Chain of Thought newsletter&lt;/a&gt; for new episodes and write-ups like this one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI assistance from the episode transcripts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>testing</category>
      <category>codereview</category>
    </item>
    <item>
      <title>The Minimum Agent Loop You Can Ship (and When to Skip It)</title>
      <dc:creator>Conor Bronsdon</dc:creator>
      <pubDate>Thu, 29 Oct 2026 20:30:25 +0000</pubDate>
      <link>https://dev.to/conorbronsdon/the-minimum-agent-loop-you-can-ship-and-when-to-skip-it-1dmb</link>
      <guid>https://dev.to/conorbronsdon/the-minimum-agent-loop-you-can-ship-and-when-to-skip-it-1dmb</guid>
      <description>&lt;p&gt;Most "agents" in production are a loop: the model picks a step, calls a tool, reads the result, and decides whether to stop. Name that loop and its stop condition before you call the thing an agent.&lt;/p&gt;

&lt;p&gt;An &lt;a href="https://chainofthought.show/glossary/ai-agent/" rel="noopener noreferrer"&gt;AI agent&lt;/a&gt; is given a goal and runs until the goal is met or it gives up. A chatbot takes a prompt and returns a response. A bigger model does not turn one into the other. The system around the model does: tools, state, and something that decides "one more step" versus "done." &lt;a href="https://chainofthought.show/guests/vikram-chatterji/" rel="noopener noreferrer"&gt;Vikram Chatterji&lt;/a&gt; described that 2025 shift as generative AI moving from chat completion toward actual task completion.&lt;/p&gt;

&lt;h2&gt;
  
  
  What belongs in the smallest useful loop?
&lt;/h2&gt;

&lt;p&gt;I'd start with four pieces only:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Model: produces the next intent (tool name and arguments, or a final answer).&lt;/li&gt;
&lt;li&gt;Tools: functions that fetch data or have real side effects (search, SQL, creating a ticket).&lt;/li&gt;
&lt;li&gt;Loop: append tool results to state, call the model again.&lt;/li&gt;
&lt;li&gt;Stop condition: max steps, an explicit &lt;code&gt;finish&lt;/code&gt; tool, or a terminal field such as &lt;code&gt;done: true&lt;/code&gt; in the model's JSON.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Memory, multiple models and evals come next, and if production is close, evals belong on day one. &lt;a href="https://chainofthought.show/guests/aishwarya-srinivasan/" rel="noopener noreferrer"&gt;Aishwarya Srinivasan&lt;/a&gt; frames the shift well: production agents are software systems to architect, and a benchmark winner alone will not get you there.&lt;/p&gt;

&lt;p&gt;The following is a sketch (not production code, no real SDK):&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;# Sketch: minimum agent loop (illustration only)
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;

&lt;span class="n"&gt;MAX_STEPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&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;Callable&lt;/span&gt;&lt;span class="p"&gt;[...,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]]&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;search_docs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;q&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;results for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="si"&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;finish&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;answer&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;answer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;answer&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;run_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;goal&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="o"&gt;-&amp;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;messages&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;role&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;user&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;goal&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;step&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAX_STEPS&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;plan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;model_next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# your LLM wrapper
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;plan&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;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;final&lt;/span&gt;&lt;span class="sh"&gt;"&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;plan&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;plan&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;args&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&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;tool&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&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;unknown tool: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&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;tool&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;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
        &lt;span class="k"&gt;if&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;finish&lt;/span&gt;&lt;span class="sh"&gt;"&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;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stopped: max steps&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the operational shape of an &lt;a href="https://chainofthought.show/glossary/agentic-workflow/" rel="noopener noreferrer"&gt;agentic workflow&lt;/a&gt;: chained decisions toward a goal, with the model choosing the next move inside bounds you set.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does this relate to ReAct?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://chainofthought.show/glossary/react-reason-act/" rel="noopener noreferrer"&gt;ReAct (Reason + Act)&lt;/a&gt; interleaves reasoning with one action at a time: reason, act, observe, repeat. Your sketch does not need the model to print long reasoning traces, but the control flow is the same. The model does not plan the full path up front; it reacts to what came back from the last tool call.&lt;/p&gt;

&lt;p&gt;That adaptability has a cost. In a reason-act loop, an agent with incomplete context can keep firing queries against data it cannot access, without ever reasoning its way to "I can't answer this." Before you widen tool access, tighten the stop rules and cap steps. Autonomy without bounds is how you get runaway tool and query volume.&lt;/p&gt;

&lt;h2&gt;
  
  
  When should I use a loop instead of a fixed workflow?
&lt;/h2&gt;

&lt;p&gt;Use a fixed workflow (scripted steps, deterministic branches) when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The path is known before runtime (same steps, same order, every time).&lt;/li&gt;
&lt;li&gt;Mistakes are cheap and easy to undo.&lt;/li&gt;
&lt;li&gt;You can test every branch without the model inventing new ones.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use the minimum loop when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The number of steps depends on the user's goal or on tool output you cannot predict.&lt;/li&gt;
&lt;li&gt;The model must choose among several tools based on intermediate results.&lt;/li&gt;
&lt;li&gt;You are okay trading predictability for flexibility, and you will add checks later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not reach for a loop because "agents" are the product story. Reach for it when a single prompt or a rigid pipeline cannot reach the goal without repeated tool use. Most shipping teams let the model decide within bounded steps, with guardrails and evaluation at each stage, rather than running a free agent. That middle ground is where a lot of practical building on &lt;a href="https://chainofthought.show/topics/ai-agents/" rel="noopener noreferrer"&gt;AI agents&lt;/a&gt; actually lives.&lt;/p&gt;

&lt;h2&gt;
  
  
  What do I add after the loop runs once?
&lt;/h2&gt;

&lt;p&gt;The canonical "chatbot to agent" stack names four production layers beyond the loop itself: orchestration across models, memory and context, tools, and evals with guardrails. The loop is the engine; those layers are how it stays trustworthy.&lt;/p&gt;

&lt;p&gt;For builders stepping from demos to systems, Aishwarya Srinivasan's line is the guardrail I keep in mind:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It is not a model that you are surfacing to your user. It is a software. It is a system that you're surfacing to your user&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Aishwarya Srinivasan, Fireworks AI, on Chain of Thought ep 42&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Her production rule from the same conversation theme: quantify each step so when something breaks, you can see where and why. Your first loop can log step index, tool name, and latency before you add fancy evals.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;So the short answer is trying to quantify anything and everything in that system that you're building.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Aishwarya Srinivasan, Fireworks AI, on Chain of Thought ep 42&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Can I write the happy path as a fixed DAG without a loop? If yes, start there.&lt;/li&gt;
&lt;li&gt;If I need a loop, do I have a named stop condition (max steps, &lt;code&gt;finish&lt;/code&gt; tool, or explicit terminal state)?&lt;/li&gt;
&lt;li&gt;Are tool schemas small and bounded so the model cannot call arbitrary endpoints?&lt;/li&gt;
&lt;li&gt;Does each iteration append observations to state so the model can recover from a bad tool call?&lt;/li&gt;
&lt;li&gt;Before scaling users, do I log every step so I can trace failures (even if evals come later)?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The longer explainer, with the episode clips, is on &lt;a href="https://chainofthought.show/ai-decoded/what-makes-an-ai-agent/" rel="noopener noreferrer"&gt;Chain of Thought&lt;/a&gt;. It draws on &lt;a href="https://chainofthought.show/podcast/42-architecting-ai-agents-the-shift-from-models-to-systems-aishwarya-srinivasan/" rel="noopener noreferrer"&gt;this episode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://newsletter.chainofthought.show/subscribe?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=newsletter" rel="noopener noreferrer"&gt;Subscribe to the Chain of Thought newsletter&lt;/a&gt; for new episodes and write-ups like this one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI assistance from the episode transcripts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>llm</category>
      <category>python</category>
    </item>
    <item>
      <title>Measure an AI agent before you call it ready to ship</title>
      <dc:creator>Conor Bronsdon</dc:creator>
      <pubDate>Thu, 29 Oct 2026 15:30:11 +0000</pubDate>
      <link>https://dev.to/conorbronsdon/measure-an-ai-agent-before-you-call-it-ready-to-ship-23e7</link>
      <guid>https://dev.to/conorbronsdon/measure-an-ai-agent-before-you-call-it-ready-to-ship-23e7</guid>
      <description>&lt;p&gt;The Chain of Thought collection on AI evaluation has five episodes. Read in order, they make a ship gate: define the measurement, engineer the eval, check the trust bar, wire the eval into release, and seed it with the failures that matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I know the agent is still a demo?
&lt;/h2&gt;

&lt;p&gt;An agent that looks finished in a demo is often unmeasured. On &lt;a href="https://chainofthought.show/podcast/57-every-ai-agent-has-an-evaluation-gap-alex-ratner-snorkel-ai/" rel="noopener noreferrer"&gt;Every AI Agent Has an Evaluation Gap&lt;/a&gt;, Alex Ratner of Snorkel AI frames the evaluation gap as a hypothesis: AI capabilities have advanced faster than our ability to define and measure them precisely. The collection page ties that gap to the moment an agent leaves the demo, when capability has outpaced measurement.&lt;/p&gt;

&lt;p&gt;Ratner maps the gap as what blocks agents from real enterprise work. In the same episode he walks through Snorkel's $3M Open Benchmarks Grant and explains why pure environment vendors don't actually understand how AI works. I would not treat an environment as a substitute for a measurement. If I cannot write down what better means on the task, the agent stays a demo.&lt;/p&gt;

&lt;p&gt;Before I widen a rollout, I write a short definition of the task and a score I can recompute. If I cannot define the measurement, I cannot tell whether a change helped, and I cannot defend a deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  When does an eval deserve to run on the request path?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://chainofthought.show/podcast/46-explaining-eval-engineering-galileos-vikram-chatterji/" rel="noopener noreferrer"&gt;Explaining Eval Engineering&lt;/a&gt; with Vikram Chatterji treats evaluation as an engineering discipline. The episode summary describes the common habit: teams write evals like unit tests, check a box, and move on. That habit fails for agents that make real decisions for customers and spend real money. The marker I would follow is to author, test, and measure the evals.&lt;/p&gt;

&lt;p&gt;The episode page adds that once an eval is accurate enough, it can run as a runtime control. I would author the eval, test it on cases I already understand, and measure how often it matches a reviewer. Only then would I put it on the request path. One green run does not justify that step.&lt;/p&gt;

&lt;h2&gt;
  
  
  What latency bar should I write down?
&lt;/h2&gt;

&lt;p&gt;Trust is the bar for shipping agents. That is how the collection page frames &lt;a href="https://chainofthought.show/podcast/32-the-ai-agent-trust-gap-bridging-risk-to-reliability-elastics-philipp-krenn/" rel="noopener noreferrer"&gt;The AI Agent Trust Gap&lt;/a&gt; with Philipp Krenn of Elastic. He recalls a 200-millisecond Elasticsearch query that once felt unacceptably slow, while a five-second LLM answer is now treated as perfectly fine. I would record both numbers for any system under review. The latency older search work rejected, and the latency the model is allowed to use, are one view of the trust gap.&lt;/p&gt;

&lt;p&gt;If a five-second answer is being treated as fine, I want that decision written down next to the 200-millisecond bar Krenn remembers, with a guardrail on the same path as the agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where should the eval sit when we ship?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://chainofthought.show/podcast/13-ai-in-2025-agents-and-the-rise-of-evaluation-driven-development-ft-dev-interrupted/" rel="noopener noreferrer"&gt;How Engineering Leaders Can Future-Proof Their AI Strategy&lt;/a&gt; is a re-shared conversation with &lt;a href="https://chainofthought.show/guests/andrew-zigler/" rel="noopener noreferrer"&gt;Andrew Zigler&lt;/a&gt; about evaluation-driven development, and the collection page states its case plainly: build the eval loop into how you ship.&lt;/p&gt;

&lt;p&gt;I would make that loop a rule of the pipeline. A change to the agent runs its eval before release, and a failed eval has a named owner. I would delay a release until that run is part of the ship.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which failure belongs in the first eval set?
&lt;/h2&gt;

&lt;p&gt;The collection page calls &lt;a href="https://chainofthought.show/podcast/5-practical-lessons-for-genai-evals-chip-huyen-and-vivienne-zhang/" rel="noopener noreferrer"&gt;Practical Lessons for GenAI Evals&lt;/a&gt; the most-cited starting point for evals on the show. Chip Huyen and Vivienne Zhang discuss practical GenAI evaluation as agents and multimodal models become more common. Generative AI is harder to assess than traditional software.&lt;/p&gt;

&lt;p&gt;The first case I would save comes from Chip Huyen's account of LinkedIn's job-fit bot. Asked if someone was a good fit for a role, it answered that they were a terrible fit. That reply finishes the question and still fails a user-facing eval. I want a set that includes judgment failures of that kind.&lt;/p&gt;

&lt;p&gt;The episode also covers objective criteria for open-ended tasks, hallucinations, and human-in-the-loop systems. I would score a small set with criteria a second person can apply, and I would keep a person in the loop until the eval is accurate enough to act as a runtime control.&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;# Sketch only: the order of checks above. Not a guest's system or a vendor SDK.
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ship_gate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;measurement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eval_report&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trust&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ship_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cases&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;measurement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;demo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;authored&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eval_report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authored&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;eval_report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tested&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;eval_report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;measured&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;authored&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prototype&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;eval_report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;accurate_enough&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;eval_report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;use_as_runtime_control&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;trust&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;five_second_answer_treated_as_fine&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;trust&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;old_bar_was_stricter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trust_review&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;ship_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eval_runs_before_release&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eval_outside_ship_path&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;harmful_judgment&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cases&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hold&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ship&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Write the measurement before the agent leaves the demo. If capability is ahead of that definition, you are still in the evaluation gap.&lt;/li&gt;
&lt;li&gt;Author, test, and measure the eval. Use it as a runtime control only after it is accurate enough.&lt;/li&gt;
&lt;li&gt;Record the latency you used to reject and the latency you now accept. Krenn's contrast is about 200 milliseconds versus a five-second answer.&lt;/li&gt;
&lt;li&gt;Run the eval before release, with a named owner for failures, so the loop is part of how you ship.&lt;/li&gt;
&lt;li&gt;Seed the set with judgment failures, such as a job-fit bot that tells someone they are a terrible fit, and keep a person in the loop until the eval earns the runtime role.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More on this topic, with the related episodes, is on &lt;a href="https://chainofthought.show/collections/best-on-ai-evals/" rel="noopener noreferrer"&gt;Chain of Thought&lt;/a&gt;. It draws on &lt;a href="https://chainofthought.show/podcast/57-every-ai-agent-has-an-evaluation-gap-alex-ratner-snorkel-ai/" rel="noopener noreferrer"&gt;this episode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/aOd_HRre7bc" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://newsletter.chainofthought.show/subscribe?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=newsletter" rel="noopener noreferrer"&gt;Subscribe to the Chain of Thought newsletter&lt;/a&gt; for new episodes and write-ups like this one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI assistance from the episode transcripts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>agents</category>
      <category>testing</category>
    </item>
    <item>
      <title>Lint your technical drafts for AI writing tells before you publish</title>
      <dc:creator>Conor Bronsdon</dc:creator>
      <pubDate>Wed, 28 Oct 2026 20:30:07 +0000</pubDate>
      <link>https://dev.to/conorbronsdon/lint-your-technical-drafts-for-ai-writing-tells-before-you-publish-1jg2</link>
      <guid>https://dev.to/conorbronsdon/lint-your-technical-drafts-for-ai-writing-tells-before-you-publish-1jg2</guid>
      <description>&lt;p&gt;A draft about your retrieval layer can read like a launch announcement and still say nothing you could test. Checking the prose is cheap. Checking the engineering claim is a different job. I treat AI-writing lint the way I treat a style checker on code: fast feedback on patterns, and zero proof that the logic is right.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does fluent technical writing fool you first?
&lt;/h2&gt;

&lt;p&gt;A &lt;a href="https://chainofthought.show/glossary/large-language-model/" rel="noopener noreferrer"&gt;large language model&lt;/a&gt; is trained to produce likely text, not verified text, so a polished explanation can be wrong and still read like documentation. Dan Klein, co-founder and CTO of Scaled Cognition, described the problem in his episode: older language technology often showed its mistakes, because a translation that read badly also tended to be unfaithful. A technology that always sounds right but often is not makes it hard to know what to trust.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Like I said, one of my biggest fears is that, as a field, we are building systems which produce outputs indistinguishable from the truth.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Dan Klein, on Chain of Thought ep 54&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The Chain of Thought writing page makes the same point with a made-up paragraph about a retrieval layer. It marks four patterns from the open-source avoid-ai-writing catalog, and then notes that fixing them makes the paragraph read better while telling you nothing about whether the retrieval layer reduces hallucinations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which four patterns should you mark?
&lt;/h2&gt;

&lt;p&gt;The page labels these:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Significance inflation: the sentence claims historic weight without saying what changed. Ask what the before and after are, in a number or a behavior.&lt;/li&gt;
&lt;li&gt;Vague attribution: a crowd of unnamed experts agrees. Ask which experts. With no source, nobody can check it.&lt;/li&gt;
&lt;li&gt;A contrast frame that rebuts a claim nobody made, the "it is not merely X, it is Y" shape. Ask who said it was merely X. Usually nobody did, and the sentence is adding drama instead of a mechanism.&lt;/li&gt;
&lt;li&gt;A generic conclusion that could end any paragraph about anything, usually an upbeat line about the future. Ask what forecast it commits to.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you edit, highlight every instance. If you cannot attach something verifiable on the next pass, cut the sentence or rewrite it into a claim a reviewer could prove wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you run a quick pass yourself?
&lt;/h2&gt;

&lt;p&gt;Two passes on a technical post, in this order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pattern pass: search for inflation openers, unnamed authorities, contrast frames, and closing lines that praise the future without a number or a boundary condition.&lt;/li&gt;
&lt;li&gt;Mechanism pass: for every claim left, write down what you would measure and what result would prove you wrong. If the answer is nothing, the sentence is marketing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On a long post I would rather let a script find the pattern families first. This sketch is mine, and deliberately small; a maintained detector is the better tool for real use.&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;# Sketch: flag a few AI-writing tells in a markdown draft
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;draft.md&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\b(experts agree|studies show|researchers say)\b&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;vague attribution&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="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\bnot (just|only|merely)\b[^.]*\bit&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;?s\b&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;contrast frame&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="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\bthe future (looks|is)\b&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;generic conclusion&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="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\b(watershed|sea change|in the evolution of)\b&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;significance inflation&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rules&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;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finditer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&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="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="nf"&gt;print&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; ~ line &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Treat the hits like linter warnings: review each one, because some will be false positives, and fix the real ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why can't a clean result mean the post is true?
&lt;/h2&gt;

&lt;p&gt;A detector only sees shape. Removing an unnamed expert does not add evidence. Replacing a claim of historic weight with a concrete before and after does, but only if the before and after are real.&lt;/p&gt;

&lt;p&gt;That is why the writing page sits next to three episodes on the gap between plausible and true: Dan Klein on plausibility engines (episode 54), Sudhir Hasbe on hallucinations as a data architecture problem (episode 55), and Alex Ratner on the evaluation gap, where everyone says their system works and almost nobody can say what "works" means in a number (episode 57). Lint gets you to honest prose. Those conversations are about what honest prose is still allowed to claim.&lt;/p&gt;

&lt;p&gt;If you want to see the patterns in a real draft, the &lt;a href="https://chainofthought.show/essays/" rel="noopener noreferrer"&gt;essays&lt;/a&gt; include a piece where an AI agent's first draft runs with formatting fixes only, so you can read it for tells yourself. More about the show and how it is made is on the &lt;a href="https://chainofthought.show/about/" rel="noopener noreferrer"&gt;about page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Highlight all four pattern families before you fact-check anything.&lt;/li&gt;
&lt;li&gt;Replace every unnamed authority with a named source or a metric, or cut the line.&lt;/li&gt;
&lt;li&gt;Run a quick regex or detector pass, then review every hit by hand.&lt;/li&gt;
&lt;li&gt;Keep "reads well" and "is true" as separate checks, and schedule the second one for every claim that matters.&lt;/li&gt;
&lt;li&gt;If the post describes AI product behavior, define what "works" means in a number before you publish.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More on this topic, with the related episodes, is on &lt;a href="https://chainofthought.show/ai-writing/" rel="noopener noreferrer"&gt;Chain of Thought&lt;/a&gt;. It draws on &lt;a href="https://chainofthought.show/podcast/54-why-llms-are-plausibility-engines-not-truth-engines-dan-klein/" rel="noopener noreferrer"&gt;this episode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/2HwtyPE6JuQ" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://newsletter.chainofthought.show/subscribe?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=newsletter" rel="noopener noreferrer"&gt;Subscribe to the Chain of Thought newsletter&lt;/a&gt; for new episodes and write-ups like this one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI assistance from the episode transcripts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>writing</category>
      <category>llm</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Ship AI features inside a hard latency budget</title>
      <dc:creator>Conor Bronsdon</dc:creator>
      <pubDate>Wed, 28 Oct 2026 15:30:08 +0000</pubDate>
      <link>https://dev.to/conorbronsdon/ship-ai-features-inside-a-hard-latency-budget-40kk</link>
      <guid>https://dev.to/conorbronsdon/ship-ai-features-inside-a-hard-latency-budget-40kk</guid>
      <description>&lt;p&gt;Superhuman's full drafting call will not finish inside a 100 millisecond interaction budget. That budget is the immediate UI response, and completed generation is separate. Prefetch context that does not depend on this turn, such as how this person writes to this recipient and what the thread already says, before they speak. Send only the new transcription when they stop. Prove the work on the most capable model you can call. Once people keep using it and the job is narrow, move that task to a smaller or fine-tuned model. Leave send on a human click.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://chainofthought.show/guests/loic-houssier/" rel="noopener noreferrer"&gt;Loïc Houssier&lt;/a&gt;, CTO of Superhuman Mail, described that constraint on Chain of Thought in May 2026. He had joined Superhuman a year and a half earlier. At 100 milliseconds the product cannot depend on the network for every step, so it works offline by default, with logic on the desktop and the phone and async jobs that sync when the device is online. Email fits that pattern because it is asynchronous. He was plain that inference under 100 milliseconds does not work, so the team changed the shape of the call.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you keep an AI feature inside a 100ms feel?
&lt;/h2&gt;

&lt;p&gt;You pull prepared context out of the waiting path and send a short payload when the user finishes.&lt;/p&gt;

&lt;p&gt;Superhuman had just released voice on mobile. The team was not satisfied with the speed. If transcription drags and a model then rewrites for voice and tone, people will not use it, because it feels unlike the rest of the product.&lt;/p&gt;

&lt;p&gt;Speech to text was the easier part. On-device transcription is one way to do it. The hard part is a draft that frames intent after people correct themselves, and that matches the thread and the tone used with that person. Answering your mom and answering your boss are different.&lt;/p&gt;

&lt;p&gt;Much of that context can sit ready before the dictation. They cached so the live step was a transcription payload, not one call with a huge context. That caching has a cost: open voice and then type anyway, and the context was sent for nothing.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A minimal sketch to adapt, not a drop-in library.&lt;/em&gt;&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="n"&gt;CONTEXT_CACHE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;# proving: capable model. specialized: one task, after the feature sticks.
&lt;/span&gt;&lt;span class="n"&gt;FEATURE_ROUTE&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;voice_draft&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;proving&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;auto_label&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;specialized&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;model_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FEATURE_ROUTE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;feature&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;frontier_model&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;proving&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;specialized_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feature&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;warm_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;context&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;tone&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;load_voice_and_tone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;thread&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;load_thread_summary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;# Preload on the model. Keep only a session reference on the client.
&lt;/span&gt;    &lt;span class="n"&gt;session_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;call_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;model_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cache_only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;CONTEXT_CACHE&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session_id&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;session_id&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_feature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;session_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CONTEXT_CACHE&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="c1"&gt;# Live call is the transcription payload plus that session, not the full context.
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;call_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;model_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;So instead of having one call with a huge context, we pre- I would say load the context as much as we can and boom, then we send just like a payload of the transcription.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Loïc Houssier, CTO at Superhuman Mail, on &lt;a href="https://chainofthought.show/podcast/59-how-superhuman-built-ai-into-a-100ms-product-lo-c-houssier/" rel="noopener noreferrer"&gt;Chain of Thought ep 59&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://podcasts.apple.com/us/podcast/how-superhuman-built-ai-into-a-100ms-product-lo%C3%AFc-houssier/id1776879655?i=1000769069413" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fis1-ssl.mzstatic.com%2Fimage%2Fthumb%2FPodcasts221%2Fv4%2F8b%2F3b%2F87%2F8b3b875c-04f4-b17d-f503-e84e50f6bfec%2Fmza_2191016408998992588.jpg%2F1200x1200ECA.PESS01-60.jpg%3FimgShow%3DPodcasts221%2Fv4%2Fee%2Ff2%2F1b%2Feef21b19-f090-f9b4-fc85-ffc84f80fad7%2Fmza_6548396687882944514.jpg" height="800" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://podcasts.apple.com/us/podcast/how-superhuman-built-ai-into-a-100ms-product-lo%C3%AFc-houssier/id1776879655?i=1000769069413" rel="noopener noreferrer" class="c-link"&gt;
            How Superhuman Built AI Into a… - Chain of Thought | AI Agents, Infrastructure &amp;amp; Engineering - Apple Podcasts
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Podcast Episode · Chain of Thought | AI Agents, Infrastructure &amp;amp; Engineering · May 22 · 50m
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpodcasts.apple.com%2Fassets%2Ffavicon%2Ffavicon-32.png" width="32" height="32"&gt;
          podcasts.apple.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  When should a feature leave the frontier model?
&lt;/h2&gt;

&lt;p&gt;When people still want the feature, and when you can name the narrow job a smaller model will own.&lt;/p&gt;

&lt;p&gt;They start with one expensive model, the best they have, to see if the feature can work and how it feels. Then each use case gets its own model. The agentic framework runs on the latest version of Opus. The sequence is to try the expensive model, make it useful, then make it efficient.&lt;/p&gt;

&lt;p&gt;Auto-label shows the handoff. The job is classification: FYI, pitch, partner, newsletter, and the rest. Auto-label started on an expensive frontier model, run on every email, which was expensive. Once they knew which 10 or 12 labels would be useful, he said, you can fine-tune dedicated BERT models and maybe run inference on dedicated infrastructure built for cheap inference at scale. With the labels known, he described it as a typical BERT classifier job: an open model, fine-tuned a bit, on cheaper dedicated infrastructure rather than a general LLM provider, and good enough for those use cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why did repeating the prompt at both ends stop helping?
&lt;/h2&gt;

&lt;p&gt;That pattern was a fix for an earlier model generation, and it helps less on newer ones.&lt;/p&gt;

&lt;p&gt;On those earlier models, repeating the request at the start and at the end worked well. The assumption was that those models weighted the beginning and the end of the message more than the middle, so copying the request into both ends lifted the middle, and they saw better results. On newer models, repeating the message does not help as much. Where you place the instruction still matters. Sometimes it goes at the end.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Repeating the message was surprisingly good for 4 models. It doesn't work as much on newer models.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Loïc Houssier, CTO at Superhuman Mail, on &lt;a href="https://chainofthought.show/podcast/59-how-superhuman-built-ai-into-a-100ms-product-lo-c-houssier/" rel="noopener noreferrer"&gt;Chain of Thought ep 59&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why auto-draft the email and leave send to the user?
&lt;/h2&gt;

&lt;p&gt;Send carries more risk than the draft, so the draft waits for the person.&lt;/p&gt;

&lt;p&gt;They do not send email in the user's name, because it is too risky. The product auto-drafts, and the person hits send. Users were not ready to let that go.&lt;/p&gt;

&lt;p&gt;If the agent can send mail or move money, the safeguards around it are probabilistic, and at some point it will mess up. His rule: if you want a real gate, you don't expose that action to the agent. He already had scars from giving an agent too much room in his own notes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We do not send, we auto-draft. It's here for you to just hit send, but we won't send any mail for you, for now.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Loïc Houssier, CTO at Superhuman Mail, on &lt;a href="https://chainofthought.show/podcast/59-how-superhuman-built-ai-into-a-100ms-product-lo-c-houssier/" rel="noopener noreferrer"&gt;Chain of Thought ep 59&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Can you make the model itself return in under 100 milliseconds?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Loïc said that does not work. Prefetch voice, tone, and thread context so the live request is mostly the new transcription.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When is a fine-tuned classifier enough?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After a capable model has shown the task is useful and the label set is known. Loïc described auto-label that way: an expensive model on every email first, then, once they knew which 10 or 12 labels would be useful, a fine-tuned open BERT-style classifier on cheaper dedicated infrastructure. The agentic framework stayed on the latest Opus.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should the agent send once drafts look reliable?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Draft quality and permission to send are separate. This team auto-drafts and does not send on the user's behalf for now. Any safeguard around an agent that can send is probabilistic. Loïc's real gate is not exposing send to the agent at all, so leave send with the person.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Write the interaction budget down (here, 100 milliseconds) before you design the model call.&lt;/li&gt;
&lt;li&gt;Prefetch recipient tone and thread context before the user speaks. Send the transcription as the live payload.&lt;/li&gt;
&lt;li&gt;Start on the most capable model. Move to a smaller or fine-tuned model only after the task and the labels are stable.&lt;/li&gt;
&lt;li&gt;Re-measure prompt tricks after a model change. A pattern that helped on an earlier model may not help on the next one.&lt;/li&gt;
&lt;li&gt;Auto-draft. Keep send, and any other hard-to-undo action, on a human confirmation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full conversation, with the transcript, is on &lt;a href="https://chainofthought.show/podcast/59-how-superhuman-built-ai-into-a-100ms-product-lo-c-houssier/" rel="noopener noreferrer"&gt;Chain of Thought&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/iBqLWoOLggM" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://newsletter.chainofthought.show/subscribe?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=newsletter" rel="noopener noreferrer"&gt;Subscribe to the Chain of Thought newsletter&lt;/a&gt; for new episodes and write-ups like this one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI assistance from the episode transcripts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>architecture</category>
      <category>performance</category>
    </item>
    <item>
      <title>When a support assistant should hand off to a person</title>
      <dc:creator>Conor Bronsdon</dc:creator>
      <pubDate>Tue, 27 Oct 2026 20:30:07 +0000</pubDate>
      <link>https://dev.to/conorbronsdon/when-a-support-assistant-should-hand-off-to-a-person-513p</link>
      <guid>https://dev.to/conorbronsdon/when-a-support-assistant-should-hand-off-to-a-person-513p</guid>
      <description>&lt;p&gt;In December 2024, &lt;a href="https://chainofthought.show/guests/vinnie-giarrusso/" rel="noopener noreferrer"&gt;Vinnie Giarrusso&lt;/a&gt;, principal software engineer at Twilio, described how to add AI to customer communication without making it colder. The worry he named is that assistants take work away and the experience gets less personal. He wants the assistant on the boring technical work and the mundane tasks, so a person can stay with the human part of the conversation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I think that there's a lot of worry about agents taking work away and resulting in like a less personal experience. But actually, I think it's, I think it's the opposite, I think that there's a huge opportunity here to use these assistants in taking away the boring technical work and the sort of like mundane tasks,that would ordinarily be done by a human.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Vinnie Giarrusso, principal software engineer at Twilio, on Chain of Thought episode 7&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Twilio calls them AI assistants on purpose. The industry word is agents. Early on, Vinnie said, the system sits side by side with a person, adding what he called superhuman powers, and depending on the setup a person may accept or reject certain actions. I would keep that accept or reject step on anything the customer cannot undo.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should the assistant take, and when should a person step in?
&lt;/h2&gt;

&lt;p&gt;I would let the assistant finish checks that are factual once the needed fact is known: order status, the customer's plan, and a single price. Vinnie described the support call where the person is reading a script and still misses the question. If those checks are already done, the person who joins can focus on the human problem, with time to be empathetic. He hopes the customer is not left waiting an hour.&lt;/p&gt;

&lt;p&gt;He also drew a line through what an assistant may do alone. He said he had not tested this pattern and was spitballing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Like there are things that an assistant can be trusted with to do. just kind of fully on their own. And then there are things that at least today, assistants should not be trusted to do fully on their own. especially in the early phase.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Vinnie Giarrusso, principal software engineer at Twilio, on Chain of Thought episode 7&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;He named the mechanism a stop mode or a request help mode. The assistant works inside a scope, then asks for supervisor approval or checks in on the steps it took. He left the customer-facing wording open. I would send one message that a person has the next step, and I would give that person a report of what was asked, what was answered, and which source was used. Complaints and account changes sit on the human side of the line. The assistant may prepare them. It may not commit them.&lt;/p&gt;

&lt;p&gt;Enterprises, he said, will be more measured than the demo cycle. Some teams will treat a new capability as about a year out. If you are building a company on this, read the &lt;a href="https://chainofthought.show/collections/best-for-ai-founders/" rel="noopener noreferrer"&gt;episodes gathered for AI founders&lt;/a&gt; before you promise full autonomy. They focus on defensibility, go to market, and market reality.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you stop a confident wrong answer?
&lt;/h2&gt;

&lt;p&gt;Accuracy in this setting is specific. Vinnie's example is the price of a text message in Spain versus another country, when the user never said where they are. The assistant can hold every price row and still not know which one applies. He said accuracy is the assistant asking a follow-up, across one answer or a series of messages, instead of picking a row at random.&lt;/p&gt;

&lt;p&gt;The follow-up itself is &lt;a href="https://chainofthought.show/glossary/generative-ai/" rel="noopener noreferrer"&gt;generative AI&lt;/a&gt;: the model produces new text. Sending it on a channel, or changing an account, is a further action. I would not let the function that drafts a reply also commit the account change.&lt;/p&gt;

&lt;p&gt;Retrieval is one of the biggest failure modes Vinnie has seen once a system scales. A pipeline from the LangChain docs comes up quickly. After 10, 15, or 20 knowledge sources, the assistant may choose the wrong source, or return top chunks that cannot support the answer. He said context-aware retrieval, informed by Anthropic's contextual research, raised their retrieval accuracy, and he declined to give hard numbers.&lt;/p&gt;

&lt;p&gt;On a bad trace, check two things. Which knowledge source did it pick? If that source was right, did the top chunks contain the answer? If you cannot tell, do not add another source.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should you measure before you widen autonomy?
&lt;/h2&gt;

&lt;p&gt;Vinnie said Twilio put an observability layer in place at day minus one. The team constantly checks context adherence, complexity, accuracy, and tone. Investigating low context or chunk adherence could reveal a mistaken assumption about the case, or an unexpected outcome in a small share of cases. I would narrow what the assistant may do alone until that signal moves.&lt;/p&gt;

&lt;p&gt;A platform cannot know every future use. Twilio runs evals on cases that generalize across some customers, but cannot predict every customer use or knowledge source. They open-sourced an evals package in the Twilio Alpha GitHub and NPM namespace. It began as security evals and grew into evals more broadly, on the view that it is more convincing when people try their own questions and find gaps in sources and prompting. I would ship a small shared set plus a way for the domain owner to add cases.&lt;/p&gt;

&lt;p&gt;Vinnie said few tools worked equally well for engineers, PMs, and business partners, and that shared view mattered. For a question like which handoffs had weak context adherence, use &lt;a href="https://chainofthought.show/glossary/conversational-analytics/" rel="noopener noreferrer"&gt;conversational analytics&lt;/a&gt;: someone asks in plain language and gets an answer from the data, without knowing the report or writing a query.&lt;/p&gt;

&lt;p&gt;Sketch of the route only. This is not a Twilio system, and it calls no vendor SDK.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Incoming&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;status&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pricing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;complaint&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;account_change&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unknown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;missingFacts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;tone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;calm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;strained&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;angry&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reply&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lookup&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;change_account&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Incoming&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clarify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;human&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;change_account&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;intent&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;complaint&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;human&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tone&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;angry&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;human&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;missingFacts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clarify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;intent&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;status&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;intent&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pricing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;human&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Write two lists before you ship: tasks the assistant may finish alone, and actions that always wait for a person.&lt;/li&gt;
&lt;li&gt;If a required fact is missing, force a clarifying question and block a random choice among price rows or sources.&lt;/li&gt;
&lt;li&gt;On every handoff, pass a short report of what was asked, what was answered, and which knowledge source was used.&lt;/li&gt;
&lt;li&gt;For each failure, check the chosen source and the top chunks, then watch context adherence, complexity, accuracy, and tone.&lt;/li&gt;
&lt;li&gt;Let domain owners add their own eval cases before you expand what the assistant is allowed to do alone.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full conversation, with the transcript, is on &lt;a href="https://chainofthought.show/podcast/7-beyond-chatbots-how-twilio-uses-ai-to-strengthen-human-connection-vinnie-giarrusso/" rel="noopener noreferrer"&gt;Chain of Thought&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://newsletter.chainofthought.show/subscribe?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=newsletter" rel="noopener noreferrer"&gt;Subscribe to the Chain of Thought newsletter&lt;/a&gt; for new episodes and write-ups like this one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI assistance from the episode transcripts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>support</category>
      <category>testing</category>
    </item>
    <item>
      <title>Count tokens before you ship so agent bills do not surprise you</title>
      <dc:creator>Conor Bronsdon</dc:creator>
      <pubDate>Tue, 27 Oct 2026 15:30:14 +0000</pubDate>
      <link>https://dev.to/conorbronsdon/count-tokens-before-you-ship-so-agent-bills-do-not-surprise-you-2123</link>
      <guid>https://dev.to/conorbronsdon/count-tokens-before-you-ship-so-agent-bills-do-not-surprise-you-2123</guid>
      <description>&lt;p&gt;Your API dashboard shows a spike, but the feature "felt small." Look at the tokens: what the model reads, writes, and re-sends on every step. &lt;a href="https://chainofthought.show/glossary/tokenization/" rel="noopener noreferrer"&gt;Tokenization&lt;/a&gt; is not academic. Context limits, per-token pricing, and latency all use the same unit, and dense code or odd formatting can cost more than the word count suggests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does billing use tokens instead of words?
&lt;/h2&gt;

&lt;p&gt;Language models do not read whole words or raw characters. They read tokens, sub-word chunks from a fixed vocabulary. In English, a common word is often one token; rare words and code can split into several, and punctuation and spaces count too. OpenAI's rule of thumb is about four characters per token, or about three-quarters of a word, so 100 tokens is roughly 75 words.&lt;/p&gt;

&lt;p&gt;That ratio drifts. Non-English text, code, and weird formatting usually burn more tokens per visible line. Before you argue about model tier, paste representative prompts into a tokenizer and note input tokens per request. Guessing from word count is how teams under-budget chat history and tool output.&lt;/p&gt;

&lt;h2&gt;
  
  
  What counts toward the context window each turn?
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://chainofthought.show/glossary/context-window/" rel="noopener noreferrer"&gt;context window&lt;/a&gt; is a token budget for one response, and the latest user message is only one part of it. System instructions, prior turns, tool definitions, and tool results all sit in that budget. Output tokens need room too. In chat, unless your app trims or summarizes, the full history goes back on the next turn, so input tokens climb every step.&lt;/p&gt;

&lt;p&gt;Exceeding the limit is not one universal behavior. Depending on the API, the request may be rejected or generation may stop, and many applications truncate or compact the input before sending it. Compaction changes what the model sees next; it does not make the window bigger. Anthropic's documentation also warns that accuracy and recall can degrade as context grows, what it calls context rot. For cost planning, whether a prompt fits in the window and whether it is cheap to keep sending are different questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where does the money go on each inference call?
&lt;/h2&gt;

&lt;p&gt;For most teams on hosted models, &lt;a href="https://chainofthought.show/glossary/inference/" rel="noopener noreferrer"&gt;inference&lt;/a&gt; is the bill that repeats: every message and agent step is another run. Training is someone else's capex; your product pays per call.&lt;/p&gt;

&lt;p&gt;Providers charge input and output separately. On Anthropic's price list as of October 2026, output costs five times as much as input for each Claude model. Reasoning models can bill hidden reasoning as output, so a short visible answer can still be expensive. Repeated static instructions may qualify for prompt caching: Anthropic charges about a tenth of normal input to read a cached block, with a higher cost the first time you write it.&lt;/p&gt;

&lt;p&gt;One successful task is rarely one call. Agents plan, call tools, retry, and often carry a growing context each time. Cost per task is roughly the sum over every call of (input tokens × input price) plus (output tokens × output price), including failures and retries.&lt;/p&gt;

&lt;p&gt;Jeetu Patel, Cisco's president and chief product officer, argued in episode 67 that price per token could turn into a vanity metric: the price per token falls while long-running agents use more tokens. What matters to him is the price of the outcome. Your estimator should still start with tokens, because that is what you control in design.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I sketch a monthly token bill?
&lt;/h2&gt;

&lt;p&gt;Use your provider's current input and output rates. If you only remember the Anthropic ratio above, set &lt;code&gt;OUTPUT_PRICE = 5 * INPUT_PRICE&lt;/code&gt; as a placeholder until you paste real numbers from the price list.&lt;/p&gt;

&lt;p&gt;Label this a sketch, not production accounting:&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;# Sketch: monthly inference cost from volume.
# Prices are $ per 1M tokens; replace the placeholders with your provider's list.
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;monthly_cost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tasks_per_month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;calls_per_task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;avg_input_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                 &lt;span class="n"&gt;avg_output_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output_price&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;calls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tasks_per_month&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;calls_per_task&lt;/span&gt;
    &lt;span class="n"&gt;per_call&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;avg_input_tokens&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;input_price&lt;/span&gt;
                &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;avg_output_tokens&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;output_price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1_000_000&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;calls&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;per_call&lt;/span&gt;

&lt;span class="n"&gt;INPUT_PRICE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;                 &lt;span class="c1"&gt;# placeholder
&lt;/span&gt;&lt;span class="n"&gt;OUTPUT_PRICE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;INPUT_PRICE&lt;/span&gt;    &lt;span class="c1"&gt;# the ratio on Anthropic's list
# 50k tasks, 8 model calls each, 12k tokens in and 800 out per call
&lt;/span&gt;&lt;span class="n"&gt;bill&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;monthly_cost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;INPUT_PRICE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OUTPUT_PRICE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run three scenarios on the same workflow: today's averages, a heavy month (longer history, more retries), and a trimmed prompt (fewer input tokens or fewer calls per task). The line that moves the total most is where you spend engineering time.&lt;/p&gt;

&lt;p&gt;Set &lt;code&gt;calls_per_task&lt;/code&gt; realistically for agents. A single user action might be dozens of inferences. Divide total cost by completed tasks, not by API calls, when you compare features.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I think that today a lot of organizations are not thinking about their token spend regularly and they're getting hit with their bills.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Jiaona Zhang, Laurel&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://chainofthought.show/guests/jiaona-zhang/" rel="noopener noreferrer"&gt;Jiaona Zhang&lt;/a&gt; ties that to "token maxxing": mandating AI use without asking whether the task earned the tokens, like using a model to redo slide fonts when one click would do. The estimator is how you catch that before finance does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which knob should I turn first?
&lt;/h2&gt;

&lt;p&gt;If output tokens dominate (long answers, reasoning traces, verbose tool JSON), tighten schemas, cap completion length, or route easy steps to a smaller model. If input tokens dominate (system prompt, full chat log, fat tool results), trim history, summarize older turns, cache stable instructions, and stop pasting whole documents when a chunk will do.&lt;/p&gt;

&lt;p&gt;Jeetu Patel describes rationing tokens like headcount: a fixed pool and an expected output. That matches measuring cost per completed task and watching context on every turn, themes that show up across &lt;a href="https://chainofthought.show/topics/ai-infrastructure/" rel="noopener noreferrer"&gt;AI infrastructure&lt;/a&gt; conversations on the show.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Tokenize real prompts and tool payloads; do not budget from word count alone.&lt;/li&gt;
&lt;li&gt;Budget context as instructions plus history plus tools plus reserved output tokens.&lt;/li&gt;
&lt;li&gt;Estimate with (input × input price + output × output price) × calls per task × tasks per month.&lt;/li&gt;
&lt;li&gt;Compare scenarios: trim input, trim output, and reduce calls per successful task.&lt;/li&gt;
&lt;li&gt;Report cost per completed task, retries included, not per isolated API call.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The longer explainer, with the episode clips, is on &lt;a href="https://chainofthought.show/ai-decoded/what-is-a-token-in-ai/" rel="noopener noreferrer"&gt;Chain of Thought&lt;/a&gt;. It draws on &lt;a href="https://chainofthought.show/podcast/64-stop-token-maxxing-find-where-ai-actually-pays-off-jiaona-zhang/" rel="noopener noreferrer"&gt;this episode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/kF7gO1TQr5Q" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://newsletter.chainofthought.show/subscribe?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=newsletter" rel="noopener noreferrer"&gt;Subscribe to the Chain of Thought newsletter&lt;/a&gt; for new episodes and write-ups like this one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI assistance from the episode transcripts.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>tokens</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
