用 Opik 追踪 LLM 应用成本:从仪表盘到自动补算的完整思路

很多团队在做 LLM 应用时,前期注意力都放在效果上:回答准不准、工具调用顺不顺、用户体验好不好。等到项目慢慢跑起来,调用量上去了,才突然发现账单涨得比预期快。这时候再回头看,很难说清楚钱到底花在哪个模型、哪条链路、哪次请求上。成本问题表面看是财务问题,实际上更像个工程可观测性问题:如果没有把成本拆到每次调用、每条 trace、每个项目上,优化就无从下手。

Opik 在这方面的设计思路比较直接:通过测量所有 trace 的 token 使用量,来追踪和监控 LLM 应用的成本。它把成本估算结果统一以 USD 显示,方便团队在不同层级上分析花费模式,也能比较快地发现成本异常。下面从仪表盘、代码接口、手动补算、支持范围几个角度,把 Opik 的成本追踪能力梳理一遍。

在仪表盘里看成本:三个层级各有各的用处

Opik 的仪表盘可以在三个层级查看成本:span、trace 和 project。每个层级提供的视角不一样,适合的问题也不一样。

Span 级成本

单个 span 会显示每个 LLM span 的计算成本,单位是 USD。也就是说,一次 LLM 调用花了多少钱,在 span 这一层就能看到。

这个层级的价值在于定位。比如一个 Agent 在一次请求里调用了多个模型:一个负责意图识别,一个负责生成回答,一个负责总结。如果只看总成本,你不知道是哪个环节贵。拆到 span 级之后,就能看出是某个模型单价高,还是 token 用得多,或者是某次调用出现了异常长的输入输出。对于优化提示词、调整模型路由、限制上下文长度,span 级成本都是最细的依据。

Trace 级成本

如果你使用了 Opik 的某个集成,它会自动把一条 trace 内所有 span 的成本聚合起来,计算整条 trace 的总成本。

这个层级更贴近“一次用户请求”的成本。用户问一个问题,背后可能触发检索、工具调用、多轮模型生成,最终产生多个 span。trace 级成本把这些都加在一起,让你知道服务一个用户请求大概要花多少钱。对于按对话收费、按调用量估算预算、或者分析高成本用户行为,trace 级数据非常实用。

Project 级分析

想看整个项目的成本,Opik 提供了两个入口:

  1. 主项目视图里的 Estimated Cost 列:

  1. 项目 Metrics 标签页,这里会显示成本随时间变化的趋势:

项目级视图适合回答更宏观的问题:这周比上周多花了多少?上线新功能之后成本曲线有没有明显抬头?某个模型版本切换后整体花费是升了还是降了?如果配合时间维度看,很容易发现异常。比如某天成本突然翻倍,可能是流量涨了,也可能是某个提示词变长导致 token 暴涨,或者某个集成出现了重试循环。仪表盘把趋势摆出来,排查就有了起点。

用代码获取成本:span 和 trace 都能拿到

除了在界面上看,Opik 也允许通过代码获取估算成本。这一点对自动化报表、预算告警、内部计费系统都很有用。

需要注意的是,如果 span 或 trace 使用了不支持的模型,返回的成本会是 None。所以拿到结果后,最好先判断一下,避免直接参与计算导致报错。

获取 Span 成本

import opik

client = opik.Opik()

span = client.get_span_content("<SPAN_ID>")
# Returns estimated cost in USD, or None for unsupported models
print(span.total_estimated_cost)

这段代码通过 span ID 拿到 span 内容,然后读取 total_estimated_cost。如果模型受支持,会返回估算成本;如果不支持,就是 None

获取 Trace 成本

import opik

client = opik.Opik()

trace = client.get_trace_content("<TRACE_ID>")
# Returns estimated cost in USD, or None for unsupported models
print(trace.total_estimated_cost)

和 span 类似,trace 也有 total_estimated_cost。对于已经使用 Opik 集成的项目,这个值通常由内部 span 成本聚合而来。对于自建埋点的项目,就需要确保每个 LLM span 都带上了足够的信息,否则聚合结果可能不完整。

不用集成时,手动指定 provider、model 和 usage

如果你没有使用 Opik 的集成,Opik 仍然可以计算成本。前提是你要把关键信息传进去。具体来说,需要确保 span 类型是 llm,并且提供以下三项:

  1. provider:提供商名称,通常是 openaianthropicgoogle_ai 等。最新的提供商列表可以查看 opik.LLMProvider 枚举对象。
  2. model:模型名称。
  3. usage:这次 LLM 调用的输入、输出和总 token 数。

然后就可以在记录 trace 和 span 时把这些信息带上。根据使用方式不同,有两种写法。

