Common AI framework utilities for the Embabel Agent system including LLM configuration, output converters, prompt contributors, and embedding service abstractions.
—
Pricing calculation system for LLM usage based on input and output tokens.
Calculate LLM usage costs from token counts.
interface PricingModel {
fun usdPerInputToken(): Double
fun usdPerOutputToken(): Double
fun costOf(inputTokens: Int, outputTokens: Int): Double
fun costOf(usage: Usage): Double
companion object {
@JvmStatic
val ALL_YOU_CAN_EAT: PricingModel
@JvmStatic
fun usdPerToken(
usdPerInputToken: Double,
usdPerOutputToken: Double
): PricingModel
@JvmStatic
fun usdPer1MTokens(
usdPer1mInputTokens: Double,
usdPer1mOutputTokens: Double
): PricingModel
}
}Basic Usage:
// Zero-cost model (local/free)
val freePricing = PricingModel.ALL_YOU_CAN_EAT
val cost1 = freePricing.costOf(10000, 5000) // $0.00
// Per-million-token pricing (most common)
val gpt4Pricing = PricingModel.usdPer1MTokens(
usdPer1mInputTokens = 30.0,
usdPer1mOutputTokens = 60.0
)
val cost2 = gpt4Pricing.costOf(1000, 500) // $0.06
// Per-token pricing (rarely used)
val perTokenPricing = PricingModel.usdPerToken(
usdPerInputToken = 0.00003,
usdPerOutputToken = 0.00006
)Concrete pricing implementation.
const val ONE_MILLION = 1000000.0
class PerTokenPricingModel(
val usdPer1mInputTokens: Double,
val usdPer1mOutputTokens: Double
) : PricingModelUsage:
val pricing = PerTokenPricingModel(
usdPer1mInputTokens = 10.0,
usdPer1mOutputTokens = 30.0
)
println("Input rate: $${pricing.usdPer1mInputTokens} per 1M tokens")
val cost = pricing.costOf(5000, 2000)// GPT-4
val gpt4 = PricingModel.usdPer1MTokens(30.0, 60.0)
// GPT-4 Turbo
val gpt4Turbo = PricingModel.usdPer1MTokens(10.0, 30.0)
// GPT-3.5 Turbo
val gpt35 = PricingModel.usdPer1MTokens(0.5, 1.5)
// o1-preview
val o1 = PricingModel.usdPer1MTokens(15.0, 60.0)// Claude 3 Opus
val claude3Opus = PricingModel.usdPer1MTokens(15.0, 75.0)
// Claude 3 Sonnet
val claude3Sonnet = PricingModel.usdPer1MTokens(3.0, 15.0)
// Claude 3 Haiku
val claude3Haiku = PricingModel.usdPer1MTokens(0.25, 1.25)val ollama = PricingModel.ALL_YOU_CAN_EAT
val localLlama = PricingModel.ALL_YOU_CAN_EATclass CostTracker(private val pricing: PricingModel) {
private var totalInputTokens = 0
private var totalOutputTokens = 0
fun recordUsage(inputTokens: Int, outputTokens: Int) {
totalInputTokens += inputTokens
totalOutputTokens += outputTokens
}
fun totalCost(): Double {
return pricing.costOf(totalInputTokens, totalOutputTokens)
}
fun summary(): String {
return """
Input tokens: $totalInputTokens
Output tokens: $totalOutputTokens
Total cost: ${"$%.4f".format(totalCost())}
""".trimIndent()
}
}
// Usage
val tracker = CostTracker(gpt4Pricing)
tracker.recordUsage(1000, 500)
println(tracker.summary())class BudgetManager(
private val pricing: PricingModel,
private val maxBudget: Double
) {
private val tracker = CostTracker(pricing)
fun canAfford(inputTokens: Int, outputTokens: Int): Boolean {
val estimatedCost = pricing.costOf(inputTokens, outputTokens)
return tracker.totalCost() + estimatedCost <= maxBudget
}
fun recordUsage(inputTokens: Int, outputTokens: Int) {
if (!canAfford(inputTokens, outputTokens)) {
throw BudgetExceededException(
"Request would exceed budget of $$maxBudget"
)
}
tracker.recordUsage(inputTokens, outputTokens)
}
fun remainingBudget(): Double {
return maxBudget - tracker.totalCost()
}
}fun comparePricing(
inputTokens: Int,
outputTokens: Int,
models: Map<String, PricingModel>
): Map<String, Double> {
return models.mapValues { (_, pricing) ->
pricing.costOf(inputTokens, outputTokens)
}.toSortedMap(compareBy { models[it]!!.costOf(inputTokens, outputTokens) })
}
// Usage
val models = mapOf(
"GPT-4" to gpt4Pricing,
"GPT-4 Turbo" to gpt4TurboPricing,
"Claude 3 Opus" to claude3OpusPricing
)
val comparison = comparePricing(10000, 5000, models)
comparison.forEach { (model, cost) ->
println("$model: ${"$%.4f".format(cost)}")
}fun selectModelByBudget(
inputTokens: Int,
outputTokens: Int,
maxCost: Double,
models: Map<String, PricingModel>
): String? {
return models
.filter { (_, pricing) ->
pricing.costOf(inputTokens, outputTokens) <= maxCost
}
.minByOrNull { (_, pricing) ->
pricing.costOf(inputTokens, outputTokens)
}
?.key
}fun calculateTokenBudget(
budget: Double,
pricing: PricingModel,
inputOutputRatio: Double = 2.0
): Pair<Int, Int> {
val inputRate = pricing.usdPerInputToken()
val outputRate = pricing.usdPerOutputToken()
val totalTokens = (budget / (inputRate + outputRate / inputOutputRatio)).toInt()
val inputTokens = (totalTokens * inputOutputRatio / (1 + inputOutputRatio)).toInt()
val outputTokens = totalTokens - inputTokens
return inputTokens to outputTokens
}val metadata = LlmMetadata(
name = "gpt-4",
provider = "openai",
knowledgeCutoffDate = LocalDate.of(2023, 4, 1),
pricingModel = PricingModel.usdPer1MTokens(30.0, 60.0)
)
metadata.pricingModel?.let { pricing ->
val cost = pricing.costOf(1000, 500)
println("Cost: $$cost")
} ?: println("Pricing not available")Install with Tessl CLI
npx tessl i tessl/maven-com-embabel-agent--embabel-agent-common@0.3.0