- Updated model profile to support new cost parameters: costPerCachedInToken and costPerReasoningOutToken. - Enhanced AgentRequestStatistic to track cached input tokens and reasoning output tokens. - Modified CompletionStatistics to include cached input tokens and reasoning output tokens. - Updated AzureAiClient, CachedClient, and other clients to handle new statistics fields. - Introduced Timings class to capture detailed timing metrics for requests. - Adjusted Usage class to include input and output token details. - Updated properties files to include new cost parameters for cached and reasoning tokens.
160 lines
4.9 KiB
Java
Executable File
160 lines
4.9 KiB
Java
Executable File
package de.extio.lmlib.agent;
|
|
|
|
import java.math.BigDecimal;
|
|
import java.text.DecimalFormat;
|
|
import java.time.Duration;
|
|
import java.time.Instant;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
import java.util.concurrent.atomic.AtomicLong;
|
|
|
|
import de.extio.lmlib.client.Completion;
|
|
|
|
public final class AgentRequestStatistic {
|
|
|
|
public static AgentRequestStatistic create() {
|
|
return new AgentRequestStatistic(true);
|
|
}
|
|
|
|
public static AgentRequestStatistic createWithoutEffectiveDuration() {
|
|
return new AgentRequestStatistic(false);
|
|
}
|
|
|
|
private AgentRequestStatistic(final boolean withEffectiveDuration) {
|
|
if (withEffectiveDuration) {
|
|
this.start = Instant.now();
|
|
}
|
|
}
|
|
|
|
private final AtomicInteger requests = new AtomicInteger();
|
|
|
|
private final AtomicInteger cachedPrompts = new AtomicInteger();
|
|
|
|
private final AtomicLong inTokens = new AtomicLong();
|
|
|
|
private final AtomicLong cachedInTokens = new AtomicLong();
|
|
|
|
private final AtomicLong outTokens = new AtomicLong();
|
|
|
|
private final AtomicLong reasoningOutTokens = new AtomicLong();
|
|
|
|
private volatile Instant start;
|
|
|
|
private volatile Duration requestDuration = Duration.ofMillis(0L);
|
|
|
|
private volatile BigDecimal cost = BigDecimal.ZERO;
|
|
|
|
public AtomicInteger getRequests() {
|
|
return this.requests;
|
|
}
|
|
|
|
public AtomicInteger getCachedPrompts() {
|
|
return this.cachedPrompts;
|
|
}
|
|
|
|
public AtomicLong getInTokens() {
|
|
return this.inTokens;
|
|
}
|
|
|
|
public AtomicLong getCachedInTokens() {
|
|
return this.cachedInTokens;
|
|
}
|
|
|
|
public AtomicLong getOutTokens() {
|
|
return this.outTokens;
|
|
}
|
|
|
|
public AtomicLong getReasoningOutTokens() {
|
|
return this.reasoningOutTokens;
|
|
}
|
|
|
|
public Duration getRequestDuration() {
|
|
return this.requestDuration;
|
|
}
|
|
|
|
public Duration getEffectiveDuration() {
|
|
if (this.start == null) {
|
|
return null;
|
|
}
|
|
return Duration.between(this.start, Instant.now());
|
|
}
|
|
|
|
public String getTps() {
|
|
final var duration = this.start == null ? this.getRequestDuration() : this.getEffectiveDuration();
|
|
return new DecimalFormat("#.##").format((double) (this.inTokens.get() + this.outTokens.get() + this.reasoningOutTokens.get()) / (double) duration.toMillis() * 1000.0);
|
|
}
|
|
|
|
public String getOutTps() {
|
|
final var duration = this.start == null ? this.getRequestDuration() : this.getEffectiveDuration();
|
|
return new DecimalFormat("#.##").format((double) (this.outTokens.get() + this.reasoningOutTokens.get()) / (double) duration.toMillis() * 1000.0);
|
|
}
|
|
|
|
public BigDecimal getCost() {
|
|
return this.cost;
|
|
}
|
|
|
|
public void add(final Completion completion) {
|
|
if (completion.statistics().cached()) {
|
|
this.cachedPrompts.incrementAndGet();
|
|
}
|
|
else {
|
|
this.getRequests().addAndGet(completion.statistics().requests());
|
|
this.getInTokens().addAndGet(completion.statistics().inTokens());
|
|
this.getCachedInTokens().addAndGet(completion.statistics().cachedInTokens());
|
|
this.getOutTokens().addAndGet(completion.statistics().outTokens());
|
|
this.getReasoningOutTokens().addAndGet(completion.statistics().reasoningOutTokens());
|
|
}
|
|
synchronized (this) {
|
|
this.requestDuration = this.requestDuration.plus(completion.statistics().duration());
|
|
this.cost = this.cost.add(completion.statistics().cost());
|
|
}
|
|
}
|
|
|
|
public void add(final AgentRequestStatistic other) {
|
|
this.getRequests().addAndGet(other.getRequests().get());
|
|
this.getCachedPrompts().addAndGet(other.getCachedPrompts().get());
|
|
this.getInTokens().addAndGet(other.getInTokens().get());
|
|
this.getCachedInTokens().addAndGet(other.getCachedInTokens().get());
|
|
this.getOutTokens().addAndGet(other.getOutTokens().get());
|
|
this.getReasoningOutTokens().addAndGet(other.getReasoningOutTokens().get());
|
|
synchronized (this) {
|
|
if (this.start != null && other.start.isBefore(this.start)) {
|
|
this.start = other.start;
|
|
}
|
|
this.requestDuration = this.requestDuration.plus(other.getRequestDuration());
|
|
this.cost = this.cost.add(other.getCost());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
final StringBuilder builder = new StringBuilder();
|
|
builder.append("AgentRequestStatistic [requests=");
|
|
builder.append(this.requests);
|
|
builder.append(", cachedPrompts=");
|
|
builder.append(this.cachedPrompts);
|
|
builder.append(", inTokens=");
|
|
builder.append(this.inTokens);
|
|
builder.append(", cachedInTokens=");
|
|
builder.append(this.cachedInTokens);
|
|
builder.append(", outTokens=");
|
|
builder.append(this.outTokens);
|
|
builder.append(", reasoningOutTokens=");
|
|
builder.append(this.reasoningOutTokens);
|
|
builder.append(", requestDuration=");
|
|
builder.append(this.requestDuration);
|
|
builder.append(", getEffectiveDuration()=");
|
|
if (this.start != null) {
|
|
builder.append(this.getEffectiveDuration());
|
|
builder.append(", getTps()=");
|
|
}
|
|
builder.append(this.getTps());
|
|
builder.append(", getOutTps()=");
|
|
builder.append(this.getOutTps());
|
|
builder.append(", getCost()=");
|
|
builder.append(this.getCost());
|
|
builder.append("]");
|
|
return builder.toString();
|
|
}
|
|
|
|
}
|