函数装饰器

如果你用函数装饰器,需要在函数内部调用 update_current_span

from opik import track, opik_context

@track(type="llm") # Note - Specifying the type is this is important
def llm_call(input):
  opik_context.update_current_span(
    provider="openai",
    model="gpt-3.5-turbo",
    usage={
      "prompt_tokens": 4,
      "completion_tokens": 6,
      "total_tokens": 10
    }
  )
  return "Hello, world!"

llm_call("Hello world!")

这里有一个细节:@track(type="llm") 里的 type 很重要。只有把 span 类型标成 llm,Opik 才会按 LLM 调用来处理成本。否则它可能只被当成普通 span,成本计算就不会触发。

低层 Python SDK

如果你直接用低层 Python SDK,可以在 client.spantrace.span 方法里传入这些字段:

import opik

client = opik.Opik()

trace = client.trace(
  name="custom_trace",
  input={"text": "Hello world!"},
)

# Logging the LLM call
span = trace.span(
  name="llm_call",
  type="llm",
  input={"text": "Hello world!"},
  output={"response": "Hello world!"},
  provider="openai",
  model="gpt-3.5-turbo",
  usage={
    "prompt_tokens": 4,
    "completion_tokens": 6,
    "total_tokens": 10
  }
)

这种方式适合自己控制埋点流程的项目。你可以把 provider、model、usage 当成普通字段传进去,Opik 会根据内置的价格表去估算成本。对于已经有一套自定义日志系统的团队,这种低层接口更容易接入现有链路。

手动设置 Span 成本:自定义价格和补算的出口

有些时候,自动成本追踪不一定覆盖你的情况。比如用了尚未支持的模型、和供应商签了自定义价格、或者想跟踪模型使用之外的额外成本。这时候可以手动设置 span 成本。Opik 提供了两种方式,分别对应不同时机。

创建 Span 时直接设置成本

如果你在手动创建 span,可以在创建时就把成本写进去:

from opik import track, opik_context

@track
def llm_call(input):
  opik_context.update_current_span(
    total_cost=0.05,
  )
  return "Hello, world!"

llm_call("Hello world!")

这个例子直接把 total_cost 设成 0.05。适合你已经知道这次调用成本,或者内部有另一套计价逻辑,想直接覆盖 Opik 的估算值。

Span 完成后更新成本

使用 Opik 集成时,span 往往是自动创建、自动关闭的,打开期间没法更新。但你可以等它结束之后,用 update_span 方法回头更新成本。这种方式很适合实现周期性的成本估算任务。

下面是一个完整的示例。它定义了自己的 token 成本映射,然后扫描没有估算成本的 LLM span,计算并回填成本:

from opik import Opik
from opik.rest_api.types.span_public import SpanPublic

# Define your own cost mapping for different models
TOKEN_COST = {
    ("openai.chat", "gpt-4o-2024-08-06"): {
        "input_tokens": 2.5e-06,
        "output_tokens": 1e-05,
    }
}

# This part would be custom for your use-case and is only here for example
def compute_cost_for_span(span: SpanPublic):
    provider = span.provider or span.input.get("ai.model.provider")
    model = span.model or span.output.get("gen_ai.response.model")
    usage = span.usage

    if (provider, model) in TOKEN_COST:
        model_cost = TOKEN_COST[(provider, model)]
        cost = (
            usage["input_tokens"] * model_cost["input_tokens"]
            + usage["output_tokens"] * model_cost["output_tokens"]
        )
        return cost
    return None

def update_span_costs(project_name, trace_id=None):
    opik_client = Opik()

    # Find LLM spans that don't have estimated costs
    spans = opik_client.search_spans(
        project_name=project_name,
        trace_id=trace_id,
        filter_string='type="llm" and total_estimated_cost=0',
    )

    for span in spans:
        cost = compute_cost_for_span(span)

        if cost:
            print(f"Updating span {span.id} of trace {span.trace_id} with cost: {cost}")
            opik_client.update_span(
                trace_id=span.trace_id,
                parent_span_id=span.parent_span_id,
                project_name=project_name,
                id=span.id,
                total_cost=cost,
            )

# Example usage in a CRON job
if __name__ == "__main__":
    update_span_costs("your-project-name")

这段代码有几个关键点。第一,TOKEN_COST 是自定义的价格表,你可以按自己的合同价、汇率、折扣来填。第二,compute_cost_for_span 会从 span 里取 provider、model 和 usage,然后按输入、输出 token 分别计算。第三,search_spans 里用了过滤条件 type="llm" and total_estimated_cost=0,专门找那些还没有成本的 LLM span。第四,update_span 会把算出来的成本写回去,参数包括 trace_id、parent_span_id、project_name、id 和 total_cost。

