[控场AI]
· 8 分钟阅读· 4,461 字

给 n8n 工作流装成本账本:LLM 调用逐次计价实战

给 n8n 工作流装成本账本:LLM 调用逐次计价实战

在每个 LLM 调用后写入一行成本记录,用日支出与自身中位数的比值告警,把月度账单盲盒变成每日可行动信号。

文章针对多工作流调用大模型时成本不可见的问题,提出一套轻量级成本账本方案。n8n 原生只按单次执行记录 token 用量,缺少按工作流的聚合与归因,导致提示词或重试策略的小改动可能悄悄使成本翻倍,却要等月底发票才能发现。方案在每个模型调用节点后接一个统一结构的 Cost 节点,把模型、token 数、美元成本和执行 id 写入 cost_log 表,价格表内嵌在节点中以避免拖慢工作流。每日定时查询计算各工作流当日支出与其 7 天中位数的比值,spike_ratio >= 2.0 即发 Slack 告警。一个真实案例中,放宽重试策略导致某工作流成本比值达 3.1,账本让作者次日早晨就收紧条件。账本只提供可见性,不解释原因,也不做精确核算;超大规模下可采样并同步调整告警分母。

当账单成为唯一线索

同时跑着十一个调用大模型的工作流,月底只收到一张 API 总账单,中间什么都没记录。作者的经历很有代表性:某次“优化”分类提示词之后,模型开销一夜翻了三倍,但直到三十天后收到发票才发现问题。

n8n 成本账本方案来源

这不是个例。n8n 的执行日志确实记录了部分 AI 节点的 token 用量,但藏在单次运行的执行数据里,必须一条一条点开看。没有聚合、没有按节点归因、没有趋势线。发票告诉你总数,却没人告诉你分布。而分布恰恰是意外发生的地方——问题很少出在总量上涨,而是某个工作流在悄悄变贵。

作者的 inbox triage agent 就从每天 0.4 美元慢慢爬到了 1.3 美元。原因:所谓“改进”后的分类提示词变长了 2.4 倍,还为“边界情况”加了第二次模型调用。工作流运行正常,只是正常得很贵。

账本设计:每次 LLM 调用后接一个 Cost 节点

核心设计刻意做得无聊:每一个调用模型的节点——OpenAI 节点、Anthropic 节点,或者指向推理端点的 HTTP 请求——后面都紧跟着一个 Cost 节点。它是一个结构统一的 Code 节点,每次调用写入一行记录:

// Cost node: append one row per LLM call
const call = $input.first().json;
const PRICE = {
  'gpt-4o-mini':        { in: 0.15,  out: 0.60  },   // USD per 1M tokens
  'gpt-4o':             { in: 2.50,  out: 10.00 },
  'claude-3-5-sonnet':  { in: 3.00,  out: 15.00 },
  'claude-3-5-haiku':   { in: 0.80,  out: 4.00  },
};
const p = PRICE[call.model];
const row = {
  run_id:     $execution.id,          // n8n execution id
  event_id:   call.event_id,          // my own correlation key
  workflow:   $workflow.name,
  node:       call.node_name,
  model:      call.model,
  in_tokens:  call.usage.prompt_tokens,
  out_tokens: call.usage.completion_tokens,
  usd:        (call.usage.prompt_tokens * p.in +
                call.usage.completion_tokens * p.out) / 1e6,
  ts:         new Date().toISOString()
};
// insert into cost_log (run_id, event_id, workflow, node, model, in_tokens, out_tokens, usd, ts)

有三个关键细节:

价格表放在节点里,不放在配置里。 价格变动很少,改一次共享的 Code 片段就行(它被做成一个共享子工作流,到处导入)。作者不想在模型调用和日志写入之间插入一次数据库查询——账本绝不能拖慢或中断它所观察的工作流。

记录的是真实的模型调用,而不是估算。 token 数量来自 API 响应的 usage 字段,不是数提示词里的词。如果某个提供商不返回 usage(有些代理端点就不返回),节点会写入 in_tokens: null 并打上 usd_estimated 标记,估算行永远不会进入告警查询,只进仪表盘。

每个 AI 工作流都得配一个,没有例外。 那些“几乎不调用模型”的工作流,恰恰是改一次提示词就悄悄让 token 数量翻倍的典型。

n8n 是一个开源的工作流自动化平台,通过可视化节点连接的方式编排任务,并支持条件分支、循环、重试等控制流。在 AI 场景中,它可以调用 OpenAI、Anthropic 等节点,或通过 HTTP Request 节点访问任意推理端点。每个工作流的一次运行称为一个 execution,n8n 会为其分配一个 execution id,并记录每个节点的输入输出。本文的 Cost 节点正是利用 $execution.id、$workflow.name 等内置变量,把调用上下文与成本行绑定在一起。由于 n8n 原生的执行日志只按单次运行存储 token 用量,无法跨运行聚合,所以需要把数据外写到数据库表 cost_log 中,才能做按工作流的趋势与异常分析。

每日查询:和自己的中位数比

