预算
项目级成本上限。调用前估算超限时提前抛出异常;调用后记录实际费用。
预算
budget(maxCostUsd) 为你的项目设置成本上限。JamJet 分两个阶段执行:调用前估算会在预计支出超过上限时立即抛出异常,甚至不会联系 LLM;调用后记录则根据 response.usage 的实际成本更新累计总额。
设置预算
向 budget() 传递一个正数美元金额。在 init() 之后,在启动时调用一次。
import { init, budget, wrap } from '@jamjet/cloud'
import OpenAI from 'openai'
init({ apiKey: process.env.JAMJET_API_KEY!, project: 'my-app' })
budget(50) // 此项目的 $50 上限
const openai = wrap(new OpenAI())import jamjet.cloud as jamjet
from openai import OpenAI
import os
jamjet.configure(api_key=os.environ['JAMJET_API_KEY'], project='my-app')
jamjet.budget(max_cost_usd=50) # 此项目的 $50 上限
client = jamjet.wrap(OpenAI())预算适用于进程中所有封装的调用。它是按进程计算的,而非按 API 密钥——使用相同密钥的不同进程各自拥有独立的上限。
调用前估算
在向 LLM 发送请求之前,JamJet 会根据提示词的 token 数量,使用模型价格表估算调用成本。如果预计总支出(进程生命周期内的累计值)超过上限,会立即抛出 JamjetBudgetExceeded 异常——不会调用 LLM,也不会产生任何费用。
import { JamjetBudgetExceeded } from '@jamjet/cloud'
try {
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: 'Long prompt...' }],
})
} catch (err) {
if (err instanceof JamjetBudgetExceeded) {
console.error(
`预算已超。已用:$${err.spent.toFixed(4)},上限:$${err.limit.toFixed(2)}`
)
}
}from jamjet.cloud.errors import JamjetBudgetExceeded
try:
response = client.chat.completions.create(
model='gpt-4o',
messages=[{'role': 'user', 'content': 'Long prompt...'}],
)
except JamjetBudgetExceeded as err:
print(f'预算已超。已用:${err.spent:.4f},上限:${err.limit:.2f}')JamjetBudgetExceeded 字段
| 字段 | 类型 | 描述 |
|---|---|---|
spent | number | 当前进程中累计记录的 USD 消费 |
limit | number | 通过 budget() 设置的上限 |
两个值均以 USD 计。spent 反映了之前调用的实际事后成本加上触发异常的调用的事前估算。
事后记录
当调用成功完成时,JamJet 从响应中读取 response.usage.input_tokens 和 response.usage.output_tokens,使用相同的价格表计算实际成本,并更新累计总额。事前估算值会被跨度中的实际成本替换。
这意味着累计总额始终基于 API 的实际计费数据,而非仅仅估算值。
修改上限
随时再次调用 budget(N) 以替换当前上限。累计总额不会重置——仅上限发生变化。要有效重置,请将新上限设置为当前限额加上您希望允许的额外消费金额。
// 初始上限
budget(50)
// ... 在获得人工操作员批准后 ...
// 将上限提高至 $100
budget(100)# 初始上限
jamjet.budget(max_cost_usd=50)
# ... 在获得人工操作员批准后 ...
# 将上限提高至 $100
jamjet.budget(max_cost_usd=100)模型识别限制
JamJet 使用以模型名称(例如 gpt-4o、claude-3-5-sonnet-20241022)为键的内部价格表。如果请求中的模型名称不在表中——例如新发布的模型或自定义微调模型——估算成本将被视为 $0。
$0 估算意味着预算门会有效允许调用,即使实际计费可能很高。事后记录仍会使用实际成本更新累计总额,因此后续调用将被准确地进行门控检查。
要验证您的模型是否被识别,请检查控制面板跨度中已完成调用的非零 cost_usd 值。如果对于应计费的模型显示 $0.0000,请打开项目设置并提交模型表更新请求。
综合示例
import OpenAI from 'openai'
import { init, budget, wrap, JamjetBudgetExceeded } from '@jamjet/cloud'
init({ apiKey: process.env.JAMJET_API_KEY!, project: 'research-pipeline' })
budget(5) // $5 硬性上限 — 适用于开发环境
const openai = wrap(new OpenAI())
async function runResearch(prompt: string): Promise<string | null> {
try {
const res = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: prompt }],
})
return res.choices[0].message.content
} catch (err) {
if (err instanceof JamjetBudgetExceeded) {
console.warn(`研究已暂停 — 预算已耗尽 ($${err.spent.toFixed(4)} / $${err.limit})`)
return null
}
throw err
}
}from openai import OpenAI
import jamjet.cloud as jamjet
from jamjet.cloud.errors import JamjetBudgetExceeded
import os
jamjet.configure(api_key=os.environ['JAMJET_API_KEY'], project='research-pipeline')
jamjet.budget(max_cost_usd=5) # $5 硬性上限 — 适用于开发环境
client = jamjet.wrap(OpenAI())
def run_research(prompt: str) -> str | None:
try:
res = client.chat.completions.create(
model='gpt-4o',
messages=[{'role': 'user', 'content': prompt}],
)
return res.choices[0].message.content
except JamjetBudgetExceeded as err:
print(f'研究已暂停 — 预算已耗尽 (${err.spent:.4f} / ${err.limit})')
return None