这种方案特别适合以下场景:

  • 使用自动成本追踪尚未支持的模型或提供商;
  • 和提供商有自定义价格协议,内置价格表不适用;
  • 想跟踪模型使用之外的额外成本,比如存储、检索、第三方 API;
  • 需要把成本估算实现为后台进程,而不是阻塞主流程;
  • 使用的集成会自动管理 span,无法在创建时直接写入成本。

文档里还给了一个提示:可以把成本更新函数作为 CRON job 运行,自动更新那些没有成本信息的 span。在生产环境里,这一点很有价值。因为线上流量不会等你,任何漏算的成本如果没人补,最后都会变成一笔糊涂账。定时补算相当于给成本数据加了一层兜底。

支持的模型、提供商和集成

Opik 目前会为以下 Python SDK 集成中的所有 LLM 调用自动计算成本:

如果你正好用这些框架或 SDK,接入之后基本不用额外操心成本字段,Opik 会自己算。

支持的提供商

成本追踪支持以下 LLM 提供商,这些定义在 opik.LLMProvider 枚举里:

这些提供商下具体支持哪些模型,可以查看 model_prices_and_context_window.json 文件。价格表更新后,自动成本估算也会跟着变化。对于使用主流模型的团队,通常不需要自己维护价格。

文档里还有一句提示:Opik 正在积极扩展成本追踪支持。如果你需要额外的模型或提供商,可以开一个 feature request,帮助团队排优先级。这一点挺务实,因为模型市场变化太快,今天的热门模型明天可能就换了一批,靠官方单方面追进度不现实,用户反馈能加快覆盖速度。

写在最后

成本追踪这件事,很容易被当成上线之后才需要考虑的“运维问题”。但从实际经验看,越早把成本可视化,后面越省事。Opik 把成本拆到 span、trace、project 三个层级,既能看到单次调用的花费,也能看整体趋势;既支持集成自动计算,也允许通过 SDK 手动传入 provider、model、usage;对于不支持的模型或自定义价格,还能在创建时设置成本,或者事后用 update_span 补算。再加上 CRON job 这种兜底手段,成本数据不至于因为某个模型没覆盖就断掉。

对于正在做 LLM 应用的团队来说,比较稳妥的做法是:先把仪表盘用起来,知道钱花在哪;再用代码接口把成本接入内部报表或告警;最后针对不支持的模型和特殊价格,建立补算流程。这样一套组合下来,成本就不再是月底账单上的一个数字,而是可以拆解、可以比较、可以优化的工程指标。Opik 提供的这些能力,本质上就是让团队在效果和成本之间,有更清楚的判断依据。