一个定时工作流每天 07:00 运行以下查询,把结果发到 Slack:

-- daily spend per workflow, vs its own 7-day median
WITH daily AS (
  SELECT workflow, DATE(ts) AS d, SUM(usd) AS spend
  FROM cost_log WHERE ts >= NOW() - INTERVAL 14 DAY
  GROUP BY workflow, DATE(ts)
),
medians AS (
  SELECT workflow, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY spend) AS med
  FROM daily WHERE d < CURRENT_DATE GROUP BY workflow
)
SELECT d.workflow, d.spend, m.med,
       ROUND(d.spend / NULLIF(m.med, 0), 2) AS spike_ratio
FROM daily d JOIN medians m ON d.workflow = m.workflow
WHERE d.d = CURRENT_DATE - 1;

告警规则只有一行:spike_ratio >= 2.0 就发 Slack 告警,附带工作流名称和昨日支出。

注意比的不是总支出,而是跟自己中位数的比值。一个平时 0.3 美元、突然变成 0.9 美元的工作流,和一个平时 30 美元、突然变成 90 美元的工作流,是同一类问题——都意味着有东西变了,但没人审查过。

早晨的摘要是一张表,不是图表:工作流、昨日支出、7 天中位数、比值。作者配着咖啡三十秒读完。图表留给季度回顾,表格留给周二早上。

PERCENTILE_CONT(0.5) 是 SQL 标准中的连续百分位函数,0.5 即中位数。与平均值相比,中位数对极端值不敏感:如果某天工作流因异常重试而支出飙升,平均值会被拉高,导致后续告警阈值失真;中位数则能稳定代表“典型日”的支出水平。查询中 WITHIN GROUP (ORDER BY spend) 指定排序依据,配合 GROUP BY workflow 为每个工作流单独计算。此外,WHERE d < CURRENT_DATE 排除了当天数据,避免不完整的当日支出拉低基线;限定 14 天窗口则是在样本量与时效性之间取平衡,既能容纳周末波动,又能跟上近期的使用模式变化。

一次让整套系统回本的告警

接好账本两周后,告警在 repurposing 工作流上触发:spike_ratio 为 3.1,当日 2.10 美元,中位数 0.68 美元。

原因是前一天改的重试策略——把重试范围放宽到了更大一类失败。更宽的重试意味着工作流会在原本直接终止的失败上,重跑它最贵的两次模型调用。这个重试改动对可靠性来说是正确的,但它同时悄悄地带来了 3 倍的成本变化。

没有账本,这件事要等下个月发票才能知道;有了账本,作者是在喝咖啡时发现,当天早上就收紧了重试条件。

这就是整个价值主张:账本不降低成本,它把“发票涨了”(月度、无法行动)转换成“这个工作流昨天行为变了”(每日、可行动)。成本控制来自可见性,而可见性就是账本做的全部事情。

在自动化工作流中,重试策略通常指定“当某类错误发生时,自动重新执行失败节点”。把重试范围从窄集合放宽到更大一类失败,会显著提高重试次数。如果失败发生在调用大模型之后,重试往往需要重新执行该调用,而大模型调用按 token 计费,因此每一次额外重试都意味着真实的美元成本。特别是当失败发生在工作流的后半段时,重试可能需要重跑前面最贵的两次调用,成本会成倍叠加。这种“为了可靠性而放宽重试”的改动,在功能测试中通常不会暴露成本问题,因为测试很少覆盖高频失败场景。只有按工作流维度、对比历史中位数的成本账本,才能把这类隐性成本变化转化为可行动告警。

账本不能做什么

它不是精确核算。来自 usage 的 token 数量是精确的,但价格表是一个快照,会随提供商调价而漂移。账本回答的是“哪个工作流、大致多少、趋势朝哪走”——它是仪表盘,不是纳税申报单。

它不是提示词优化器。它永远不会告诉你某个工作流为什么变贵——重试那次事件,还是得靠人去读 diff。账本把搜索范围缩小到一个工作流、一天。诊断仍然是人的工作。

它也不是免费的:每次模型调用现在都要写一行数据库记录。以作者的量级,每天几百行,可以忽略。如果你每天要跑几百万次调用,就采样(记录百分之一,然后乘以倍数)。这个模式经得起采样,只要在告警规则的分母里带上采样率。

把成本变成可行动的信号

这套方案的启发不在于非要用 n8n,而在于一个更通用的思路:在模型调用和账单之间,必须存在一个观测层。 只靠供应商发票做成本管理,本质上是月度盲盒;而在每个调用点写一行结构化成本记录,就能把不可行动的账单转成每日可行动的异常。

对个人开发者和小团队来说,在自建 Agent 编排、自动化流水线时,值得在架构里预留一个类似的 Cost 节点位。它不需要复杂,几百行代码就够,但它能把“这个月怎么这么贵”变成“昨天这个工作流为什么变贵了”。

#n8n 成本监控#LLM 成本追踪#n8n 工作流#AI 自动化成本#token 用量监控#成本告警#LLM API 账单管理
分享:

相关推荐