发布

  • [OPIK-4909] [BE] fix: use pre-computed gen_ai.usage.cost from OTel (#6893)

    frostbyte_neo 发布于 2026-06-01 10:53:46 +00:00

    • [OPIK-4909] [BE] fix: use pre-computed gen_ai.usage.cost from OTel spans

    LiteLLM and similar integrations send the exact request cost as the float
    OTel attribute gen_ai.usage.cost. It matched the broad gen_ai.usage. prefix
    rule and was routed to the integer-only usage map, where the double value
    was silently dropped; Opik then recalculated cost from its bundled price
    table, diverging from the value LiteLLM/Langfuse/PostHog report.

    Route gen_ai.usage.cost to a new COST outcome (registered before the
    gen_ai.usage. prefix rule) that sets the span's totalEstimatedCost
    directly, so the SDK/DAO treats it as authoritative and does not overwrite
    it with a recalculated estimate.

    Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

    • [OPIK-4909] [BE] fix: guard non-finite cost; consolidate cost tests

    Address Baz review:

    • extractCost now skips non-finite DOUBLE_VALUE inputs (NaN, +/-
      Infinity). BigDecimal.valueOf throws NumberFormatException for
      those, which would abort the whole span-enrichment loop instead of
      just dropping the cost.
    • Replace the two cost tests with one @ParameterizedTest +
      @MethodSource covering double, int, numeric string, non-numeric
      string, NaN, +Infinity, and -Infinity. Keep the regression test that
      guards against the original bug (cost leaking into the integer-only
      usage map).

    Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

    • [OPIK-4909] [BE] refactor: address cost extractor review feedback
    • Extract parseCostDouble / parseCostInt / parseCostString aux methods,
      each with a RuntimeException catch so cost extraction never aborts
      span enrichment.
    • Drop the explicit Double.isFinite guard; the try/catch now covers
      NaN/Infinity uniformly with the same Optional.empty() outcome.
    • Switch trim() to strip() (Unicode-aware) and bump the string-parse
      log to warn for consistency with the other branches.
    • Test: add newSpanBuilder() helper, fold the no-pollution regression
      into the parameterized test (now exercises the usage-map guard for
      every cost shape), and add a whitespace-strip case.
    • [OPIK-4909] [BE] chore: log exception in cost parse warnings

    Pass the caught RuntimeException to log.warn in parseCostDouble /
    parseCostInt / parseCostString so the stack trace is preserved for
    non-NumberFormatException cases now reachable via the wider catch.

    Keeps the RuntimeException catch per the prior review thread
    (comment 3324055545); only the logging gap is closed.

    • [OPIK-4909] [BE] test: build cost-test span via Podam

    Switch newSpanBuilder() to PodamFactoryUtils.newPodamFactory() +
    .manufacturePojo(Span.class).toBuilder() per the test guidelines,
    nulling out totalEstimatedCost so malformed-cost cases don't inherit
    PODAM's random BigDecimal (enrich only writes the field on a
    successful parse).


    Co-authored-by: Claude Opus 4.7 (1M context) noreply@anthropic.com

    下载附件