<?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: Tapas Mohanty</title>
    <description>The latest articles on DEV Community by Tapas Mohanty (@tapas_mohanty_a3df1d162a6).</description>
    <link>https://dev.to/tapas_mohanty_a3df1d162a6</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%2F1389306%2Faa0aea0c-b57c-4127-86a2-3a9d932fbcb4.png</url>
      <title>DEV Community: Tapas Mohanty</title>
      <link>https://dev.to/tapas_mohanty_a3df1d162a6</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tapas_mohanty_a3df1d162a6"/>
    <language>en</language>
    <item>
      <title>Your AI Agent Said “Success” The Database Says Otherwise</title>
      <dc:creator>Tapas Mohanty</dc:creator>
      <pubDate>Mon, 19 Oct 2026 15:27:13 +0000</pubDate>
      <link>https://dev.to/tapas_mohanty_a3df1d162a6/your-ai-agent-said-success-the-database-says-otherwise-232</link>
      <guid>https://dev.to/tapas_mohanty_a3df1d162a6/your-ai-agent-said-success-the-database-says-otherwise-232</guid>
      <description>&lt;p&gt;&lt;em&gt;Why testing AI agents requires verifying what actually happened, not just what the agent reported.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Imagine asking an AI agent to update a customer's subscription.&lt;/p&gt;

&lt;p&gt;The agent calls a tool. The tool returns a success response. The agent tells the user:&lt;/p&gt;

&lt;p&gt;“Your subscription has been updated successfully.”&lt;/p&gt;

&lt;p&gt;The logs look fine. The tool call completed. The final answer is confident.&lt;/p&gt;

&lt;p&gt;But the database still contains the old subscription.&lt;/p&gt;

&lt;p&gt;What happened?&lt;/p&gt;

&lt;p&gt;Perhaps the SQL &lt;code&gt;UPDATE&lt;/code&gt; matched zero rows. Perhaps the API accepted the request but rejected the operation later. Perhaps a browser agent clicked a button, but the form submission failed because the session had expired.&lt;/p&gt;

&lt;p&gt;From the agent's perspective, the task is complete.&lt;/p&gt;

&lt;p&gt;From the application's perspective, nothing changed.&lt;/p&gt;

&lt;p&gt;This is one of the important testing problems we need to solve as AI agents move from answering questions to taking actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with trusting a successful tool call
&lt;/h2&gt;

&lt;p&gt;Traditional application code usually has explicit success and failure conditions. An HTTP response code, a database result, or an exception can tell us something about what happened.&lt;/p&gt;

&lt;p&gt;Agentic systems add another layer of uncertainty.&lt;/p&gt;

&lt;p&gt;An agent decides which tool to call, supplies its arguments, interprets the response, and decides whether to continue or stop. Each step can appear successful while the overall task remains incomplete.&lt;/p&gt;

&lt;p&gt;Consider this example:&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    UPDATE subscriptions
    SET plan = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;premium&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;
    WHERE customer_id = :customer_id
    &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;customer_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;customer_id&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;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The update might affect one row, several rows, or zero rows. Returning &lt;code&gt;success: True&lt;/code&gt; without checking the result makes all three outcomes look identical to the caller.&lt;/p&gt;

&lt;p&gt;The problem is not necessarily the LLM. The tool's success contract is too weak.&lt;/p&gt;

&lt;p&gt;If an agent is allowed to treat a tool response as proof of completion, the application can report a successful action that never happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why checking the final answer is not enough
&lt;/h2&gt;

&lt;p&gt;Suppose an evaluation checks only this:&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;assert&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;updated successfully&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The test passes when the agent produces the expected sentence.&lt;/p&gt;

&lt;p&gt;It says nothing about whether the database changed.&lt;/p&gt;

&lt;p&gt;Even checking whether the agent called the correct tool is insufficient. A tool can be called with the correct arguments and still fail to produce the intended result.&lt;/p&gt;

&lt;p&gt;For action-taking agents, there are at least three different things to verify:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Intent:&lt;/strong&gt; Did the agent choose the right action and arguments?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution:&lt;/strong&gt; Did the tool actually perform the operation?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outcome:&lt;/strong&gt; Does the real system now have the expected state?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These are related, but they are not interchangeable.&lt;/p&gt;

