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")tessl i tessl/maven-com-embabel-agent--embabel-agent-common@0.3.1