Signals

成本

概览参考
每判定 10 万个事件约 6 美元,每分钟 1,200 次调用,被保留事件在 drain 前最多等待 2 秒,以及离开进程的事件内容。每项都有对应的调节手段。

下面按影响出现的顺序列出四种成本。每种成本旁边都有调节手段,而且都会“故障开放”:达到限制时,事件会未经判定直接通过,请求路径不会等待。

默认值调节手段
费用每百万输入 token 0.042 美元,每判定 10 万个事件约 6 美元when、cacheKey、state
速率每个账号每分钟 1,200 次调用budget.perMinute、cacheKey
延迟keep 事件在 drain 前最多等待 2 秒,客户端不受影响timeoutMs、更严格的 when
出站数据脱敏前的完整事件state、providerOptions.gateway.zeroDataRetention

费用

Jev 只按输入 token 计费,本文撰写时的价格是每百万个 token 0.042 美元。概览中的 15 个请求成本为 0.00007 美元。一个包含 1.5k token 的事件约为 0.00006 美元,因此 10 万个判定事件约为 6 美元,一百万个约为 60 美元。价格会变化;模型页面提供当前数值。

决定账单的是到达模型的事件数量,而不是你定义了多少 signal。一个事件需要运行的所有 signal 共享一次调用,因此向已经运行的 signal 添加问题几乎不产生额外成本:

what gets billed·idle
eventmodel
GET/api/products200
no call
POST/api/checkout200
1 call
POST/api/checkout502
1 call
GET/api/health200
no call
POST/api/checkout502
cached
POST/api/checkout502
cached
GET/api/orders500
1 call
events0
questions0
model calls0
from cache0
  • when 是第一种调节手段。在 status >= 400 时运行的 fault 不会在成功请求上产生费用。
  • cacheKey 是第二种。一次故障会产生数千个相同的 502;使用 path + error.name 作为键可以将其合并为一次调用,其余请求从缓存获取结果。
  • state 是第三种。默认发送完整事件。只选择问题需要的六个字段可以减少 token,也能同时解决下面的出站数据问题。

速率

在费用限制之前生效的是账号速率:每个 TypeSafe 账号每分钟 1,200 个请求,即每秒约 20 个。budget.perMinute(默认值 600)是每个进程固定的一分钟窗口,因此一个账号有四个实例时应设置为 300。超过窗口后,事件会未经判定直接通过,stats().skipped 会增加。

失败调用会打开持续 budget.cooldownMs(默认 30 秒)的断路器,因此模型返回 429 或发生故障时,结果会出现 30 秒的空档,而不是形成队列。

延迟

keep signal 会在采样决策前运行并等待判定,最长等待 timeoutMs(默认 2 秒)。两点让这通常可以接受:

  • 响应已经发送。keep 和 enrich 在请求结束后运行,因此客户端永远不会等待模型。
  • 事件上的 durationMs 是请求持续时间,在 keep 钩子运行前测量。判定不会抬高你的延迟图表。

它会延迟事件到达 drain 的时间,延迟量是模型往返时间。Keep signal 应该用于狭窄路径(例如 /api/checkout,而不是每个 200 响应),只有 enrich 的 signal 不会产生这种等待。

出站数据

模型读取 state 提供的内容。默认情况下,这是去掉 signals 列的完整宽事件;对于 keep signal,则是脱敏运行之前的请求上下文。如果处理程序记录了你不会粘贴到第三方 API 的内容,请设置 state 选择字段:

createSignals({
  signals,
  state: e => ({ status: e.status, path: e.path, durationMs: e.durationMs, error: e.error, payment: e.payment }),
  providerOptions: { gateway: { zeroDataRetention: true } },
})

zeroDataRetention 会原样传递给 AI Gateway。推理在你的进程中使用你的密钥运行;evlog 不保存密钥,也不代理任何内容。

不会发生的事情

  • keep signal 永远不会丢弃事件。它只会提升保留级别,头部采样仍然是确定性的。
  • 判定永远不是散文。列是带概率的类型化值,除非你主动要求(stampModel),否则不会向事件添加其他内容。
  • 达到限制永远不会表现为错误。预算耗尽、断路器打开、状态过大或模型不可用时,事件仍会像没有 signals 时一样 drain,只有 stats() 中的计数器会变化。