&lt;p&gt;A correct tool call does not guarantee a successful operation. A successful operation does not automatically guarantee the intended end state either.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify the outcome independently
&lt;/h2&gt;

&lt;p&gt;A stronger approach is to check the result against the system of record.&lt;/p&gt;

&lt;p&gt;For a database update, inspect the affected-row count and verify the relevant fields. For an external API, retrieve the resource and confirm its persisted state. For a browser agent, check the resulting page or the underlying record rather than relying on the click event.&lt;/p&gt;

&lt;p&gt;For example:&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;update_subscription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_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;premium&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="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;affected_rows&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;raise&lt;/span&gt; &lt;span class="nc"&gt;AssertionError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Expected exactly one subscription to change&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;get_subscription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;subscription&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;premium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is illustrative code; the actual result fields depend on the database driver and application's data-access layer.&lt;/p&gt;

&lt;p&gt;The key principle is independent verification. The check should obtain evidence from a source that can establish whether the requested action really took effect.&lt;/p&gt;

&lt;p&gt;For eventually consistent systems, verification may need to wait for a final state rather than treating an intermediate &lt;code&gt;pending&lt;/code&gt; status as completion.&lt;/p&gt;

&lt;p&gt;And when the evidence is inconclusive, the system should say so. “Unverified” is more honest—and often safer—than “Done.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Test whether the verification itself works
&lt;/h2&gt;

&lt;p&gt;There is a further problem: a test can contain a success check that looks meaningful but does not detect failure.&lt;/p&gt;

&lt;p&gt;A useful negative test deliberately simulates an action that reports success without changing anything.&lt;/p&gt;

&lt;p&gt;Then ask: does the verification still pass?&lt;/p&gt;

&lt;p&gt;If it does, the check is not proving the behavior we care about.&lt;/p&gt;

&lt;p&gt;This is the same idea behind testing failure paths in ordinary software. We should not only demonstrate that a system works when everything goes right. We should also demonstrate that our tests catch cases where an operation silently does nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where AI evaluation fits
&lt;/h2&gt;

&lt;p&gt;These problems are part of a broader shift in AI testing.&lt;/p&gt;

&lt;p&gt;An evaluation should not stop at whether the answer sounds correct. It should also examine tool selection, tool arguments, action order, side effects, and the resulting application state.&lt;/p&gt;

&lt;p&gt;This matters particularly for agents that handle refunds, update records, manage bookings, send communications, or trigger other consequential operations.&lt;/p&gt;

&lt;p&gt;A useful regression test should establish what the agent was expected to do, record what it actually did, and verify whether the intended outcome occurred.&lt;/p&gt;

&lt;p&gt;That gives us evidence we can compare across prompt changes, model upgrades, tool changes, and application releases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building this into Assay
&lt;/h2&gt;

&lt;p&gt;This is one of the problems I have been exploring while building &lt;a href="https://github.com/tap222/assay-evals" rel="noopener noreferrer"&gt;Assay Evals&lt;/a&gt;, an open-source project for behavioral regression testing of AI applications and agents.&lt;/p&gt;

&lt;p&gt;Assay focuses on evaluating more than the final response. It can check agent trajectories, expected tool calls, end states, and behavioral changes between runs.&lt;/p&gt;

&lt;p&gt;The project's roadmap also explores stronger independent verification: reading the result back from an API, database, or another system of record, and treating an inconclusive outcome separately from verified success.&lt;/p&gt;

&lt;p&gt;You can explore the implementation and roadmap in the &lt;a href="https://github.com/tap222/assay-evals" rel="noopener noreferrer"&gt;Assay repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The engineering principle
&lt;/h2&gt;

&lt;p&gt;As AI agents become more capable of changing the world around them, our definition of success must become stricter.&lt;/p&gt;

&lt;p&gt;A successful model response is not necessarily a successful tool call. A successful tool call is not necessarily a successful business operation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The right question is not “Did the agent say it worked?” It is “What evidence proves that it worked?”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That distinction is essential to making agentic systems reliable.&lt;/p&gt;

&lt;p&gt;Because in production, confidence is not evidence, a completed tool call is not proof of an outcome, and a green evaluation is only as useful as the behavior it actually verifies.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>softwaredevelopment</category>
    </item>
  </channel>
</rss>
