<?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: TokenAir</title>
    <description>The latest articles on DEV Community by TokenAir (tokenair).</description>
    <link>https://dev.to/tokenair</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%2Forganization%2Fprofile_image%2F13981%2F9bb208d4-9a5e-4cb2-b84b-c8cc3dff2742.png</url>
      <title>DEV Community: TokenAir</title>
      <link>https://dev.to/tokenair</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tokenair"/>
    <language>en</language>
    <item>
      <title>Your token dashboard can't tell you what one successful agent workflow costs</title>
      <dc:creator>dualdust</dc:creator>
      <pubDate>Sat, 11 Jul 2026 10:18:58 +0000</pubDate>
      <link>https://dev.to/tokenair/your-token-dashboard-cant-tell-you-what-one-successful-agent-workflow-costs-21de</link>
      <guid>https://dev.to/tokenair/your-token-dashboard-cant-tell-you-what-one-successful-agent-workflow-costs-21de</guid>
      <description>&lt;p&gt;Most teams can find last month's model spend. Far fewer can price one agent result that somebody accepted and used.&lt;/p&gt;

&lt;p&gt;Consider a support agent handling a refund. It reads the conversation, searches a policy document, calls a billing tool, drafts a reply, and retries after the first answer fails review. A person edits the second answer and sends it.&lt;/p&gt;

&lt;p&gt;The provider records several model calls. The tool vendor records a search and a transaction. The tracing system records a chain of steps. The support team sees one request.&lt;/p&gt;

&lt;p&gt;Each system is correct, but none of them has the whole job. A token dashboard can be detailed and still leave the product team unable to answer a basic question: how much did the accepted result cost?&lt;/p&gt;

&lt;h2&gt;
  
  
  The provider bill stops at the call
&lt;/h2&gt;

&lt;p&gt;Provider usage data helps finance reconcile spend. It can group usage by model, project, user, or API key. That is useful, but the provider cannot see the complete business workflow inside your application.&lt;/p&gt;

&lt;p&gt;An agent may call tools, delegate work, retry a failed step, switch models, and wait for human review before it produces anything useful. If each model call becomes a separate unit, retries and workers lose their connection to the request that caused them. If you only report token cost, tool charges and review work disappear.&lt;/p&gt;

&lt;p&gt;This distorts model comparisons. A cheap first call can trigger repairs and a premium fallback. A route with a higher call price can cost less when a reviewer accepts its first result.&lt;/p&gt;

&lt;p&gt;The comparison needs a record that follows the work from the original request to the final outcome.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give the requested job one parent run
&lt;/h2&gt;

&lt;p&gt;Create a parent run when the user request or scheduled job begins. Give it a stable &lt;code&gt;run_id&lt;/code&gt;. Every planner, worker, model call, tool call, retry, fallback, and review step becomes a child event linked through &lt;code&gt;parent_run_id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A compact event can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"run_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"run_refund_8421"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parent_run_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"run_refund_8421"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"event_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"model_call"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"attempt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example-provider"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"requested_model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"model-small"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"returned_model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"model-large"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4812&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"output_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;623&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"estimated_cost_usd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.041&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"retry_reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"review_rejected"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fallback_reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"quality_threshold"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"occurred_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-07-11T14:32:18Z"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The values are illustrative. The shape matters more than the numbers.&lt;/p&gt;

&lt;p&gt;Keep &lt;code&gt;requested_model&lt;/code&gt; and &lt;code&gt;returned_model&lt;/code&gt; separate. A gateway may change the route after a capacity error or policy check. Logging only the requested model can assign cost and quality to the wrong route.&lt;/p&gt;

&lt;p&gt;Keep failed attempts too. Updating one trace span with the latest attempt hides the money spent on the first attempt and removes the evidence you need to fix the failure.&lt;/p&gt;

&lt;p&gt;The first version of the ledger only needs to answer four questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Which requested job caused this work?&lt;/li&gt;
&lt;li&gt;Which model and provider served each call?&lt;/li&gt;
&lt;li&gt;Which tools, retries, and route changes added cost?&lt;/li&gt;
&lt;li&gt;Did the owner accept the final result?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Close the parent run with an outcome
&lt;/h2&gt;

