按量计费的大模型 API,用起来总有点心理负担:月底账单一出才发现超预期,却说不清钱花在了哪次调用、哪个项目、哪段对话上。控制台的日志页是有的,但那是"事后查表"——不区分你的项目,也不在你跑代码的时候实时告诉你"这一轮 Agent 又花了几毛"。解决办法很简单:在客户端自己装一块电表。所有 OpenAI 兼容端点(官方、中转、自建网关)的响应里都自带用量字段,捞出来记账就行。
每次调用返回的 response.usage 里有 prompt_tokens(输入)、completion_tokens(输出),以及 prompt_tokens_details.cached_tokens(命中缓存的部分——这是省钱大头,很多端点对缓存命中只收标准价几个百分点的费用)。这些字段够还原每一次调用的成本,缺的只是有人把它们存下来。
```python
from openai import OpenAI
from functools import wraps
import sqlite3, time, json
client = OpenAI(
base_url="https://api.julanjing.com/v1", # 任意 OpenAI 兼容端点
api_key="sk-xxxxxxxx",
)
db = sqlite3.connect("llm_meter.db")
db.execute("""CREATE TABLE IF NOT EXISTS calls(
ts REAL, tag TEXT, model TEXT, prompt_t INT,
cached_t INT, completion_t INT, latency REAL)""")
def metered(tag=""):
def deco(fn):
@wraps(fn)
def wrapper(*a, **kw):
t0 = time.time()
r = fn(*a, **kw)
u = r.usage
db.execute("INSERT INTO calls VALUES(?,?,?,?,?,?,?)", (
t0, tag, r.model,
u.prompt_tokens,
getattr(u.prompt_tokens_details, "cached_tokens", 0) or 0,
u.completion_tokens, time.time() - t0))
db.commit()
return r
return wrapper
return deco
@metered(tag="agent-demo")
def ask(prompt):
return client.chat.completions.create(
model="glm-5.3-flash",
messages=[{"role": "user", "content": prompt}])
```tag 按项目或实验名打标,是后面归因的关键——同一个 Key 跑五个项目,月底谁欠谁的钱一目了然。
```python
import pandas as pd
df = pd.read_sql("SELECT * FROM calls", db,
parse_dates={"ts": "s", "utc": True})
print(df.assign(day=df.ts.dt.date)
.groupby(["day", "tag", "model"])
.agg(次数=("model", "size"),
输入token=("prompt_t", "sum"),
缓存命中=("cached_t", "sum"),
输出token=("completion_t", "sum"),
平均耗时秒=("latency", "mean")))
```要折算成钱,加一列单价即可——单价从你所用端点的价格页抄进一个字典,倍率换算各家不同,这里不预设。跑批任务前,先用一条真实请求校准"每条大概多少 token",乘上总量就是预算,比拍脑袋准得多。
【此处插入:按天聚合的读表输出截图】
这块电表记在你本地,账本本身别往第三方服务传;它也不替代端点控制台的日志——对不上数时以控制台为准,通常是某处裸调没包装饰器。另外,单价字典要跟着端点的价格页更新,模型调价不通知你。
计费焦虑的根源不是贵,是不透明。两段代码、一张本地表,把"这个月大模型花了多少"从玄学变成可以 groupby 的问题。电表装上之后,反而敢放开用了——因为每一毛钱都有去处。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。