{"slug": "stop-paying-for-invisible-retries-how-to-measure-what-an-ai-agent-really-costs", "title": "Stop Paying for Invisible Retries: How to Measure What an AI Agent Really Costs", "summary": "A developer has released SpendGraph, an SDK and stage-based framework that prices every retry attempt of an AI agent call rather than only the successful one, arguing that success-only cost tracking understates real spend. In an illustrative two-step job, the dashboard showed $0.034 while the provider billed $0.066, leaving 48% of the spend invisible. The library records each attempt as its own priced row, emits stage:failed events, and returns pricing as a promise so billing lookups stay off the user-facing response path.", "body_md": "Imagine you hire a researcher to answer a question.\n\nThey hand you a neat one-page report and say, *\"That took me 10 minutes.\"*\n\nWhat they don't tell you:\n\nThat is how most AI agents report their cost today.\n\nAn agent step rarely succeeds on the first call. The model answers in prose when you asked for JSON, so the step asks again. A reviewer rejects the answer, so the review runs again.\n\nYour provider bills every one of those calls. Most tracking only keeps the call whose answer you ended up using. The failed attempts are spent, billed, and missing from your own numbers.\n\nHere is one small job, two steps, with every call on the receipt:\n\n```\nstep       attempt   result                         cost\nextract    1         failed: prose instead of JSON  $0.005\nextract    2         ok                             $0.006\nreview     1         failed: answer rejected        $0.027\nreview     2         ok                             $0.028\n                                                    ──────\n                                   what you paid    $0.066\n                         what success-only shows    $0.034\n```\n\nThe dashboard says $0.034. The provider charges $0.066. In this run, 48% of the spend is invisible, and nothing about the answer tells you it happened.\n\nThe numbers are illustrative, but the shape is not. Any retry that happens below the layer that records cost is a retry you pay for twice and see once.\n\n[spendgraph](https://spendgraph.locusgraph.com/docs/stage/overview) makes one design choice about this: the retry wraps the whole recorded call, not just the model request inside it.\n\n```\nretry inside the call              retry around the call\n\n┌ recorded call ──────────┐        ┌ recorded call ┐  attempt 1  $0.005\n│ model  ✗                │        └───────────────┘\n│ model  ✓                │        ┌ recorded call ┐  attempt 2  $0.006\n└─────────────────────────┘        └───────────────┘\none row: $0.006                    two rows: $0.011\n```\n\nOn the left, the retry is smaller and cheaper to build, and your accounting is wrong. On the right, every attempt is its own priced record, so the total adds up.\n\nTwo other choices follow from it:\n\nA stage is one prompt, one schema, and one priced reply. You get the answer as soon as it is ready, and the price when it resolves:\n\n``` js\nimport { runStage } from \"@spendgraph/stage\";\n\nconst outcome = await runStage(prompts, llm, \"classify-email\", SCHEMA, {\n  question: \"Is this email spam or clean?\",\n}, {\n  attempts: 3,\n  emit: (event) => {\n    if (event.type === \"stage:failed\") {\n      console.warn(`attempt ${event.attempt} failed: ${event.error.message}`);\n    }\n  },\n});\n\nconsole.log(outcome.data);\n\nconst micros = await outcome.pricing;\n```\n\nA few things worth knowing:\n\n`prompts` is your prompt store and `llm` is your model client. The `pricing` is a promise, and the answer does not wait for it. A billing lookup has no business on the path of a user waiting for a reply.`undefined` when no price could be found. That is deliberate: an unknown price is not the same as a zero one, and it should not look like one.`stage:failed` as it happens, and shows up as its own priced record, so the extra spend is on the bill and not only in your logs.\nIf you only want spend tracking on the client you already use, without stages, the SDK wraps it in one line:\n\n``` python\nimport OpenAI from \"openai\";\nimport { SpendGraph } from \"@spendgraph/sdk\";\n\nconst meter = new SpendGraph({\n  apiKey: process.env.SPENDGRAPH_API_KEY,\n  baseUrl: process.env.SPENDGRAPH_BASE_URL,\n});\nconst openai = meter.wrap(new OpenAI());\n```\n\nUse `openai` exactly as before. Each call's usage is read off the reply and reported in the background, and the meter never throws into your code.\n\nIf a retry happens where your cost tracking cannot see it, your cost tracking is wrong, and wrong in the direction that makes things look cheaper than they are.\n\nCount every attempt. Look at which steps fail most. The prompt that fails half the time is usually a cheaper fix than a cheaper model.", "url": "https://wpnews.pro/news/stop-paying-for-invisible-retries-how-to-measure-what-an-ai-agent-really-costs", "canonical_source": "https://dev.to/fnlog0/stop-paying-for-invisible-retries-how-to-measure-what-an-ai-agent-really-costs-4a1h", "published_at": "2026-09-26 13:12:00+00:00", "updated_at": "2026-09-26 13:30:06.217211+00:00", "lang": "en", "topics": ["ai-agents", "ai-infrastructure", "developer-tools", "mlops", "ai-tools"], "entities": ["SpendGraph", "LocusGraph", "OpenAI"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/stop-paying-for-invisible-retries-how-to-measure-what-an-ai-agent-really-costs", "markdown": "https://wpnews.pro/news/stop-paying-for-invisible-retries-how-to-measure-what-an-ai-agent-really-costs.md", "text": "https://wpnews.pro/news/stop-paying-for-invisible-retries-how-to-measure-what-an-ai-agent-really-costs.txt", "jsonld": "https://wpnews.pro/news/stop-paying-for-invisible-retries-how-to-measure-what-an-ai-agent-really-costs.jsonld"}}