
Llm Cost Optimizer
- 72 installs
- 451 repo stars
- Updated July 21, 2026
- borghei/claude-skills
llm-cost-optimizer is a skill that counts tokens, estimates LLM costs across providers, and optimizes prompts to reduce token usage without losing quality.
About
This skill counts tokens, estimates costs across LLM providers, and optimizes prompts to reduce token usage without sacrificing quality. It ships a token counter and a prompt optimizer, plus an LLM pricing reference. Developers use it to budget LLM projects, compare model pricing, and cut API costs on high-volume prompts.
- Counts tokens in prompts and estimates costs across LLM providers
- Analyzes prompts for token-reduction opportunities with a target reduction flag
- Includes an LLM pricing guide and model-selection guidance for cost-quality tradeoffs
Llm Cost Optimizer by the numbers
- 72 all-time installs (skills.sh)
- Ranked #5,620 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
llm-cost-optimizer capabilities & compatibility
- Capabilities
- token counting · cost estimation · prompt optimization · model comparison
- Use cases
- token optimization
- Pricing
- Free
What llm-cost-optimizer says it does
The **LLM Cost Optimizer** skill provides tools for counting tokens, estimating costs across different LLM providers, and optimizing prompts to reduce token usage without sacrificing quality.
python scripts/token_counter.py --file prompt.txt --models gpt-4o claude-sonnet
Optimize with target reduction
npx skills add https://github.com/borghei/claude-skills --skill llm-cost-optimizerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 72 |
|---|---|
| repo stars | ★ 451 |
| Last updated | July 21, 2026 |
| Repository | borghei/claude-skills ↗ |
What it does
Count prompt tokens, estimate LLM costs across models, and optimize prompts to reduce token usage.
Who is it for?
Developers and teams managing LLM API budgets who need token counts, cost estimates, and prompt optimization.
Skip if: Teams not using LLM APIs or without token-cost concerns.
When should I use this skill?
You want to estimate LLM costs, count tokens, optimize prompt token usage, or compare model pricing.
What you get
Produces per-request token counts, cross-model cost estimates, and prompt optimization suggestions to reduce spend.
- Token counts
- Per-model cost estimates
- Prompt optimization suggestions
By the numbers
- Two Python tools: token_counter.py and prompt_optimizer.py
- Prompt optimizer accepts a target-reduction percentage
Files
LLM Cost Optimizer
Category: Engineering
Domain: AI Cost Management
Overview
The LLM Cost Optimizer skill provides tools for counting tokens, estimating costs across different LLM providers, and optimizing prompts to reduce token usage without sacrificing quality. Essential for teams managing LLM API budgets at scale.
Quick Start
# Count tokens in a prompt file and estimate costs
python scripts/token_counter.py --file prompt.txt --models gpt-4o claude-sonnet
# Count tokens from stdin
echo "Hello world" | python scripts/token_counter.py --stdin --models all
# Analyze a prompt for optimization opportunities
python scripts/prompt_optimizer.py --file system_prompt.txt
# Optimize with target reduction
python scripts/prompt_optimizer.py --file prompt.txt --target-reduction 30Tools Overview
| Tool | Purpose | Key Flags |
|---|---|---|
token_counter.py | Count tokens and estimate costs across models | --file, --text, --stdin, --models |
prompt_optimizer.py | Analyze prompts for token reduction opportunities | --file, --target-reduction, --format |
Workflows
Cost Estimation for New Project
1. Collect sample prompts (system prompt + user messages) 2. Run token_counter.py with target models 3. Multiply per-request cost by expected daily volume 4. Compare models on cost-quality tradeoff
Prompt Optimization Sprint
1. Identify highest-cost prompts from usage logs 2. Run prompt_optimizer.py on each 3. Apply suggested optimizations 4. Re-count tokens to verify reduction 5. A/B test optimized vs. original for quality
Reference Documentation
- LLM Pricing Guide - Current pricing for major LLM providers, token estimation methods
Common Patterns
Token Reduction Techniques
- Remove redundant instructions and examples
- Use shorter variable names in few-shot examples
- Compress verbose system prompts
- Replace repeated context with references
- Use structured output formats (JSON) to reduce response tokens
- Batch multiple requests into single prompts where possible
Cost-Effective Model Selection
- Use smaller models for classification/extraction tasks
- Reserve large models for complex reasoning
- Implement model routing based on query complexity
- Cache responses for identical or similar queries
LLM Pricing Guide
Token Estimation
What is a Token?
Tokens are the basic units LLMs process. Roughly:
- 1 token ~ 4 characters in English
- 1 token ~ 0.75 words
- 100 tokens ~ 75 words
- 1,000 tokens ~ 750 words
Tokenizer Differences
Different models use different tokenizers:
- GPT-4/GPT-4o: cl100k_base (100K vocabulary)
- Claude: Custom BPE tokenizer (~100K vocabulary)
- Llama/Mistral: SentencePiece-based
- Gemini: SentencePiece-based
Token counts can vary 10-20% between tokenizers for the same text.
Pricing Table (as of Q1 2026)
OpenAI Models
| Model | Input (per 1M tokens) | Output (per 1M tokens) | Context Window |
|---|---|---|---|
| GPT-4o | $2.50 | $10.00 | 128K |
| GPT-4o-mini | $0.15 | $0.60 | 128K |
| GPT-4 Turbo | $10.00 | $30.00 | 128K |
| o1 | $15.00 | $60.00 | 200K |
| o1-mini | $3.00 | $12.00 | 128K |
| o3-mini | $1.10 | $4.40 | 200K |
Anthropic Models
| Model | Input (per 1M tokens) | Output (per 1M tokens) | Context Window |
|---|---|---|---|
| Claude Opus 4 | $15.00 | $75.00 | 200K |
| Claude Sonnet 4 | $3.00 | $15.00 | 200K |
| Claude Haiku 3.5 | $0.80 | $4.00 | 200K |
Google Models
| Model | Input (per 1M tokens) | Output (per 1M tokens) | Context Window |
|---|---|---|---|
| Gemini 2.0 Pro | $1.25 | $5.00 | 1M |
| Gemini 2.0 Flash | $0.075 | $0.30 | 1M |
| Gemini 1.5 Pro | $1.25 | $5.00 | 2M |
Open Source (Self-Hosted Cost Estimates)
| Model | GPU Required | Approx. Cost/hr | Equivalent per 1M tokens |
|---|---|---|---|
| Llama 3 70B | 2x A100 80GB | $6.00 | ~$0.50 |
| Llama 3 8B | 1x A100 40GB | $3.00 | ~$0.10 |
| Mistral 7B | 1x A100 40GB | $3.00 | ~$0.08 |
Cost Optimization Strategies
1. Model Tiering
Route requests to the cheapest model that meets quality requirements:
- Tier 1 (cheap): Classification, extraction, formatting -> GPT-4o-mini, Haiku
- Tier 2 (mid): Summarization, Q&A, code review -> GPT-4o, Sonnet
- Tier 3 (premium): Complex reasoning, creative writing -> o1, Opus
2. Prompt Compression
- Remove filler words and redundant instructions
- Use abbreviations in system prompts
- Replace examples with schema definitions
- Typical savings: 20-40% token reduction
3. Response Caching
- Cache responses for identical prompts (exact match)
- Use semantic caching for similar prompts (embedding similarity)
- Typical savings: 30-60% cost reduction for repetitive workloads
4. Batching
- Combine multiple small requests into one prompt
- Use structured output to parse multiple results
- Typical savings: 15-30% from reduced overhead tokens
5. Context Window Management
- Summarize long conversations instead of sending full history
- Use RAG to inject only relevant context
- Implement sliding window for chat applications
#!/usr/bin/env python3
"""
Prompt Optimizer - Analyze prompts for token reduction opportunities.
Identifies verbose patterns, redundancies, and optimization opportunities
in LLM prompts to reduce token usage while preserving intent.
Author: Claude Skills Engineering Team
License: MIT
"""
import argparse
import json
import math
import re
import sys
from dataclasses import dataclass, asdict, field
from pathlib import Path
from typing import List, Dict, Optional, Tuple
@dataclass
class Optimization:
"""A single optimization opportunity."""
category: str
description: str
original_text: str
suggested_text: str
token_savings_estimate: int
line_number: Optional[int] = None
confidence: str = "medium" # high, medium, low
@dataclass
class OptimizationReport:
"""Full optimization analysis."""
original_tokens: int
optimized_tokens_estimate: int
reduction_pct: float
optimizations: List[Optimization] = field(default_factory=list)
summary: Dict[str, int] = field(default_factory=dict)
warnings: List[str] = field(default_factory=list)
# Filler phrases that can be removed without changing meaning
FILLER_PHRASES = [
(r'\bplease\s+', '', "Remove 'please' - LLMs don't need politeness tokens"),
(r'\bkindly\s+', '', "Remove 'kindly'"),
(r'\bbasically\b\s*,?\s*', '', "Remove filler word 'basically'"),
(r'\bactually\b\s*,?\s*', '', "Remove filler word 'actually'"),
(r'\bessentially\b\s*,?\s*', '', "Remove filler word 'essentially'"),
(r'\bliterally\b\s*,?\s*', '', "Remove filler word 'literally'"),
(r'\bhonestly\b\s*,?\s*', '', "Remove filler word 'honestly'"),
(r'\bobviously\b\s*,?\s*', '', "Remove filler word 'obviously'"),
(r'\bclearly\b\s*,?\s*', '', "Remove filler word 'clearly'"),
(r'\bsimply\b\s*,?\s*', '', "Remove filler word 'simply'"),
(r'\bjust\b\s+', '', "Remove filler word 'just'"),
(r'\breally\b\s*', '', "Remove filler word 'really'"),
(r'\bvery\b\s+', '', "Remove filler word 'very'"),
(r'\bin order to\b', 'to', "Simplify 'in order to' -> 'to'"),
(r'\bdue to the fact that\b', 'because', "Simplify verbose conjunction"),
(r'\bat this point in time\b', 'now', "Simplify verbose phrase"),
(r'\bin the event that\b', 'if', "Simplify 'in the event that' -> 'if'"),
(r'\bfor the purpose of\b', 'to', "Simplify verbose phrase"),
(r'\bwith regard to\b', 'about', "Simplify 'with regard to' -> 'about'"),
(r'\bin light of\b', 'given', "Simplify verbose phrase"),
(r'\bit is important to note that\b', '', "Remove unnecessary preamble"),
(r'\bI would like you to\b', '', "Remove unnecessary preamble"),
(r'\bcould you please\b', '', "Remove unnecessary politeness"),
(r'\bI want you to\b', '', "Remove unnecessary preamble"),
(r'\bmake sure to\b', '', "Simplify - the instruction itself implies this"),
(r'\bensure that you\b', '', "Remove unnecessary emphasis"),
]
# Redundant instruction patterns
REDUNDANT_PATTERNS = [
(r'(?:be|try to be)\s+(?:as\s+)?(?:concise|brief|short)\s+(?:as\s+possible|and\s+clear)',
"Redundant conciseness instruction - set max tokens instead"),
(r'(?:do not|don\'t)\s+(?:make up|hallucinate|fabricate)\s+(?:information|data|facts)',
"Common instruction that most models already follow - consider removing"),
(r'(?:you are|act as)\s+(?:a|an)\s+(?:helpful|expert|professional|skilled)',
"Role preamble can often be shortened to just the role name"),
(r'(?:remember|keep in mind|note)\s+that\s+you\s+',
"Unnecessary meta-instruction - state the requirement directly"),
(r'(?:the following|below)\s+(?:is|are)\s+(?:the|a)\s+',
"Verbose introduction to content - just present the content"),
]
def estimate_tokens(text: str) -> int:
"""Quick token estimation."""
if not text:
return 0
chars = len(text)
words = len(text.split())
return max(1, int((chars / 4.0 * 0.4) + (words / 0.75 * 0.4) + (len(re.findall(r'\w+|[^\w\s]', text)) * 0.85 * 0.2)))
def find_repeated_content(text: str) -> List[Optimization]:
"""Find repeated phrases and sentences."""
optimizations = []
sentences = re.split(r'[.!?]\s+', text)
seen = {}
for i, sent in enumerate(sentences):
normalized = sent.strip().lower()
if len(normalized) < 20:
continue
if normalized in seen:
tokens_saved = estimate_tokens(sent)
optimizations.append(Optimization(
category="repetition",
description=f"Sentence repeated (first at position {seen[normalized]})",
original_text=sent.strip()[:80],
suggested_text="[remove duplicate]",
token_savings_estimate=tokens_saved,
confidence="high",
))
else:
seen[normalized] = i
# Find repeated phrases (3+ words, appearing 3+ times)
words = text.split()
for n in range(3, 8):
phrase_counts: Dict[str, int] = {}
for i in range(len(words) - n + 1):
phrase = " ".join(words[i:i+n]).lower()
phrase_counts[phrase] = phrase_counts.get(phrase, 0) + 1
for phrase, count in phrase_counts.items():
if count >= 3 and len(phrase) > 15:
tokens_saved = estimate_tokens(phrase) * (count - 1)
optimizations.append(Optimization(
category="repetition",
description=f"Phrase repeated {count} times",
original_text=phrase[:80],
suggested_text=f"[define once, reference {count-1} times]",
token_savings_estimate=tokens_saved,
confidence="medium",
))
return optimizations
def find_filler_optimizations(text: str) -> List[Optimization]:
"""Find filler words and verbose phrases."""
optimizations = []
lines = text.split("\n")
for filler_pattern, replacement, desc in FILLER_PHRASES:
for i, line in enumerate(lines, 1):
matches = list(re.finditer(filler_pattern, line, re.IGNORECASE))
for match in matches:
original = match.group()
tokens_saved = max(1, estimate_tokens(original) - estimate_tokens(replacement))
optimizations.append(Optimization(
category="filler",
description=desc,
original_text=original.strip(),
suggested_text=replacement if replacement else "[remove]",
token_savings_estimate=tokens_saved,
line_number=i,
confidence="high",
))
return optimizations
def find_redundant_instructions(text: str) -> List[Optimization]:
"""Find redundant or unnecessary instructions."""
optimizations = []
lines = text.split("\n")
for pattern, desc in REDUNDANT_PATTERNS:
for i, line in enumerate(lines, 1):
if re.search(pattern, line, re.IGNORECASE):
match = re.search(pattern, line, re.IGNORECASE)
tokens_saved = estimate_tokens(match.group()) if match else 3
optimizations.append(Optimization(
category="redundant",
description=desc,
original_text=line.strip()[:80],
suggested_text="[consider removing or simplifying]",
token_savings_estimate=tokens_saved,
line_number=i,
confidence="medium",
))
return optimizations
def find_formatting_optimizations(text: str) -> List[Optimization]:
"""Find formatting-based optimization opportunities."""
optimizations = []
lines = text.split("\n")
# Excessive blank lines
consecutive_blank = 0
blank_start = 0
for i, line in enumerate(lines, 1):
if not line.strip():
if consecutive_blank == 0:
blank_start = i
consecutive_blank += 1
else:
if consecutive_blank >= 3:
optimizations.append(Optimization(
category="formatting",
description=f"{consecutive_blank} consecutive blank lines (lines {blank_start}-{blank_start+consecutive_blank-1})",
original_text=f"[{consecutive_blank} blank lines]",
suggested_text="[1 blank line]",
token_savings_estimate=consecutive_blank - 1,
line_number=blank_start,
confidence="high",
))
consecutive_blank = 0
# Long markdown headers/dividers
for i, line in enumerate(lines, 1):
if re.match(r'^[-=*#]{10,}$', line.strip()):
tokens_saved = max(1, estimate_tokens(line) - 2)
optimizations.append(Optimization(
category="formatting",
description="Long decorative divider line",
original_text=line.strip()[:40],
suggested_text="---",
token_savings_estimate=tokens_saved,
line_number=i,
confidence="high",
))
# Verbose list markers
numbered_items = [i for i, l in enumerate(lines) if re.match(r'^\s*\d+\.\s', l)]
if len(numbered_items) > 10:
optimizations.append(Optimization(
category="formatting",
description=f"Long numbered list ({len(numbered_items)} items) - consider condensing",
original_text=f"[{len(numbered_items)} numbered items]",
suggested_text="Use dash lists (-) or combine related items",
token_savings_estimate=len(numbered_items),
confidence="low",
))
return optimizations
def analyze_prompt(text: str, target_reduction: Optional[float] = None) -> OptimizationReport:
"""Perform full prompt optimization analysis."""
original_tokens = estimate_tokens(text)
all_optimizations = []
all_optimizations.extend(find_filler_optimizations(text))
all_optimizations.extend(find_redundant_instructions(text))
all_optimizations.extend(find_repeated_content(text))
all_optimizations.extend(find_formatting_optimizations(text))
# Deduplicate by line number and category
seen = set()
unique_optimizations = []
for opt in all_optimizations:
key = (opt.category, opt.line_number, opt.original_text[:30])
if key not in seen:
seen.add(key)
unique_optimizations.append(opt)
# Sort by savings descending
unique_optimizations.sort(key=lambda x: x.token_savings_estimate, reverse=True)
total_savings = sum(o.token_savings_estimate for o in unique_optimizations)
optimized_estimate = max(1, original_tokens - total_savings)
reduction_pct = (total_savings / max(original_tokens, 1)) * 100
# Category summary
summary: Dict[str, int] = {}
for opt in unique_optimizations:
summary[opt.category] = summary.get(opt.category, 0) + opt.token_savings_estimate
report = OptimizationReport(
original_tokens=original_tokens,
optimized_tokens_estimate=optimized_estimate,
reduction_pct=round(reduction_pct, 1),
optimizations=unique_optimizations,
summary=summary,
)
if target_reduction and reduction_pct < target_reduction:
report.warnings.append(
f"Target reduction of {target_reduction}% not achievable through automated "
f"optimization alone ({reduction_pct:.1f}% found). Consider manual rewriting."
)
return report
def format_human(report: OptimizationReport) -> str:
"""Format for human reading."""
lines = []
lines.append("=" * 65)
lines.append("PROMPT OPTIMIZATION REPORT")
lines.append("=" * 65)
lines.append(f"Original tokens (est.): {report.original_tokens:,}")
lines.append(f"Optimized tokens (est.): {report.optimized_tokens_estimate:,}")
lines.append(f"Potential reduction: {report.reduction_pct}%")
lines.append(f"Token savings: ~{report.original_tokens - report.optimized_tokens_estimate:,}")
lines.append("")
if report.summary:
lines.append("Savings by Category:")
for cat, savings in sorted(report.summary.items(), key=lambda x: -x[1]):
lines.append(f" {cat}: ~{savings} tokens")
lines.append("")
if report.warnings:
for w in report.warnings:
lines.append(f" WARNING: {w}")
lines.append("")
lines.append(f"Optimization Opportunities ({len(report.optimizations)} found):")
lines.append("-" * 55)
for i, opt in enumerate(report.optimizations[:20], 1):
ln = f" (line {opt.line_number})" if opt.line_number else ""
lines.append(f" {i}. [{opt.category.upper()}]{ln} ~{opt.token_savings_estimate} tokens")
lines.append(f" {opt.description}")
lines.append(f" Before: {opt.original_text}")
lines.append(f" After: {opt.suggested_text}")
lines.append("")
if len(report.optimizations) > 20:
lines.append(f" ... and {len(report.optimizations) - 20} more optimizations")
lines.append("=" * 65)
return "\n".join(lines)
def format_json(report: OptimizationReport) -> str:
"""Format as JSON."""
data = {
"original_tokens": report.original_tokens,
"optimized_tokens_estimate": report.optimized_tokens_estimate,
"reduction_pct": report.reduction_pct,
"summary": report.summary,
"warnings": report.warnings,
"optimizations": [asdict(o) for o in report.optimizations],
}
return json.dumps(data, indent=2)
def main():
parser = argparse.ArgumentParser(
description="Prompt Optimizer - Analyze prompts for token reduction opportunities"
)
input_group = parser.add_mutually_exclusive_group(required=True)
input_group.add_argument("--file", help="Path to prompt file")
input_group.add_argument("--text", help="Prompt text")
input_group.add_argument("--stdin", action="store_true", help="Read from stdin")
parser.add_argument("--target-reduction", type=float,
help="Target token reduction percentage (e.g., 30 for 30%%)")
parser.add_argument("--format", choices=["human", "json"], default="human",
help="Output format (default: human)")
args = parser.parse_args()
if args.file:
path = Path(args.file)
if not path.exists():
print(f"Error: File not found: {args.file}", file=sys.stderr)
sys.exit(1)
text = path.read_text(encoding="utf-8", errors="ignore")
elif args.text:
text = args.text
else:
text = sys.stdin.read()
if not text.strip():
print("Error: Empty input", file=sys.stderr)
sys.exit(1)
report = analyze_prompt(text, args.target_reduction)
if args.format == "json":
print(format_json(report))
else:
print(format_human(report))
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Token Counter - Count tokens in prompts and estimate costs across LLM models.
Uses heuristic tokenization (character and word-based estimation) to provide
accurate token counts without requiring external tokenizer libraries.
Author: Claude Skills Engineering Team
License: MIT
"""
import argparse
import json
import math
import re
import sys
from dataclasses import dataclass, field
from pathlib import Path
from typing import List, Dict, Optional, Tuple
@dataclass
class ModelPricing:
"""Pricing information for an LLM model."""
name: str
provider: str
input_per_million: float # USD per 1M input tokens
output_per_million: float # USD per 1M output tokens
context_window: int
token_ratio: float = 1.0 # Multiplier vs. GPT-4 tokenizer baseline
# Pricing as of Q1 2026
MODEL_CATALOG = {
"gpt-4o": ModelPricing("GPT-4o", "OpenAI", 2.50, 10.00, 128000, 1.0),
"gpt-4o-mini": ModelPricing("GPT-4o-mini", "OpenAI", 0.15, 0.60, 128000, 1.0),
"gpt-4-turbo": ModelPricing("GPT-4 Turbo", "OpenAI", 10.00, 30.00, 128000, 1.0),
"o1": ModelPricing("o1", "OpenAI", 15.00, 60.00, 200000, 1.0),
"o1-mini": ModelPricing("o1-mini", "OpenAI", 3.00, 12.00, 128000, 1.0),
"o3-mini": ModelPricing("o3-mini", "OpenAI", 1.10, 4.40, 200000, 1.0),
"claude-opus": ModelPricing("Claude Opus 4", "Anthropic", 15.00, 75.00, 200000, 1.05),
"claude-sonnet": ModelPricing("Claude Sonnet 4", "Anthropic", 3.00, 15.00, 200000, 1.05),
"claude-haiku": ModelPricing("Claude Haiku 3.5", "Anthropic", 0.80, 4.00, 200000, 1.05),
"gemini-pro": ModelPricing("Gemini 2.0 Pro", "Google", 1.25, 5.00, 1000000, 0.95),
"gemini-flash": ModelPricing("Gemini 2.0 Flash", "Google", 0.075, 0.30, 1000000, 0.95),
}
def estimate_tokens(text: str, token_ratio: float = 1.0) -> int:
"""
Estimate token count using heuristic methods.
Uses multiple estimation strategies and averages them for accuracy:
1. Character-based: ~4 chars per token for English
2. Word-based: ~0.75 words per token
3. Whitespace + punctuation based
"""
if not text:
return 0
# Strategy 1: Character-based (4 chars per token average)
char_estimate = len(text) / 4.0
# Strategy 2: Word-based
words = text.split()
word_estimate = len(words) / 0.75
# Strategy 3: More refined - split on whitespace and punctuation
# Accounts for subword tokenization
pieces = re.findall(r'\w+|[^\w\s]', text)
piece_estimate = len(pieces) * 0.85 # Most pieces are 1 token, some merge
# Strategy 4: Account for numbers (often multiple tokens)
numbers = re.findall(r'\d+', text)
number_extra = sum(max(0, len(n) // 3 - 1) for n in numbers)
# Strategy 5: Account for code (different tokenization patterns)
code_indicators = len(re.findall(r'[{}()\[\];:=<>]', text))
code_adjustment = code_indicators * 0.3
# Weighted average
base_estimate = (char_estimate * 0.35 + word_estimate * 0.35 + piece_estimate * 0.30)
adjusted = base_estimate + number_extra + code_adjustment
# Apply model-specific ratio
return max(1, int(math.ceil(adjusted * token_ratio)))
def estimate_costs(token_count: int, models: List[str],
assume_output_ratio: float = 1.5) -> List[Dict]:
"""Estimate costs for given token count across models."""
results = []
for model_key in models:
model = MODEL_CATALOG.get(model_key)
if not model:
continue
adjusted_tokens = int(token_count * model.token_ratio)
estimated_output = int(adjusted_tokens * assume_output_ratio)
input_cost = (adjusted_tokens / 1_000_000) * model.input_per_million
output_cost = (estimated_output / 1_000_000) * model.output_per_million
total_cost = input_cost + output_cost
fits_context = adjusted_tokens <= model.context_window
results.append({
"model": model.name,
"provider": model.provider,
"estimated_input_tokens": adjusted_tokens,
"estimated_output_tokens": estimated_output,
"input_cost_usd": round(input_cost, 6),
"output_cost_usd": round(output_cost, 6),
"total_cost_usd": round(total_cost, 6),
"cost_per_1k_requests": round(total_cost * 1000, 2),
"cost_per_1m_requests": round(total_cost * 1_000_000, 2),
"fits_context_window": fits_context,
"context_window": model.context_window,
"context_utilization_pct": round(adjusted_tokens / model.context_window * 100, 1),
})
results.sort(key=lambda x: x["total_cost_usd"])
return results
def analyze_text_composition(text: str) -> Dict:
"""Analyze the composition of the text for optimization insights."""
lines = text.split("\n")
words = text.split()
# Detect content types
code_lines = sum(1 for l in lines if re.search(r'[{}()\[\];=].*[{}()\[\];=]', l))
empty_lines = sum(1 for l in lines if not l.strip())
comment_lines = sum(1 for l in lines if l.strip().startswith(("#", "//", "/*", "*", "<!--")))
# Detect repetition
unique_words = set(w.lower() for w in words)
repetition_ratio = 1 - (len(unique_words) / max(len(words), 1))
# Detect verbose patterns
filler_words = {"please", "kindly", "basically", "actually", "essentially",
"literally", "honestly", "obviously", "clearly", "simply",
"just", "really", "very", "quite", "rather"}
filler_count = sum(1 for w in words if w.lower() in filler_words)
return {
"total_characters": len(text),
"total_words": len(words),
"total_lines": len(lines),
"empty_lines": empty_lines,
"code_lines": code_lines,
"comment_lines": comment_lines,
"unique_word_ratio": round(1 - repetition_ratio, 3),
"repetition_ratio": round(repetition_ratio, 3),
"filler_word_count": filler_count,
"avg_word_length": round(sum(len(w) for w in words) / max(len(words), 1), 1),
"avg_line_length": round(sum(len(l) for l in lines) / max(len(lines), 1), 1),
}
def format_human(text: str, token_count: int, costs: List[Dict],
composition: Dict) -> str:
"""Format results for human reading."""
lines = []
lines.append("=" * 65)
lines.append("TOKEN COUNT & COST ESTIMATION")
lines.append("=" * 65)
lines.append(f"Estimated tokens: {token_count:,}")
lines.append(f"Characters: {composition['total_characters']:,}")
lines.append(f"Words: {composition['total_words']:,}")
lines.append(f"Lines: {composition['total_lines']:,}")
lines.append("")
lines.append("Text Composition:")
lines.append(f" Unique word ratio: {composition['unique_word_ratio']:.1%}")
lines.append(f" Filler words: {composition['filler_word_count']}")
lines.append(f" Code lines: {composition['code_lines']}")
lines.append(f" Empty lines: {composition['empty_lines']}")
lines.append("")
lines.append("Cost Estimates (sorted by total cost):")
lines.append(f" {'Model':<22} {'Input $':>10} {'Output $':>10} {'Total $':>10} {'Per 1K req':>12}")
lines.append(" " + "-" * 64)
for c in costs:
ctx = "OK" if c["fits_context_window"] else "EXCEEDS"
lines.append(
f" {c['model']:<22} "
f"${c['input_cost_usd']:>8.4f} "
f"${c['output_cost_usd']:>8.4f} "
f"${c['total_cost_usd']:>8.4f} "
f"${c['cost_per_1k_requests']:>10.2f}"
)
if not c["fits_context_window"]:
lines.append(f" WARNING: {ctx} context window ({c['context_window']:,} tokens)")
lines.append("")
if costs:
cheapest = costs[0]
most_expensive = costs[-1]
if len(costs) > 1:
savings = most_expensive["total_cost_usd"] - cheapest["total_cost_usd"]
lines.append(f"Cheapest: {cheapest['model']} (${cheapest['total_cost_usd']:.4f}/request)")
lines.append(f"Most expensive: {most_expensive['model']} (${most_expensive['total_cost_usd']:.4f}/request)")
if most_expensive["total_cost_usd"] > 0:
pct = (savings / most_expensive["total_cost_usd"]) * 100
lines.append(f"Potential savings by switching: ${savings:.4f}/request ({pct:.0f}%)")
lines.append("=" * 65)
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(
description="Token Counter - Count tokens and estimate costs across LLM models"
)
input_group = parser.add_mutually_exclusive_group(required=True)
input_group.add_argument("--file", help="Path to text/prompt file")
input_group.add_argument("--text", help="Text string to count")
input_group.add_argument("--stdin", action="store_true", help="Read from stdin")
parser.add_argument("--models", nargs="+", default=["all"],
help="Models to estimate costs for (default: all). "
f"Options: {', '.join(MODEL_CATALOG.keys())}, all")
parser.add_argument("--output-ratio", type=float, default=1.5,
help="Assumed output/input token ratio (default: 1.5)")
parser.add_argument("--format", choices=["human", "json"], default="human",
help="Output format (default: human)")
args = parser.parse_args()
# Read input
if args.file:
path = Path(args.file)
if not path.exists():
print(f"Error: File not found: {args.file}", file=sys.stderr)
sys.exit(1)
text = path.read_text(encoding="utf-8", errors="ignore")
elif args.text:
text = args.text
else:
text = sys.stdin.read()
if not text.strip():
print("Error: Empty input", file=sys.stderr)
sys.exit(1)
# Resolve models
if "all" in args.models:
model_keys = list(MODEL_CATALOG.keys())
else:
model_keys = args.models
# Count and estimate
token_count = estimate_tokens(text)
costs = estimate_costs(token_count, model_keys, args.output_ratio)
composition = analyze_text_composition(text)
if args.format == "json":
output = {
"estimated_tokens": token_count,
"composition": composition,
"cost_estimates": costs,
}
print(json.dumps(output, indent=2))
else:
print(format_human(text, token_count, costs, composition))
if __name__ == "__main__":
main()
Related skills
FAQ
What tools does it provide?
A token counter that counts tokens and estimates costs across models, and a prompt optimizer that analyzes prompts for token reduction opportunities.
Can it target a specific reduction?
Yes, the prompt optimizer accepts a target-reduction flag, for example 30 percent.