AI Cost Manager & Reducer
Audit as an efficiency engineer, not a summarizer. Every finding must name a concrete waste pattern, its cost risk, and a safe optimization strategy that preserves reasoning quality and chain correctness.
Quick Start
- Identify all AI call sites: LLM API calls, embedding generation, vector search, tool dispatch, agent loops.
- Trace each call's purpose, frequency, input size, output size, and model selection.
- Detect waste patterns (see catalogue below).
- Rank findings by severity and estimated cost impact.
- Propose safe optimizations with validation steps.
Never recommend removing a reasoning step unless you have verified the step is truly redundant or its output is unused downstream.
Audit Scope
AI Call Sites to Inspect
- LLM completions:
openai, @anthropic-ai/sdk, Supabase Edge Functions calling AI APIs, server actions, background workers, cron jobs
- Embedding generation:
embeddings.create(), embed(), pgvector insert paths, semantic search pipelines
- Vector search: cosine similarity queries,
<=> operator, HNSW/IVFFlat index queries
- Tool/function calls: agent tool dispatch loops, multi-step orchestration, MCP tool invocations
- Streaming flows: streamed completions feeding downstream parsers or UI
- Retry logic: exponential backoff, retry-on-failure wrappers, queue consumers
- Caching layers: Redis/KV caches keyed on prompts, memoization wrappers, CDN-cached AI responses
- Classification / extraction calls: sentiment, category, entity extraction, intent detection
- Summarization pipelines: document chunking, recursive summarization, context compression
- Model selection logic: environment switches, tier routing, fallback chains
Waste Pattern Catalogue
Token Waste
| ID |
Pattern |
Signal |
| TW-1 |
Oversized system prompt injected on every call |
System prompt > 500 tokens with mostly static content |
| TW-2 |
Full conversation history resent without truncation |
Context grows unboundedly per session |
| TW-3 |
Redundant context injection |
Same DB rows / user profile fetched and embedded in prompt on every request |
| TW-4 |
Verbose output without max_tokens cap |
Responses regularly exceed task requirements |
| TW-5 |
Unstructured output where JSON/schema would halve tokens |
Free-text response parsed by regex downstream |
| TW-6 |
Recursive summarization without memoization |
Same document re-summarized on every call |
Repeated / Duplicate Calls
| ID |
Pattern |
Signal |
| RC-1 |
Identical prompt sent multiple times per request |
No cache; same user query triggers 2+ completions |
| RC-2 |
Duplicate embedding generation |
Same text embedded on insert and on query with no stored cache |
| RC-3 |
Classification called once per item in a loop |
Per-row intent/sentiment when batch classification is available |
| RC-4 |
Agent re-reads same tool output in next iteration |
Tool result not stored in agent state |
| RC-5 |
Background job re-processes unchanged records |
No updated_at / version gate before AI call |
Model Overuse
| ID |
Pattern |
Signal |
| MO-1 |
GPT-4/Claude Opus used for simple classification or formatting |
Task needs < 200 tokens and has deterministic answer |
| MO-2 |
Expensive model used in high-frequency cron |
Cron calls Opus/GPT-4 every minute on potentially unchanged data |
| MO-3 |
No model routing between tiers |
Same model regardless of task complexity or latency budget |
| MO-4 |
Embedding model overqualified for the retrieval task |
Ada-3 on short single-word lookups where text-embedding-3-small suffices |
Retry & Loop Storms
| ID |
Pattern |
Signal |
| RL-1 |
Unbounded agent loop |
while (true) or recursive agent with no step cap |
| RL-2 |
Retry on every error including non-retryable (400s) |
Retry wrapper doesn't skip validation errors |
| RL-3 |
Retry storm on quota hit without jitter |
Simultaneous retries after 429 with no backoff spread |
| RL-4 |
Tool call in loop without early exit |
Agent calls search tool repeatedly even after finding answer |
Caching Gaps
| ID |
Pattern |
Signal |
| CG-1 |
No prompt-level cache |
Identical prompts hit the API on every call |
| CG-2 |
No embedding cache |
pgvector rows recalculated instead of reused |
| CG-3 |
No semantic cache |
Similar (not identical) prompts bypass cache |
| CG-4 |
Short or missing TTL on AI responses |
Cache evicts results before they can be reused |
| CG-5 |
Streaming response not cached |
Streamed output never stored; replays cost full tokens |
Chain Inefficiency
| ID |
Pattern |
Signal |
| CI-1 |
Sequential calls that could be parallelized |
Step B doesn't need step A's output but waits for it |
| CI-2 |
Multi-step chain where one call could replace two |
Classify then reformat is one structured-output call |
| CI-3 |
Intermediate results discarded and regenerated |
Summarization result thrown away; re-run next request |
| CI-4 |
Unnecessary tool calls |
Agent calls search when result is already in context |
Review Workflow
1. Map the AI Call Graph
For each AI call site, record:
File → function → purpose → model → avg input tokens → avg output tokens → call frequency → cached?
Flag any call where: frequency × token-cost > threshold, or model tier doesn't match task complexity.
2. Check Caching Coverage
- Is there a cache keyed on the normalized prompt or embedding input?
- What is the TTL? Is it appropriate for data freshness requirements?
- Is the cache hit rate observable?
- For embeddings: are vectors stored in pgvector and reused, or regenerated on every query?
3. Evaluate Model Routing
For each LLM call:
- Is the task classification/formatting/extraction with a deterministic answer? → Route to smallest capable model.
- Is the task reasoning/generation/planning with variable depth? → Justify the model tier.
- Is there a fallback to a cheaper model on timeout or quota?
4. Inspect Agent Loops
- Does the loop have an explicit step cap (
maxIterations, maxSteps)?
- Is there an early-exit condition checked before each tool call?
- Are tool results stored and checked before re-calling the same tool?
- Are all tool calls necessary, or can some be replaced with deterministic code?
5. Assess Prompt Size
- What is the static vs. dynamic portion of the prompt? Can static parts use prompt caching (Anthropic prefix caching, OpenAI system message caching)?
- Is context truncated or summarized before injection?
- Is the conversation history bounded?
6. Measure Observability
Verify these metrics are tracked or identify where they should be added:
- Cost per request / per feature
- Token usage breakdown (input vs. output)
- Cache hit rate
- AI call count per workflow
- Model tier distribution
- Retry rate
Output Format
Each finding must include:
ID: <waste-pattern-id>
Severity: critical | high | medium | low
Affected: <file:line or function or workflow name>
Current cost risk: <what happens at scale — e.g., "1,000 battle evaluations/day × 4,000 tokens = $X/day">
Failure / explosion scenario: <what breaks or costs explode under load>
Optimization strategy: <concrete change — model swap, caching, dedup, batching, prompt compression, etc.>
Preserves reasoning: <yes/no + explanation of why chain still works>
Validation steps:
1. <unit test or integration check>
2. <metric to observe before/after>
3. <rollback condition>
Order findings by severity. Group by call site when multiple findings share a file.
Optimization Strategies Reference
Prompt Compression
- Strip redundant preamble; move static instructions to prefix-cached system prompt.
- Use bullet points over paragraphs for instructions.
- Replace examples with a reference to a cached few-shot prompt ID.
Cheaper Model Routing
- Classification, extraction, formatting →
gpt-4o-mini, claude-haiku-4-5, or gemini-flash.
- Reasoning, planning, long-form generation → justify Sonnet/GPT-4o; Opus only for highest complexity.
- Add a
model_tier: 'fast' | 'standard' | 'premium' config to each call site.
Call Deduplication / Memoization
- Hash the normalized prompt; store result in Redis/KV with appropriate TTL.
- For embeddings: store vector in pgvector at insert time; never recompute at query time.
- For classifications: store result in a
classifications table keyed on (content_hash, classifier_version).
Semantic Caching
- Use embedding similarity to match near-identical prompts to cached responses.
- Apply only to read-heavy, low-variance query patterns (e.g., FAQ answering, tag suggestion).
Batching
- Replace per-item loops with
embeddings.create({ input: [...] }) batch calls.
- Batch classification requests using structured multi-item prompts.
- Group background job records into single API calls with array inputs.
Early Exits
- Check deterministic conditions before calling AI (e.g., if content is empty, skip summarization).
- Add tool result staleness check before re-calling the same tool in an agent loop.
- Add
if (cache.has(key)) return cache.get(key) before every AI call.
Stricter Output Control
- Always set
max_tokens proportional to expected output size.
- Use
response_format: { type: 'json_object' } or Zod schemas to prevent verbose free-text.
- Set
temperature: 0 for deterministic classification/extraction tasks.
Reusable Intermediate Results
- Store summarization outputs in the DB; invalidate only on source update.
- Cache agent scratchpad state between steps; serialize to Redis on each tool return.
Fallback Strategy
- On 429 / timeout: route to cheaper model before retrying same tier.
- On repeated tool failure: exit loop with partial result rather than infinite retry.
Constraints
- Do not recommend removing a reasoning step unless you can show the output is unused or redundant.
- Do not recommend switching models unless you verify the cheaper model produces equivalent quality on this task.
- Do not recommend aggressive caching for calls where staleness would break product correctness (e.g., real-time scoring).
- Mark every recommendation with "Preserves reasoning: yes/no" and explain.
- If a call site cannot be safely optimized, say so and explain the constraint.
- Prefer observable, incremental changes (add a cache layer, tune max_tokens) over restructuring the entire chain.
Example Triggers
- Review our AI battle evaluation pipeline for token waste and model overuse.
- Our monthly AI bill doubled; find the hotspots before we scale to 10k users.
- Audit agent workflows in
libs/domains/execution/src/ for unbounded loops and retry storms.
- Check whether our embedding pipeline is regenerating vectors that are already stored.
- Before we launch this new AI feature, review it for cost explosion scenarios under load.
1---2name: ai-cost-manager-reducer3description: Audit AI-powered features, API calls, agent workflows, prompt chains, tool calls, embeddings, vector search, retries, streaming flows, background jobs, cron tasks, caching layers, logs, and model selection logic to detect token waste, repeated AI calls, and inefficient prompt chains. Produces severity-ranked findings with safe optimization strategies that preserve reasoning quality and chain reliability. Use before approving or modifying any AI-powered feature, agent workflow, or model-calling code.4---56# AI Cost Manager & Reducer78Audit as an efficiency engineer, not a summarizer. Every finding must name a concrete waste pattern, its cost risk, and a safe optimization strategy that preserves reasoning quality and chain correctness.910## Quick Start11121. Identify all AI call sites: LLM API calls, embedding generation, vector search, tool dispatch, agent loops.132. Trace each call's purpose, frequency, input size, output size, and model selection.143. Detect waste patterns (see catalogue below).154. Rank findings by severity and estimated cost impact.165. Propose safe optimizations with validation steps.1718**Never recommend removing a reasoning step unless you have verified the step is truly redundant or its output is unused downstream.**1920---2122## Audit Scope2324### AI Call Sites to Inspect2526- LLM completions: `openai`, `@anthropic-ai/sdk`, Supabase Edge Functions calling AI APIs, server actions, background workers, cron jobs27- Embedding generation: `embeddings.create()`, `embed()`, pgvector insert paths, semantic search pipelines28- Vector search: cosine similarity queries, `<=>` operator, HNSW/IVFFlat index queries29- Tool/function calls: agent tool dispatch loops, multi-step orchestration, MCP tool invocations30- Streaming flows: streamed completions feeding downstream parsers or UI31- Retry logic: exponential backoff, retry-on-failure wrappers, queue consumers32- Caching layers: Redis/KV caches keyed on prompts, memoization wrappers, CDN-cached AI responses33- Classification / extraction calls: sentiment, category, entity extraction, intent detection34- Summarization pipelines: document chunking, recursive summarization, context compression35- Model selection logic: environment switches, tier routing, fallback chains3637---3839## Waste Pattern Catalogue4041### Token Waste4243| ID | Pattern | Signal |44|----|---------|--------|45| TW-1 | Oversized system prompt injected on every call | System prompt > 500 tokens with mostly static content |46| TW-2 | Full conversation history resent without truncation | Context grows unboundedly per session |47| TW-3 | Redundant context injection | Same DB rows / user profile fetched and embedded in prompt on every request |48| TW-4 | Verbose output without `max_tokens` cap | Responses regularly exceed task requirements |49| TW-5 | Unstructured output where JSON/schema would halve tokens | Free-text response parsed by regex downstream |50| TW-6 | Recursive summarization without memoization | Same document re-summarized on every call |5152### Repeated / Duplicate Calls5354| ID | Pattern | Signal |55|----|---------|--------|56| RC-1 | Identical prompt sent multiple times per request | No cache; same user query triggers 2+ completions |57| RC-2 | Duplicate embedding generation | Same text embedded on insert and on query with no stored cache |58| RC-3 | Classification called once per item in a loop | Per-row intent/sentiment when batch classification is available |59| RC-4 | Agent re-reads same tool output in next iteration | Tool result not stored in agent state |60| RC-5 | Background job re-processes unchanged records | No `updated_at` / version gate before AI call |6162### Model Overuse6364| ID | Pattern | Signal |65|----|---------|--------|66| MO-1 | GPT-4/Claude Opus used for simple classification or formatting | Task needs < 200 tokens and has deterministic answer |67| MO-2 | Expensive model used in high-frequency cron | Cron calls Opus/GPT-4 every minute on potentially unchanged data |68| MO-3 | No model routing between tiers | Same model regardless of task complexity or latency budget |69| MO-4 | Embedding model overqualified for the retrieval task | Ada-3 on short single-word lookups where `text-embedding-3-small` suffices |7071### Retry & Loop Storms7273| ID | Pattern | Signal |74|----|---------|--------|75| RL-1 | Unbounded agent loop | `while (true)` or recursive agent with no step cap |76| RL-2 | Retry on every error including non-retryable (400s) | Retry wrapper doesn't skip validation errors |77| RL-3 | Retry storm on quota hit without jitter | Simultaneous retries after 429 with no backoff spread |78| RL-4 | Tool call in loop without early exit | Agent calls search tool repeatedly even after finding answer |7980### Caching Gaps8182| ID | Pattern | Signal |83|----|---------|--------|84| CG-1 | No prompt-level cache | Identical prompts hit the API on every call |85| CG-2 | No embedding cache | pgvector rows recalculated instead of reused |86| CG-3 | No semantic cache | Similar (not identical) prompts bypass cache |87| CG-4 | Short or missing TTL on AI responses | Cache evicts results before they can be reused |88| CG-5 | Streaming response not cached | Streamed output never stored; replays cost full tokens |8990### Chain Inefficiency9192| ID | Pattern | Signal |93|----|---------|--------|94| CI-1 | Sequential calls that could be parallelized | Step B doesn't need step A's output but waits for it |95| CI-2 | Multi-step chain where one call could replace two | Classify then reformat is one structured-output call |96| CI-3 | Intermediate results discarded and regenerated | Summarization result thrown away; re-run next request |97| CI-4 | Unnecessary tool calls | Agent calls `search` when result is already in context |9899---100101## Review Workflow102103### 1. Map the AI Call Graph104105For each AI call site, record:106107```108File → function → purpose → model → avg input tokens → avg output tokens → call frequency → cached?109```110111Flag any call where: frequency × token-cost > threshold, or model tier doesn't match task complexity.112113### 2. Check Caching Coverage114115- Is there a cache keyed on the normalized prompt or embedding input?116- What is the TTL? Is it appropriate for data freshness requirements?117- Is the cache hit rate observable?118- For embeddings: are vectors stored in pgvector and reused, or regenerated on every query?119120### 3. Evaluate Model Routing121122For each LLM call:123- Is the task classification/formatting/extraction with a deterministic answer? → Route to smallest capable model.124- Is the task reasoning/generation/planning with variable depth? → Justify the model tier.125- Is there a fallback to a cheaper model on timeout or quota?126127### 4. Inspect Agent Loops128129- Does the loop have an explicit step cap (`maxIterations`, `maxSteps`)?130- Is there an early-exit condition checked before each tool call?131- Are tool results stored and checked before re-calling the same tool?132- Are all tool calls necessary, or can some be replaced with deterministic code?133134### 5. Assess Prompt Size135136- What is the static vs. dynamic portion of the prompt? Can static parts use prompt caching (Anthropic prefix caching, OpenAI system message caching)?137- Is context truncated or summarized before injection?138- Is the conversation history bounded?139140### 6. Measure Observability141142Verify these metrics are tracked or identify where they should be added:143- Cost per request / per feature144- Token usage breakdown (input vs. output)145- Cache hit rate146- AI call count per workflow147- Model tier distribution148- Retry rate149150---151152## Output Format153154Each finding must include:155156```157ID: <waste-pattern-id>158Severity: critical | high | medium | low159Affected: <file:line or function or workflow name>160Current cost risk: <what happens at scale — e.g., "1,000 battle evaluations/day × 4,000 tokens = $X/day">161Failure / explosion scenario: <what breaks or costs explode under load>162Optimization strategy: <concrete change — model swap, caching, dedup, batching, prompt compression, etc.>163Preserves reasoning: <yes/no + explanation of why chain still works>164Validation steps:165 1. <unit test or integration check>166 2. <metric to observe before/after>167 3. <rollback condition>168```169170Order findings by severity. Group by call site when multiple findings share a file.171172---173174## Optimization Strategies Reference175176### Prompt Compression177- Strip redundant preamble; move static instructions to prefix-cached system prompt.178- Use bullet points over paragraphs for instructions.179- Replace examples with a reference to a cached few-shot prompt ID.180181### Cheaper Model Routing182- Classification, extraction, formatting → `gpt-4o-mini`, `claude-haiku-4-5`, or `gemini-flash`.183- Reasoning, planning, long-form generation → justify Sonnet/GPT-4o; Opus only for highest complexity.184- Add a `model_tier: 'fast' | 'standard' | 'premium'` config to each call site.185186### Call Deduplication / Memoization187- Hash the normalized prompt; store result in Redis/KV with appropriate TTL.188- For embeddings: store vector in pgvector at insert time; never recompute at query time.189- For classifications: store result in a `classifications` table keyed on `(content_hash, classifier_version)`.190191### Semantic Caching192- Use embedding similarity to match near-identical prompts to cached responses.193- Apply only to read-heavy, low-variance query patterns (e.g., FAQ answering, tag suggestion).194195### Batching196- Replace per-item loops with `embeddings.create({ input: [...] })` batch calls.197- Batch classification requests using structured multi-item prompts.198- Group background job records into single API calls with array inputs.199200### Early Exits201- Check deterministic conditions before calling AI (e.g., if content is empty, skip summarization).202- Add tool result staleness check before re-calling the same tool in an agent loop.203- Add `if (cache.has(key)) return cache.get(key)` before every AI call.204205### Stricter Output Control206- Always set `max_tokens` proportional to expected output size.207- Use `response_format: { type: 'json_object' }` or Zod schemas to prevent verbose free-text.208- Set `temperature: 0` for deterministic classification/extraction tasks.209210### Reusable Intermediate Results211- Store summarization outputs in the DB; invalidate only on source update.212- Cache agent scratchpad state between steps; serialize to Redis on each tool return.213214### Fallback Strategy215- On 429 / timeout: route to cheaper model before retrying same tier.216- On repeated tool failure: exit loop with partial result rather than infinite retry.217218---219220## Constraints221222- Do not recommend removing a reasoning step unless you can show the output is unused or redundant.223- Do not recommend switching models unless you verify the cheaper model produces equivalent quality on this task.224- Do not recommend aggressive caching for calls where staleness would break product correctness (e.g., real-time scoring).225- Mark every recommendation with "Preserves reasoning: yes/no" and explain.226- If a call site cannot be safely optimized, say so and explain the constraint.227- Prefer observable, incremental changes (add a cache layer, tune max_tokens) over restructuring the entire chain.228229---230231## Example Triggers232233- Review our AI battle evaluation pipeline for token waste and model overuse.234- Our monthly AI bill doubled; find the hotspots before we scale to 10k users.235- Audit agent workflows in `libs/domains/execution/src/` for unbounded loops and retry storms.236- Check whether our embedding pipeline is regenerating vectors that are already stored.237- Before we launch this new AI feature, review it for cost explosion scenarios under load.