&lt;p&gt;Runtime completion is not a business outcome. An API can return successfully while a reviewer rejects the answer.&lt;/p&gt;

&lt;p&gt;Give the parent run a state such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;accepted
rejected
abandoned
pending_review
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The workflow owner should define &lt;code&gt;accepted&lt;/code&gt; before the run starts. A support team might require a sent reply that does not reopen the ticket within a set period. A coding team might require a merged patch with passing tests. A research workflow may need a reviewer to approve the sources.&lt;/p&gt;

&lt;p&gt;Some outcomes arrive late. Do not pretend that problem has disappeared. Store the current state, keep the time of each decision, and update the outcome when new evidence arrives. Your first report can separate immediate acceptance from later reversal.&lt;/p&gt;

&lt;p&gt;Human review creates another awkward field. If you have a defensible labor rate, include the cost. If you do not, report review minutes beside the monetary total. An honest incomplete field is more useful than a precise number built on an invented rate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compare cost per accepted outcome
&lt;/h2&gt;

&lt;p&gt;Once every child event belongs to a parent run, add the provider cost, paid tool cost, and any material review cost for that run. Then compare total workflow cost with accepted outcomes.&lt;/p&gt;

&lt;p&gt;A basic calculation is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cost per accepted outcome =
  total cost of completed parent runs / number of accepted parent runs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will probably want the distribution as well as the average. One runaway loop can hide inside a reasonable mean. Track the median, a high percentile, and the most expensive rejected runs.&lt;/p&gt;

&lt;p&gt;This view gives the workflow owner better questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which route produces accepted work with the least retry overhead?&lt;/li&gt;
&lt;li&gt;How often does the default route depend on a premium fallback?&lt;/li&gt;
&lt;li&gt;Which workflow version creates the most reviewer rework?&lt;/li&gt;
&lt;li&gt;Which agent keeps spending money without producing accepted results?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Token counts still help with diagnosis. The parent workflow gives the team a unit for budget and routing decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with one workflow
&lt;/h2&gt;

&lt;p&gt;Pick one agent workflow with meaningful spend, volume, or risk. Write down its start event, end event, owner, and acceptance rule before adding instrumentation.&lt;/p&gt;

&lt;p&gt;Generate the parent ID at the application edge. Pass it through the agent framework, gateway, and tools. Record each attempt instead of overwriting the previous one. Keep raw provider exports for reconciliation because trace estimates and billed costs can differ.&lt;/p&gt;

&lt;p&gt;Review one week of runs. Reconstruct several expensive or rejected examples by hand. You will probably find missing IDs, tool costs that never reached the trace, and acceptance rules that sounded clear until two reviewers disagreed.&lt;/p&gt;

&lt;p&gt;Do not start with a company-wide agent cost platform. A broad dashboard built on weak identifiers gives you precise totals that nobody can connect to a result.&lt;/p&gt;

&lt;p&gt;Start with one question: how much did one accepted result cost?&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://openai.github.io/openai-agents-python/tracing/" rel="noopener noreferrer"&gt;OpenAI Agents SDK tracing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/reference/resources/admin/subresources/organization/subresources/usage" rel="noopener noreferrer"&gt;OpenAI organization Usage API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://platform.claude.com/docs/en/manage-claude/usage-cost-api" rel="noopener noreferrer"&gt;Anthropic Usage and Cost API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.langchain.com/langsmith/cost-tracking" rel="noopener noreferrer"&gt;LangSmith cost tracking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://langfuse.com/docs/evaluation/scores/overview" rel="noopener noreferrer"&gt;Langfuse scores&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/open-telemetry/semantic-conventions/blob/main/docs/gen-ai/gen-ai-metrics.md" rel="noopener noreferrer"&gt;OpenTelemetry Generative AI metrics&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Originally published on the &lt;a href="https://tokenair.ai/blog/ai-agent-cost-tracking?utm_source=dev&amp;amp;utm_medium=community&amp;amp;utm_campaign=agent_cost_tracking" rel="noopener noreferrer"&gt;TokenAir Blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Disclosure: I used AI tools to help edit this post. I checked the technical claims and sources before publication.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>observability</category>
      <category>finops</category>
    </item>
  </channel>
</rss>