大气污染是影响公众健康与生态环境的重要问题,精准的空气质量时空预测与污染源贡献度量化是精准治污的关键支撑。针对现有研究多源融合不充分、时空关联刻画不足、预测与源解析割裂三方面缺陷,本文设计实现了城市空气质量时空预测与污染源贡献度分析系统,融合监测、气象、工业排放与交通四类数据,构建基于时空注意力的LSTM(STAM-LSTM)预测模型与基于正定矩阵因子分解(PMF)的源解析模型,形成数据融合-特征工程-预测-源解析-可视化闭环。 系统实现四类数据时空对齐与融合,构建时序与空间邻域特征,以普通克里金插值生成1km网格浓度场;STAM-LSTM引入时空注意力自适应学习站点间污染传输时变权重,以72小时输入预测未来24小时逐小时PM2.5浓度;PMF识别交通、工业、燃煤、扬尘与二次生成五个源因子,量化各源全年贡献度并分析时空演变。 实验表明:STAM-LSTM预测RMSE 24.6、MAE 17.8、R² 0.88,相对LSTM基线(30.2)提升18.5%;普通克里金插值误差8.9,优于反距离加权(11.4);源解析显示交通源28.4%、工业源23.1%、燃煤源19.6%为主要贡献源,冬季燃煤源升至27.3%、早高峰交通源达34.8%,下风向工业源贡献高出上风向8~12个百分点;减排情景显示交通源减排20%可使年均PM2.5下降5.7%,与源贡献度排序一致。 系统按五模块14组件实现,功能测试16项用例全部通过,为大气污染预警、源管控与减排政策制定提供了决策依据。 【课程报告内容】 摘要 第1章 绪论 第2章 相关技术与理论 第3章 系统需求分析 第4章 系统总体设计 第5章 系统详细设计与实现 第6章 系统测试与分析 第7章 总结与展望 参考文献 附件-实现指南
基于iTransformer-BiGRU-KAN多模型融合的滚动轴承剩余寿命预测研究(Python代码实现)内容概要:本文提出了一种基于iTransformer-BiGRU-KAN多模型融合的滚动轴承剩余寿命预测方法,旨在通过结合多种先进深度学习模型的优势,提升在复杂工况下的预测精度与鲁棒性。该方法利用iTransformer捕捉长期时间序列中的全局依赖关系,通过BiGRU模型提取双向时序特征,最后引入KAN(Kernel Attention Network)增强非线性映射与关键特征的自适应加权能力,实现对轴承退化过程的精准建模。文中详细介绍了模型架构设计、训练流程及在公开数据集上的实验验证,结果表明该融合模型相比单一模型在预测精度和稳定性方面均有显著提升。; 适合人群:具备一定机器学习与深度学习基础,从事设备故障诊断、工业大数据分析或智能运维相关领域的研究人员及工程技术人员,尤其适合研究生及以上学历或有相关项目经验的专业人员。; 使用场景及目标:①应用于工业设备状态监测与预测性维护系统中,实现对滚动轴承等关键部件剩余寿命的精准预测;②为复杂时间序列回归任务提供多模型融合的设计思路与技术参考;③推动深度学习在智能制造与工业物联网领域的落地应用。; 阅读建议:建议读者结合Python代码实现部分,深入理解各子模型的接口设计与融合逻辑,重点关注特征融合机制与注意力权重的可视化分析,以便在实际项目中灵活调整与优化模型结构。
代码下载地址: https://pan.quark.cn/s/f675b88243cd 《华大HC32L110库函数与例程详解》 华大HC32L110属于低功耗且高性能的微控制器,在众多嵌入式系统设计中具有广泛的应用,特别是在需要电池供电的物联网设备和便携式装置中表现出色。该微控制器的库函数与例程为程序设计者提供了重要的参考资料,包含了丰富的功能接口和示范性代码,从而辅助开发者迅速掌握并运用该芯片。库函数是事先编写完成且可反复使用的代码单元,针对HC32L110的特定硬件特性进行了优化,使得开发者无需深入探究底层机制,仅需调用相应的库函数即可达成预期功能。这些库函数一般涵盖了时钟管理、GPIO操控、ADC转换、串行通信(包含UART、SPI、I2C等形式)以及中断管理等多个方面。比如,若需将一个GPIO端口设置为输出模式并设定其电平状态,开发者可通过调用`HAL_GPIO_Init()`与`HAL_GPIO_WritePin()`函数来实现。 例程则是展示如何运用库函数的应用范例代码,它们具体说明了在实际操作中如何适当地调用库函数及设定相关参数。以HC32L110的串行通信例程为例,它可能涉及初始化UART接口、传输数据、接收数据等环节,借助这些例程,开发者能够清晰地洞察每个功能的具体实现途径。对于新手而言,例程是理解芯片特性及库函数使用的理想途径。 在华大HC32L110的库函数与例程中,通常包含以下核心组成部分: 1. **初始化函数**:诸如`SystemInit()`,其作用是配置系统时钟,作为其他功能的基础。 2. **外设驱动函数**:例如GPIO的`HAL_GPIO_xxx()`系列函数,ADC的`HAL_ADC_xxx()`函数等,用于管理和设定...
【多变量输入超前多步预测】基于CNN-BiGRU的光伏功率预测研究(Matlab代码实现)内容概要:本文研究基于CNN-BiGRU混合神经网络模型的多变量输入超前多步光伏功率预测方法,并提供了完整的Matlab代码实现。该模型结合卷积神经网络(CNN)强大的局部特征提取能力和双向门控循环单元(BiGRU)对时间序列前后向依赖关系的建模能力,能够有效处理光伏发电受光照强度、温度、湿度等多因素影响的非线性、非平稳特性,实现对未来多个时间步长的功率输出进行精准预测。研究涵盖了数据预处理、模型构建、训练优化及结果分析全过程,并通过实验验证了模型在不同天气条件下的预测性能,展示了其在提升预测精度方面的有效性。; 适合人群:具备一定机器学习和时间序列预测基础知识,从事新能源发电预测、电力系统调度或相关领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①应用于光伏发电站的功率预测系统,为电网调度、能量管理和电力交易提供数据支持;②作为深度学习在可再生能源预测领域应用的教学案例,帮助理解CNN与RNN类模型的融合机制;③为进一步研究更复杂的预测模型(如加入注意力机制)提供基础框架和技术参考。; 阅读建议:建议读者结合Matlab代码逐步复现文中实验,重点关注数据预处理流程、模型结构设计细节以及超参数调优策略,同时可尝试在不同数据集上验证模型泛化能力,以深入掌握多变量时间序列预测的关键技术要点。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oscar999

送以玫瑰,手留余香

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值